mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2024-11-21 06:15:56 -07:00
Introduce 'c' (constant) as symbol kind
This is preparatory work for addressing issue #30. It also fixes a bug where --prettify made the constants writable.
This commit is contained in:
parent
c924f3ae5c
commit
5841c2c17a
2 changed files with 70 additions and 13 deletions
|
@ -1009,7 +1009,7 @@ class parser(object):
|
|||
return nr(nt='FNCALL', t=sym['Type'], name=name, ch=args)
|
||||
|
||||
sym = self.FindSymbolFull(val)
|
||||
if sym is None or sym['Kind'] != 'v':
|
||||
if sym is None or sym['Kind'] not in {'v', 'c'}:
|
||||
self.errorpos = savepos
|
||||
raise EParseUndefined(self)
|
||||
|
||||
|
@ -1052,9 +1052,8 @@ class parser(object):
|
|||
self.AddSymbol('f', 0, 'lazy_list_set', Loc=self.usedspots,
|
||||
Type='list', ParamTypes=params[0], ParamNames=params[1],
|
||||
Inline=False)
|
||||
self.AddSymbol('v', paramscope, 'L', Type='list')
|
||||
self.AddSymbol('v', paramscope, 'i', Type='integer')
|
||||
self.AddSymbol('v', paramscope, 'v', Type='list')
|
||||
for typ, name in zip(*params):
|
||||
self.AddSymbol('v', paramscope, name, Type=typ)
|
||||
#self.PushScope() # no locals
|
||||
|
||||
# Add body (apologies for the wall of text)
|
||||
|
@ -1187,6 +1186,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
)])
|
||||
|
||||
if tok0 == '.':
|
||||
if sym['Kind'] == 'c':
|
||||
raise EParseSyntax(self)
|
||||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
self.ValidateField(typ, self.tok[1])
|
||||
|
@ -1196,6 +1197,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
typ = 'float'
|
||||
|
||||
if tok0 in ('++', '--'):
|
||||
if sym['Kind'] == 'c':
|
||||
raise EParseSyntax(self)
|
||||
self.NextToken()
|
||||
if lvalue.t not in ('integer', 'float'):
|
||||
raise EParseTypeMismatch(self)
|
||||
|
@ -1204,6 +1207,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
if AllowAssignment and (tok0 in self.assignment_toks
|
||||
or self.extendedassignment
|
||||
and tok0 in self.extassignment_toks):
|
||||
if sym['Kind'] == 'c':
|
||||
raise EParseSyntax(self)
|
||||
self.NextToken()
|
||||
expr = self.Parse_expression()
|
||||
rtyp = expr.t
|
||||
|
@ -1765,6 +1770,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
name = self.tok[1]
|
||||
if name in self.symtab[0] and self.symtab[0][name]['Kind'] == 'c':
|
||||
raise EParseSyntax(self)
|
||||
if name in self.symtab[self.scopeindex]:
|
||||
raise EParseAlreadyDefined(self)
|
||||
# shrinknames *needs* all labels renamed, so they are out of the way
|
||||
|
@ -2258,6 +2265,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
self.NextToken()
|
||||
self.expect('IDENT')
|
||||
name = self.tok[1]
|
||||
if name in self.symtab[0] and self.symtab[0][name]['Kind'] == 'c':
|
||||
raise EParseSyntax(self)
|
||||
if name in self.symtab[self.scopeindex]:
|
||||
raise EParseAlreadyDefined(self)
|
||||
self.NextToken()
|
||||
|
@ -2354,8 +2363,8 @@ list lazy_list_set(list L, integer i, list v)
|
|||
sym = self.FindSymbolPartial(tok[1])
|
||||
# The parser accepts library function names here as valid variables
|
||||
# (it chokes at RAIL in Mono, and at runtime in LSO for some types)
|
||||
if sym is None or sym['Kind'] != 'v' and (sym['Kind'] != 'f'
|
||||
or 'ParamNames' in sym): # only UDFs have ParamNames
|
||||
if sym is None or sym['Kind'] not in {'v', 'c'} and (sym['Kind'] !=
|
||||
'f' or 'ParamNames' in sym): # only UDFs have ParamNames
|
||||
raise EParseUndefined(self)
|
||||
typ = sym['Type']
|
||||
if ForbidList and lslcommon.LSO and typ == 'key':
|
||||
|
@ -2429,6 +2438,10 @@ list lazy_list_set(list L, integer i, list v)
|
|||
self.expect('IDENT')
|
||||
|
||||
name = self.tok[1]
|
||||
if (name in self.symtab[0]
|
||||
and self.symtab[0][name]['Kind'] == 'c'
|
||||
):
|
||||
raise EParseSyntax(self)
|
||||
if name in self.symtab[self.scopeindex]:
|
||||
raise EParseAlreadyDefined(self)
|
||||
|
||||
|
@ -2928,14 +2941,16 @@ list lazy_list_set(list L, integer i, list v)
|
|||
# The first element (0) is the global scope. Each symbol table is a
|
||||
# dictionary of symbols, whose elements are in turn dictionaries of
|
||||
# attributes. Each has a 'Kind', which can be:
|
||||
# 'v' for variable, 'f' for function, 'l' for label, 's' for state,
|
||||
# or 'e' for event. Some have a 'Loc' indicating the location (index)
|
||||
# of the definition in the tree root.
|
||||
# Variables have 'Scope' and 'Type' (a string).
|
||||
# 'v' for variable, 'c' for constant, 'f' for function, 'l' for label,
|
||||
# 's' for state, or 'e' for event. Some have a 'Loc' indicating the
|
||||
# location (index) of the definition in the tree's root.
|
||||
# Variables and constants have 'Scope' and 'Type' (a string).
|
||||
# Global variables also have 'Loc'.
|
||||
# Variables that are parameters also have 'Param'.
|
||||
# Functions have 'Type' (return type, a string) and 'ParamTypes' (a list of strings).
|
||||
# User-defined functions also have 'Loc' and 'ParamNames' (a list of strings).
|
||||
# Functions have 'Type' (return type, a string) and 'ParamTypes' (a
|
||||
# list of strings).
|
||||
# User-defined functions also have 'Loc' and 'ParamNames' (a list of
|
||||
# strings).
|
||||
# Labels only have 'Scope'.
|
||||
# States only have 'Loc'.
|
||||
# Events have 'ParamTypes' and 'ParamNames', just like UDFs.
|
||||
|
@ -2953,7 +2968,7 @@ list lazy_list_set(list L, integer i, list v)
|
|||
if self.prettify:
|
||||
# Add the constants as symbol table variables...
|
||||
for i in self.constants:
|
||||
self.symtab[0][i] = {'Kind':'v', 'Scope':0,
|
||||
self.symtab[0][i] = {'Kind':'c', 'Scope':0,
|
||||
'Type':lslcommon.PythonType2LSL[type(self.constants[i])]}
|
||||
# ... and remove them as constants.
|
||||
self.constants = {}
|
||||
|
|
42
run-tests.py
42
run-tests.py
|
@ -418,6 +418,48 @@ class UnitTestRegression(UnitTestCase):
|
|||
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
|
||||
'default{timer(){if(1)return 1;}}')
|
||||
|
||||
# Constants with 'c' in symbol table (introduced to solve issue #30)
|
||||
# Some errors are not the expected ones. Most (all?) should be syntax.
|
||||
parser.parse('integer a=LOOP;default{timer(){llOwnerSay(NAK+EOF);}}')
|
||||
parser.parse('integer a=LOOP;default{timer(){llOwnerSay(NAK+EOF);}}',
|
||||
('prettify',))
|
||||
parser.parse('default{timer(){LOOP;}}')
|
||||
parser.parse('default{timer(){LOOP;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{touch(integer LOOP){}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){ZERO_VECTOR.x;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){LOOP.x;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){LOOP=1;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){LOOP++;}}', ('prettify',))
|
||||
# should raise EParseSyntax instead
|
||||
self.assertRaises(lslparse.EParseUndefined, parser.parse,
|
||||
'default{timer(){++LOOP;}}', ('prettify',))
|
||||
# should raise EParseSyntax instead
|
||||
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
|
||||
'integer LOOP=0;', ('prettify',))
|
||||
# should raise EParseSyntax instead
|
||||
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
|
||||
'integer LOOP(){}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){integer LOOP=1;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){integer LOOP;}}', ('prettify',))
|
||||
# should raise EParseSyntax instead
|
||||
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
|
||||
'default{timer(){}}state LOOP{timer(){}}', ('prettify',))
|
||||
# should raise EParseSyntax instead
|
||||
self.assertRaises(lslparse.EParseUndefined, parser.parse,
|
||||
'default{timer(){state LOOP;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){@LOOP;}}', ('prettify',))
|
||||
self.assertRaises(lslparse.EParseSyntax, parser.parse,
|
||||
'default{timer(){integer LOOP;}}', ('prettify',))
|
||||
|
||||
|
||||
class UnitTestCoverage(UnitTestCase):
|
||||
def test_coverage_misc(self):
|
||||
"""Miscellaneous tests that can't be computed or are too difficult
|
||||
|
|
Loading…
Reference in a new issue