mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +00:00
Add "lazy lists" assignment support (mylist[index] = value).
Add support for LAMBDA (empty) tree nodes while on it, that allow us to define private stuff at the top without caring about Loc.
This commit is contained in:
parent
7e521780d6
commit
b73805e0ce
4 changed files with 75 additions and 19 deletions
|
@ -1015,9 +1015,10 @@ class foldconst(object):
|
|||
node['SEF'] = True
|
||||
return
|
||||
|
||||
if nt in ('JUMP', '@', 'V++', 'V--', '--V', '++V'):
|
||||
# These all have side effects, as in, can't be eliminated as
|
||||
# statements.
|
||||
if nt in ('JUMP', '@', 'V++', 'V--', '--V', '++V', 'LAMBDA'):
|
||||
# Except LAMBDA, these all have side effects, as in, can't be
|
||||
# eliminated as statements.
|
||||
# LAMBDA can't be eliminated without scrolling Loc's.
|
||||
return
|
||||
|
||||
assert False, 'Internal error: This should not happen, node type = ' \
|
||||
|
|
|
@ -366,6 +366,9 @@ class outscript(object):
|
|||
if nt == 'EXPR':
|
||||
return self.dent() + self.OutExpr(child[0]) + ';\n'
|
||||
|
||||
if nt == 'LAMBDA':
|
||||
return ''
|
||||
|
||||
assert False, "Internal error: node type not handled: " + nt # pragma: no cover
|
||||
|
||||
def output(self, treesymtab, options = ('optsigns','optfloats')):
|
||||
|
|
|
@ -544,12 +544,14 @@ class parser(object):
|
|||
rotation_literal: '<' expression ',' expression ',' expression
|
||||
',' expression '>'
|
||||
list_literal: '[' optional_expression_list ']'
|
||||
assignment: lvalue '=' expression | lvalue '+=' expression
|
||||
assignment: xlvalue '=' expression | lvalue '+=' expression
|
||||
| lvalue '-=' expression | lvalue '*=' expression
|
||||
| lvalue '/=' expression | lvalue '%=' expression
|
||||
%EXTENDED RULES:
|
||||
| lvalue '|=' expression | lvalue '&=' expression
|
||||
| lvalue '<<=' expression | lvalue '>>=' expression
|
||||
| lvalue '|=' expression %if extendedassignment
|
||||
| lvalue '&=' expression %if extendedassignment
|
||||
| lvalue '<<=' expression %if extendedassignment
|
||||
| lvalue '>>=' expression %if extendedassignment
|
||||
xlvalue: lvalue | IDENT '[' expression ']' %if lazylists
|
||||
lvalue: IDENT | IDENT '.' IDENT
|
||||
"""
|
||||
tok0 = self.tok[0]
|
||||
|
@ -677,7 +679,21 @@ class parser(object):
|
|||
raise EParseTypeMismatch(self)
|
||||
return {'nt':'V++' if tok0 == '++' else 'V--', 't':lvalue['t'], 'ch':[lvalue]}
|
||||
if AllowAssignment and (tok0 in self.assignment_toks
|
||||
or self.extendedassignment and tok0 in self.extassignment_toks):
|
||||
or self.extendedassignment and tok0 in self.extassignment_toks
|
||||
or self.lazylists and tok0 == '['):
|
||||
if tok0 == '[':
|
||||
if lvalue['nt'] != 'IDENT':
|
||||
raise EParseSyntax(self)
|
||||
if lvalue['t'] != 'list':
|
||||
raise EParseTypeMismatch(self)
|
||||
self.NextToken()
|
||||
idxexpr = self.Parse_expression()
|
||||
if idxexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
self.expect(']')
|
||||
self.NextToken()
|
||||
self.expect('=')
|
||||
|
||||
self.NextToken()
|
||||
expr = self.Parse_expression()
|
||||
rtyp = expr['t']
|
||||
|
@ -690,6 +706,37 @@ class parser(object):
|
|||
if tok0 != '*=' or typ == 'float':
|
||||
expr = self.autocastcheck(expr, typ)
|
||||
rtyp = typ
|
||||
# Lazy list handler
|
||||
if tok0 == '[':
|
||||
# Define aux function if it doesn't exist
|
||||
# (leaves users room for writing their own replacement, e.g.
|
||||
# one that fills with something other than zeros)
|
||||
if 'lazy_list_set' not in self.symtab[0]:
|
||||
self.PushScope()
|
||||
paramscope = self.scopeindex
|
||||
params = (['list', 'integer', 'list'],
|
||||
['L', 'i', 'v'])
|
||||
self.AddSymbol('f', 0, 'lazy_list_set', Loc=self.usedspots,
|
||||
Type='list', ParamTypes=params[0], ParamNames=params[1])
|
||||
self.AddSymbol('v', paramscope, 'L', Type='list')
|
||||
self.AddSymbol('v', paramscope, 'i', Type='integer')
|
||||
self.AddSymbol('v', paramscope, 'v', Type='list')
|
||||
self.PushScope()
|
||||
localscope = self.scopeindex
|
||||
self.AddSymbol('v', localscope, 'ins', Type='integer',
|
||||
Local=True)
|
||||
# Add body (apologies for the wall of text)
|
||||
self.tree[self.usedspots] = {'ch': [{'ch': [{'scope':localscope, 'ch': [{'ch': [{'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'L'}, {'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'v'}], 'nt': '!=', 't': 'integer'}], 'nt': 'DECL', 't': 'integer', 'name': 'ins'}, {'ch': [{'ch': [{'ch': [{'scope':localscope, 'nt': 'IDENT', 't': 'integer', 'name': 'ins'}], 'nt': '++V', 't': 'integer'}, {'scope':paramscope, 'nt': 'IDENT', 't': 'integer', 'name': 'i'}], 'nt': '<', 't': 'integer'}, {'ch': [{'ch': [{'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'L'}, {'ch': [{'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'L'}, {'ch': [{'scope':localscope, 'nt': 'IDENT', 't': 'integer', 'name': 'ins'}, {'scope':localscope, 'nt': 'IDENT', 't': 'integer', 'name': 'ins'}], 'nt': '^', 't': 'integer'}], 'nt': '+', 't': 'list'}], 'nt': '=', 't': 'list'}], 'nt': 'EXPR', 't': 'list'}], 'nt': 'WHILE', 't': None}, {'ch': [{'ch': [{'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'L'}, {'scope':paramscope, 'nt': 'IDENT', 't': 'list', 'name': 'v'}, {'ch': [{'scope':localscope, 'nt': 'IDENT', 't': 'integer', 'name': 'ins'}, {'scope':paramscope, 'nt': 'IDENT', 't': 'integer', 'name': 'i'}], 'nt': '=', 't': 'integer'}, {'scope':localscope, 'nt': 'IDENT', 't': 'integer', 'name': 'ins'}], 'nt': 'FNCALL', 't': 'list', 'name': 'llListReplaceList'}], 'nt': 'RETURN', 't': None, 'LIR': True}], 'nt': '{}', 't': None, 'LIR': True}], 't': 'list', 'pnames': ['L', 'i', 'v'], 'scope': 0, 'pscope': 1, 'nt': 'FNDEF', 'ptypes': ['list', 'integer', 'list'], 'name': 'lazy_list_set'}
|
||||
self.usedspots += 1
|
||||
self.PopScope()
|
||||
self.PopScope()
|
||||
|
||||
return {'nt':'=', 't':'list', 'ch':[lvalue, {
|
||||
'nt':'FNCALL', 't':'list', 'name':'lazy_list_set',
|
||||
'ch':[lvalue.copy(), idxexpr,
|
||||
{'nt':'LIST','t':'list', 'ch':[expr]}]
|
||||
}]}
|
||||
|
||||
# Lots of drama for checking types. This is pretty much like
|
||||
# addition, subtraction, multiply, divide, etc. all in one go.
|
||||
if tok0 == '=':
|
||||
|
@ -1825,8 +1872,8 @@ class parser(object):
|
|||
# TODO: Enable switch statements.
|
||||
#self.enableswitch = 'enableswitch' in options
|
||||
|
||||
# TODO: Enable brackets for list elements e.g. (float)mylist[3], or mylist[5]=4
|
||||
#self.lazylists = 'lazylists' in options
|
||||
# Allow brackets for assignment of list elements e.g. mylist[5]=4
|
||||
self.lazylists = 'lazylists' in options
|
||||
|
||||
# TODO: Enable break/continue
|
||||
#self.breakcont = 'breakcont' in options
|
||||
|
@ -1889,7 +1936,9 @@ class parser(object):
|
|||
self.pos = 0
|
||||
self.tok = self.GetToken()
|
||||
|
||||
self.tree = []
|
||||
# Reserve spots at the beginning for functions we add
|
||||
self.tree = [{'nt':'LAMBDA','t':None}]
|
||||
self.usedspots = 0
|
||||
|
||||
# Start the parsing proper
|
||||
self.Parse_script()
|
||||
|
|
19
main.py
19
main.py
|
@ -42,14 +42,14 @@ Options (+ means active by default, - means inactive by default):
|
|||
directives like: # 123 "filename".
|
||||
optimize + Runs the optimizer.
|
||||
optsigns + Optimize signs in float and integer constants.
|
||||
optfloats + Optimize a float when it is an integral value.
|
||||
constfold + Fold constant expressions to their values.
|
||||
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.
|
||||
optfloats + Optimize floats that represent an integral value.
|
||||
constfold + Fold constant expressions to their values, and simplify
|
||||
some expressions.
|
||||
foldtabs - Tabs can't be copy-pasted, so expressions that produce
|
||||
tabs (like llUnescapeURL("%09") aren't optimized by
|
||||
default. This option overrides that check, enabling
|
||||
optimization of strings with tabs. The resulting source
|
||||
isn't guaranteed to be copy-paste-able to the viewer.
|
||||
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
|
||||
|
@ -61,6 +61,9 @@ Options (+ means active by default, - means inactive by default):
|
|||
process, it turns the script into unreadable gibberish,
|
||||
hard to debug, but this gets big savings for complex
|
||||
scripts.
|
||||
lazylists - Support syntax like mylist[index] = 5; rather than using
|
||||
llListReplaceList. Not recommended, as it adds a new
|
||||
function.
|
||||
''' % sys.argv[0])
|
||||
return 1
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue