mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Fix the obnoxious issue with globals propagation in full expressions.
Fixed by backtracking in the parser, and keeping a copy of the original expression if it's a simple_expr, which is used for output in place of the folded one. There's still the potential issue that if a global is optimized away, then it will "come back" during output and cause an error because the definition is missing.
This commit is contained in:
parent
5b401ff9a5
commit
e5714eba25
3 changed files with 43 additions and 10 deletions
|
@ -46,6 +46,16 @@ class optimizer(object):
|
||||||
return value
|
return value
|
||||||
return {'nt':'CAST', 't':newtype, 'ch':[value]}
|
return {'nt':'CAST', 't':newtype, 'ch':[value]}
|
||||||
|
|
||||||
|
def CopyNode(self, node):
|
||||||
|
# This is mainly for simple_expr so not a big deal.
|
||||||
|
ret = node.copy()
|
||||||
|
if 'ch' in ret:
|
||||||
|
new = []
|
||||||
|
for subnode in ret['ch']:
|
||||||
|
new.append(self.CopyNode(subnode))
|
||||||
|
ret['ch'] = new
|
||||||
|
return ret
|
||||||
|
|
||||||
def FoldTree(self, parent, index):
|
def FoldTree(self, parent, index):
|
||||||
"""Recursively traverse the tree to fold constants, changing it in
|
"""Recursively traverse the tree to fold constants, changing it in
|
||||||
place.
|
place.
|
||||||
|
@ -512,10 +522,14 @@ class optimizer(object):
|
||||||
|
|
||||||
if nt == 'DECL':
|
if nt == 'DECL':
|
||||||
if child:
|
if child:
|
||||||
# TODO: Decide if child is a simple_expr.
|
# Check if child is a simple_expr. If it is, then we keep the
|
||||||
# If it is, then we should keep the original
|
# original attached to the folded node and use it in the output.
|
||||||
# attached to the folded node and use it in the output.
|
if child[0].pop('Simple', False):
|
||||||
self.FoldTree(child, 0)
|
orig = self.CopyNode(child[0])
|
||||||
|
self.FoldTree(child, 0)
|
||||||
|
child[0]['orig'] = orig
|
||||||
|
else:
|
||||||
|
self.FoldTree(child, 0)
|
||||||
# Remove assignment if integer zero.
|
# Remove assignment if integer zero.
|
||||||
if node['t'] == 'integer' and child[0]['nt'] == 'CONST' \
|
if node['t'] == 'integer' and child[0]['nt'] == 'CONST' \
|
||||||
and not child[0]['value']:
|
and not child[0]['value']:
|
||||||
|
@ -569,7 +583,7 @@ class optimizer(object):
|
||||||
self.FoldTree(tree, idx)
|
self.FoldTree(tree, idx)
|
||||||
self.globalmode = False
|
self.globalmode = False
|
||||||
if not self.IsValidGlobalConstant(tree[idx]):
|
if not self.IsValidGlobalConstant(tree[idx]):
|
||||||
warning('WARNING: Expression does not collapse to a single constant.')
|
warning('WARNING: Expression does not resolve to a single constant.')
|
||||||
else:
|
else:
|
||||||
self.FoldTree(tree, idx)
|
self.FoldTree(tree, idx)
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,10 @@ class outscript(object):
|
||||||
if nt == 'DECL':
|
if nt == 'DECL':
|
||||||
ret = self.dent() + node['t'] + ' ' + node['name']
|
ret = self.dent() + node['t'] + ' ' + node['name']
|
||||||
if child:
|
if child:
|
||||||
ret += ' = ' + self.OutExpr(child[0])
|
if 'orig' in child[0]:
|
||||||
|
ret += ' = ' + self.OutExpr(child[0]['orig'])
|
||||||
|
else:
|
||||||
|
ret += ' = ' + self.OutExpr(child[0])
|
||||||
return ret + ';\n'
|
return ret + ';\n'
|
||||||
if nt == ';':
|
if nt == ';':
|
||||||
return self.dent() + ';\n'
|
return self.dent() + ';\n'
|
||||||
|
|
|
@ -1465,7 +1465,7 @@ class parser(object):
|
||||||
raise EParseAlreadyDefined(self)
|
raise EParseAlreadyDefined(self)
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
|
||||||
if self.tok[0] == '=' or self.tok[0] == ';':
|
if self.tok[0] in ('=', ';'):
|
||||||
# This is a variable definition
|
# This is a variable definition
|
||||||
if typ is None: # Typeless variables are not allowed
|
if typ is None: # Typeless variables are not allowed
|
||||||
raise EParseSyntax(self)
|
raise EParseSyntax(self)
|
||||||
|
@ -1474,11 +1474,27 @@ class parser(object):
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
if self.extendedglobalexpr:
|
if self.extendedglobalexpr:
|
||||||
self.globalmode = True # Disallow forward globals.
|
self.globalmode = True # Disallow forward globals.
|
||||||
value = self.Parse_expression() # Use advanced expression evaluation.
|
# Mark backtracking position
|
||||||
|
pos = self.pos
|
||||||
|
errorpos = self.errorpos
|
||||||
|
tok = self.tok
|
||||||
|
try:
|
||||||
|
value = self.Parse_simple_expr()
|
||||||
|
self.expect(';')
|
||||||
|
value['Simple'] = True # Success - mark it as simple
|
||||||
|
except EParse:
|
||||||
|
# Backtrack
|
||||||
|
self.pos = pos
|
||||||
|
self.errorpos = errorpos
|
||||||
|
self.tok = tok
|
||||||
|
# Use advanced expression evaluation.
|
||||||
|
value = self.Parse_expression()
|
||||||
|
self.expect(';')
|
||||||
self.globalmode = False # Allow forward globals again.
|
self.globalmode = False # Allow forward globals again.
|
||||||
else:
|
else:
|
||||||
value = self.Parse_simple_expr() # Use LSL's dull global expression.
|
# Use LSL's dull global expression.
|
||||||
self.expect(';')
|
value = self.Parse_simple_expr()
|
||||||
|
self.expect(';')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
else: # must be semicolon
|
else: # must be semicolon
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue