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

@ -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: