diff --git a/lslopt/lsllastpass.py b/lslopt/lsllastpass.py new file mode 100644 index 0000000..e03a1ae --- /dev/null +++ b/lslopt/lsllastpass.py @@ -0,0 +1,102 @@ +# (C) Copyright 2015-2017 Sei Lisa. All rights reserved. +# +# This file is part of LSL PyOptimizer. +# +# LSL PyOptimizer is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# LSL PyOptimizer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LSL PyOptimizer. If not, see . + +# Optimizations that have a negative effect on other stages. + +import lslcommon +#from lslcommon import Vector, Quaternion +#import lslfuncs +#from lslfuncs import ZERO_VECTOR, ZERO_ROTATION +#import math +#from lslparse import warning +#from lslfuncopt import OptimizeFunc, OptimizeArgs, FuncOptSetup + +class lastpass(object): + def LastPassPreOrder(self, parent, index): + node = parent[index] + nt = node['nt'] + child = node['ch'] if 'ch' in node else None + + if (self.optlistadd and not self.globalmode + and (nt == 'CONST' and node['t'] == 'list' or nt == 'LIST' + or nt == '+' and child[0]['t'] == 'list' and + (child[1]['nt'] == 'CONST' and child[1]['t'] == 'list' + or child[1]['nt'] == 'LIST') + ) + ): + # Perform these transformations if the list is SEF: + # [a, b, ...] -> (list)a + b... + # ListExpr + [a, b, ..] -> ListExpr + a + b... + # (ListExpr doesn't need to be SEF for this to work) + + # This transformation makes it difficult to handle lists during + # optimization, that's why it's done in a separate pass. + top = child[0] if nt == '+' else None + elemnode = child[1] if nt == '+' else node + if 'SEF' in elemnode: + elements = (elemnode['value'] if elemnode['nt'] == 'CONST' + else elemnode['ch']) + for v in elements: + elem = v if elemnode['nt'] != 'CONST' else { + 'nt':'CONST', + 't':lslcommon.PythonType2LSL[type(v)], + 'SEF':True, + 'value':v} + top = {'nt':'CAST', 't':'list', 'SEF':True, + 'ch':[elem] + } if top is None else { + 'nt':'+', 't':'list', 'SEF':True, + 'ch':[top, elem] + } + del elem + if top is not None: + parent[index] = top + nt = top['nt'] + # Do another pass on the result + self.RecursiveLastPass(parent, index) + del top + return + + def LastPassPostOrder(self, parent, index): + pass + + def RecursiveLastPass(self, parent, index): + self.LastPassPreOrder(parent, index) + + if 'ch' in parent[index]: + child = parent[index]['ch'] + idx = 0 + while idx < len(child): + self.RecursiveLastPass(child, idx) + idx += 1 + + self.LastPassPostOrder(parent, index) + + def LastPass(self): + self.globalmode = False + + tree = self.tree + + # Last optimizations pass + for idx in xrange(len(tree)): + if tree[idx]['nt'] == 'DECL': + self.globalmode = True + self.RecursiveLastPass(tree, idx) + self.globalmode = False + else: + self.RecursiveLastPass(tree, idx) + pass diff --git a/lslopt/lsloptimizer.py b/lslopt/lsloptimizer.py index c53f5dd..7492463 100644 --- a/lslopt/lsloptimizer.py +++ b/lslopt/lsloptimizer.py @@ -22,8 +22,9 @@ import lslfuncs from lslfoldconst import foldconst from lslrenamer import renamer from lsldeadcode import deadcode +from lsllastpass import lastpass -class optimizer(foldconst, renamer, deadcode): +class optimizer(foldconst, renamer, deadcode, lastpass): # Default values per type when declaring variables DefaultValues = {'integer': 0, 'float': 0.0, 'string': u'', @@ -67,6 +68,7 @@ class optimizer(foldconst, renamer, deadcode): self.constfold = 'constfold' in options self.optlistlength = 'listlength' in options + self.optlistadd = 'listadd' in options self.dcr = 'dcr' in options # Math that works fine except in rare corner-cases can be optimized. @@ -88,6 +90,8 @@ class optimizer(foldconst, renamer, deadcode): if self.constfold: self.FoldScript(warningpass=True) + self.LastPass() + if self.shrinknames: self.ShrinkNames() diff --git a/main.py b/main.py index 5bc8514..8648af8 100755 --- a/main.py +++ b/main.py @@ -290,6 +290,7 @@ Case insensitive. take memory. ListLength + Optimize llGetListLength(arg) to arg!=[]. Needs constant folding active to work. + ListAdd + Convert [a,b,c...] to (list)a + b + c... if possible. Miscellaneous options @@ -326,7 +327,7 @@ validoptions = frozenset(('extendedglobalexpr','breakcont','extendedtypecast', 'extendedassignment','allowkeyconcat','allowmultistrings','duplabels', 'lazylists','enableswitch','errmissingdefault','funcoverride','optimize', 'optsigns','optfloats','constfold','dcr','shrinknames','addstrings', - 'foldtabs','warntabs','processpre','explicitcast','listlength', + 'foldtabs','warntabs','processpre','explicitcast','listlength','listadd', 'help', # undocumented 'lso','expr','rsrclimit', @@ -344,7 +345,7 @@ def main(argv): options = set(('extendedglobalexpr','extendedtypecast','extendedassignment', 'allowkeyconcat','allowmultistrings','processpre','warntabs','optimize', 'optsigns','optfloats','constfold','dcr','errmissingdefault', - 'listlength', + 'listlength','listadd', )) assert not (options - validoptions), (u"Default options not present in"