Overall renaming of stuff to make it more understandable.

This commit is contained in:
Sei Lisa 2014-07-30 16:00:00 +02:00
parent fb68273eed
commit 895e4f4668
3 changed files with 336 additions and 335 deletions

View file

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

View file

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

View file

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