mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Deal with the state change in globals error.
This commit is contained in:
parent
400809671e
commit
dce6419b4f
2 changed files with 40 additions and 10 deletions
|
@ -3,8 +3,9 @@ import lslfuncs
|
||||||
from lslparse import warning
|
from lslparse import warning
|
||||||
|
|
||||||
from lslrenamer import renamer
|
from lslrenamer import renamer
|
||||||
|
from lsldeadcode import deadcode
|
||||||
|
|
||||||
class optimizer(renamer):
|
class optimizer(renamer, deadcode):
|
||||||
|
|
||||||
# Default values per type when declaring variables
|
# Default values per type when declaring variables
|
||||||
DefaultValues = {'integer': 0, 'float': 0.0, 'string': u'',
|
DefaultValues = {'integer': 0, 'float': 0.0, 'string': u'',
|
||||||
|
@ -450,20 +451,30 @@ class optimizer(renamer):
|
||||||
for idx in xrange(len(child)):
|
for idx in xrange(len(child)):
|
||||||
self.FoldTree(child, idx)
|
self.FoldTree(child, idx)
|
||||||
self.FoldStmt(child, idx)
|
self.FoldStmt(child, idx)
|
||||||
|
if 'StSw' in child[idx]:
|
||||||
|
node['StSw'] = True
|
||||||
return
|
return
|
||||||
|
|
||||||
if nt == 'IF':
|
if nt == 'IF':
|
||||||
self.FoldTree(child, 0)
|
self.FoldTree(child, 0)
|
||||||
if child[0]['nt'] == 'CONST':
|
if child[0]['nt'] == 'CONST':
|
||||||
# We can remove one of the branches safely.
|
# We might be able to remove one of the branches.
|
||||||
if lslfuncs.cond(child[0]['value']):
|
if lslfuncs.cond(child[0]['value']):
|
||||||
self.FoldTree(child, 1)
|
self.FoldTree(child, 1)
|
||||||
parent[index] = child[1]
|
# If it has a state switch, the if() must be preserved
|
||||||
self.FoldStmt(child, 1)
|
# (but the else branch may be removed).
|
||||||
|
if 'StSw' in child[1]:
|
||||||
|
if len(child) > 2:
|
||||||
|
del child[2] # Delete ELSE if present
|
||||||
|
child[0]['t'] = 'integer'
|
||||||
|
child[0]['value'] = 1
|
||||||
|
else:
|
||||||
|
self.FoldStmt(child, 1)
|
||||||
|
parent[index] = child[1]
|
||||||
elif len(child) > 2:
|
elif len(child) > 2:
|
||||||
self.FoldTree(child, 2)
|
self.FoldTree(child, 2)
|
||||||
parent[index] = child[2]
|
|
||||||
self.FoldStmt(child, 2)
|
self.FoldStmt(child, 2)
|
||||||
|
parent[index] = child[2]
|
||||||
else:
|
else:
|
||||||
# No ELSE branch, replace the statement with an empty one.
|
# No ELSE branch, replace the statement with an empty one.
|
||||||
parent[index] = {'nt':';', 't':None}
|
parent[index] = {'nt':';', 't':None}
|
||||||
|
@ -568,6 +579,10 @@ class optimizer(renamer):
|
||||||
lslfuncs.ZERO_ROTATION}]
|
lslfuncs.ZERO_ROTATION}]
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if nt == 'STSW':
|
||||||
|
node['StSw'] = True
|
||||||
|
return
|
||||||
|
|
||||||
if nt in self.ignored_stmts:
|
if nt in self.ignored_stmts:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# TODO: Check "Not All Code Paths return a Value"
|
||||||
|
|
||||||
from lslcommon import Key, Vector, Quaternion
|
from lslcommon import Key, Vector, Quaternion
|
||||||
import lslfuncs
|
import lslfuncs
|
||||||
|
@ -92,6 +93,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 EParseCantChangeState(EParse):
|
||||||
|
def __init__(self, parser):
|
||||||
|
super(EParseCantChangeState, self).__init__(parser,
|
||||||
|
u"Global functions can't change state")
|
||||||
|
|
||||||
class EParseDuplicateLabel(EParse):
|
class EParseDuplicateLabel(EParse):
|
||||||
def __init__(self, parser):
|
def __init__(self, parser):
|
||||||
super(EParseDuplicateLabel, self).__init__(parser,
|
super(EParseDuplicateLabel, self).__init__(parser,
|
||||||
|
@ -1127,7 +1133,7 @@ class parser(object):
|
||||||
raise EParseFunctionMismatch(self)
|
raise EParseFunctionMismatch(self)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def Parse_statement(self, ReturnType, AllowDecl = False):
|
def Parse_statement(self, ReturnType, AllowDecl = False, AllowStSw = False):
|
||||||
"""Grammar parsed here:
|
"""Grammar parsed here:
|
||||||
|
|
||||||
statement: ';' | single_statement | code_block
|
statement: ';' | single_statement | code_block
|
||||||
|
@ -1219,6 +1225,8 @@ class parser(object):
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
self.expect(';')
|
self.expect(';')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
if self.localevents is None and not AllowStSw:
|
||||||
|
raise EParseCantChangeState(self)
|
||||||
return {'nt':'STSW', 't':None, 'name':name, 'scope':0}
|
return {'nt':'STSW', 't':None, 'name':name, 'scope':0}
|
||||||
if tok0 == 'RETURN':
|
if tok0 == 'RETURN':
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
@ -1245,7 +1253,12 @@ class parser(object):
|
||||||
cur['ch'].append(self.Parse_expression())
|
cur['ch'].append(self.Parse_expression())
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
cur['ch'].append(self.Parse_statement(ReturnType))
|
# INCOMPATIBILITY NOTE: This is more permissive than LSL.
|
||||||
|
# In LSL, an if...then...else does NOT allow a state change
|
||||||
|
# in either branch. Only an if...then without else does.
|
||||||
|
# BUT we're not going to check the branch after the fact, just
|
||||||
|
# to report that error. The compiler will report it.
|
||||||
|
cur['ch'].append(self.Parse_statement(ReturnType, AllowStSw = True))
|
||||||
if self.tok[0] == 'ELSE':
|
if self.tok[0] == 'ELSE':
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
if self.tok[0] == 'IF':
|
if self.tok[0] == 'IF':
|
||||||
|
@ -1262,10 +1275,11 @@ class parser(object):
|
||||||
condition = self.Parse_expression()
|
condition = self.Parse_expression()
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
return {'nt':'WHILE', 't':None, 'ch':[condition, self.Parse_statement(ReturnType)]}
|
return {'nt':'WHILE', 't':None, 'ch':[condition,
|
||||||
|
self.Parse_statement(ReturnType, AllowStSw = True)]}
|
||||||
if tok0 == 'DO':
|
if tok0 == 'DO':
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
stmt = self.Parse_statement(ReturnType)
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True)
|
||||||
self.expect('WHILE')
|
self.expect('WHILE')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
self.expect('(')
|
self.expect('(')
|
||||||
|
@ -1289,7 +1303,7 @@ class parser(object):
|
||||||
iterator = self.Parse_optional_expression_list()
|
iterator = self.Parse_optional_expression_list()
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
stmt = self.Parse_statement(ReturnType)
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True)
|
||||||
return {'nt':'FOR', 't':None,
|
return {'nt':'FOR', 't':None,
|
||||||
'ch':[{'nt':'EXPRLIST','t':None, 'ch':initializer},
|
'ch':[{'nt':'EXPRLIST','t':None, 'ch':initializer},
|
||||||
condition,
|
condition,
|
||||||
|
@ -1561,6 +1575,7 @@ class parser(object):
|
||||||
params = self.Parse_optional_param_list()
|
params = self.Parse_optional_param_list()
|
||||||
self.expect(')')
|
self.expect(')')
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
self.localevents = None
|
||||||
self.locallabels = set()
|
self.locallabels = set()
|
||||||
body = self.Parse_code_block(typ)
|
body = self.Parse_code_block(typ)
|
||||||
del self.locallabels
|
del self.locallabels
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue