diff --git a/fndata.txt b/fndata.txt index a4eb2a0..1ae18e3 100644 --- a/fndata.txt +++ b/fndata.txt @@ -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 [if ]: # Self-explanatory. There can be several; they are evaluated in order. # can be a parameter or a LSL constant. 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 diff --git a/lslopt/lslloadlib.py b/lslopt/lslloadlib.py index 3efb269..d91e068 100644 --- a/lslopt/lslloadlib.py +++ b/lslopt/lslloadlib.py @@ -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)) diff --git a/lslopt/lslparse.py b/lslopt/lslparse.py index ece5526..86ac786 100644 --- a/lslopt/lslparse.py +++ b/lslopt/lslparse.py @@ -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: