mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Overall renaming of stuff to make it more understandable.
This commit is contained in:
parent
fb68273eed
commit
895e4f4668
3 changed files with 336 additions and 335 deletions
|
@ -17,7 +17,7 @@ class optimizer(object):
|
|||
LSL2PythonType = {'integer':int, 'float':float, 'string':unicode, 'key':lslfuncs.Key,
|
||||
'vector':lslfuncs.Vector, 'rotation':lslfuncs.Quaternion, 'list':list}
|
||||
|
||||
ignored_stmts = frozenset(('V++','V--','--V','++V',';','STATE','JUMP','@'))
|
||||
ignored_stmts = frozenset(('V++','V--','--V','++V',';','STSW','JUMP','@'))
|
||||
|
||||
def FoldAndRemoveEmptyStmts(self, lst):
|
||||
"""Utility function for elimination of useless expressions in FOR"""
|
||||
|
@ -26,7 +26,7 @@ class optimizer(object):
|
|||
self.FoldTree(lst, idx)
|
||||
self.FoldStmt(lst, idx)
|
||||
# If eliminated, it must be totally removed. A ';' won't do.
|
||||
if lst[idx]['node'] == ';':
|
||||
if lst[idx]['nt'] == ';':
|
||||
del lst[idx]
|
||||
else:
|
||||
idx += 1
|
||||
|
@ -36,8 +36,8 @@ class optimizer(object):
|
|||
nothing.
|
||||
"""
|
||||
# Ideally this should consider side effect analysis of the whole thing.
|
||||
if parent[index]['node'] in ('CONST', 'IDENT', 'FIELD'):
|
||||
parent[index] = {'node':';','type':None}
|
||||
if parent[index]['nt'] in ('CONST', 'IDENT', 'FIELD'):
|
||||
parent[index] = {'nt':';','t':None}
|
||||
|
||||
def FoldTree(self, parent, index):
|
||||
"""Recursively traverse the tree to fold constants, changing it in
|
||||
|
@ -45,51 +45,51 @@ class optimizer(object):
|
|||
|
||||
Also optimizes away IF, WHILE, etc.
|
||||
"""
|
||||
code = parent[index]
|
||||
if code is None: return # Deleted statement
|
||||
node = code['node']
|
||||
child = code['br'] if 'br' in code else None
|
||||
node = parent[index]
|
||||
if node is None: return # Deleted statement
|
||||
nt = node['nt']
|
||||
child = node['ch'] if 'ch' in node else None
|
||||
|
||||
if node == 'CONST':
|
||||
if nt == 'CONST':
|
||||
# Job already done
|
||||
return
|
||||
|
||||
if node == 'CAST':
|
||||
if nt == 'CAST':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
if child[0]['nt'] == 'CONST':
|
||||
# Enable key constants. We'll typecast them back on output, but
|
||||
# this enables some optimizations.
|
||||
#if code['type'] != 'key': # key constants not possible
|
||||
#if node['t'] != 'key': # key constants not possible
|
||||
|
||||
parent[index] = {'node':'CONST', 'type':code['type'],
|
||||
parent[index] = {'nt':'CONST', 't':node['t'],
|
||||
'value':lslfuncs.typecast(
|
||||
child[0]['value'], self.LSL2PythonType[code['type']])}
|
||||
child[0]['value'], self.LSL2PythonType[node['t']])}
|
||||
return
|
||||
|
||||
if node == 'NEG':
|
||||
if nt == 'NEG':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
code = parent[index] = child[0]
|
||||
code['value'] = lslfuncs.neg(code['value'])
|
||||
if child[0]['nt'] == 'CONST':
|
||||
node = parent[index] = child[0]
|
||||
node['value'] = lslfuncs.neg(node['value'])
|
||||
return
|
||||
|
||||
if node == '!':
|
||||
if nt == '!':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
code = parent[index] = child[0]
|
||||
code['value'] = int(not code['value'])
|
||||
if child[0]['nt'] == 'CONST':
|
||||
node = parent[index] = child[0]
|
||||
node['value'] = int(not node['value'])
|
||||
return
|
||||
|
||||
if node == '~':
|
||||
if nt == '~':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
code = parent[index] = child[0]
|
||||
code['value'] = ~code['value']
|
||||
if child[0]['nt'] == 'CONST':
|
||||
node = parent[index] = child[0]
|
||||
node['value'] = ~node['value']
|
||||
return
|
||||
|
||||
if node == '()':
|
||||
if nt == '()':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] in ('CONST', 'VECTOR', 'ROTATION', 'LIST',
|
||||
if child[0]['nt'] in ('CONST', 'VECTOR', 'ROTATION', 'LIST',
|
||||
'IDENT', 'FIELD', 'V++', 'V--', 'FUNCTION', 'PRINT'):
|
||||
# Child is an unary postfix expression; parentheses are
|
||||
# redundant and can be removed safely. Not strictly an
|
||||
|
@ -100,73 +100,72 @@ class optimizer(object):
|
|||
parent[index] = child[0]
|
||||
return
|
||||
|
||||
if node in self.binary_ops:
|
||||
if nt in self.binary_ops:
|
||||
# RTL evaluation
|
||||
self.FoldTree(child, 1)
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == child[1]['node'] == 'CONST':
|
||||
op = node
|
||||
if child[0]['nt'] == child[1]['nt'] == 'CONST':
|
||||
op1 = child[0]['value']
|
||||
op2 = child[1]['value']
|
||||
if op == '+':
|
||||
if nt == '+':
|
||||
result = lslfuncs.add(op1, op2)
|
||||
elif op == '-':
|
||||
elif nt == '-':
|
||||
result = lslfuncs.sub(op1, op2)
|
||||
elif op == '*':
|
||||
elif nt == '*':
|
||||
result = lslfuncs.mul(op1, op2)
|
||||
elif op == '/':
|
||||
elif nt == '/':
|
||||
result = lslfuncs.div(op1, op2)
|
||||
elif op == '%':
|
||||
elif nt == '%':
|
||||
result = lslfuncs.mod(op1, op2)
|
||||
elif op == '<<':
|
||||
elif nt == '<<':
|
||||
result = lslfuncs.S32(op1 << (op2 & 31))
|
||||
elif op == '>>':
|
||||
elif nt == '>>':
|
||||
result = lslfuncs.S32(op1 >> (op2 & 31))
|
||||
elif op == '==' or op == '!=':
|
||||
result = lslfuncs.compare(op1, op2, Eq = (op == '=='))
|
||||
elif op in ('<', '<=', '>', '>='):
|
||||
if op in ('>', '<='):
|
||||
elif nt == '==' or nt == '!=':
|
||||
result = lslfuncs.compare(op1, op2, Eq = (nt == '=='))
|
||||
elif nt in ('<', '<=', '>', '>='):
|
||||
if nt in ('>', '<='):
|
||||
result = lslfuncs.less(op2, op1)
|
||||
else:
|
||||
result = lslfuncs.less(op1, op2)
|
||||
if op in ('>=', '<='):
|
||||
if nt in ('>=', '<='):
|
||||
result = 1-result
|
||||
elif op == '|':
|
||||
elif nt == '|':
|
||||
result = op1 | op2
|
||||
elif op == '^':
|
||||
elif nt == '^':
|
||||
result = op1 ^ op2
|
||||
elif op == '&':
|
||||
elif nt == '&':
|
||||
result = op1 & op2
|
||||
elif op == '||':
|
||||
elif nt == '||':
|
||||
result = int(op1 or op2)
|
||||
elif op == '&&':
|
||||
elif nt == '&&':
|
||||
result = int(op1 and op2)
|
||||
else:
|
||||
raise Exception(u'Internal error: Operator not found: ' + op.decode('utf8')) # pragma: no cover
|
||||
parent[index] = {'node':'CONST', 'type':code['type'], 'value':result}
|
||||
elif node == '-' and child[0]['type'] in ('integer', 'float') \
|
||||
and child[1]['type'] in ('integer', 'float'):
|
||||
raise Exception(u'Internal error: Operator not found: ' + nt.decode('utf8')) # pragma: no cover
|
||||
parent[index] = {'nt':'CONST', 't':node['t'], 'value':result}
|
||||
elif nt == '-' and child[0]['t'] in ('integer', 'float') \
|
||||
and child[1]['t'] in ('integer', 'float'):
|
||||
# Change - to + - for int/float
|
||||
if child[1]['node'] == 'CONST':
|
||||
if child[1]['nt'] == 'CONST':
|
||||
if child[1]['value'] == 0:
|
||||
parent[index] = child[0]
|
||||
else:
|
||||
code['node'] = '+'
|
||||
node['nt'] = '+'
|
||||
child[1]['value'] = lslfuncs.neg(child[1]['value'])
|
||||
#TODO: Implement to transform 0-x into -x: elif child[0]['node'] == 'CONST':
|
||||
#TODO: Implement to transform 0-x into -x: elif child[0]['nt'] == 'CONST':
|
||||
else:
|
||||
code['node'] = '+'
|
||||
child[1] = {'node':'NEG', 'type':child[1]['type'], 'br':[child[1]]}
|
||||
elif node == '<<' and child[1]['node'] == 'CONST':
|
||||
node['nt'] = '+'
|
||||
child[1] = {'nt':'NEG', 't':child[1]['t'], 'ch':[child[1]]}
|
||||
elif nt == '<<' and child[1]['nt'] == 'CONST':
|
||||
# Transforming << into multiply saves some bytes.
|
||||
if child[1]['value'] & 31:
|
||||
# x << 3 --> x * 8
|
||||
# Do we need parentheses for *? It depends on x
|
||||
# e.g. x+3<<3 needs parentheses when converted to (x+3)*8
|
||||
if child[0]['node'] in ('+', '-', 'NEG'): # operands with priority between * and << #TODO: CHECK
|
||||
child[0] = {'node':'()', 'type':child[0]['type'], 'br':[child[0]]}
|
||||
if child[0]['nt'] in ('+', '-', 'NEG'): # operands with priority between * and << #TODO: CHECK
|
||||
child[0] = {'nt':'()', 't':child[0]['t'], 'ch':[child[0]]}
|
||||
# we have {<<, something, {CONST n}}, transform into {*, something, {CONST n}}
|
||||
code['node'] = '*'
|
||||
node['nt'] = '*'
|
||||
child[1]['value'] = 1<<(child[1]['value'] & 31)
|
||||
else: # x << 0 --> x
|
||||
parent[index] = child[0]
|
||||
|
@ -179,7 +178,7 @@ class optimizer(object):
|
|||
# Maybe turn != -1 into ~ in if()'s.
|
||||
return
|
||||
|
||||
if node in self.assign_ops:
|
||||
if nt in self.assign_ops:
|
||||
# TODO: Eliminate redundant operations, e.g. a += 0; etc.
|
||||
# Consider also e.g. x -= 1 or x -= a transforming it into +=.
|
||||
# Actually just consider transforming the whole thing into a
|
||||
|
@ -188,9 +187,9 @@ class optimizer(object):
|
|||
self.FoldTree(child, 1)
|
||||
return
|
||||
|
||||
if node == 'IDENT' or node == 'FLD':
|
||||
if nt == 'IDENT' or nt == 'FLD':
|
||||
if self.globalmode:
|
||||
ident = code if node == 'IDENT' else child[0]
|
||||
ident = child[0] if nt == 'FLD' else node
|
||||
# Resolve constant values so they can be optimized
|
||||
sym = self.symtab[ident['scope']][ident['name']]
|
||||
|
||||
|
@ -198,62 +197,62 @@ class optimizer(object):
|
|||
assert defn['name'] == ident['name']
|
||||
|
||||
# Assume we already were there
|
||||
if 'br' in defn:
|
||||
val = defn['br'][0]
|
||||
if val['node'] != 'CONST' or ident['type'] in ('list', 'key'):
|
||||
if 'ch' in defn:
|
||||
val = defn['ch'][0]
|
||||
if val['nt'] != 'CONST' or ident['t'] in ('list', 'key'):
|
||||
return
|
||||
else:
|
||||
val = {'node':'CONST', 'type':defn['type'],
|
||||
'value':self.DefaultValues[defn['type']]}
|
||||
if node == 'FLD':
|
||||
val = {'node':'CONST', 'type':'float',
|
||||
'value':val['value']['xyzs'.index(code['fld'])]}
|
||||
val = {'nt':'CONST', 't':defn['t'],
|
||||
'value':self.DefaultValues[defn['t']]}
|
||||
if nt == 'FLD':
|
||||
val = {'nt':'CONST', 't':'float',
|
||||
'value':val['value']['xyzs'.index(node['fld'])]}
|
||||
parent[index] = val
|
||||
return
|
||||
|
||||
if node == 'FNCALL':
|
||||
if nt == 'FNCALL':
|
||||
for idx in xrange(len(child)-1, -1, -1):
|
||||
self.FoldTree(child, idx)
|
||||
if code['name'] in self.symtab[0]:
|
||||
fn = self.symtab[0][code['name']]['Loc']
|
||||
if fn is not None and type(fn) != int and all(arg['node'] == 'CONST' for arg in child):
|
||||
if 'fn' in self.symtab[0][node['name']]:
|
||||
fn = self.symtab[0][node['name']]['fn']
|
||||
if all(arg['nt'] == 'CONST' for arg in child):
|
||||
# Call it
|
||||
value = fn(*tuple(arg['value'] for arg in child))
|
||||
if not self.foldtabs and isinstance(value, unicode) and '\t' in value:
|
||||
warning('WARNING: Tab in function result and foldtabs option not used.')
|
||||
return
|
||||
parent[index] = {'node':'CONST', 'type':code['type'], 'value':value}
|
||||
parent[index] = {'nt':'CONST', 't':node['t'], 'value':value}
|
||||
return
|
||||
|
||||
if node == 'PRINT':
|
||||
if nt == 'PRINT':
|
||||
# useless but who knows
|
||||
self.FoldTree(child, 0)
|
||||
return
|
||||
|
||||
if node in ('VECTOR', 'ROTATION', 'LIST'):
|
||||
if nt in ('VECTOR', 'ROTATION', 'LIST'):
|
||||
isconst = True
|
||||
for idx in xrange(len(child)-1, -1, -1):
|
||||
self.FoldTree(child, idx)
|
||||
if child[idx]['node'] != 'CONST':
|
||||
if child[idx]['nt'] != 'CONST':
|
||||
isconst = False
|
||||
if isconst:
|
||||
value = [elem['value'] for elem in child]
|
||||
if node == 'VECTOR':
|
||||
if nt == 'VECTOR':
|
||||
value = lslfuncs.Vector([lslfuncs.ff(x) for x in value])
|
||||
elif node == 'ROTATION':
|
||||
elif nt == 'ROTATION':
|
||||
value = lslfuncs.Quaternion([lslfuncs.ff(x) for x in value])
|
||||
parent[index] = {'node':'CONST', 'type':code['type'], 'value':value}
|
||||
parent[index] = {'nt':'CONST', 't':node['t'], 'value':value}
|
||||
return
|
||||
|
||||
if node in ('{}', 'FNDEF', 'STATEDEF'):
|
||||
if nt in ('{}', 'FNDEF', 'STDEF'):
|
||||
for idx in xrange(len(child)):
|
||||
self.FoldTree(child, idx)
|
||||
self.FoldStmt(child, idx)
|
||||
return
|
||||
|
||||
if node == 'IF':
|
||||
if nt == 'IF':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
if child[0]['nt'] == 'CONST':
|
||||
# We can remove one of the branches safely.
|
||||
if lslfuncs.cond(child[0]['value']):
|
||||
self.FoldTree(child, 1)
|
||||
|
@ -265,7 +264,7 @@ class optimizer(object):
|
|||
self.FoldStmt(child, 2)
|
||||
else:
|
||||
# No ELSE branch, replace the statement with an empty one.
|
||||
parent[index] = {'node':';', 'type':None}
|
||||
parent[index] = {'nt':';', 't':None}
|
||||
else:
|
||||
self.FoldTree(child, 1)
|
||||
self.FoldStmt(child, 1)
|
||||
|
@ -274,46 +273,46 @@ class optimizer(object):
|
|||
self.FoldStmt(child, 2)
|
||||
return
|
||||
|
||||
if node == 'WHILE':
|
||||
if nt == 'WHILE':
|
||||
self.FoldTree(child, 0)
|
||||
if child[0]['node'] == 'CONST':
|
||||
if child[0]['nt'] == 'CONST':
|
||||
# See if the whole WHILE can be eliminated.
|
||||
if lslfuncs.cond(child[0]['value']):
|
||||
# Endless loop which must be kept.
|
||||
# First, replace the constant.
|
||||
child[0].update({'type':'integer', 'value':1})
|
||||
child[0].update({'t':'integer', 'value':1})
|
||||
# Recurse on the statement.
|
||||
self.FoldTree(child, 1)
|
||||
self.FoldStmt(child, 1)
|
||||
else:
|
||||
# Can be removed.
|
||||
parent[index] = {'node':';', 'type':None}
|
||||
parent[index] = {'nt':';', 't':None}
|
||||
else:
|
||||
self.FoldTree(child, 1)
|
||||
self.FoldStmt(child, 1)
|
||||
return
|
||||
|
||||
if node == 'DO':
|
||||
if nt == 'DO':
|
||||
self.FoldTree(child, 0) # This one is always executed.
|
||||
self.FoldStmt(child, 0)
|
||||
self.FoldTree(child, 1)
|
||||
# See if the latest part is a constant.
|
||||
if child[1]['node'] == 'CONST':
|
||||
if child[1]['nt'] == 'CONST':
|
||||
if lslfuncs.cond(child[1]['value']):
|
||||
# Endless loop. Replace the constant.
|
||||
child[1].update({'type':'integer', 'value':1})
|
||||
child[1].update({'t':'integer', 'value':1})
|
||||
else:
|
||||
# Only one go. Replace with the statement(s).
|
||||
parent[index] = child[0]
|
||||
return
|
||||
|
||||
if node == 'FOR':
|
||||
assert child[0]['node'] == 'EXPRLIST'
|
||||
assert child[2]['node'] == 'EXPRLIST'
|
||||
self.FoldAndRemoveEmptyStmts(child[0]['br'])
|
||||
if nt == 'FOR':
|
||||
assert child[0]['nt'] == 'EXPRLIST'
|
||||
assert child[2]['nt'] == 'EXPRLIST'
|
||||
self.FoldAndRemoveEmptyStmts(child[0]['ch'])
|
||||
|
||||
self.FoldTree(child, 1) # Condition.
|
||||
if child[1]['node'] == 'CONST':
|
||||
if child[1]['nt'] == 'CONST':
|
||||
# FOR is delicate. It can have multiple expressions at start.
|
||||
# And if there is more than one, these expressions will need a
|
||||
# new block, which means new scope, which is dangerous.
|
||||
|
@ -321,28 +320,28 @@ class optimizer(object):
|
|||
# it feels creepy.
|
||||
if lslfuncs.cond(child[1]['value']):
|
||||
# Endless loop. Just replace the constant and traverse the rest.
|
||||
child[1].update({'type':'integer', 'value':1})
|
||||
self.FoldAndRemoveEmptyStmts(child[2]['br'])
|
||||
child[1].update({'t':'integer', 'value':1})
|
||||
self.FoldAndRemoveEmptyStmts(child[2]['ch'])
|
||||
self.FoldTree(child, 3)
|
||||
self.FoldStmt(child, 3)
|
||||
elif len(child[0]['br']) > 1:
|
||||
parent[index] = {'node':'{}', 'type':None, 'br':child[0]['br']}
|
||||
elif child[0]['br']:
|
||||
parent[index] = child[0]['br'][0]
|
||||
elif len(child[0]['ch']) > 1:
|
||||
parent[index] = {'nt':'{}', 't':None, 'ch':child[0]['ch']}
|
||||
elif child[0]['ch']:
|
||||
parent[index] = child[0]['ch'][0]
|
||||
else:
|
||||
parent[index] = {'node':';', 'type':None}
|
||||
parent[index] = {'nt':';', 't':None}
|
||||
else:
|
||||
self.FoldAndRemoveEmptyStmts(child[2]['br'])
|
||||
self.FoldAndRemoveEmptyStmts(child[2]['ch'])
|
||||
self.FoldTree(child, 3)
|
||||
self.FoldStmt(child, 3)
|
||||
return
|
||||
|
||||
if node == 'RETURN':
|
||||
if nt == 'RETURN':
|
||||
if child:
|
||||
self.FoldTree(child, 0)
|
||||
return
|
||||
|
||||
if node == 'DECL':
|
||||
if nt == 'DECL':
|
||||
# The expression code is elsewhere.
|
||||
if child:
|
||||
self.FoldTree(child, 0)
|
||||
|
@ -352,20 +351,20 @@ class optimizer(object):
|
|||
pass
|
||||
return
|
||||
|
||||
if node in self.ignored_stmts:
|
||||
if nt in self.ignored_stmts:
|
||||
return
|
||||
|
||||
raise Exception('Internal error: This should not happen, node = ' + node) # pragma: no cover
|
||||
assert False, 'Internal error: This should not happen, node type = ' + nt # pragma: no cover
|
||||
|
||||
def IsValidGlobalConstant(self, decl):
|
||||
if 'br' not in decl:
|
||||
if 'ch' not in decl:
|
||||
return True
|
||||
expr = decl['br'][0]
|
||||
if expr['node'] in ('CONST', 'IDENT'):
|
||||
expr = decl['ch'][0]
|
||||
if expr['nt'] in ('CONST', 'IDENT'):
|
||||
return True
|
||||
if expr['node'] not in ('VECTOR', 'ROTATION', 'LIST'):
|
||||
if expr['nt'] not in ('VECTOR', 'ROTATION', 'LIST'):
|
||||
return False
|
||||
return all(elem['node'] in ('CONST', 'IDENT') for elem in expr['br'])
|
||||
return all(elem['nt'] in ('CONST', 'IDENT') for elem in expr['ch'])
|
||||
|
||||
def optimize(self, treesymtab, options = ('optimize',)):
|
||||
"""Optimize the symbolic table symtab in place. Requires a table of
|
||||
|
@ -385,7 +384,7 @@ class optimizer(object):
|
|||
|
||||
# Constant folding pass. It does some other optimizations along the way.
|
||||
for idx in xrange(len(tree)):
|
||||
if tree[idx]['node'] == 'DECL':
|
||||
if tree[idx]['nt'] == 'DECL':
|
||||
self.globalmode = True
|
||||
self.FoldTree(tree, idx)
|
||||
self.globalmode = False
|
||||
|
|
|
@ -134,11 +134,11 @@ class outscript(object):
|
|||
def dent(self):
|
||||
return self.indent * self.indentlevel
|
||||
|
||||
def OutIndented(self, code):
|
||||
if code['node'] != '{}':
|
||||
def OutIndented(self, node):
|
||||
if node['nt'] != '{}':
|
||||
self.indentlevel += 1
|
||||
ret = self.OutCode(code)
|
||||
if code['node'] != '{}':
|
||||
ret = self.OutCode(node)
|
||||
if node['nt'] != '{}':
|
||||
self.indentlevel -= 1
|
||||
return ret
|
||||
|
||||
|
@ -155,96 +155,96 @@ class outscript(object):
|
|||
|
||||
def OutExpr(self, expr):
|
||||
# Handles expression nodes (as opposed to statement nodes)
|
||||
node = expr['node']
|
||||
if 'br' in expr:
|
||||
child = expr['br']
|
||||
nt = expr['nt']
|
||||
if 'ch' in expr:
|
||||
child = expr['ch']
|
||||
|
||||
if node == '()':
|
||||
if nt == '()':
|
||||
return '(' + self.OutExpr(child[0]) + ')'
|
||||
|
||||
if node in self.binary_operands:
|
||||
return self.OutExpr(child[0]) + ' ' + node + ' ' + self.OutExpr(child[1])
|
||||
if nt in self.binary_operands:
|
||||
return self.OutExpr(child[0]) + ' ' + nt + ' ' + self.OutExpr(child[1])
|
||||
|
||||
if node == 'IDENT':
|
||||
if nt == 'IDENT':
|
||||
return expr['name']
|
||||
|
||||
if node == 'CONST':
|
||||
if nt == 'CONST':
|
||||
return self.Value2LSL(expr['value'])
|
||||
|
||||
if node == 'CAST':
|
||||
ret = '(' + expr['type'] + ')'
|
||||
if nt == 'CAST':
|
||||
ret = '(' + expr['t'] + ')'
|
||||
expr = child[0]
|
||||
if expr['node'] in ('CONST', 'IDENT', 'V++', 'V--', 'VECTOR',
|
||||
if expr['nt'] in ('CONST', 'IDENT', 'V++', 'V--', 'VECTOR',
|
||||
'ROTATION', 'LIST', 'FIELD', 'PRINT', 'FUNCTION', '()'):
|
||||
return ret + self.OutExpr(expr)
|
||||
return ret + '(' + self.OutExpr(expr) + ')'
|
||||
|
||||
if node == 'LIST':
|
||||
if nt == 'LIST':
|
||||
self.listmode = True
|
||||
ret = '[' + self.OutExprList(child) + ']'
|
||||
self.listmode = False
|
||||
return ret
|
||||
|
||||
if node in ('VECTOR', 'ROTATION'):
|
||||
if nt in ('VECTOR', 'ROTATION'):
|
||||
return '<' + self.OutExprList(child) + '>'
|
||||
|
||||
if node == 'FNCALL':
|
||||
if nt == 'FNCALL':
|
||||
return expr['name'] + '(' + self.OutExprList(child) + ')'
|
||||
|
||||
if node == 'PRINT':
|
||||
if nt == 'PRINT':
|
||||
return 'print(' + self.OutExpr(child[0]) + ')'
|
||||
|
||||
if node in self.unary_operands:
|
||||
if node == 'NEG':
|
||||
node = '- '
|
||||
return node + self.OutExpr(child[0])
|
||||
if nt in self.unary_operands:
|
||||
if nt == 'NEG':
|
||||
nt = '- '
|
||||
return nt + self.OutExpr(child[0])
|
||||
|
||||
if node == 'FLD':
|
||||
if nt == 'FLD':
|
||||
return self.OutExpr(child[0]) + '.' + expr['fld']
|
||||
|
||||
if node in ('V--', 'V++'):
|
||||
return self.OutExpr(child[0]) + ('++' if node == 'V++' else '--')
|
||||
if nt in ('V--', 'V++'):
|
||||
return self.OutExpr(child[0]) + ('++' if nt == 'V++' else '--')
|
||||
|
||||
if node in ('--V', '++V'):
|
||||
return ('++' if node == '++V' else '--') + self.OutExpr(child[0])
|
||||
if nt in ('--V', '++V'):
|
||||
return ('++' if nt == '++V' else '--') + self.OutExpr(child[0])
|
||||
|
||||
if node in self.extended_assignments:
|
||||
if nt in self.extended_assignments:
|
||||
lvalue = self.OutExpr(child[0])
|
||||
return lvalue + ' = ' + lvalue + ' ' + node[:-1] + ' (' + self.OutExpr(child[1]) + ')'
|
||||
return lvalue + ' = ' + lvalue + ' ' + nt[:-1] + ' (' + self.OutExpr(child[1]) + ')'
|
||||
|
||||
if node == 'EXPRLIST':
|
||||
if nt == 'EXPRLIST':
|
||||
return self.OutExprList(child)
|
||||
|
||||
assert False, 'Internal error: expression type "' + node + '" not handled' # pragma: no cover
|
||||
assert False, 'Internal error: expression type "' + nt + '" not handled' # pragma: no cover
|
||||
|
||||
def OutCode(self, code):
|
||||
node = code['node']
|
||||
if 'br' in code:
|
||||
child = code['br']
|
||||
def OutCode(self, node):
|
||||
nt = node['nt']
|
||||
if 'ch' in node:
|
||||
child = node['ch']
|
||||
else:
|
||||
child = None
|
||||
|
||||
if node == 'IF':
|
||||
if nt == 'IF':
|
||||
ret = self.dent()
|
||||
while True:
|
||||
ret += 'if (' + self.OutExpr(child[0]) + ')\n' + self.OutIndented(child[1])
|
||||
if len(child) < 3:
|
||||
return ret
|
||||
if child[2]['node'] != 'IF':
|
||||
if child[2]['nt'] != 'IF':
|
||||
ret += self.dent() + 'else\n' + self.OutIndented(child[2])
|
||||
return ret
|
||||
ret += self.dent() + 'else '
|
||||
code = child[2]
|
||||
child = code['br']
|
||||
if node == 'WHILE':
|
||||
node = child[2]
|
||||
child = node['ch']
|
||||
if nt == 'WHILE':
|
||||
ret = self.dent() + 'while (' + self.OutExpr(child[0]) + ')\n'
|
||||
ret += self.OutIndented(child[1])
|
||||
return ret
|
||||
if node == 'DO':
|
||||
if nt == 'DO':
|
||||
ret = self.dent() + 'do\n'
|
||||
ret += self.OutIndented(child[0])
|
||||
return ret + self.dent() + 'while (' + self.OutExpr(child[1]) + ');\n'
|
||||
if node == 'FOR':
|
||||
if nt == 'FOR':
|
||||
ret = self.dent() + 'for ('
|
||||
ret += self.OutExpr(child[0])
|
||||
ret += '; ' + self.OutExpr(child[1]) + '; '
|
||||
|
@ -252,48 +252,48 @@ class outscript(object):
|
|||
ret += ')\n'
|
||||
ret += self.OutIndented(child[3])
|
||||
return ret
|
||||
if node == '@':
|
||||
return self.dent() + '@' + code['name'] + ';\n'
|
||||
if node == 'JUMP':
|
||||
return self.dent() + 'jump ' + code['name'] + ';\n'
|
||||
if node == 'STATE':
|
||||
return self.dent() + 'state ' + code['name'] + ';\n'
|
||||
if node == 'RETURN':
|
||||
if nt == '@':
|
||||
return self.dent() + '@' + node['name'] + ';\n'
|
||||
if nt == 'JUMP':
|
||||
return self.dent() + 'jump ' + node['name'] + ';\n'
|
||||
if nt == 'STSW':
|
||||
return self.dent() + 'state ' + node['name'] + ';\n'
|
||||
if nt == 'RETURN':
|
||||
if child:
|
||||
return self.dent() + 'return ' + self.OutExpr(child[0]) + ';\n'
|
||||
return self.dent() + 'return;\n'
|
||||
if node == 'DECL':
|
||||
ret = self.dent() + code['type'] + ' ' + code['name']
|
||||
if nt == 'DECL':
|
||||
ret = self.dent() + node['t'] + ' ' + node['name']
|
||||
if child:
|
||||
ret += ' = ' + self.OutExpr(child[0])
|
||||
return ret + ';\n'
|
||||
if node == ';':
|
||||
if nt == ';':
|
||||
return self.dent() + ';\n'
|
||||
|
||||
if node in ('STATEDEF', '{}'):
|
||||
if nt in ('STDEF', '{}'):
|
||||
ret = ''
|
||||
if node == 'STATEDEF':
|
||||
if code['name'] == 'default':
|
||||
if nt == 'STDEF':
|
||||
if node['name'] == 'default':
|
||||
ret = self.dent() + 'default\n'
|
||||
else:
|
||||
ret = self.dent() + 'state ' + code['name'] + '\n'
|
||||
ret = self.dent() + 'state ' + node['name'] + '\n'
|
||||
|
||||
ret += self.dent() + '{\n'
|
||||
self.indentlevel += 1
|
||||
for stmt in code['br']:
|
||||
for stmt in node['ch']:
|
||||
ret += self.OutCode(stmt)
|
||||
self.indentlevel -= 1
|
||||
return ret + self.dent() + '}\n'
|
||||
|
||||
if node == 'FNDEF':
|
||||
if nt == 'FNDEF':
|
||||
ret = self.dent()
|
||||
if code['type'] is not None:
|
||||
ret += code['type'] + ' '
|
||||
ret += code['name'] + '('
|
||||
ret += ', '.join(typ + ' ' + name for typ, name in zip(code['ptypes'], code['pnames']))
|
||||
if node['t'] is not None:
|
||||
ret += node['t'] + ' '
|
||||
ret += node['name'] + '('
|
||||
ret += ', '.join(typ + ' ' + name for typ, name in zip(node['ptypes'], node['pnames']))
|
||||
return ret + ')\n' + self.OutCode(child[0])
|
||||
|
||||
return self.dent() + self.OutExpr(code) + ';\n'
|
||||
return self.dent() + self.OutExpr(node) + ';\n'
|
||||
|
||||
def output(self, treesymtab, options = ('optsigns',)):
|
||||
# Build a sorted list of dict entries
|
||||
|
@ -307,12 +307,12 @@ class outscript(object):
|
|||
self.indentlevel = 0
|
||||
self.globalmode = False
|
||||
self.listmode = False
|
||||
for code in self.tree:
|
||||
if code['node'] == 'DECL':
|
||||
for node in self.tree:
|
||||
if node['nt'] == 'DECL': # TODO: self.globalmode = node['nt'] == 'DECL'
|
||||
self.globalmode = True
|
||||
ret += self.OutCode(code)
|
||||
ret += self.OutCode(node)
|
||||
self.globalmode = False
|
||||
else:
|
||||
ret += self.OutCode(code)
|
||||
ret += self.OutCode(node)
|
||||
|
||||
return ret
|
||||
|
|
|
@ -186,13 +186,13 @@ class parser(object):
|
|||
"""Check if automatic dynamic cast is possible, and insert it if
|
||||
requested explicitly.
|
||||
"""
|
||||
tval = value['type']
|
||||
tval = value['t']
|
||||
if tval == tgttype:
|
||||
return value
|
||||
if tval in ('string', 'key') and tgttype in ('string', 'key') \
|
||||
or tval == 'integer' and tgttype == 'float':
|
||||
if self.explicitcast:
|
||||
return {'node':'CAST', 'type':tgttype, 'br':[value]}
|
||||
return {'nt':'CAST', 't':tgttype, 'ch':[value]}
|
||||
return value
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
|
@ -481,11 +481,11 @@ class parser(object):
|
|||
ret.append(inequality)
|
||||
return ret
|
||||
# This is basically a copy/paste of the Parse_inequality handler
|
||||
ltype = inequality['type']
|
||||
ltype = inequality['t']
|
||||
if ltype not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
rexpr = self.Parse_shift()
|
||||
rtype = rexpr['type']
|
||||
rtype = rexpr['t']
|
||||
if rtype not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
if ltype != rtype:
|
||||
|
@ -493,7 +493,7 @@ class parser(object):
|
|||
inequality = self.autocastcheck(inequality, rtype)
|
||||
else:
|
||||
rexpr = self.autocastcheck(rexpr, ltype)
|
||||
inequality = {'node':op, 'type':'integer', 'br':[inequality, rexpr]}
|
||||
inequality = {'nt':op, 't':'integer', 'ch':[inequality, rexpr]}
|
||||
|
||||
# Reaching this means an operator or lower precedence happened,
|
||||
# e.g. <1,1,1,2==2> (that's syntax error in ==)
|
||||
|
@ -529,28 +529,28 @@ class parser(object):
|
|||
tok0 = self.tok[0]
|
||||
val = self.tok[1]
|
||||
self.NextToken()
|
||||
return {'node':CONST, 'type':'integer' if type(val) == int else 'float', 'value':-val}
|
||||
return {'nt':CONST, 't':'integer' if type(val) == int else 'float', 'value':-val}
|
||||
if tok0 == 'INTEGER_VALUE':
|
||||
return {'node':CONST, 'type':'integer', 'value':val}
|
||||
return {'nt':CONST, 't':'integer', 'value':val}
|
||||
if tok0 == 'FLOAT_VALUE':
|
||||
return {'node':CONST, 'type':'float', 'value':val}
|
||||
return {'nt':CONST, 't':'float', 'value':val}
|
||||
if tok0 == 'STRING_VALUE':
|
||||
if self.allowmultistrings:
|
||||
while self.tok[0] == 'STRING_VALUE':
|
||||
val += self.tok[1]
|
||||
self.NextToken()
|
||||
return {'node':CONST, 'type':'string', 'value':val}
|
||||
return {'nt':CONST, 't':'string', 'value':val}
|
||||
# Key constants are not currently supported - use string
|
||||
#if tok0 == 'KEY_VALUE':
|
||||
# return [CONST, 'key', val]
|
||||
if tok0 == 'VECTOR_VALUE':
|
||||
return {'node':CONST, 'type':'vector', 'value':val}
|
||||
return {'nt':CONST, 't':'vector', 'value':val}
|
||||
if tok0 == 'ROTATION_VALUE':
|
||||
return {'node':CONST, 'type':'rotation', 'value':val}
|
||||
return {'nt':CONST, 't':'rotation', 'value':val}
|
||||
if tok0 == 'LIST_VALUE':
|
||||
return {'node':CONST, 'type':'list', 'value':val}
|
||||
return {'nt':CONST, 't':'list', 'value':val}
|
||||
if tok0 in ('TRUE', 'FALSE'):
|
||||
return {'node':CONST, 'type':'integer', 'value':int(tok0 == 'TRUE')}
|
||||
return {'nt':CONST, 't':'integer', 'value':int(tok0 == 'TRUE')}
|
||||
if tok0 == '<':
|
||||
val = [self.Parse_expression()]
|
||||
self.expect(',')
|
||||
|
@ -586,23 +586,23 @@ class parser(object):
|
|||
val += self.Parse_vector_rotation_tail()
|
||||
|
||||
if len(val) == 3:
|
||||
return {'node':'VECTOR', 'type':'vector', 'br':val}
|
||||
return {'node':'ROTATION', 'type':'rotation', 'br':val}
|
||||
return {'nt':'VECTOR', 't':'vector', 'ch':val}
|
||||
return {'nt':'ROTATION', 't':'rotation', 'ch':val}
|
||||
|
||||
if tok0 == '[':
|
||||
val = self.Parse_optional_expression_list()
|
||||
self.expect(']')
|
||||
self.NextToken()
|
||||
return {'node':'LIST', 'type':'list', 'br':val}
|
||||
return {'nt':'LIST', 't':'list', 'ch':val}
|
||||
if tok0 == 'PRINT':
|
||||
self.expect('(')
|
||||
self.NextToken()
|
||||
expr = self.Parse_expression()
|
||||
if expr['type'] not in self.types:
|
||||
raise EParseTypeMismatch(self) if expr['type'] is None else EParseUndefined(self)
|
||||
if expr['t'] not in self.types:
|
||||
raise EParseTypeMismatch(self) if expr['t'] is None else EParseUndefined(self)
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
return {'node':'PRINT', 'type':None, 'br':[expr]}
|
||||
return {'nt':'PRINT', 't':None, 'ch':[expr]}
|
||||
|
||||
if tok0 != 'IDENT':
|
||||
if tok0 == 'EOF':
|
||||
|
@ -623,30 +623,30 @@ class parser(object):
|
|||
args = self.Parse_optional_expression_list(sym['ParamTypes'])
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
return {'node':'FNCALL', 'type':sym['Type'], 'name':name,
|
||||
'scope':self.scopeindex, 'br':args}
|
||||
return {'nt':'FNCALL', 't':sym['Type'], 'name':name,
|
||||
'scope':self.scopeindex, 'ch':args}
|
||||
if sym['Kind'] != 'v':
|
||||
raise EParseTypeMismatch(self)
|
||||
typ = sym['Type']
|
||||
lvalue = {'node':'IDENT', 'type':typ, 'name':name, 'scope':sym['Scope']}
|
||||
lvalue = {'nt':'IDENT', 't':typ, 'name':name, 'scope':sym['Scope']}
|
||||
if tok0 == '.':
|
||||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
self.ValidateField(typ, self.tok[1])
|
||||
lvalue = {'node':'FLD', 'type':'float', 'br':[lvalue], 'fld':self.tok[1]}
|
||||
lvalue = {'nt':'FLD', 't':'float', 'ch':[lvalue], 'fld':self.tok[1]}
|
||||
self.NextToken()
|
||||
tok0 = self.tok[0]
|
||||
|
||||
if tok0 in ('++', '--'):
|
||||
self.NextToken()
|
||||
if lvalue['type'] not in ('integer', 'float'):
|
||||
if lvalue['t'] not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
return {'node':'V++' if tok0 == '++' else 'V--', 'type':lvalue['type'], 'br':[lvalue]}
|
||||
return {'nt':'V++' if tok0 == '++' else 'V--', 't':lvalue['t'], 'ch':[lvalue]}
|
||||
if AllowAssignment and (tok0 in self.assignment_ops
|
||||
or self.extendedassignment and tok0 in self.extassignment_ops):
|
||||
self.NextToken()
|
||||
expr = self.Parse_expression()
|
||||
rtyp = expr['type']
|
||||
rtyp = expr['t']
|
||||
if rtyp not in self.types:
|
||||
raise EParseTypeMismatch(self)
|
||||
if typ in ('integer', 'float'):
|
||||
|
@ -661,11 +661,11 @@ class parser(object):
|
|||
if tok0 == '=':
|
||||
if typ == 'list' != rtyp:
|
||||
if self.explicitcast:
|
||||
expr = {'node':'CAST', 'type':typ, 'br':[expr]}
|
||||
expr = {'nt':'CAST', 't':typ, 'ch':[expr]}
|
||||
else:
|
||||
expr = self.autocastcheck(expr, typ)
|
||||
|
||||
return {'node':'=', 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':'=', 't':typ, 'ch':[lvalue, expr]}
|
||||
|
||||
if tok0 == '+=':
|
||||
if typ == 'float':
|
||||
|
@ -675,34 +675,34 @@ class parser(object):
|
|||
raise EParseTypeMismatch(self)
|
||||
if self.explicitcast:
|
||||
if typ == 'list' != rtyp:
|
||||
expr = {'node':'CAST', 'type':typ, 'br':[expr]}
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
expr = {'nt':'CAST', 't':typ, 'ch':[expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
|
||||
if tok0 == '-=':
|
||||
if typ == rtyp in ('integer', 'float', 'vector', 'rotation'):
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
if tok0 in ('*=', '/='):
|
||||
# There is a special case dealt with in advance.
|
||||
if tok0 == '*=' and typ == 'integer' and rtyp == 'float':
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
|
||||
if (typ == rtyp or typ == 'vector') and rtyp in ('integer', 'float', 'rotation'):
|
||||
if typ == 'vector' and rtyp == 'integer':
|
||||
expr = self.autocastcheck(expr, 'float')
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
if tok0 == '%=':
|
||||
if typ == rtyp in ('integer', 'vector'):
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
# Rest take integer operands only
|
||||
|
||||
if typ == rtyp == 'integer':
|
||||
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]}
|
||||
return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
return lvalue
|
||||
|
@ -726,16 +726,16 @@ class parser(object):
|
|||
# Unary minus
|
||||
self.NextToken()
|
||||
value = self.Parse_factor()
|
||||
if value['type'] not in ('integer', 'float', 'vector', 'rotation'):
|
||||
if value['t'] not in ('integer', 'float', 'vector', 'rotation'):
|
||||
raise EParseTypeMismatch(self)
|
||||
return {'node':'NEG', 'type':value['type'], 'br':[value]}
|
||||
return {'nt':'NEG', 't':value['t'], 'ch':[value]}
|
||||
if tok0 in ('!', '~'):
|
||||
# Unary logic and bitwise NOT - applies to integers only
|
||||
self.NextToken()
|
||||
value = self.Parse_unary_expression()
|
||||
if value['type'] != 'integer':
|
||||
if value['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
return {'node':tok0, 'type':'integer', 'br':[value]}
|
||||
return {'nt':tok0, 't':'integer', 'ch':[value]}
|
||||
if tok0 in ('++', '--'):
|
||||
# Pre-increment / pre-decrement
|
||||
self.NextToken()
|
||||
|
@ -747,20 +747,20 @@ class parser(object):
|
|||
raise EParseUndefined(self)
|
||||
typ = sym['Type']
|
||||
|
||||
ret = {'node':'IDENT', 'type':typ, 'name':name, 'scope':sym['Scope']}
|
||||
ret = {'nt':'IDENT', 't':typ, 'name':name, 'scope':sym['Scope']}
|
||||
self.NextToken()
|
||||
if self.tok[0] == '.':
|
||||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
self.ValidateField(typ, self.tok[1])
|
||||
ret = {'node':'FLD', 'type':'float', 'br':[ret], 'fld':self.tok[1]}
|
||||
ret = {'nt':'FLD', 't':'float', 'ch':[ret], 'fld':self.tok[1]}
|
||||
self.NextToken()
|
||||
|
||||
typ = ret['type']
|
||||
typ = ret['t']
|
||||
if typ not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
return {'node':'++V' if tok0 == '++' else '--V', 'type':typ, 'br':[ret]}
|
||||
return {'nt':'++V' if tok0 == '++' else '--V', 't':typ, 'ch':[ret]}
|
||||
|
||||
if tok0 == '(':
|
||||
# Parenthesized expression or typecast
|
||||
|
@ -771,7 +771,7 @@ class parser(object):
|
|||
expr = self.Parse_expression()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
return {'node':'()', 'type':expr['type'], 'br':[expr]}
|
||||
return {'nt':'()', 't':expr['t'], 'ch':[expr]}
|
||||
|
||||
# Typecast
|
||||
typ = self.tok[1]
|
||||
|
@ -789,10 +789,10 @@ class parser(object):
|
|||
expr = self.Parse_expression()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
expr = {'node':'()', 'type':expr['type'], 'br':[expr]}
|
||||
expr = {'nt':'()', 't':expr['t'], 'ch':[expr]}
|
||||
else:
|
||||
expr = self.Parse_unary_postfix_expression(AllowAssignment = False)
|
||||
basetype = expr['type']
|
||||
basetype = expr['t']
|
||||
if typ == 'list' and basetype in self.types \
|
||||
or basetype in ('integer', 'float') and typ in ('integer', 'float', 'string') \
|
||||
or basetype == 'string' and typ in self.types \
|
||||
|
@ -800,7 +800,7 @@ class parser(object):
|
|||
or basetype == 'vector' and typ in ('string', 'vector') \
|
||||
or basetype == 'rotation' and typ in ('string', 'rotation') \
|
||||
or basetype == 'list' and typ == 'string':
|
||||
return {'node':'CAST', 'type':typ, 'br':[expr]}
|
||||
return {'nt':'CAST', 't':typ, 'ch':[expr]}
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
# Must be a postfix expression.
|
||||
|
@ -815,7 +815,7 @@ class parser(object):
|
|||
factor = self.Parse_unary_expression()
|
||||
while self.tok[0] in ('*', '/', '%'):
|
||||
op = self.tok[0]
|
||||
ltype = factor['type']
|
||||
ltype = factor['t']
|
||||
# Acceptable types for LHS
|
||||
if op in ('*', '/') and ltype not in ('integer', 'float',
|
||||
'vector', 'rotation') \
|
||||
|
@ -823,13 +823,13 @@ class parser(object):
|
|||
raise EParseTypeMismatch(self)
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_unary_expression()
|
||||
rtype = rexpr['type']
|
||||
rtype = rexpr['t']
|
||||
# Mod is easier to check for
|
||||
if op == '%' and ltype != rtype:
|
||||
raise EParseTypeMismatch(self)
|
||||
if op == '%' or ltype == rtype == 'integer':
|
||||
# Deal with the special cases first (it's easy)
|
||||
factor = {'node':op, 'type':ltype, 'br':[factor, rexpr]}
|
||||
factor = {'nt':op, 't':ltype, 'ch':[factor, rexpr]}
|
||||
else:
|
||||
# Any integer must be promoted to float now
|
||||
if ltype == 'integer':
|
||||
|
@ -851,7 +851,7 @@ class parser(object):
|
|||
resulttype = 'float'
|
||||
else:
|
||||
resulttype = ltype
|
||||
factor = {'node':op, 'type':resulttype, 'br':[factor, rexpr]}
|
||||
factor = {'nt':op, 't':resulttype, 'ch':[factor, rexpr]}
|
||||
else:
|
||||
raise EParseTypeMismatch(self)
|
||||
|
||||
|
@ -865,14 +865,14 @@ class parser(object):
|
|||
term = self.Parse_factor()
|
||||
while self.tok[0] in ('+', '-'):
|
||||
op = self.tok[0]
|
||||
ltype = term['type']
|
||||
ltype = term['t']
|
||||
if op == '+' and ltype not in self.types \
|
||||
or op == '-' and ltype not in ('integer', 'float',
|
||||
'vector', 'rotation'):
|
||||
raise EParseTypeMismatch(self)
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_factor()
|
||||
rtype = rexpr['type']
|
||||
rtype = rexpr['t']
|
||||
# This is necessary, but the reason is subtle.
|
||||
# The types must match in principle (except integer/float), so it
|
||||
# doesn't seem necessary to check rtype. But there's the case
|
||||
|
@ -889,12 +889,12 @@ class parser(object):
|
|||
raise EParseTypeMismatch(self)
|
||||
if self.explicitcast:
|
||||
if ltype == 'list' != rtype:
|
||||
rexpr = {'node':'CAST', 'type':ltype, 'br':[rexpr]}
|
||||
rexpr = {'nt':'CAST', 't':ltype, 'ch':[rexpr]}
|
||||
#rtype = ltype # unused
|
||||
elif rtype == 'list' != ltype:
|
||||
term = {'node':'CAST', 'type':rtype, 'br':[term]}
|
||||
term = {'nt':'CAST', 't':rtype, 'ch':[term]}
|
||||
ltype = rtype
|
||||
term = {'node':op, 'type':ltype, 'br':[term, rexpr]}
|
||||
term = {'nt':op, 't':ltype, 'ch':[term, rexpr]}
|
||||
# Note that although list + nonlist is semantically the same as
|
||||
# list + (list)nonlist and same goes for nonlist + list, they
|
||||
# don't compile to the same thing, but the optimizer should deal
|
||||
|
@ -903,11 +903,11 @@ class parser(object):
|
|||
and ltype in ('key', 'string') and rtype in ('key', 'string'):
|
||||
# Allow string+key addition (but add explicit cast)
|
||||
if ltype == 'key':
|
||||
term = {'node':op, 'type':rtype,
|
||||
'br':[{'node':'CAST', 'type':rtype, 'br':[term]}, rexpr]}
|
||||
term = {'nt':op, 't':rtype,
|
||||
'ch':[{'nt':'CAST', 't':rtype, 'ch':[term]}, rexpr]}
|
||||
else:
|
||||
term = {'node':op, 'type':ltype,
|
||||
'br':[term, {'node':'CAST', 'type':ltype, 'br':[rexpr]}]}
|
||||
term = {'nt':op, 't':ltype,
|
||||
'ch':[term, {'nt':'CAST', 't':ltype, 'ch':[rexpr]}]}
|
||||
elif ltype == 'key' or rtype == 'key':
|
||||
# Only list + key or key + list is allowed, otherwise keys can't
|
||||
# be added or subtracted with anything.
|
||||
|
@ -915,10 +915,10 @@ class parser(object):
|
|||
else:
|
||||
if ltype == 'float':
|
||||
# Promote rexpr to float
|
||||
term = {'node':op, 'type':ltype, 'br':[term, self.autocastcheck(rexpr, ltype)]}
|
||||
term = {'nt':op, 't':ltype, 'ch':[term, self.autocastcheck(rexpr, ltype)]}
|
||||
else:
|
||||
# Convert LHS to rtype if possible (note no keys arrive here)
|
||||
term = {'node':op, 'type':rtype, 'br':[self.autocastcheck(term, rtype), rexpr]}
|
||||
term = {'nt':op, 't':rtype, 'ch':[self.autocastcheck(term, rtype), rexpr]}
|
||||
|
||||
return term
|
||||
|
||||
|
@ -929,14 +929,14 @@ class parser(object):
|
|||
"""
|
||||
shift = self.Parse_term()
|
||||
while self.tok[0] in ('<<', '>>'):
|
||||
if shift['type'] != 'integer':
|
||||
if shift['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
op = self.tok[0]
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_term()
|
||||
if rexpr['type'] != 'integer':
|
||||
if rexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
shift = {'node':op, 'type':'integer', 'br':[shift , rexpr]}
|
||||
shift = {'nt':op, 't':'integer', 'ch':[shift , rexpr]}
|
||||
|
||||
return shift
|
||||
|
||||
|
@ -949,12 +949,12 @@ class parser(object):
|
|||
inequality = self.Parse_shift()
|
||||
while self.tok[0] in ('<', '<=', '>', '>='):
|
||||
op = self.tok[0]
|
||||
ltype = inequality['type']
|
||||
ltype = inequality['t']
|
||||
if ltype not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_shift()
|
||||
rtype = rexpr['type']
|
||||
rtype = rexpr['t']
|
||||
if rtype not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
if ltype != rtype:
|
||||
|
@ -962,7 +962,7 @@ class parser(object):
|
|||
inequality = self.autocastcheck(inequality, rtype)
|
||||
else:
|
||||
rexpr = self.autocastcheck(rexpr, ltype)
|
||||
inequality = {'node':op, 'type':'integer', 'br':[inequality, rexpr]}
|
||||
inequality = {'nt':op, 't':'integer', 'ch':[inequality, rexpr]}
|
||||
|
||||
return inequality
|
||||
|
||||
|
@ -975,19 +975,19 @@ class parser(object):
|
|||
comparison = self.Parse_inequality()
|
||||
while self.tok[0] in ('==', '!='):
|
||||
op = self.tok[0]
|
||||
ltype = comparison['type']
|
||||
ltype = comparison['t']
|
||||
if ltype not in self.types:
|
||||
raise EParseTypeMismatch(self)
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_inequality()
|
||||
rtype = rexpr['type']
|
||||
rtype = rexpr['t']
|
||||
if ltype == 'float':
|
||||
rexpr = self.autocastcheck(rexpr, ltype)
|
||||
else:
|
||||
# For string & key, RHS (rtype) mandates the conversion
|
||||
# (that's room for optimization: always compare strings)
|
||||
comparison = self.autocastcheck(comparison, rtype)
|
||||
comparison = {'node':op, 'type':'integer', 'br':[comparison, rexpr]}
|
||||
comparison = {'nt':op, 't':'integer', 'ch':[comparison, rexpr]}
|
||||
|
||||
return comparison
|
||||
|
||||
|
@ -998,14 +998,14 @@ class parser(object):
|
|||
"""
|
||||
bitbool_factor = self.Parse_comparison()
|
||||
while self.tok[0] == '&':
|
||||
if bitbool_factor['type'] != 'integer':
|
||||
if bitbool_factor['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
op = self.tok[0]
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_comparison()
|
||||
if rexpr['type'] != 'integer':
|
||||
if rexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
bitbool_factor = {'node':op, 'type':'integer', 'br':[bitbool_factor, rexpr]}
|
||||
bitbool_factor = {'nt':op, 't':'integer', 'ch':[bitbool_factor, rexpr]}
|
||||
|
||||
return bitbool_factor
|
||||
|
||||
|
@ -1016,14 +1016,14 @@ class parser(object):
|
|||
"""
|
||||
bitxor_term = self.Parse_bitbool_factor()
|
||||
while self.tok[0] == '^':
|
||||
if bitxor_term['type'] != 'integer':
|
||||
if bitxor_term['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
op = self.tok[0]
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_bitbool_factor()
|
||||
if rexpr['type'] != 'integer':
|
||||
if rexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
bitxor_term = {'node':op, 'type':'integer', 'br':[bitxor_term, rexpr]}
|
||||
bitxor_term = {'nt':op, 't':'integer', 'ch':[bitxor_term, rexpr]}
|
||||
|
||||
return bitxor_term
|
||||
|
||||
|
@ -1034,14 +1034,14 @@ class parser(object):
|
|||
"""
|
||||
bitbool_term = self.Parse_bitxor_term()
|
||||
while self.tok[0] == '|':
|
||||
if bitbool_term['type'] != 'integer':
|
||||
if bitbool_term['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
op = self.tok[0]
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_bitxor_term()
|
||||
if rexpr['type'] != 'integer':
|
||||
if rexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
bitbool_term = {'node':op, 'type':'integer', 'br':[bitbool_term, rexpr]}
|
||||
bitbool_term = {'nt':op, 't':'integer', 'ch':[bitbool_term, rexpr]}
|
||||
|
||||
return bitbool_term
|
||||
|
||||
|
@ -1064,14 +1064,14 @@ class parser(object):
|
|||
"""
|
||||
expression = self.Parse_bitbool_term()
|
||||
while self.tok[0] in ('&&', '||'):
|
||||
if expression['type'] != 'integer':
|
||||
if expression['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
op = self.tok[0]
|
||||
self.NextToken()
|
||||
rexpr = self.Parse_bitbool_term()
|
||||
if rexpr['type'] != 'integer':
|
||||
if rexpr['t'] != 'integer':
|
||||
raise EParseTypeMismatch(self)
|
||||
expression = {'node':op, 'type':'integer', 'br':[expression, rexpr]}
|
||||
expression = {'nt':op, 't':'integer', 'ch':[expression, rexpr]}
|
||||
|
||||
return expression
|
||||
|
||||
|
@ -1090,19 +1090,19 @@ class parser(object):
|
|||
idx = 0
|
||||
if self.tok[0] not in (']', ')', ';'):
|
||||
while True:
|
||||
val = self.Parse_expression()
|
||||
expr = self.Parse_expression()
|
||||
if expected_types is not None:
|
||||
if idx >= len(expected_types):
|
||||
raise EParseFunctionMismatch(self)
|
||||
try:
|
||||
val = self.autocastcheck(val, expected_types[idx]);
|
||||
expr = self.autocastcheck(expr, expected_types[idx]);
|
||||
except EParseTypeMismatch:
|
||||
raise EParseFunctionMismatch(self)
|
||||
else:
|
||||
if val['type'] not in self.types:
|
||||
if expr['t'] not in self.types:
|
||||
raise EParseTypeMismatch(self)
|
||||
idx += 1
|
||||
ret.append(val)
|
||||
ret.append(expr)
|
||||
if self.tok[0] != ',':
|
||||
break
|
||||
self.NextToken()
|
||||
|
@ -1136,7 +1136,7 @@ class parser(object):
|
|||
return self.Parse_code_block(ReturnType)
|
||||
if tok0 == ';':
|
||||
self.NextToken()
|
||||
return {'node':';', 'type':None}
|
||||
return {'nt':';', 't':None}
|
||||
if tok0 == '@':
|
||||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
|
@ -1147,13 +1147,13 @@ class parser(object):
|
|||
self.NextToken()
|
||||
self.expect(';')
|
||||
self.NextToken()
|
||||
return {'node':'@', 'type':None, 'name':name}
|
||||
return {'nt':'@', 't':None, 'name':name}
|
||||
if tok0 == 'JUMP':
|
||||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
name = self.tok[1]
|
||||
sym = self.FindSymbolPartial(name, MustBeLabel=True)
|
||||
jumpnode = {'node':'JUMP', 'type':None, 'name':name}
|
||||
jumpnode = {'nt':'JUMP', 't':None, 'name':name}
|
||||
if not sym or sym['Kind'] != 'l':
|
||||
# It might still be a forward reference, so we add it to the
|
||||
# list of things to look up when done
|
||||
|
@ -1175,7 +1175,7 @@ class parser(object):
|
|||
self.NextToken()
|
||||
self.expect(';')
|
||||
self.NextToken()
|
||||
return {'node':'STATE', 'type':None, 'name':name}
|
||||
return {'nt':'STSW', 't':None, 'name':name}
|
||||
if tok0 == 'RETURN':
|
||||
self.NextToken()
|
||||
if self.tok[0] == ';':
|
||||
|
@ -1189,9 +1189,9 @@ class parser(object):
|
|||
if ReturnType is not None and value is None:
|
||||
raise EParseReturnIsEmpty(self)
|
||||
if value is None:
|
||||
return {'node':'RETURN', 'type':None}
|
||||
return {'node':'RETURN', 'type':None, 'br':[self.autocastcheck(value, ReturnType)]}
|
||||
if tok0 == 'IF':
|
||||
return {'nt':'RETURN', 't':None}
|
||||
return {'nt':'RETURN', 't':None, 'ch':[self.autocastcheck(value, ReturnType)]}
|
||||
if tok0 == 'IF': # TODO: Convert this into a loop for ELSE IF's, saving recursion
|
||||
self.NextToken()
|
||||
self.expect('(')
|
||||
self.NextToken()
|
||||
|
@ -1204,8 +1204,8 @@ class parser(object):
|
|||
self.NextToken()
|
||||
else_branch = self.Parse_statement(ReturnType)
|
||||
if else_branch is not None:
|
||||
return {'node':'IF', 'type':None, 'br':[condition, then_branch, else_branch]}
|
||||
return {'node':'IF', 'type':None, 'br':[condition, then_branch]}
|
||||
return {'nt':'IF', 't':None, 'ch':[condition, then_branch, else_branch]}
|
||||
return {'nt':'IF', 't':None, 'ch':[condition, then_branch]}
|
||||
|
||||
if tok0 == 'WHILE':
|
||||
self.NextToken()
|
||||
|
@ -1214,7 +1214,7 @@ class parser(object):
|
|||
condition = self.Parse_expression()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
return {'node':'WHILE', 'type':None, 'br':[condition, self.Parse_statement(ReturnType)]}
|
||||
return {'nt':'WHILE', 't':None, 'ch':[condition, self.Parse_statement(ReturnType)]}
|
||||
if tok0 == 'DO':
|
||||
self.NextToken()
|
||||
stmt = self.Parse_statement(ReturnType)
|
||||
|
@ -1227,7 +1227,7 @@ class parser(object):
|
|||
self.NextToken()
|
||||
self.expect(';')
|
||||
self.NextToken()
|
||||
return {'node':'DO', 'type':None, 'br':[stmt, condition]}
|
||||
return {'nt':'DO', 't':None, 'ch':[stmt, condition]}
|
||||
if tok0 == 'FOR':
|
||||
self.NextToken()
|
||||
self.expect('(')
|
||||
|
@ -1242,10 +1242,10 @@ class parser(object):
|
|||
self.expect(')')
|
||||
self.NextToken()
|
||||
stmt = self.Parse_statement(ReturnType)
|
||||
return {'node':'FOR', 'type':None,
|
||||
'br':[{'node':'EXPRLIST','type':None, 'br':initializer},
|
||||
return {'nt':'FOR', 't':None,
|
||||
'ch':[{'nt':'EXPRLIST','t':None, 'ch':initializer},
|
||||
condition,
|
||||
{'node':'EXPRLIST','type':None, 'br':iterator},
|
||||
{'nt':'EXPRLIST','t':None, 'ch':iterator},
|
||||
stmt]}
|
||||
if tok0 == 'TYPE':
|
||||
if not AllowDecl:
|
||||
|
@ -1258,10 +1258,10 @@ class parser(object):
|
|||
raise EParseAlreadyDefined(self)
|
||||
self.NextToken()
|
||||
value = None
|
||||
decl = {'node':'DECL','type':typ, 'name':name, 'scope':self.scopeindex}
|
||||
decl = {'nt':'DECL','t':typ, 'name':name, 'scope':self.scopeindex}
|
||||
if self.tok[0] == '=':
|
||||
self.NextToken()
|
||||
decl['br'] = [self.Parse_expression()]
|
||||
decl['ch'] = [self.Parse_expression()]
|
||||
self.expect(';')
|
||||
self.NextToken()
|
||||
self.AddSymbol('v', self.scopeindex, name, Type=typ)
|
||||
|
@ -1297,7 +1297,7 @@ class parser(object):
|
|||
self.expect('}')
|
||||
self.NextToken()
|
||||
|
||||
return {'node':'{}', 'type':None, 'br':body}
|
||||
return {'nt':'{}', 't':None, 'ch':body}
|
||||
|
||||
def Parse_simple_expr(self, ForbidList=False):
|
||||
"""Grammar parsed here:
|
||||
|
@ -1315,19 +1315,19 @@ class parser(object):
|
|||
tok = self.tok
|
||||
self.NextToken()
|
||||
if tok[0] in ('TRUE', 'FALSE'): # TRUE and FALSE don't admit sign in globals
|
||||
return {'node':'CONST', 'type':'integer', 'value':int(tok[0]=='TRUE')}
|
||||
return {'nt':'CONST', 't':'integer', 'value':int(tok[0]=='TRUE')}
|
||||
if tok[0] in ('STRING_VALUE', 'KEY_VALUE', 'VECTOR_VALUE', 'ROTATION_VALUE', 'LIST_VALUE'):
|
||||
val = tok[1]
|
||||
if tok[0] == 'STRING_VALUE' and self.allowmultistrings:
|
||||
while self.tok[0] == 'STRING_VALUE':
|
||||
val += self.tok[1]
|
||||
self.NextToken()
|
||||
return {'node':'CONST', 'type':self.PythonType2LSL[type(val)], 'value':val}
|
||||
return {'nt':'CONST', 't':self.PythonType2LSL[type(val)], 'value':val}
|
||||
if tok[0] == 'IDENT':
|
||||
sym = self.FindSymbolPartial(tok[1])
|
||||
if sym is None or sym['Kind'] != 'v':
|
||||
raise EParseUndefined(self)
|
||||
return {'node':'IDENT', 'type':sym['Type'], 'name':tok[1], 'scope':sym['Scope']}
|
||||
return {'nt':'IDENT', 't':sym['Type'], 'name':tok[1], 'scope':sym['Scope']}
|
||||
if tok[0] == '<':
|
||||
value = [self.Parse_simple_expr()]
|
||||
self.autocastcheck(value[0], 'float')
|
||||
|
@ -1341,25 +1341,25 @@ class parser(object):
|
|||
self.autocastcheck(value[2], 'float')
|
||||
if self.tok[0] == '>':
|
||||
self.NextToken()
|
||||
return {'node':'VECTOR', 'type':'vector', 'br':value}
|
||||
return {'nt':'VECTOR', 't':'vector', 'ch':value}
|
||||
self.expect(',')
|
||||
self.NextToken()
|
||||
value.append(self.Parse_simple_expr())
|
||||
self.autocastcheck(value[3], 'float')
|
||||
self.expect('>')
|
||||
self.NextToken()
|
||||
return {'node':'ROTATION', 'type':'rotation', 'br':value}
|
||||
return {'nt':'ROTATION', 't':'rotation', 'ch':value}
|
||||
|
||||
if tok[0] == '[' and not ForbidList:
|
||||
value = []
|
||||
if self.tok[0] == ']':
|
||||
self.NextToken()
|
||||
return {'node':'LIST','type':'list','br':value}
|
||||
return {'nt':'LIST','t':'list','ch':value}
|
||||
while True:
|
||||
value.append(self.Parse_simple_expr(ForbidList=True))
|
||||
if self.tok[0] == ']':
|
||||
self.NextToken()
|
||||
return {'node':'LIST','type':'list','br':value}
|
||||
return {'nt':'LIST','t':'list','ch':value}
|
||||
self.expect(',')
|
||||
self.NextToken()
|
||||
# Integer or Float constant expected
|
||||
|
@ -1373,7 +1373,7 @@ class parser(object):
|
|||
value = tok[1]
|
||||
if neg and (tok[0] != 'INTEGER_VALUE' or value == -2147483648):
|
||||
value = -value
|
||||
return {'node':'CONST', 'type':'float' if tok[0] == 'FLOAT_VALUE' else 'integer', 'value':value}
|
||||
return {'nt':'CONST', 't':'float' if tok[0] == 'FLOAT_VALUE' else 'integer', 'value':value}
|
||||
|
||||
def Parse_optional_param_list(self):
|
||||
"""Grammar parsed here:
|
||||
|
@ -1431,9 +1431,9 @@ class parser(object):
|
|||
self.expect(')')
|
||||
self.NextToken()
|
||||
body = self.Parse_code_block(None)
|
||||
ret.append({'node':'FNDEF', 'type':None, 'name':name,
|
||||
ret.append({'nt':'FNDEF', 't':None, 'name':name,
|
||||
'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
|
||||
'br':[body]})
|
||||
'ch':[body]})
|
||||
self.PopScope()
|
||||
|
||||
return ret
|
||||
|
@ -1478,10 +1478,10 @@ class parser(object):
|
|||
value = None
|
||||
|
||||
assert self.scopeindex == 0
|
||||
decl = {'node':'DECL', 'type':typ, 'name':name, 'scope':0}
|
||||
decl = {'nt':'DECL', 't':typ, 'name':name, 'scope':0}
|
||||
if value is not None:
|
||||
value = self.autocastcheck(value, typ)
|
||||
decl['br'] = [value]
|
||||
decl['ch'] = [value]
|
||||
self.AddSymbol('v', 0, name, Loc=len(self.tree), Type=typ)
|
||||
self.tree.append(decl)
|
||||
|
||||
|
@ -1496,9 +1496,9 @@ class parser(object):
|
|||
paramscope = self.scopeindex
|
||||
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
|
||||
ParamTypes=params[0], ParamNames=params[1])
|
||||
self.tree.append({'node':'FNDEF', 'type':typ, 'name':name,
|
||||
self.tree.append({'nt':'FNDEF', 't':typ, 'name':name,
|
||||
'pscope':paramscope,
|
||||
'ptypes':params[0], 'pnames':params[1], 'br':[body]})
|
||||
'ptypes':params[0], 'pnames':params[1], 'ch':[body]})
|
||||
self.PopScope()
|
||||
assert self.scopeindex == 0
|
||||
else:
|
||||
|
@ -1543,7 +1543,7 @@ class parser(object):
|
|||
events = self.Parse_events()
|
||||
|
||||
self.expect('}')
|
||||
self.tree.append({'node':'STATEDEF', 'type':None, 'name':name, 'br':events})
|
||||
self.tree.append({'nt':'STDEF', 't':None, 'name':name, 'ch':events})
|
||||
self.NextToken()
|
||||
|
||||
def Parse_script(self):
|
||||
|
@ -1867,8 +1867,10 @@ class parser(object):
|
|||
# reference to the implementation; otherwise None.
|
||||
if name in self.functions:
|
||||
warning('Function already defined in bultins.txt, overwriting: ' + name)
|
||||
self.functions[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args,
|
||||
'Loc':getattr(lslfuncs, name, None)}
|
||||
fn = getattr(lslfuncs, name, None)
|
||||
self.functions[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args}
|
||||
if fn is not None:
|
||||
self.functions['Fn'] = fn
|
||||
elif match.group(4):
|
||||
# constant
|
||||
name = match.group(5)
|
||||
|
@ -1878,67 +1880,67 @@ class parser(object):
|
|||
typ = match.group(4)
|
||||
if typ == 'quaternion':
|
||||
typ = 'rotation'
|
||||
val = match.group(6)
|
||||
value = match.group(6)
|
||||
if typ == 'integer':
|
||||
val = int(val, 0)
|
||||
value = int(value, 0)
|
||||
elif typ == 'float':
|
||||
val = lslfuncs.F32(float(val))
|
||||
value = lslfuncs.F32(float(value))
|
||||
elif typ == 'string':
|
||||
val = val.decode('utf8')
|
||||
if not parse_str_re.match(val):
|
||||
value = value.decode('utf8')
|
||||
if not parse_str_re.match(value):
|
||||
raise EInternal
|
||||
esc = False
|
||||
tmp = val[1:-1]
|
||||
val = u''
|
||||
tmp = value[1:-1]
|
||||
value = u''
|
||||
for c in tmp:
|
||||
if esc:
|
||||
if c == u'n':
|
||||
c = u'\n'
|
||||
elif c == u't':
|
||||
c = u' '
|
||||
val += c
|
||||
value += c
|
||||
esc = False
|
||||
elif c == u'\\':
|
||||
esc = True
|
||||
else:
|
||||
val += c
|
||||
value += c
|
||||
#if typ == 'key':
|
||||
# val = Key(val)
|
||||
# value = Key(value)
|
||||
elif typ == 'key':
|
||||
warning('Key constants not supported in builtins.txt: ' + line)
|
||||
val = None
|
||||
value = None
|
||||
elif typ in ('vector', 'rotation'):
|
||||
if val[0:1] != '<' or val[-1:] != '>':
|
||||
if value[0:1] != '<' or value[-1:] != '>':
|
||||
raise ValueError
|
||||
val = val[1:-1].split(',')
|
||||
if len(val) != (3 if typ == 'vector' else 4):
|
||||
value = value[1:-1].split(',')
|
||||
if len(value) != (3 if typ == 'vector' else 4):
|
||||
raise ValueError
|
||||
num = parse_num_re.match(val[0])
|
||||
num = parse_num_re.match(value[0])
|
||||
if not num:
|
||||
raise ValueError
|
||||
val[0] = lslfuncs.F32(float(num.group(1)))
|
||||
num = parse_num_re.match(val[1])
|
||||
value[0] = lslfuncs.F32(float(num.group(1)))
|
||||
num = parse_num_re.match(value[1])
|
||||
if not num:
|
||||
raise ValueError
|
||||
val[1] = lslfuncs.F32(float(num.group(1)))
|
||||
num = parse_num_re.match(val[2])
|
||||
value[1] = lslfuncs.F32(float(num.group(1)))
|
||||
num = parse_num_re.match(value[2])
|
||||
if not num:
|
||||
raise ValueError
|
||||
val[2] = lslfuncs.F32(float(num.group(1)))
|
||||
if typ != 'vector':
|
||||
num = parse_num_re.match(val[3])
|
||||
if not num:
|
||||
raise ValueError
|
||||
val[3] = lslfuncs.F32(float(num.group(1)))
|
||||
val = Quaternion(val)
|
||||
value[2] = lslfuncs.F32(float(num.group(1)))
|
||||
if typ == 'vector':
|
||||
value = Vector(value)
|
||||
else:
|
||||
val = Vector(val)
|
||||
num = parse_num_re.match(value[3])
|
||||
if not num:
|
||||
raise ValueError
|
||||
value[3] = lslfuncs.F32(float(num.group(1)))
|
||||
value = Quaternion(value)
|
||||
else:
|
||||
assert typ == 'list'
|
||||
warning('List constants not supported in builtins.txt: ' + line)
|
||||
val = None
|
||||
if val is not None:
|
||||
self.constants[name] = val
|
||||
value = None
|
||||
if value is not None:
|
||||
self.constants[name] = value
|
||||
|
||||
except EInternal:
|
||||
warning('Invalid string in builtins.txt: ' + line)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue