mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +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
|
||||
import lslfuncs
|
||||
import sys, re
|
||||
|
@ -89,6 +90,11 @@ class EParseDeclarationScope(EParse):
|
|||
super(EParseDeclarationScope, self).__init__(parser,
|
||||
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):
|
||||
"""This exception is a construct to allow a different function to cause an
|
||||
immediate return of EOF from parser.GetToken(). Reused elsewhere for
|
||||
|
@ -1150,6 +1156,10 @@ class parser(object):
|
|||
name = self.tok[1]
|
||||
if name in self.symtab[self.scopeindex]:
|
||||
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.NextToken()
|
||||
self.expect(';')
|
||||
|
@ -1441,7 +1451,9 @@ class parser(object):
|
|||
raise EParseSyntax(self)
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
self.locallabels = set()
|
||||
body = self.Parse_code_block(None)
|
||||
del self.locallabels
|
||||
ret.append({'nt':'FNDEF', 't':None, 'name':name,
|
||||
'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
|
||||
'ch':[body]})
|
||||
|
@ -1519,7 +1531,9 @@ class parser(object):
|
|||
params = self.Parse_optional_param_list()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
self.locallabels = set()
|
||||
body = self.Parse_code_block(typ)
|
||||
del self.locallabels
|
||||
paramscope = self.scopeindex
|
||||
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
|
||||
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
|
||||
#self.lazylists = 'lazylists' in options
|
||||
|
||||
# Enable use of local labels with duplicate names
|
||||
self.duplabels = 'duplabels' in options
|
||||
|
||||
# Symbol table:
|
||||
# This is a list of all local and global symbol tables.
|
||||
# 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.
|
||||
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
|
||||
dull simple expressions allowed by regular LSL). Needs
|
||||
the optimizer to run for the result to be compilable.
|
||||
extendedtypecast + Allows extended typecast syntax e.g. (string)(integer)a
|
||||
is valid with this option.
|
||||
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
|
||||
basically no use in general.
|
||||
allowkeyconcat + Allow string + key and key + string (both return string)
|
||||
|
@ -37,12 +37,19 @@ Options (+ means default):
|
|||
optimize + Runs the optimizer.
|
||||
optsigns + Optimize signs in float and integer constants.
|
||||
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
|
||||
folded too and make it to the uploaded source. This
|
||||
option overrides that check, enabling optimization of
|
||||
strings with tabs. The resulting source isn't guaranteed
|
||||
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
|
||||
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,\
|
||||
EParseUndefined,EParseTypeMismatch,EParseReturnShouldBeEmpty,EParseReturnIsEmpty,\
|
||||
EParseInvalidField,EParseFunctionMismatch,EParseDeclarationScope,\
|
||||
fieldpos
|
||||
EParseDuplicateLabel,fieldpos
|
||||
from lslopt.lsloutput import outscript
|
||||
from lslopt.lsloptimizer import optimizer
|
||||
from lslopt import lslfuncs
|
||||
|
@ -44,7 +44,7 @@ const string q="\t"
|
|||
parser()
|
||||
|
||||
|
||||
class Test02_Compiler(UnitTestCase):
|
||||
class Test02_Parser(UnitTestCase):
|
||||
def setUp(self):
|
||||
self.parser = parser()
|
||||
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, '''g(){integer k;k=g();}''')
|
||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){@x;x;}state x{}''')
|
||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){print(g());}state x{}''')
|
||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''g(){@x;x;}default{}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(){++x;}state x{}''')
|
||||
self.assertRaises(EParseUndefined, self.parser.parse, '''g(){print(x);}state x{}''')
|
||||
self.assertRaises(EParseUEOF, self.parser.parse, '''f(){(integer)''')
|
||||
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, '''#blah;\ndefault{timer(){}}''')
|
||||
self.assertRaises(EParseTypeMismatch, self.parser.parse, '''f(){<1,2,3,4>"">;}''')
|
||||
|
@ -209,11 +210,11 @@ class Test02_Compiler(UnitTestCase):
|
|||
i |= i;
|
||||
"a" "b" "c";
|
||||
"a"+(key)"b"; (key)"a" + "b";
|
||||
i>>=i;
|
||||
i>>=i; {@x;{@x;jump x;}jump x;}
|
||||
}}''',
|
||||
['explicitcast','extendedtypecast','extendedassignment',
|
||||
'extendedglobalexpr', 'allowmultistrings', 'allowkeyconcat',
|
||||
'skippreproc']
|
||||
'skippreproc', 'duplabels']
|
||||
))
|
||||
print self.parser.scopeindex
|
||||
#self.assertRaises(EParseUnexpected, self.parser.PopScope)
|
||||
|
@ -241,6 +242,7 @@ class Test03_Optimizer(UnitTestCase):
|
|||
list L1 = L;
|
||||
list L2 = [1,2,3,4,5,6.0];
|
||||
list L3 = [];
|
||||
list L4 = [1,2,3,4,5,6.0,""]+[];
|
||||
integer RemovesInt = 0;
|
||||
vector AddsVector;
|
||||
vector v=<1,2,f>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue