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, LSL2PythonType = {'integer':int, 'float':float, 'string':unicode, 'key':lslfuncs.Key,
'vector':lslfuncs.Vector, 'rotation':lslfuncs.Quaternion, 'list':list} '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): def FoldAndRemoveEmptyStmts(self, lst):
"""Utility function for elimination of useless expressions in FOR""" """Utility function for elimination of useless expressions in FOR"""
@ -26,7 +26,7 @@ class optimizer(object):
self.FoldTree(lst, idx) self.FoldTree(lst, idx)
self.FoldStmt(lst, idx) self.FoldStmt(lst, idx)
# If eliminated, it must be totally removed. A ';' won't do. # If eliminated, it must be totally removed. A ';' won't do.
if lst[idx]['node'] == ';': if lst[idx]['nt'] == ';':
del lst[idx] del lst[idx]
else: else:
idx += 1 idx += 1
@ -36,8 +36,8 @@ class optimizer(object):
nothing. nothing.
""" """
# Ideally this should consider side effect analysis of the whole thing. # Ideally this should consider side effect analysis of the whole thing.
if parent[index]['node'] in ('CONST', 'IDENT', 'FIELD'): if parent[index]['nt'] in ('CONST', 'IDENT', 'FIELD'):
parent[index] = {'node':';','type':None} parent[index] = {'nt':';','t':None}
def FoldTree(self, parent, index): def FoldTree(self, parent, index):
"""Recursively traverse the tree to fold constants, changing it in """Recursively traverse the tree to fold constants, changing it in
@ -45,51 +45,51 @@ class optimizer(object):
Also optimizes away IF, WHILE, etc. Also optimizes away IF, WHILE, etc.
""" """
code = parent[index] node = parent[index]
if code is None: return # Deleted statement if node is None: return # Deleted statement
node = code['node'] nt = node['nt']
child = code['br'] if 'br' in code else None child = node['ch'] if 'ch' in node else None
if node == 'CONST': if nt == 'CONST':
# Job already done # Job already done
return return
if node == 'CAST': if nt == 'CAST':
self.FoldTree(child, 0) 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 # Enable key constants. We'll typecast them back on output, but
# this enables some optimizations. # 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( 'value':lslfuncs.typecast(
child[0]['value'], self.LSL2PythonType[code['type']])} child[0]['value'], self.LSL2PythonType[node['t']])}
return return
if node == 'NEG': if nt == 'NEG':
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == 'CONST': if child[0]['nt'] == 'CONST':
code = parent[index] = child[0] node = parent[index] = child[0]
code['value'] = lslfuncs.neg(code['value']) node['value'] = lslfuncs.neg(node['value'])
return return
if node == '!': if nt == '!':
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == 'CONST': if child[0]['nt'] == 'CONST':
code = parent[index] = child[0] node = parent[index] = child[0]
code['value'] = int(not code['value']) node['value'] = int(not node['value'])
return return
if node == '~': if nt == '~':
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == 'CONST': if child[0]['nt'] == 'CONST':
code = parent[index] = child[0] node = parent[index] = child[0]
code['value'] = ~code['value'] node['value'] = ~node['value']
return return
if node == '()': if nt == '()':
self.FoldTree(child, 0) 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'): 'IDENT', 'FIELD', 'V++', 'V--', 'FUNCTION', 'PRINT'):
# Child is an unary postfix expression; parentheses are # Child is an unary postfix expression; parentheses are
# redundant and can be removed safely. Not strictly an # redundant and can be removed safely. Not strictly an
@ -100,73 +100,72 @@ class optimizer(object):
parent[index] = child[0] parent[index] = child[0]
return return
if node in self.binary_ops: if nt in self.binary_ops:
# RTL evaluation # RTL evaluation
self.FoldTree(child, 1) self.FoldTree(child, 1)
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == child[1]['node'] == 'CONST': if child[0]['nt'] == child[1]['nt'] == 'CONST':
op = node
op1 = child[0]['value'] op1 = child[0]['value']
op2 = child[1]['value'] op2 = child[1]['value']
if op == '+': if nt == '+':
result = lslfuncs.add(op1, op2) result = lslfuncs.add(op1, op2)
elif op == '-': elif nt == '-':
result = lslfuncs.sub(op1, op2) result = lslfuncs.sub(op1, op2)
elif op == '*': elif nt == '*':
result = lslfuncs.mul(op1, op2) result = lslfuncs.mul(op1, op2)
elif op == '/': elif nt == '/':
result = lslfuncs.div(op1, op2) result = lslfuncs.div(op1, op2)
elif op == '%': elif nt == '%':
result = lslfuncs.mod(op1, op2) result = lslfuncs.mod(op1, op2)
elif op == '<<': elif nt == '<<':
result = lslfuncs.S32(op1 << (op2 & 31)) result = lslfuncs.S32(op1 << (op2 & 31))
elif op == '>>': elif nt == '>>':
result = lslfuncs.S32(op1 >> (op2 & 31)) result = lslfuncs.S32(op1 >> (op2 & 31))
elif op == '==' or op == '!=': elif nt == '==' or nt == '!=':
result = lslfuncs.compare(op1, op2, Eq = (op == '==')) result = lslfuncs.compare(op1, op2, Eq = (nt == '=='))
elif op in ('<', '<=', '>', '>='): elif nt in ('<', '<=', '>', '>='):
if op in ('>', '<='): if nt in ('>', '<='):
result = lslfuncs.less(op2, op1) result = lslfuncs.less(op2, op1)
else: else:
result = lslfuncs.less(op1, op2) result = lslfuncs.less(op1, op2)
if op in ('>=', '<='): if nt in ('>=', '<='):
result = 1-result result = 1-result
elif op == '|': elif nt == '|':
result = op1 | op2 result = op1 | op2
elif op == '^': elif nt == '^':
result = op1 ^ op2 result = op1 ^ op2
elif op == '&': elif nt == '&':
result = op1 & op2 result = op1 & op2
elif op == '||': elif nt == '||':
result = int(op1 or op2) result = int(op1 or op2)
elif op == '&&': elif nt == '&&':
result = int(op1 and op2) result = int(op1 and op2)
else: else:
raise Exception(u'Internal error: Operator not found: ' + op.decode('utf8')) # pragma: no cover raise Exception(u'Internal error: Operator not found: ' + nt.decode('utf8')) # pragma: no cover
parent[index] = {'node':'CONST', 'type':code['type'], 'value':result} parent[index] = {'nt':'CONST', 't':node['t'], 'value':result}
elif node == '-' and child[0]['type'] in ('integer', 'float') \ elif nt == '-' and child[0]['t'] in ('integer', 'float') \
and child[1]['type'] in ('integer', 'float'): and child[1]['t'] in ('integer', 'float'):
# Change - to + - for int/float # Change - to + - for int/float
if child[1]['node'] == 'CONST': if child[1]['nt'] == 'CONST':
if child[1]['value'] == 0: if child[1]['value'] == 0:
parent[index] = child[0] parent[index] = child[0]
else: else:
code['node'] = '+' node['nt'] = '+'
child[1]['value'] = lslfuncs.neg(child[1]['value']) 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: else:
code['node'] = '+' node['nt'] = '+'
child[1] = {'node':'NEG', 'type':child[1]['type'], 'br':[child[1]]} child[1] = {'nt':'NEG', 't':child[1]['t'], 'ch':[child[1]]}
elif node == '<<' and child[1]['node'] == 'CONST': elif nt == '<<' and child[1]['nt'] == 'CONST':
# Transforming << into multiply saves some bytes. # Transforming << into multiply saves some bytes.
if child[1]['value'] & 31: if child[1]['value'] & 31:
# x << 3 --> x * 8 # x << 3 --> x * 8
# Do we need parentheses for *? It depends on x # Do we need parentheses for *? It depends on x
# e.g. x+3<<3 needs parentheses when converted to (x+3)*8 # 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 if child[0]['nt'] in ('+', '-', 'NEG'): # operands with priority between * and << #TODO: CHECK
child[0] = {'node':'()', 'type':child[0]['type'], 'br':[child[0]]} child[0] = {'nt':'()', 't':child[0]['t'], 'ch':[child[0]]}
# we have {<<, something, {CONST n}}, transform into {*, something, {CONST n}} # we have {<<, something, {CONST n}}, transform into {*, something, {CONST n}}
code['node'] = '*' node['nt'] = '*'
child[1]['value'] = 1<<(child[1]['value'] & 31) child[1]['value'] = 1<<(child[1]['value'] & 31)
else: # x << 0 --> x else: # x << 0 --> x
parent[index] = child[0] parent[index] = child[0]
@ -179,7 +178,7 @@ class optimizer(object):
# Maybe turn != -1 into ~ in if()'s. # Maybe turn != -1 into ~ in if()'s.
return return
if node in self.assign_ops: if nt in self.assign_ops:
# TODO: Eliminate redundant operations, e.g. a += 0; etc. # TODO: Eliminate redundant operations, e.g. a += 0; etc.
# Consider also e.g. x -= 1 or x -= a transforming it into +=. # Consider also e.g. x -= 1 or x -= a transforming it into +=.
# Actually just consider transforming the whole thing into a # Actually just consider transforming the whole thing into a
@ -188,9 +187,9 @@ class optimizer(object):
self.FoldTree(child, 1) self.FoldTree(child, 1)
return return
if node == 'IDENT' or node == 'FLD': if nt == 'IDENT' or nt == 'FLD':
if self.globalmode: 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 # Resolve constant values so they can be optimized
sym = self.symtab[ident['scope']][ident['name']] sym = self.symtab[ident['scope']][ident['name']]
@ -198,62 +197,62 @@ class optimizer(object):
assert defn['name'] == ident['name'] assert defn['name'] == ident['name']
# Assume we already were there # Assume we already were there
if 'br' in defn: if 'ch' in defn:
val = defn['br'][0] val = defn['ch'][0]
if val['node'] != 'CONST' or ident['type'] in ('list', 'key'): if val['nt'] != 'CONST' or ident['t'] in ('list', 'key'):
return return
else: else:
val = {'node':'CONST', 'type':defn['type'], val = {'nt':'CONST', 't':defn['t'],
'value':self.DefaultValues[defn['type']]} 'value':self.DefaultValues[defn['t']]}
if node == 'FLD': if nt == 'FLD':
val = {'node':'CONST', 'type':'float', val = {'nt':'CONST', 't':'float',
'value':val['value']['xyzs'.index(code['fld'])]} 'value':val['value']['xyzs'.index(node['fld'])]}
parent[index] = val parent[index] = val
return return
if node == 'FNCALL': if nt == 'FNCALL':
for idx in xrange(len(child)-1, -1, -1): for idx in xrange(len(child)-1, -1, -1):
self.FoldTree(child, idx) self.FoldTree(child, idx)
if code['name'] in self.symtab[0]: if 'fn' in self.symtab[0][node['name']]:
fn = self.symtab[0][code['name']]['Loc'] fn = self.symtab[0][node['name']]['fn']
if fn is not None and type(fn) != int and all(arg['node'] == 'CONST' for arg in child): if all(arg['nt'] == 'CONST' for arg in child):
# Call it # Call it
value = fn(*tuple(arg['value'] for arg in child)) value = fn(*tuple(arg['value'] for arg in child))
if not self.foldtabs and isinstance(value, unicode) and '\t' in value: if not self.foldtabs and isinstance(value, unicode) and '\t' in value:
warning('WARNING: Tab in function result and foldtabs option not used.') warning('WARNING: Tab in function result and foldtabs option not used.')
return return
parent[index] = {'node':'CONST', 'type':code['type'], 'value':value} parent[index] = {'nt':'CONST', 't':node['t'], 'value':value}
return return
if node == 'PRINT': if nt == 'PRINT':
# useless but who knows # useless but who knows
self.FoldTree(child, 0) self.FoldTree(child, 0)
return return
if node in ('VECTOR', 'ROTATION', 'LIST'): if nt in ('VECTOR', 'ROTATION', 'LIST'):
isconst = True isconst = True
for idx in xrange(len(child)-1, -1, -1): for idx in xrange(len(child)-1, -1, -1):
self.FoldTree(child, idx) self.FoldTree(child, idx)
if child[idx]['node'] != 'CONST': if child[idx]['nt'] != 'CONST':
isconst = False isconst = False
if isconst: if isconst:
value = [elem['value'] for elem in child] value = [elem['value'] for elem in child]
if node == 'VECTOR': if nt == 'VECTOR':
value = lslfuncs.Vector([lslfuncs.ff(x) for x in value]) 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]) 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 return
if node in ('{}', 'FNDEF', 'STATEDEF'): if nt in ('{}', 'FNDEF', 'STDEF'):
for idx in xrange(len(child)): for idx in xrange(len(child)):
self.FoldTree(child, idx) self.FoldTree(child, idx)
self.FoldStmt(child, idx) self.FoldStmt(child, idx)
return return
if node == 'IF': if nt == 'IF':
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == 'CONST': if child[0]['nt'] == 'CONST':
# We can remove one of the branches safely. # We can remove one of the branches safely.
if lslfuncs.cond(child[0]['value']): if lslfuncs.cond(child[0]['value']):
self.FoldTree(child, 1) self.FoldTree(child, 1)
@ -265,7 +264,7 @@ class optimizer(object):
self.FoldStmt(child, 2) self.FoldStmt(child, 2)
else: else:
# No ELSE branch, replace the statement with an empty one. # No ELSE branch, replace the statement with an empty one.
parent[index] = {'node':';', 'type':None} parent[index] = {'nt':';', 't':None}
else: else:
self.FoldTree(child, 1) self.FoldTree(child, 1)
self.FoldStmt(child, 1) self.FoldStmt(child, 1)
@ -274,46 +273,46 @@ class optimizer(object):
self.FoldStmt(child, 2) self.FoldStmt(child, 2)
return return
if node == 'WHILE': if nt == 'WHILE':
self.FoldTree(child, 0) self.FoldTree(child, 0)
if child[0]['node'] == 'CONST': if child[0]['nt'] == 'CONST':
# See if the whole WHILE can be eliminated. # See if the whole WHILE can be eliminated.
if lslfuncs.cond(child[0]['value']): if lslfuncs.cond(child[0]['value']):
# Endless loop which must be kept. # Endless loop which must be kept.
# First, replace the constant. # First, replace the constant.
child[0].update({'type':'integer', 'value':1}) child[0].update({'t':'integer', 'value':1})
# Recurse on the statement. # Recurse on the statement.
self.FoldTree(child, 1) self.FoldTree(child, 1)
self.FoldStmt(child, 1) self.FoldStmt(child, 1)
else: else:
# Can be removed. # Can be removed.
parent[index] = {'node':';', 'type':None} parent[index] = {'nt':';', 't':None}
else: else:
self.FoldTree(child, 1) self.FoldTree(child, 1)
self.FoldStmt(child, 1) self.FoldStmt(child, 1)
return return
if node == 'DO': if nt == 'DO':
self.FoldTree(child, 0) # This one is always executed. self.FoldTree(child, 0) # This one is always executed.
self.FoldStmt(child, 0) self.FoldStmt(child, 0)
self.FoldTree(child, 1) self.FoldTree(child, 1)
# See if the latest part is a constant. # See if the latest part is a constant.
if child[1]['node'] == 'CONST': if child[1]['nt'] == 'CONST':
if lslfuncs.cond(child[1]['value']): if lslfuncs.cond(child[1]['value']):
# Endless loop. Replace the constant. # Endless loop. Replace the constant.
child[1].update({'type':'integer', 'value':1}) child[1].update({'t':'integer', 'value':1})
else: else:
# Only one go. Replace with the statement(s). # Only one go. Replace with the statement(s).
parent[index] = child[0] parent[index] = child[0]
return return
if node == 'FOR': if nt == 'FOR':
assert child[0]['node'] == 'EXPRLIST' assert child[0]['nt'] == 'EXPRLIST'
assert child[2]['node'] == 'EXPRLIST' assert child[2]['nt'] == 'EXPRLIST'
self.FoldAndRemoveEmptyStmts(child[0]['br']) self.FoldAndRemoveEmptyStmts(child[0]['ch'])
self.FoldTree(child, 1) # Condition. 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. # FOR is delicate. It can have multiple expressions at start.
# And if there is more than one, these expressions will need a # And if there is more than one, these expressions will need a
# new block, which means new scope, which is dangerous. # new block, which means new scope, which is dangerous.
@ -321,28 +320,28 @@ class optimizer(object):
# it feels creepy. # it feels creepy.
if lslfuncs.cond(child[1]['value']): if lslfuncs.cond(child[1]['value']):
# Endless loop. Just replace the constant and traverse the rest. # Endless loop. Just replace the constant and traverse the rest.
child[1].update({'type':'integer', 'value':1}) child[1].update({'t':'integer', 'value':1})
self.FoldAndRemoveEmptyStmts(child[2]['br']) self.FoldAndRemoveEmptyStmts(child[2]['ch'])
self.FoldTree(child, 3) self.FoldTree(child, 3)
self.FoldStmt(child, 3) self.FoldStmt(child, 3)
elif len(child[0]['br']) > 1: elif len(child[0]['ch']) > 1:
parent[index] = {'node':'{}', 'type':None, 'br':child[0]['br']} parent[index] = {'nt':'{}', 't':None, 'ch':child[0]['ch']}
elif child[0]['br']: elif child[0]['ch']:
parent[index] = child[0]['br'][0] parent[index] = child[0]['ch'][0]
else: else:
parent[index] = {'node':';', 'type':None} parent[index] = {'nt':';', 't':None}
else: else:
self.FoldAndRemoveEmptyStmts(child[2]['br']) self.FoldAndRemoveEmptyStmts(child[2]['ch'])
self.FoldTree(child, 3) self.FoldTree(child, 3)
self.FoldStmt(child, 3) self.FoldStmt(child, 3)
return return
if node == 'RETURN': if nt == 'RETURN':
if child: if child:
self.FoldTree(child, 0) self.FoldTree(child, 0)
return return
if node == 'DECL': if nt == 'DECL':
# The expression code is elsewhere. # The expression code is elsewhere.
if child: if child:
self.FoldTree(child, 0) self.FoldTree(child, 0)
@ -352,20 +351,20 @@ class optimizer(object):
pass pass
return return
if node in self.ignored_stmts: if nt in self.ignored_stmts:
return 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): def IsValidGlobalConstant(self, decl):
if 'br' not in decl: if 'ch' not in decl:
return True return True
expr = decl['br'][0] expr = decl['ch'][0]
if expr['node'] in ('CONST', 'IDENT'): if expr['nt'] in ('CONST', 'IDENT'):
return True return True
if expr['node'] not in ('VECTOR', 'ROTATION', 'LIST'): if expr['nt'] not in ('VECTOR', 'ROTATION', 'LIST'):
return False 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',)): def optimize(self, treesymtab, options = ('optimize',)):
"""Optimize the symbolic table symtab in place. Requires a table of """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. # Constant folding pass. It does some other optimizations along the way.
for idx in xrange(len(tree)): for idx in xrange(len(tree)):
if tree[idx]['node'] == 'DECL': if tree[idx]['nt'] == 'DECL':
self.globalmode = True self.globalmode = True
self.FoldTree(tree, idx) self.FoldTree(tree, idx)
self.globalmode = False self.globalmode = False

View file

@ -134,11 +134,11 @@ class outscript(object):
def dent(self): def dent(self):
return self.indent * self.indentlevel return self.indent * self.indentlevel
def OutIndented(self, code): def OutIndented(self, node):
if code['node'] != '{}': if node['nt'] != '{}':
self.indentlevel += 1 self.indentlevel += 1
ret = self.OutCode(code) ret = self.OutCode(node)
if code['node'] != '{}': if node['nt'] != '{}':
self.indentlevel -= 1 self.indentlevel -= 1
return ret return ret
@ -155,96 +155,96 @@ class outscript(object):
def OutExpr(self, expr): def OutExpr(self, expr):
# Handles expression nodes (as opposed to statement nodes) # Handles expression nodes (as opposed to statement nodes)
node = expr['node'] nt = expr['nt']
if 'br' in expr: if 'ch' in expr:
child = expr['br'] child = expr['ch']
if node == '()': if nt == '()':
return '(' + self.OutExpr(child[0]) + ')' return '(' + self.OutExpr(child[0]) + ')'
if node in self.binary_operands: if nt in self.binary_operands:
return self.OutExpr(child[0]) + ' ' + node + ' ' + self.OutExpr(child[1]) return self.OutExpr(child[0]) + ' ' + nt + ' ' + self.OutExpr(child[1])
if node == 'IDENT': if nt == 'IDENT':
return expr['name'] return expr['name']
if node == 'CONST': if nt == 'CONST':
return self.Value2LSL(expr['value']) return self.Value2LSL(expr['value'])
if node == 'CAST': if nt == 'CAST':
ret = '(' + expr['type'] + ')' ret = '(' + expr['t'] + ')'
expr = child[0] 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', '()'): 'ROTATION', 'LIST', 'FIELD', 'PRINT', 'FUNCTION', '()'):
return ret + self.OutExpr(expr) return ret + self.OutExpr(expr)
return ret + '(' + self.OutExpr(expr) + ')' return ret + '(' + self.OutExpr(expr) + ')'
if node == 'LIST': if nt == 'LIST':
self.listmode = True self.listmode = True
ret = '[' + self.OutExprList(child) + ']' ret = '[' + self.OutExprList(child) + ']'
self.listmode = False self.listmode = False
return ret return ret
if node in ('VECTOR', 'ROTATION'): if nt in ('VECTOR', 'ROTATION'):
return '<' + self.OutExprList(child) + '>' return '<' + self.OutExprList(child) + '>'
if node == 'FNCALL': if nt == 'FNCALL':
return expr['name'] + '(' + self.OutExprList(child) + ')' return expr['name'] + '(' + self.OutExprList(child) + ')'
if node == 'PRINT': if nt == 'PRINT':
return 'print(' + self.OutExpr(child[0]) + ')' return 'print(' + self.OutExpr(child[0]) + ')'
if node in self.unary_operands: if nt in self.unary_operands:
if node == 'NEG': if nt == 'NEG':
node = '- ' nt = '- '
return node + self.OutExpr(child[0]) return nt + self.OutExpr(child[0])
if node == 'FLD': if nt == 'FLD':
return self.OutExpr(child[0]) + '.' + expr['fld'] return self.OutExpr(child[0]) + '.' + expr['fld']
if node in ('V--', 'V++'): if nt in ('V--', 'V++'):
return self.OutExpr(child[0]) + ('++' if node == 'V++' else '--') return self.OutExpr(child[0]) + ('++' if nt == 'V++' else '--')
if node in ('--V', '++V'): if nt in ('--V', '++V'):
return ('++' if node == '++V' else '--') + self.OutExpr(child[0]) 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]) 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) 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): def OutCode(self, node):
node = code['node'] nt = node['nt']
if 'br' in code: if 'ch' in node:
child = code['br'] child = node['ch']
else: else:
child = None child = None
if node == 'IF': if nt == 'IF':
ret = self.dent() ret = self.dent()
while True: while True:
ret += 'if (' + self.OutExpr(child[0]) + ')\n' + self.OutIndented(child[1]) ret += 'if (' + self.OutExpr(child[0]) + ')\n' + self.OutIndented(child[1])
if len(child) < 3: if len(child) < 3:
return ret return ret
if child[2]['node'] != 'IF': if child[2]['nt'] != 'IF':
ret += self.dent() + 'else\n' + self.OutIndented(child[2]) ret += self.dent() + 'else\n' + self.OutIndented(child[2])
return ret return ret
ret += self.dent() + 'else ' ret += self.dent() + 'else '
code = child[2] node = child[2]
child = code['br'] child = node['ch']
if node == 'WHILE': if nt == 'WHILE':
ret = self.dent() + 'while (' + self.OutExpr(child[0]) + ')\n' ret = self.dent() + 'while (' + self.OutExpr(child[0]) + ')\n'
ret += self.OutIndented(child[1]) ret += self.OutIndented(child[1])
return ret return ret
if node == 'DO': if nt == 'DO':
ret = self.dent() + 'do\n' ret = self.dent() + 'do\n'
ret += self.OutIndented(child[0]) ret += self.OutIndented(child[0])
return ret + self.dent() + 'while (' + self.OutExpr(child[1]) + ');\n' return ret + self.dent() + 'while (' + self.OutExpr(child[1]) + ');\n'
if node == 'FOR': if nt == 'FOR':
ret = self.dent() + 'for (' ret = self.dent() + 'for ('
ret += self.OutExpr(child[0]) ret += self.OutExpr(child[0])
ret += '; ' + self.OutExpr(child[1]) + '; ' ret += '; ' + self.OutExpr(child[1]) + '; '
@ -252,48 +252,48 @@ class outscript(object):
ret += ')\n' ret += ')\n'
ret += self.OutIndented(child[3]) ret += self.OutIndented(child[3])
return ret return ret
if node == '@': if nt == '@':
return self.dent() + '@' + code['name'] + ';\n' return self.dent() + '@' + node['name'] + ';\n'
if node == 'JUMP': if nt == 'JUMP':
return self.dent() + 'jump ' + code['name'] + ';\n' return self.dent() + 'jump ' + node['name'] + ';\n'
if node == 'STATE': if nt == 'STSW':
return self.dent() + 'state ' + code['name'] + ';\n' return self.dent() + 'state ' + node['name'] + ';\n'
if node == 'RETURN': if nt == 'RETURN':
if child: if child:
return self.dent() + 'return ' + self.OutExpr(child[0]) + ';\n' return self.dent() + 'return ' + self.OutExpr(child[0]) + ';\n'
return self.dent() + 'return;\n' return self.dent() + 'return;\n'
if node == 'DECL': if nt == 'DECL':
ret = self.dent() + code['type'] + ' ' + code['name'] ret = self.dent() + node['t'] + ' ' + node['name']
if child: if child:
ret += ' = ' + self.OutExpr(child[0]) ret += ' = ' + self.OutExpr(child[0])
return ret + ';\n' return ret + ';\n'
if node == ';': if nt == ';':
return self.dent() + ';\n' return self.dent() + ';\n'
if node in ('STATEDEF', '{}'): if nt in ('STDEF', '{}'):
ret = '' ret = ''
if node == 'STATEDEF': if nt == 'STDEF':
if code['name'] == 'default': if node['name'] == 'default':
ret = self.dent() + 'default\n' ret = self.dent() + 'default\n'
else: else:
ret = self.dent() + 'state ' + code['name'] + '\n' ret = self.dent() + 'state ' + node['name'] + '\n'
ret += self.dent() + '{\n' ret += self.dent() + '{\n'
self.indentlevel += 1 self.indentlevel += 1
for stmt in code['br']: for stmt in node['ch']:
ret += self.OutCode(stmt) ret += self.OutCode(stmt)
self.indentlevel -= 1 self.indentlevel -= 1
return ret + self.dent() + '}\n' return ret + self.dent() + '}\n'
if node == 'FNDEF': if nt == 'FNDEF':
ret = self.dent() ret = self.dent()
if code['type'] is not None: if node['t'] is not None:
ret += code['type'] + ' ' ret += node['t'] + ' '
ret += code['name'] + '(' ret += node['name'] + '('
ret += ', '.join(typ + ' ' + name for typ, name in zip(code['ptypes'], code['pnames'])) ret += ', '.join(typ + ' ' + name for typ, name in zip(node['ptypes'], node['pnames']))
return ret + ')\n' + self.OutCode(child[0]) 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',)): def output(self, treesymtab, options = ('optsigns',)):
# Build a sorted list of dict entries # Build a sorted list of dict entries
@ -307,12 +307,12 @@ class outscript(object):
self.indentlevel = 0 self.indentlevel = 0
self.globalmode = False self.globalmode = False
self.listmode = False self.listmode = False
for code in self.tree: for node in self.tree:
if code['node'] == 'DECL': if node['nt'] == 'DECL': # TODO: self.globalmode = node['nt'] == 'DECL'
self.globalmode = True self.globalmode = True
ret += self.OutCode(code) ret += self.OutCode(node)
self.globalmode = False self.globalmode = False
else: else:
ret += self.OutCode(code) ret += self.OutCode(node)
return ret return ret

View file

@ -186,13 +186,13 @@ class parser(object):
"""Check if automatic dynamic cast is possible, and insert it if """Check if automatic dynamic cast is possible, and insert it if
requested explicitly. requested explicitly.
""" """
tval = value['type'] tval = value['t']
if tval == tgttype: if tval == tgttype:
return value return value
if tval in ('string', 'key') and tgttype in ('string', 'key') \ if tval in ('string', 'key') and tgttype in ('string', 'key') \
or tval == 'integer' and tgttype == 'float': or tval == 'integer' and tgttype == 'float':
if self.explicitcast: if self.explicitcast:
return {'node':'CAST', 'type':tgttype, 'br':[value]} return {'nt':'CAST', 't':tgttype, 'ch':[value]}
return value return value
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
@ -481,11 +481,11 @@ class parser(object):
ret.append(inequality) ret.append(inequality)
return ret return ret
# This is basically a copy/paste of the Parse_inequality handler # This is basically a copy/paste of the Parse_inequality handler
ltype = inequality['type'] ltype = inequality['t']
if ltype not in ('integer', 'float'): if ltype not in ('integer', 'float'):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
rexpr = self.Parse_shift() rexpr = self.Parse_shift()
rtype = rexpr['type'] rtype = rexpr['t']
if rtype not in ('integer', 'float'): if rtype not in ('integer', 'float'):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if ltype != rtype: if ltype != rtype:
@ -493,7 +493,7 @@ class parser(object):
inequality = self.autocastcheck(inequality, rtype) inequality = self.autocastcheck(inequality, rtype)
else: else:
rexpr = self.autocastcheck(rexpr, ltype) 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, # Reaching this means an operator or lower precedence happened,
# e.g. <1,1,1,2==2> (that's syntax error in ==) # e.g. <1,1,1,2==2> (that's syntax error in ==)
@ -529,28 +529,28 @@ class parser(object):
tok0 = self.tok[0] tok0 = self.tok[0]
val = self.tok[1] val = self.tok[1]
self.NextToken() 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': if tok0 == 'INTEGER_VALUE':
return {'node':CONST, 'type':'integer', 'value':val} return {'nt':CONST, 't':'integer', 'value':val}
if tok0 == 'FLOAT_VALUE': if tok0 == 'FLOAT_VALUE':
return {'node':CONST, 'type':'float', 'value':val} return {'nt':CONST, 't':'float', 'value':val}
if tok0 == 'STRING_VALUE': if tok0 == 'STRING_VALUE':
if self.allowmultistrings: if self.allowmultistrings:
while self.tok[0] == 'STRING_VALUE': while self.tok[0] == 'STRING_VALUE':
val += self.tok[1] val += self.tok[1]
self.NextToken() self.NextToken()
return {'node':CONST, 'type':'string', 'value':val} return {'nt':CONST, 't':'string', 'value':val}
# Key constants are not currently supported - use string # Key constants are not currently supported - use string
#if tok0 == 'KEY_VALUE': #if tok0 == 'KEY_VALUE':
# return [CONST, 'key', val] # return [CONST, 'key', val]
if tok0 == 'VECTOR_VALUE': if tok0 == 'VECTOR_VALUE':
return {'node':CONST, 'type':'vector', 'value':val} return {'nt':CONST, 't':'vector', 'value':val}
if tok0 == 'ROTATION_VALUE': if tok0 == 'ROTATION_VALUE':
return {'node':CONST, 'type':'rotation', 'value':val} return {'nt':CONST, 't':'rotation', 'value':val}
if tok0 == 'LIST_VALUE': if tok0 == 'LIST_VALUE':
return {'node':CONST, 'type':'list', 'value':val} return {'nt':CONST, 't':'list', 'value':val}
if tok0 in ('TRUE', 'FALSE'): 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 == '<': if tok0 == '<':
val = [self.Parse_expression()] val = [self.Parse_expression()]
self.expect(',') self.expect(',')
@ -586,23 +586,23 @@ class parser(object):
val += self.Parse_vector_rotation_tail() val += self.Parse_vector_rotation_tail()
if len(val) == 3: if len(val) == 3:
return {'node':'VECTOR', 'type':'vector', 'br':val} return {'nt':'VECTOR', 't':'vector', 'ch':val}
return {'node':'ROTATION', 'type':'rotation', 'br':val} return {'nt':'ROTATION', 't':'rotation', 'ch':val}
if tok0 == '[': if tok0 == '[':
val = self.Parse_optional_expression_list() val = self.Parse_optional_expression_list()
self.expect(']') self.expect(']')
self.NextToken() self.NextToken()
return {'node':'LIST', 'type':'list', 'br':val} return {'nt':'LIST', 't':'list', 'ch':val}
if tok0 == 'PRINT': if tok0 == 'PRINT':
self.expect('(') self.expect('(')
self.NextToken() self.NextToken()
expr = self.Parse_expression() expr = self.Parse_expression()
if expr['type'] not in self.types: if expr['t'] not in self.types:
raise EParseTypeMismatch(self) if expr['type'] is None else EParseUndefined(self) raise EParseTypeMismatch(self) if expr['t'] is None else EParseUndefined(self)
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
return {'node':'PRINT', 'type':None, 'br':[expr]} return {'nt':'PRINT', 't':None, 'ch':[expr]}
if tok0 != 'IDENT': if tok0 != 'IDENT':
if tok0 == 'EOF': if tok0 == 'EOF':
@ -623,30 +623,30 @@ class parser(object):
args = self.Parse_optional_expression_list(sym['ParamTypes']) args = self.Parse_optional_expression_list(sym['ParamTypes'])
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
return {'node':'FNCALL', 'type':sym['Type'], 'name':name, return {'nt':'FNCALL', 't':sym['Type'], 'name':name,
'scope':self.scopeindex, 'br':args} 'scope':self.scopeindex, 'ch':args}
if sym['Kind'] != 'v': if sym['Kind'] != 'v':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
typ = sym['Type'] 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 == '.': if tok0 == '.':
self.NextToken() self.NextToken()
self.expect('IDENT') self.expect('IDENT')
self.ValidateField(typ, self.tok[1]) 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() self.NextToken()
tok0 = self.tok[0] tok0 = self.tok[0]
if tok0 in ('++', '--'): if tok0 in ('++', '--'):
self.NextToken() self.NextToken()
if lvalue['type'] not in ('integer', 'float'): if lvalue['t'] not in ('integer', 'float'):
raise EParseTypeMismatch(self) 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 if AllowAssignment and (tok0 in self.assignment_ops
or self.extendedassignment and tok0 in self.extassignment_ops): or self.extendedassignment and tok0 in self.extassignment_ops):
self.NextToken() self.NextToken()
expr = self.Parse_expression() expr = self.Parse_expression()
rtyp = expr['type'] rtyp = expr['t']
if rtyp not in self.types: if rtyp not in self.types:
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if typ in ('integer', 'float'): if typ in ('integer', 'float'):
@ -661,11 +661,11 @@ class parser(object):
if tok0 == '=': if tok0 == '=':
if typ == 'list' != rtyp: if typ == 'list' != rtyp:
if self.explicitcast: if self.explicitcast:
expr = {'node':'CAST', 'type':typ, 'br':[expr]} expr = {'nt':'CAST', 't':typ, 'ch':[expr]}
else: else:
expr = self.autocastcheck(expr, typ) expr = self.autocastcheck(expr, typ)
return {'node':'=', 'type':typ, 'br':[lvalue, expr]} return {'nt':'=', 't':typ, 'ch':[lvalue, expr]}
if tok0 == '+=': if tok0 == '+=':
if typ == 'float': if typ == 'float':
@ -675,34 +675,34 @@ class parser(object):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if self.explicitcast: if self.explicitcast:
if typ == 'list' != rtyp: if typ == 'list' != rtyp:
expr = {'node':'CAST', 'type':typ, 'br':[expr]} expr = {'nt':'CAST', 't':typ, 'ch':[expr]}
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]} return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
if tok0 == '-=': if tok0 == '-=':
if typ == rtyp in ('integer', 'float', 'vector', 'rotation'): 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) raise EParseTypeMismatch(self)
if tok0 in ('*=', '/='): if tok0 in ('*=', '/='):
# There is a special case dealt with in advance. # There is a special case dealt with in advance.
if tok0 == '*=' and typ == 'integer' and rtyp == 'float': 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 == rtyp or typ == 'vector') and rtyp in ('integer', 'float', 'rotation'):
if typ == 'vector' and rtyp == 'integer': if typ == 'vector' and rtyp == 'integer':
expr = self.autocastcheck(expr, 'float') expr = self.autocastcheck(expr, 'float')
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]} return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if tok0 == '%=': if tok0 == '%=':
if typ == rtyp in ('integer', 'vector'): 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) raise EParseTypeMismatch(self)
# Rest take integer operands only # Rest take integer operands only
if typ == rtyp == 'integer': if typ == rtyp == 'integer':
return {'node':tok0, 'type':typ, 'br':[lvalue, expr]} return {'nt':tok0, 't':typ, 'ch':[lvalue, expr]}
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
return lvalue return lvalue
@ -726,16 +726,16 @@ class parser(object):
# Unary minus # Unary minus
self.NextToken() self.NextToken()
value = self.Parse_factor() 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) raise EParseTypeMismatch(self)
return {'node':'NEG', 'type':value['type'], 'br':[value]} return {'nt':'NEG', 't':value['t'], 'ch':[value]}
if tok0 in ('!', '~'): if tok0 in ('!', '~'):
# Unary logic and bitwise NOT - applies to integers only # Unary logic and bitwise NOT - applies to integers only
self.NextToken() self.NextToken()
value = self.Parse_unary_expression() value = self.Parse_unary_expression()
if value['type'] != 'integer': if value['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
return {'node':tok0, 'type':'integer', 'br':[value]} return {'nt':tok0, 't':'integer', 'ch':[value]}
if tok0 in ('++', '--'): if tok0 in ('++', '--'):
# Pre-increment / pre-decrement # Pre-increment / pre-decrement
self.NextToken() self.NextToken()
@ -747,20 +747,20 @@ class parser(object):
raise EParseUndefined(self) raise EParseUndefined(self)
typ = sym['Type'] 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() self.NextToken()
if self.tok[0] == '.': if self.tok[0] == '.':
self.NextToken() self.NextToken()
self.expect('IDENT') self.expect('IDENT')
self.ValidateField(typ, self.tok[1]) 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() self.NextToken()
typ = ret['type'] typ = ret['t']
if typ not in ('integer', 'float'): if typ not in ('integer', 'float'):
raise EParseTypeMismatch(self) 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 == '(': if tok0 == '(':
# Parenthesized expression or typecast # Parenthesized expression or typecast
@ -771,7 +771,7 @@ class parser(object):
expr = self.Parse_expression() expr = self.Parse_expression()
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
return {'node':'()', 'type':expr['type'], 'br':[expr]} return {'nt':'()', 't':expr['t'], 'ch':[expr]}
# Typecast # Typecast
typ = self.tok[1] typ = self.tok[1]
@ -789,10 +789,10 @@ class parser(object):
expr = self.Parse_expression() expr = self.Parse_expression()
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
expr = {'node':'()', 'type':expr['type'], 'br':[expr]} expr = {'nt':'()', 't':expr['t'], 'ch':[expr]}
else: else:
expr = self.Parse_unary_postfix_expression(AllowAssignment = False) expr = self.Parse_unary_postfix_expression(AllowAssignment = False)
basetype = expr['type'] basetype = expr['t']
if typ == 'list' and basetype in self.types \ if typ == 'list' and basetype in self.types \
or basetype in ('integer', 'float') and typ in ('integer', 'float', 'string') \ or basetype in ('integer', 'float') and typ in ('integer', 'float', 'string') \
or basetype == 'string' and typ in self.types \ 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 == 'vector' and typ in ('string', 'vector') \
or basetype == 'rotation' and typ in ('string', 'rotation') \ or basetype == 'rotation' and typ in ('string', 'rotation') \
or basetype == 'list' and typ == 'string': or basetype == 'list' and typ == 'string':
return {'node':'CAST', 'type':typ, 'br':[expr]} return {'nt':'CAST', 't':typ, 'ch':[expr]}
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
# Must be a postfix expression. # Must be a postfix expression.
@ -815,7 +815,7 @@ class parser(object):
factor = self.Parse_unary_expression() factor = self.Parse_unary_expression()
while self.tok[0] in ('*', '/', '%'): while self.tok[0] in ('*', '/', '%'):
op = self.tok[0] op = self.tok[0]
ltype = factor['type'] ltype = factor['t']
# Acceptable types for LHS # Acceptable types for LHS
if op in ('*', '/') and ltype not in ('integer', 'float', if op in ('*', '/') and ltype not in ('integer', 'float',
'vector', 'rotation') \ 'vector', 'rotation') \
@ -823,13 +823,13 @@ class parser(object):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
self.NextToken() self.NextToken()
rexpr = self.Parse_unary_expression() rexpr = self.Parse_unary_expression()
rtype = rexpr['type'] rtype = rexpr['t']
# Mod is easier to check for # Mod is easier to check for
if op == '%' and ltype != rtype: if op == '%' and ltype != rtype:
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if op == '%' or ltype == rtype == 'integer': if op == '%' or ltype == rtype == 'integer':
# Deal with the special cases first (it's easy) # 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: else:
# Any integer must be promoted to float now # Any integer must be promoted to float now
if ltype == 'integer': if ltype == 'integer':
@ -851,7 +851,7 @@ class parser(object):
resulttype = 'float' resulttype = 'float'
else: else:
resulttype = ltype resulttype = ltype
factor = {'node':op, 'type':resulttype, 'br':[factor, rexpr]} factor = {'nt':op, 't':resulttype, 'ch':[factor, rexpr]}
else: else:
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
@ -865,14 +865,14 @@ class parser(object):
term = self.Parse_factor() term = self.Parse_factor()
while self.tok[0] in ('+', '-'): while self.tok[0] in ('+', '-'):
op = self.tok[0] op = self.tok[0]
ltype = term['type'] ltype = term['t']
if op == '+' and ltype not in self.types \ if op == '+' and ltype not in self.types \
or op == '-' and ltype not in ('integer', 'float', or op == '-' and ltype not in ('integer', 'float',
'vector', 'rotation'): 'vector', 'rotation'):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
self.NextToken() self.NextToken()
rexpr = self.Parse_factor() rexpr = self.Parse_factor()
rtype = rexpr['type'] rtype = rexpr['t']
# This is necessary, but the reason is subtle. # This is necessary, but the reason is subtle.
# The types must match in principle (except integer/float), so it # The types must match in principle (except integer/float), so it
# doesn't seem necessary to check rtype. But there's the case # doesn't seem necessary to check rtype. But there's the case
@ -889,12 +889,12 @@ class parser(object):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if self.explicitcast: if self.explicitcast:
if ltype == 'list' != rtype: if ltype == 'list' != rtype:
rexpr = {'node':'CAST', 'type':ltype, 'br':[rexpr]} rexpr = {'nt':'CAST', 't':ltype, 'ch':[rexpr]}
#rtype = ltype # unused #rtype = ltype # unused
elif rtype == 'list' != ltype: elif rtype == 'list' != ltype:
term = {'node':'CAST', 'type':rtype, 'br':[term]} term = {'nt':'CAST', 't':rtype, 'ch':[term]}
ltype = rtype 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 # Note that although list + nonlist is semantically the same as
# list + (list)nonlist and same goes for nonlist + list, they # list + (list)nonlist and same goes for nonlist + list, they
# don't compile to the same thing, but the optimizer should deal # 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'): and ltype in ('key', 'string') and rtype in ('key', 'string'):
# Allow string+key addition (but add explicit cast) # Allow string+key addition (but add explicit cast)
if ltype == 'key': if ltype == 'key':
term = {'node':op, 'type':rtype, term = {'nt':op, 't':rtype,
'br':[{'node':'CAST', 'type':rtype, 'br':[term]}, rexpr]} 'ch':[{'nt':'CAST', 't':rtype, 'ch':[term]}, rexpr]}
else: else:
term = {'node':op, 'type':ltype, term = {'nt':op, 't':ltype,
'br':[term, {'node':'CAST', 'type':ltype, 'br':[rexpr]}]} 'ch':[term, {'nt':'CAST', 't':ltype, 'ch':[rexpr]}]}
elif ltype == 'key' or rtype == 'key': elif ltype == 'key' or rtype == 'key':
# Only list + key or key + list is allowed, otherwise keys can't # Only list + key or key + list is allowed, otherwise keys can't
# be added or subtracted with anything. # be added or subtracted with anything.
@ -915,10 +915,10 @@ class parser(object):
else: else:
if ltype == 'float': if ltype == 'float':
# Promote rexpr to 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: else:
# Convert LHS to rtype if possible (note no keys arrive here) # 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 return term
@ -929,14 +929,14 @@ class parser(object):
""" """
shift = self.Parse_term() shift = self.Parse_term()
while self.tok[0] in ('<<', '>>'): while self.tok[0] in ('<<', '>>'):
if shift['type'] != 'integer': if shift['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
op = self.tok[0] op = self.tok[0]
self.NextToken() self.NextToken()
rexpr = self.Parse_term() rexpr = self.Parse_term()
if rexpr['type'] != 'integer': if rexpr['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
shift = {'node':op, 'type':'integer', 'br':[shift , rexpr]} shift = {'nt':op, 't':'integer', 'ch':[shift , rexpr]}
return shift return shift
@ -949,12 +949,12 @@ class parser(object):
inequality = self.Parse_shift() inequality = self.Parse_shift()
while self.tok[0] in ('<', '<=', '>', '>='): while self.tok[0] in ('<', '<=', '>', '>='):
op = self.tok[0] op = self.tok[0]
ltype = inequality['type'] ltype = inequality['t']
if ltype not in ('integer', 'float'): if ltype not in ('integer', 'float'):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
self.NextToken() self.NextToken()
rexpr = self.Parse_shift() rexpr = self.Parse_shift()
rtype = rexpr['type'] rtype = rexpr['t']
if rtype not in ('integer', 'float'): if rtype not in ('integer', 'float'):
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
if ltype != rtype: if ltype != rtype:
@ -962,7 +962,7 @@ class parser(object):
inequality = self.autocastcheck(inequality, rtype) inequality = self.autocastcheck(inequality, rtype)
else: else:
rexpr = self.autocastcheck(rexpr, ltype) rexpr = self.autocastcheck(rexpr, ltype)
inequality = {'node':op, 'type':'integer', 'br':[inequality, rexpr]} inequality = {'nt':op, 't':'integer', 'ch':[inequality, rexpr]}
return inequality return inequality
@ -975,19 +975,19 @@ class parser(object):
comparison = self.Parse_inequality() comparison = self.Parse_inequality()
while self.tok[0] in ('==', '!='): while self.tok[0] in ('==', '!='):
op = self.tok[0] op = self.tok[0]
ltype = comparison['type'] ltype = comparison['t']
if ltype not in self.types: if ltype not in self.types:
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
self.NextToken() self.NextToken()
rexpr = self.Parse_inequality() rexpr = self.Parse_inequality()
rtype = rexpr['type'] rtype = rexpr['t']
if ltype == 'float': if ltype == 'float':
rexpr = self.autocastcheck(rexpr, ltype) rexpr = self.autocastcheck(rexpr, ltype)
else: else:
# For string & key, RHS (rtype) mandates the conversion # For string & key, RHS (rtype) mandates the conversion
# (that's room for optimization: always compare strings) # (that's room for optimization: always compare strings)
comparison = self.autocastcheck(comparison, rtype) comparison = self.autocastcheck(comparison, rtype)
comparison = {'node':op, 'type':'integer', 'br':[comparison, rexpr]} comparison = {'nt':op, 't':'integer', 'ch':[comparison, rexpr]}
return comparison return comparison
@ -998,14 +998,14 @@ class parser(object):
""" """
bitbool_factor = self.Parse_comparison() bitbool_factor = self.Parse_comparison()
while self.tok[0] == '&': while self.tok[0] == '&':
if bitbool_factor['type'] != 'integer': if bitbool_factor['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
op = self.tok[0] op = self.tok[0]
self.NextToken() self.NextToken()
rexpr = self.Parse_comparison() rexpr = self.Parse_comparison()
if rexpr['type'] != 'integer': if rexpr['t'] != 'integer':
raise EParseTypeMismatch(self) 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 return bitbool_factor
@ -1016,14 +1016,14 @@ class parser(object):
""" """
bitxor_term = self.Parse_bitbool_factor() bitxor_term = self.Parse_bitbool_factor()
while self.tok[0] == '^': while self.tok[0] == '^':
if bitxor_term['type'] != 'integer': if bitxor_term['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
op = self.tok[0] op = self.tok[0]
self.NextToken() self.NextToken()
rexpr = self.Parse_bitbool_factor() rexpr = self.Parse_bitbool_factor()
if rexpr['type'] != 'integer': if rexpr['t'] != 'integer':
raise EParseTypeMismatch(self) 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 return bitxor_term
@ -1034,14 +1034,14 @@ class parser(object):
""" """
bitbool_term = self.Parse_bitxor_term() bitbool_term = self.Parse_bitxor_term()
while self.tok[0] == '|': while self.tok[0] == '|':
if bitbool_term['type'] != 'integer': if bitbool_term['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
op = self.tok[0] op = self.tok[0]
self.NextToken() self.NextToken()
rexpr = self.Parse_bitxor_term() rexpr = self.Parse_bitxor_term()
if rexpr['type'] != 'integer': if rexpr['t'] != 'integer':
raise EParseTypeMismatch(self) 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 return bitbool_term
@ -1064,14 +1064,14 @@ class parser(object):
""" """
expression = self.Parse_bitbool_term() expression = self.Parse_bitbool_term()
while self.tok[0] in ('&&', '||'): while self.tok[0] in ('&&', '||'):
if expression['type'] != 'integer': if expression['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
op = self.tok[0] op = self.tok[0]
self.NextToken() self.NextToken()
rexpr = self.Parse_bitbool_term() rexpr = self.Parse_bitbool_term()
if rexpr['type'] != 'integer': if rexpr['t'] != 'integer':
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
expression = {'node':op, 'type':'integer', 'br':[expression, rexpr]} expression = {'nt':op, 't':'integer', 'ch':[expression, rexpr]}
return expression return expression
@ -1090,19 +1090,19 @@ class parser(object):
idx = 0 idx = 0
if self.tok[0] not in (']', ')', ';'): if self.tok[0] not in (']', ')', ';'):
while True: while True:
val = self.Parse_expression() expr = self.Parse_expression()
if expected_types is not None: if expected_types is not None:
if idx >= len(expected_types): if idx >= len(expected_types):
raise EParseFunctionMismatch(self) raise EParseFunctionMismatch(self)
try: try:
val = self.autocastcheck(val, expected_types[idx]); expr = self.autocastcheck(expr, expected_types[idx]);
except EParseTypeMismatch: except EParseTypeMismatch:
raise EParseFunctionMismatch(self) raise EParseFunctionMismatch(self)
else: else:
if val['type'] not in self.types: if expr['t'] not in self.types:
raise EParseTypeMismatch(self) raise EParseTypeMismatch(self)
idx += 1 idx += 1
ret.append(val) ret.append(expr)
if self.tok[0] != ',': if self.tok[0] != ',':
break break
self.NextToken() self.NextToken()
@ -1136,7 +1136,7 @@ class parser(object):
return self.Parse_code_block(ReturnType) return self.Parse_code_block(ReturnType)
if tok0 == ';': if tok0 == ';':
self.NextToken() self.NextToken()
return {'node':';', 'type':None} return {'nt':';', 't':None}
if tok0 == '@': if tok0 == '@':
self.NextToken() self.NextToken()
self.expect('IDENT') self.expect('IDENT')
@ -1147,13 +1147,13 @@ class parser(object):
self.NextToken() self.NextToken()
self.expect(';') self.expect(';')
self.NextToken() self.NextToken()
return {'node':'@', 'type':None, 'name':name} return {'nt':'@', 't':None, 'name':name}
if tok0 == 'JUMP': if tok0 == 'JUMP':
self.NextToken() self.NextToken()
self.expect('IDENT') self.expect('IDENT')
name = self.tok[1] name = self.tok[1]
sym = self.FindSymbolPartial(name, MustBeLabel=True) 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': if not sym or sym['Kind'] != 'l':
# It might still be a forward reference, so we add it to the # It might still be a forward reference, so we add it to the
# list of things to look up when done # list of things to look up when done
@ -1175,7 +1175,7 @@ class parser(object):
self.NextToken() self.NextToken()
self.expect(';') self.expect(';')
self.NextToken() self.NextToken()
return {'node':'STATE', 'type':None, 'name':name} return {'nt':'STSW', 't':None, 'name':name}
if tok0 == 'RETURN': if tok0 == 'RETURN':
self.NextToken() self.NextToken()
if self.tok[0] == ';': if self.tok[0] == ';':
@ -1189,9 +1189,9 @@ class parser(object):
if ReturnType is not None and value is None: if ReturnType is not None and value is None:
raise EParseReturnIsEmpty(self) raise EParseReturnIsEmpty(self)
if value is None: if value is None:
return {'node':'RETURN', 'type':None} return {'nt':'RETURN', 't':None}
return {'node':'RETURN', 'type':None, 'br':[self.autocastcheck(value, ReturnType)]} return {'nt':'RETURN', 't':None, 'ch':[self.autocastcheck(value, ReturnType)]}
if tok0 == 'IF': if tok0 == 'IF': # TODO: Convert this into a loop for ELSE IF's, saving recursion
self.NextToken() self.NextToken()
self.expect('(') self.expect('(')
self.NextToken() self.NextToken()
@ -1204,8 +1204,8 @@ class parser(object):
self.NextToken() self.NextToken()
else_branch = self.Parse_statement(ReturnType) else_branch = self.Parse_statement(ReturnType)
if else_branch is not None: if else_branch is not None:
return {'node':'IF', 'type':None, 'br':[condition, then_branch, else_branch]} return {'nt':'IF', 't':None, 'ch':[condition, then_branch, else_branch]}
return {'node':'IF', 'type':None, 'br':[condition, then_branch]} return {'nt':'IF', 't':None, 'ch':[condition, then_branch]}
if tok0 == 'WHILE': if tok0 == 'WHILE':
self.NextToken() self.NextToken()
@ -1214,7 +1214,7 @@ class parser(object):
condition = self.Parse_expression() condition = self.Parse_expression()
self.expect(')') self.expect(')')
self.NextToken() 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': if tok0 == 'DO':
self.NextToken() self.NextToken()
stmt = self.Parse_statement(ReturnType) stmt = self.Parse_statement(ReturnType)
@ -1227,7 +1227,7 @@ class parser(object):
self.NextToken() self.NextToken()
self.expect(';') self.expect(';')
self.NextToken() self.NextToken()
return {'node':'DO', 'type':None, 'br':[stmt, condition]} return {'nt':'DO', 't':None, 'ch':[stmt, condition]}
if tok0 == 'FOR': if tok0 == 'FOR':
self.NextToken() self.NextToken()
self.expect('(') self.expect('(')
@ -1242,10 +1242,10 @@ class parser(object):
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
stmt = self.Parse_statement(ReturnType) stmt = self.Parse_statement(ReturnType)
return {'node':'FOR', 'type':None, return {'nt':'FOR', 't':None,
'br':[{'node':'EXPRLIST','type':None, 'br':initializer}, 'ch':[{'nt':'EXPRLIST','t':None, 'ch':initializer},
condition, condition,
{'node':'EXPRLIST','type':None, 'br':iterator}, {'nt':'EXPRLIST','t':None, 'ch':iterator},
stmt]} stmt]}
if tok0 == 'TYPE': if tok0 == 'TYPE':
if not AllowDecl: if not AllowDecl:
@ -1258,10 +1258,10 @@ class parser(object):
raise EParseAlreadyDefined(self) raise EParseAlreadyDefined(self)
self.NextToken() self.NextToken()
value = None 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] == '=': if self.tok[0] == '=':
self.NextToken() self.NextToken()
decl['br'] = [self.Parse_expression()] decl['ch'] = [self.Parse_expression()]
self.expect(';') self.expect(';')
self.NextToken() self.NextToken()
self.AddSymbol('v', self.scopeindex, name, Type=typ) self.AddSymbol('v', self.scopeindex, name, Type=typ)
@ -1297,7 +1297,7 @@ class parser(object):
self.expect('}') self.expect('}')
self.NextToken() self.NextToken()
return {'node':'{}', 'type':None, 'br':body} return {'nt':'{}', 't':None, 'ch':body}
def Parse_simple_expr(self, ForbidList=False): def Parse_simple_expr(self, ForbidList=False):
"""Grammar parsed here: """Grammar parsed here:
@ -1315,19 +1315,19 @@ class parser(object):
tok = self.tok tok = self.tok
self.NextToken() self.NextToken()
if tok[0] in ('TRUE', 'FALSE'): # TRUE and FALSE don't admit sign in globals 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'): if tok[0] in ('STRING_VALUE', 'KEY_VALUE', 'VECTOR_VALUE', 'ROTATION_VALUE', 'LIST_VALUE'):
val = tok[1] val = tok[1]
if tok[0] == 'STRING_VALUE' and self.allowmultistrings: if tok[0] == 'STRING_VALUE' and self.allowmultistrings:
while self.tok[0] == 'STRING_VALUE': while self.tok[0] == 'STRING_VALUE':
val += self.tok[1] val += self.tok[1]
self.NextToken() 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': if tok[0] == 'IDENT':
sym = self.FindSymbolPartial(tok[1]) sym = self.FindSymbolPartial(tok[1])
if sym is None or sym['Kind'] != 'v': if sym is None or sym['Kind'] != 'v':
raise EParseUndefined(self) 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] == '<': if tok[0] == '<':
value = [self.Parse_simple_expr()] value = [self.Parse_simple_expr()]
self.autocastcheck(value[0], 'float') self.autocastcheck(value[0], 'float')
@ -1341,25 +1341,25 @@ class parser(object):
self.autocastcheck(value[2], 'float') self.autocastcheck(value[2], 'float')
if self.tok[0] == '>': if self.tok[0] == '>':
self.NextToken() self.NextToken()
return {'node':'VECTOR', 'type':'vector', 'br':value} return {'nt':'VECTOR', 't':'vector', 'ch':value}
self.expect(',') self.expect(',')
self.NextToken() self.NextToken()
value.append(self.Parse_simple_expr()) value.append(self.Parse_simple_expr())
self.autocastcheck(value[3], 'float') self.autocastcheck(value[3], 'float')
self.expect('>') self.expect('>')
self.NextToken() self.NextToken()
return {'node':'ROTATION', 'type':'rotation', 'br':value} return {'nt':'ROTATION', 't':'rotation', 'ch':value}
if tok[0] == '[' and not ForbidList: if tok[0] == '[' and not ForbidList:
value = [] value = []
if self.tok[0] == ']': if self.tok[0] == ']':
self.NextToken() self.NextToken()
return {'node':'LIST','type':'list','br':value} return {'nt':'LIST','t':'list','ch':value}
while True: while True:
value.append(self.Parse_simple_expr(ForbidList=True)) value.append(self.Parse_simple_expr(ForbidList=True))
if self.tok[0] == ']': if self.tok[0] == ']':
self.NextToken() self.NextToken()
return {'node':'LIST','type':'list','br':value} return {'nt':'LIST','t':'list','ch':value}
self.expect(',') self.expect(',')
self.NextToken() self.NextToken()
# Integer or Float constant expected # Integer or Float constant expected
@ -1373,7 +1373,7 @@ class parser(object):
value = tok[1] value = tok[1]
if neg and (tok[0] != 'INTEGER_VALUE' or value == -2147483648): if neg and (tok[0] != 'INTEGER_VALUE' or value == -2147483648):
value = -value 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): def Parse_optional_param_list(self):
"""Grammar parsed here: """Grammar parsed here:
@ -1431,9 +1431,9 @@ class parser(object):
self.expect(')') self.expect(')')
self.NextToken() self.NextToken()
body = self.Parse_code_block(None) 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], 'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
'br':[body]}) 'ch':[body]})
self.PopScope() self.PopScope()
return ret return ret
@ -1478,10 +1478,10 @@ class parser(object):
value = None value = None
assert self.scopeindex == 0 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: if value is not None:
value = self.autocastcheck(value, typ) value = self.autocastcheck(value, typ)
decl['br'] = [value] decl['ch'] = [value]
self.AddSymbol('v', 0, name, Loc=len(self.tree), Type=typ) self.AddSymbol('v', 0, name, Loc=len(self.tree), Type=typ)
self.tree.append(decl) self.tree.append(decl)
@ -1496,9 +1496,9 @@ class parser(object):
paramscope = self.scopeindex paramscope = self.scopeindex
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ, self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
ParamTypes=params[0], ParamNames=params[1]) 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, 'pscope':paramscope,
'ptypes':params[0], 'pnames':params[1], 'br':[body]}) 'ptypes':params[0], 'pnames':params[1], 'ch':[body]})
self.PopScope() self.PopScope()
assert self.scopeindex == 0 assert self.scopeindex == 0
else: else:
@ -1543,7 +1543,7 @@ class parser(object):
events = self.Parse_events() events = self.Parse_events()
self.expect('}') 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() self.NextToken()
def Parse_script(self): def Parse_script(self):
@ -1867,8 +1867,10 @@ class parser(object):
# reference to the implementation; otherwise None. # reference to the implementation; otherwise None.
if name in self.functions: if name in self.functions:
warning('Function already defined in bultins.txt, overwriting: ' + name) warning('Function already defined in bultins.txt, overwriting: ' + name)
self.functions[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args, fn = getattr(lslfuncs, name, None)
'Loc':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): elif match.group(4):
# constant # constant
name = match.group(5) name = match.group(5)
@ -1878,67 +1880,67 @@ class parser(object):
typ = match.group(4) typ = match.group(4)
if typ == 'quaternion': if typ == 'quaternion':
typ = 'rotation' typ = 'rotation'
val = match.group(6) value = match.group(6)
if typ == 'integer': if typ == 'integer':
val = int(val, 0) value = int(value, 0)
elif typ == 'float': elif typ == 'float':
val = lslfuncs.F32(float(val)) value = lslfuncs.F32(float(value))
elif typ == 'string': elif typ == 'string':
val = val.decode('utf8') value = value.decode('utf8')
if not parse_str_re.match(val): if not parse_str_re.match(value):
raise EInternal raise EInternal
esc = False esc = False
tmp = val[1:-1] tmp = value[1:-1]
val = u'' value = u''
for c in tmp: for c in tmp:
if esc: if esc:
if c == u'n': if c == u'n':
c = u'\n' c = u'\n'
elif c == u't': elif c == u't':
c = u' ' c = u' '
val += c value += c
esc = False esc = False
elif c == u'\\': elif c == u'\\':
esc = True esc = True
else: else:
val += c value += c
#if typ == 'key': #if typ == 'key':
# val = Key(val) # value = Key(value)
elif typ == 'key': elif typ == 'key':
warning('Key constants not supported in builtins.txt: ' + line) warning('Key constants not supported in builtins.txt: ' + line)
val = None value = None
elif typ in ('vector', 'rotation'): elif typ in ('vector', 'rotation'):
if val[0:1] != '<' or val[-1:] != '>': if value[0:1] != '<' or value[-1:] != '>':
raise ValueError raise ValueError
val = val[1:-1].split(',') value = value[1:-1].split(',')
if len(val) != (3 if typ == 'vector' else 4): if len(value) != (3 if typ == 'vector' else 4):
raise ValueError raise ValueError
num = parse_num_re.match(val[0]) num = parse_num_re.match(value[0])
if not num: if not num:
raise ValueError raise ValueError
val[0] = lslfuncs.F32(float(num.group(1))) value[0] = lslfuncs.F32(float(num.group(1)))
num = parse_num_re.match(val[1]) num = parse_num_re.match(value[1])
if not num: if not num:
raise ValueError raise ValueError
val[1] = lslfuncs.F32(float(num.group(1))) value[1] = lslfuncs.F32(float(num.group(1)))
num = parse_num_re.match(val[2]) num = parse_num_re.match(value[2])
if not num: if not num:
raise ValueError raise ValueError
val[2] = lslfuncs.F32(float(num.group(1))) value[2] = lslfuncs.F32(float(num.group(1)))
if typ != 'vector': if typ == 'vector':
num = parse_num_re.match(val[3]) value = Vector(value)
else:
num = parse_num_re.match(value[3])
if not num: if not num:
raise ValueError raise ValueError
val[3] = lslfuncs.F32(float(num.group(1))) value[3] = lslfuncs.F32(float(num.group(1)))
val = Quaternion(val) value = Quaternion(value)
else:
val = Vector(val)
else: else:
assert typ == 'list' assert typ == 'list'
warning('List constants not supported in builtins.txt: ' + line) warning('List constants not supported in builtins.txt: ' + line)
val = None value = None
if val is not None: if value is not None:
self.constants[name] = val self.constants[name] = value
except EInternal: except EInternal:
warning('Invalid string in builtins.txt: ' + line) warning('Invalid string in builtins.txt: ' + line)