mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Add duplabels option (not yet implemented).
When disabled, it now disallows duplicate labels. The plan is that when enabled, it will auto-rename labels so that there are no repetitions within a function. Add coverage tests too, and also a coverage test that was missed after the latest changes.
This commit is contained in:
parent
523857ed23
commit
e29f16d3eb
3 changed files with 35 additions and 9 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
from lslcommon import Key, Vector, Quaternion
|
from lslcommon import Key, Vector, Quaternion
|
||||||
import lslfuncs
|
import lslfuncs
|
||||||
import sys, re
|
import sys, re
|
||||||
|
@ -89,6 +90,11 @@ class EParseDeclarationScope(EParse):
|
||||||
super(EParseDeclarationScope, self).__init__(parser,
|
super(EParseDeclarationScope, self).__init__(parser,
|
||||||
u"Declaration requires a new scope -- use { and }")
|
u"Declaration requires a new scope -- use { and }")
|
||||||
|
|
||||||
|
class EParseDuplicateLabel(EParse):
|
||||||
|
def __init__(self, parser):
|
||||||
|
super(EParseDuplicateLabel, self).__init__(parser,
|
||||||
|
u"Duplicate local label name. That won't allow the Mono script to be saved, and will not work as expected in LSO.")
|
||||||
|
|
||||||
class EInternal(Exception):
|
class EInternal(Exception):
|
||||||
"""This exception is a construct to allow a different function to cause an
|
"""This exception is a construct to allow a different function to cause an
|
||||||
immediate return of EOF from parser.GetToken(). Reused elsewhere for
|
immediate return of EOF from parser.GetToken(). Reused elsewhere for
|
||||||
|
@ -1150,6 +1156,10 @@ class parser(object):
|
||||||
name = self.tok[1]
|
name = self.tok[1]
|
||||||
if name in self.symtab[self.scopeindex]:
|
if name in self.symtab[self.scopeindex]:
|
||||||
raise EParseAlreadyDefined(self)
|
raise EParseAlreadyDefined(self)
|
||||||
|
if not self.duplabels and name in self.locallabels:
|
||||||
|
raise EParseDuplicateLabel(self)
|
||||||
|
# All labels go to a common pool local to the current function.
|
||||||
|
self.locallabels.add(name)
|
||||||
self.AddSymbol('l', self.scopeindex, name)
|
self.AddSymbol('l', self.scopeindex, name)
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
self.expect(';')
|
self.expect(';')
|
||||||
|
@ -1441,7 +1451,9 @@ class parser(object):
|
||||||
raise EParseSyntax(self)
|
raise EParseSyntax(self)
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
self.locallabels = set()
|
||||||
body = self.Parse_code_block(None)
|
body = self.Parse_code_block(None)
|
||||||
|
del self.locallabels
|
||||||
ret.append({'nt':'FNDEF', 't':None, 'name':name,
|
ret.append({'nt':'FNDEF', 't':None, 'name':name,
|
||||||
'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
|
'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
|
||||||
'ch':[body]})
|
'ch':[body]})
|
||||||
|
@ -1519,7 +1531,9 @@ class parser(object):
|
||||||
params = self.Parse_optional_param_list()
|
params = self.Parse_optional_param_list()
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
self.locallabels = set()
|
||||||
body = self.Parse_code_block(typ)
|
body = self.Parse_code_block(typ)
|
||||||
|
del self.locallabels
|
||||||
paramscope = self.scopeindex
|
paramscope = self.scopeindex
|
||||||
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
|
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
|
||||||
ParamTypes=params[0], ParamNames=params[1])
|
ParamTypes=params[0], ParamNames=params[1])
|
||||||
|
@ -1748,6 +1762,9 @@ class parser(object):
|
||||||
# TODO: Enable brackets for list elements e.g. (float)mylist[3], or mylist[5]=4
|
# TODO: Enable brackets for list elements e.g. (float)mylist[3], or mylist[5]=4
|
||||||
#self.lazylists = 'lazylists' in options
|
#self.lazylists = 'lazylists' in options
|
||||||
|
|
||||||
|
# Enable use of local labels with duplicate names
|
||||||
|
self.duplabels = 'duplabels' in options
|
||||||
|
|
||||||
# Symbol table:
|
# Symbol table:
|
||||||
# This is a list of all local and global symbol tables.
|
# This is a list of all local and global symbol tables.
|
||||||
# The first element (0) is the global scope. Each symbol table is a
|
# The first element (0) is the global scope. Each symbol table is a
|
||||||
|
|
13
main.py
13
main.py
|
@ -14,14 +14,14 @@ Usage: %s [-O [+|-]option[,[+|-]option[,...]]] filename
|
||||||
That's an upper case o, not the number zero.
|
That's an upper case o, not the number zero.
|
||||||
If filename is a dash (-) then standard input is used.
|
If filename is a dash (-) then standard input is used.
|
||||||
|
|
||||||
Options (+ means default):
|
Options (+ means active by default, - means inactive by default):
|
||||||
extendedglobalexpr + Enables arbitrary expressions in globals (as opposed to
|
extendedglobalexpr + Enables arbitrary expressions in globals (as opposed to
|
||||||
dull simple expressions allowed by regular LSL). Needs
|
dull simple expressions allowed by regular LSL). Needs
|
||||||
the optimizer to run for the result to be compilable.
|
the optimizer to run for the result to be compilable.
|
||||||
extendedtypecast + Allows extended typecast syntax e.g. (string)(integer)a
|
extendedtypecast + Allows extended typecast syntax e.g. (string)(integer)a
|
||||||
is valid with this option.
|
is valid with this option.
|
||||||
extendedassignment + Enables &=, |=, ^=, <<=, >>= assignment operators.
|
extendedassignment + Enables &=, |=, ^=, <<=, >>= assignment operators.
|
||||||
explicitcast Add explicit casts where they are implicit. This option
|
explicitcast - Add explicit casts where they are implicit. This option
|
||||||
is useless with 'optimize' and 'optsigns', and is of
|
is useless with 'optimize' and 'optsigns', and is of
|
||||||
basically no use in general.
|
basically no use in general.
|
||||||
allowkeyconcat + Allow string + key and key + string (both return string)
|
allowkeyconcat + Allow string + key and key + string (both return string)
|
||||||
|
@ -37,12 +37,19 @@ Options (+ means default):
|
||||||
optimize + Runs the optimizer.
|
optimize + Runs the optimizer.
|
||||||
optsigns + Optimize signs in float and integer constants.
|
optsigns + Optimize signs in float and integer constants.
|
||||||
optfloats + Optimize a float when it is an integral value.
|
optfloats + Optimize a float when it is an integral value.
|
||||||
foldtabs Tabs can't be copy-pasted, so they aren't optimized by
|
foldtabs - Tabs can't be copy-pasted, so they aren't optimized by
|
||||||
default. But with support from the viewer, they can be
|
default. But with support from the viewer, they can be
|
||||||
folded too and make it to the uploaded source. This
|
folded too and make it to the uploaded source. This
|
||||||
option overrides that check, enabling optimization of
|
option overrides that check, enabling optimization of
|
||||||
strings with tabs. The resulting source isn't guaranteed
|
strings with tabs. The resulting source isn't guaranteed
|
||||||
to be copy-paste-able to a different script, though.
|
to be copy-paste-able to a different script, though.
|
||||||
|
duplabels - Normally, a duplicate label within a function is allowed
|
||||||
|
by the syntax by using {} blocks; however, the server
|
||||||
|
will just refuse to save the script (under Mono) or do
|
||||||
|
something completely unexpected (under LSO: all jumps
|
||||||
|
will go to the last label with that name). This flag
|
||||||
|
works around that limitation by replacing the names of
|
||||||
|
the labels in the output with unique ones.
|
||||||
|
|
||||||
Note that the optimizer doesn't reorder expressions to fold constants. This
|
Note that the optimizer doesn't reorder expressions to fold constants. This
|
||||||
means that e.g. a + 3 + 5 is not optimized to a + 8; however a + (3 + 5) is.
|
means that e.g. a + 3 + 5 is not optimized to a + 8; however a + (3 + 5) is.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from lslopt.lslparse import parser,EParseSyntax,EParseUEOF,EParseAlreadyDefined,\
|
from lslopt.lslparse import parser,EParseSyntax,EParseUEOF,EParseAlreadyDefined,\
|
||||||
EParseUndefined,EParseTypeMismatch,EParseReturnShouldBeEmpty,EParseReturnIsEmpty,\
|
EParseUndefined,EParseTypeMismatch,EParseReturnShouldBeEmpty,EParseReturnIsEmpty,\
|
||||||
EParseInvalidField,EParseFunctionMismatch,EParseDeclarationScope,\
|
EParseInvalidField,EParseFunctionMismatch,EParseDeclarationScope,\
|
||||||
fieldpos
|
EParseDuplicateLabel,fieldpos
|
||||||
from lslopt.lsloutput import outscript
|
from lslopt.lsloutput import outscript
|
||||||
from lslopt.lsloptimizer import optimizer
|
from lslopt.lsloptimizer import optimizer
|
||||||
from lslopt import lslfuncs
|
from lslopt import lslfuncs
|
||||||
|
@ -44,7 +44,7 @@ const string q="\t"
|
||||||
parser()
|
parser()
|
||||||
|
|
||||||
|
|
||||||
class Test02_Compiler(UnitTestCase):
|
class Test02_Parser(UnitTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.parser = parser()
|
self.parser = parser()
|
||||||
self.outscript = outscript()
|
self.outscript = outscript()
|
||||||
|
@ -171,13 +171,14 @@ class Test02_Compiler(UnitTestCase):
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){string i;!i;}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){string i;!i;}''')
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){string i;++i;}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){string i;++i;}''')
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){integer k;k=g();}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){integer k;k=g();}''')
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){@x;x;}state x{}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){@x;x;}default{}state x{}''')
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){print(g());}state x{}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){print(g());}default{}state x{}''')
|
||||||
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){integer k;k();}''')
|
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){integer k;k();}''')
|
||||||
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){++x;}state x{}''')
|
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){++x;}state x{}''')
|
||||||
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){print(x);}state x{}''')
|
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){print(x);}state x{}''')
|
||||||
self.assertRaises(EParseUEOF, self.parser.parse, '''f(){(integer)''')
|
self.assertRaises(EParseUEOF, self.parser.parse, '''f(){(integer)''')
|
||||||
self.assertRaises(EParseInvalidField, self.parser.parse, '''f(){vector v;v.s;}''')
|
self.assertRaises(EParseInvalidField, self.parser.parse, '''f(){vector v;v.s;}''')
|
||||||
|
self.assertRaises(EParseDuplicateLabel, self.parser.parse, 'f(){@x;{@x;}}')
|
||||||
self.assertRaises(EParseSyntax, self.parser.parse, '''f(){<1,2,3,4==5>;}''')
|
self.assertRaises(EParseSyntax, self.parser.parse, '''f(){<1,2,3,4==5>;}''')
|
||||||
self.assertRaises(EParseSyntax, self.parser.parse, '''#blah;\ndefault{timer(){}}''')
|
self.assertRaises(EParseSyntax, self.parser.parse, '''#blah;\ndefault{timer(){}}''')
|
||||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){<1,2,3,4>"">;}''')
|
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){<1,2,3,4>"">;}''')
|
||||||
|
@ -209,11 +210,11 @@ class Test02_Compiler(UnitTestCase):
|
||||||
i |= i;
|
i |= i;
|
||||||
"a" "b" "c";
|
"a" "b" "c";
|
||||||
"a"+(key)"b"; (key)"a" + "b";
|
"a"+(key)"b"; (key)"a" + "b";
|
||||||
i>>=i;
|
i>>=i; {@x;{@x;jump x;}jump x;}
|
||||||
}}''',
|
}}''',
|
||||||
['explicitcast','extendedtypecast','extendedassignment',
|
['explicitcast','extendedtypecast','extendedassignment',
|
||||||
'extendedglobalexpr', 'allowmultistrings', 'allowkeyconcat',
|
'extendedglobalexpr', 'allowmultistrings', 'allowkeyconcat',
|
||||||
'skippreproc']
|
'skippreproc', 'duplabels']
|
||||||
))
|
))
|
||||||
print self.parser.scopeindex
|
print self.parser.scopeindex
|
||||||
#self.assertRaises(EParseUnexpected, self.parser.PopScope)
|
#self.assertRaises(EParseUnexpected, self.parser.PopScope)
|
||||||
|
@ -241,6 +242,7 @@ class Test03_Optimizer(UnitTestCase):
|
||||||
list L1 = L;
|
list L1 = L;
|
||||||
list L2 = [1,2,3,4,5,6.0];
|
list L2 = [1,2,3,4,5,6.0];
|
||||||
list L3 = [];
|
list L3 = [];
|
||||||
|
list L4 = [1,2,3,4,5,6.0,""]+[];
|
||||||
integer RemovesInt = 0;
|
integer RemovesInt = 0;
|
||||||
vector AddsVector;
|
vector AddsVector;
|
||||||
vector v=<1,2,f>;
|
vector v=<1,2,f>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue