Add 'listto' to fndata.txt; remove more magic names from the code

Rather than using a hardcoded table of list-to-type extraction function, add a 'ListTo' attribute to the function data. No error is raised if more than one function exists to convert to the same type.

This change is of questionable usefulness, but it should soothe those allergic to magic names/numbers. I cringed a bit myself.

While on it, change the syntax error that was raised when the corresponding conversion function did not exist, to a tailor-made error.
This commit is contained in:
Sei Lisa 2018-12-22 15:44:14 +01:00
parent a052bf499c
commit 0855b8ad1d
3 changed files with 70 additions and 45 deletions

View file

@ -75,6 +75,10 @@
# max:
# Like min, but for the maximum value.
#
# listto:
# Identifies the function as a list-extracting function, for use with
# lazy lists. It needs an LSL type as a parameter.
#
# return <value> [if <condition>]:
# Self-explanatory. There can be several; they are evaluated in order.
# <value> can be a parameter or a LSL constant. <condition> is explaned
@ -927,30 +931,37 @@ string llList2CSV(list src)
float llList2Float(list src, integer index)
- SEF
- listto float
integer llList2Integer(list src, integer index)
- SEF
- listto integer
string llList2Json(string type, list values)
- SEF
key llList2Key(list src, integer index)
- SEF
- listto key
list llList2List(list src, integer start, integer end)
- SEF
- listto list
list llList2ListStrided(list src, integer start, integer end, integer stride)
- SEF
rotation llList2Rot(list src, integer index)
- SEF
- listto rotation
string llList2String(list src, integer index)
- SEF
- listto string
vector llList2Vector(list src, integer index)
- SEF
- listto vector
integer llListFindList(list src, list test)
- SEF

View file

@ -235,7 +235,9 @@ def LoadLibrary(builtins = None, fndata = None):
r'|\[(?:[^]"]|"(?:\\.|[^"])*")*\]))' # lists
r'(?:\s+if\s+(.*\S))?'
r'|(unstable|stop|strlen|detect|touch|grab)'
r'|(min|max|delay)\s+([-0-9.]+))\s*$', re.I)
r'|(min|max|delay)\s+([-0-9.]+)'
r'|listto\s+(integer|float|string|key|vector|rotation|list)'
r')\s*$', re.I)
# TODO: "quaternion" doesn't compare equal to "rotation" even if they are
# equivalent. Canonicalize it before comparison, to avoid false
@ -382,44 +384,50 @@ def LoadLibrary(builtins = None, fndata = None):
functions[curr_fn]['uns'] = True
else:
functions[curr_fn][flag] = True
elif match_flag.group(5).lower() in ('min', 'max'):
minmax = match_flag.group(5).lower()
value = match_flag.group(6)
typ = functions[curr_fn]['Type']
if typ == 'integer':
good = parse_int_re.search(value)
elif match_flag.group(5):
if match_flag.group(5).lower() in ('min', 'max'):
minmax = match_flag.group(5).lower()
value = match_flag.group(6)
typ = functions[curr_fn]['Type']
if typ == 'integer':
good = parse_int_re.search(value)
if good:
value = lslfuncs.S32(int(good.group(1), 0))
elif typ == 'float':
good = parse_fp_re.search(value)
if good:
value = lslfuncs.F32(float(good.group(1)))
else:
good = False
if good:
value = lslfuncs.S32(int(good.group(1), 0))
elif typ == 'float':
good = parse_fp_re.search(value)
if good:
value = lslfuncs.F32(float(good.group(1)))
else:
good = False
if good:
functions[curr_fn][minmax] = value
else:
warning(u"Type mismatch or value error in %s"
u" line %d: %s"
% (ufndata, linenum, uline))
continue
else: # delay
value = parse_fp_re.search(match_flag.group(6))
if not value:
warning(u"Invalid delay value in %s"
u" line %d: %s"
% (ufndata, linenum, uline))
continue
functions[curr_fn][minmax] = value
else:
warning(u"Type mismatch or value error in %s"
u" line %d: %s"
% (ufndata, linenum, uline))
continue
else: # delay
value = parse_fp_re.search(match_flag.group(6))
if not value:
warning(u"Invalid delay value in %s"
u" line %d: %s"
% (ufndata, linenum, uline))
continue
value = float(value.group(1)) # no need to F32
if value != 0 and 'SEF' in functions[curr_fn]:
warning(u"Side-effect-free function"
u" %s contradicts delay, in %s"
u" line %d"
% (ucurr_fn, ufndata, linenum))
continue
value = float(value.group(1)) # no need to F32
if value != 0 and 'SEF' in functions[curr_fn]:
warning(u"Side-effect-free function"
u" %s contradicts delay, in %s"
u" line %d"
% (ucurr_fn, ufndata, linenum))
continue
functions[curr_fn]['delay'] = value
functions[curr_fn]['delay'] = value
elif match_flag.group(7):
functions[curr_fn]['ListTo'] = match_flag.group(7)
continue
else:
pass
else:
warning(u"Syntax error in %s line %d, skipping: %s"
% (ufndata, linenum, uline))

View file

@ -200,6 +200,11 @@ class EParseInvalidLabelOpt(EParse):
u" child of a 'for', 'if', 'while' or 'do'. Disable optimization"
u" or rewrite the code in some other way.")
class EParseNoConversion(EParse):
def __init__(self, parser):
super(EParseNoConversion, self).__init__(parser,
u"There's no conversion function in the library for this type")
class EInternal(Exception):
"""This exception is a construct to allow a different function to cause an
immediate return of EOF from parser.GetToken().
@ -225,9 +230,7 @@ class parser(object):
unicode:'STRING_VALUE', Key:'KEY_VALUE', Vector:'VECTOR_VALUE',
Quaternion:'ROTATION_VALUE', list:'LIST_VALUE'}
TypeToExtractionFunction = {'integer':'llList2Integer',
'float':'llList2Float', 'string':'llList2String', 'key':'llList2Key',
'vector':'llList2Vector', 'rotation':'llList2Rot', 'list':'llList2List'}
TypeToExtractionFunction = {}
# Utility function
def GenerateLabel(self):
@ -1316,14 +1319,11 @@ list lazy_list_set(list L, integer i, list v)
expr = self.Parse_unary_postfix_expression(AllowAssignment = False)
basetype = expr.t
if self.lazylists and basetype is None and expr.nt == 'SUBIDX':
if typ not in self.TypeToExtractionFunction:
raise EParseNoConversion(self)
fn = self.TypeToExtractionFunction[typ]
sym = self.FindSymbolFull(fn, 0)
if sym is None:
# in the unlikely event that the underlying function is not
# defined in builtins.txt, throw a syntax error (making a
# new exception just for this seems overkill, and throwing
# an unknown identifier error would be confusing)
raise EParseSyntax(self)
assert sym is not None
fnparamtypes = sym['ParamTypes']
subparamtypes = [x.t for x in expr.ch]
if fnparamtypes != subparamtypes:
@ -2713,6 +2713,12 @@ list lazy_list_set(list L, integer i, list v)
self.constants = lib[1]
self.funclibrary = lib[2]
self.TypeToExtractionFunction.clear()
for name in self.funclibrary:
fn = self.funclibrary[name]
if 'ListTo' in fn:
self.TypeToExtractionFunction[fn['ListTo']] = name
self.filename = filename
if type(script) is unicode: