Deal with the state change in globals error.

This commit is contained in:
Sei Lisa 2014-08-01 23:51:24 +02:00
parent 400809671e
commit dce6419b4f
2 changed files with 40 additions and 10 deletions

View file

@ -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

View file

@ -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