Parse_unary_postfix_expression shouldn't accept the token (i.e. advance to the next) if it's not processed. This caused a mismatch between the reported syntax error and the position where it should have been detected. Fixed.

Added corresponding regression test.
This commit is contained in:
Sei Lisa 2016-01-03 01:20:05 +01:00
parent ceb442e931
commit cfb9dee941
2 changed files with 28 additions and 5 deletions

View file

@ -642,18 +642,22 @@ class parser(object):
""" """
tok0 = self.tok[0] tok0 = self.tok[0]
val = self.tok[1] if len(self.tok) > 1 else None val = self.tok[1] if len(self.tok) > 1 else None
self.NextToken()
CONST = 'CONST' CONST = 'CONST'
if tok0 == '-' and self.tok[0] in ('INTEGER_VALUE', 'FLOAT_VALUE'): if tok0 == '-':
tok0 = self.tok[0]
val = self.tok[1]
self.NextToken() self.NextToken()
return {'nt':CONST, 't':'integer' if type(val) == int else 'float', 'value':-val} if self.tok[0] in ('INTEGER_VALUE', 'FLOAT_VALUE'):
tok0 = self.tok[0]
val = self.tok[1]
self.NextToken()
return {'nt':CONST, 't':'integer' if type(val) == int else 'float', 'value':-val}
if tok0 == 'INTEGER_VALUE': if tok0 == 'INTEGER_VALUE':
self.NextToken()
return {'nt':CONST, 't':'integer', 'value':val} return {'nt':CONST, 't':'integer', 'value':val}
if tok0 == 'FLOAT_VALUE': if tok0 == 'FLOAT_VALUE':
self.NextToken()
return {'nt':CONST, 't':'float', 'value':val} return {'nt':CONST, 't':'float', 'value':val}
if tok0 == 'STRING_VALUE': if tok0 == 'STRING_VALUE':
self.NextToken()
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]
@ -663,14 +667,19 @@ class parser(object):
#if tok0 == 'KEY_VALUE': #if tok0 == 'KEY_VALUE':
# return [CONST, 'key', val] # return [CONST, 'key', val]
if tok0 == 'VECTOR_VALUE': if tok0 == 'VECTOR_VALUE':
self.NextToken()
return {'nt':CONST, 't':'vector', 'value':val} return {'nt':CONST, 't':'vector', 'value':val}
if tok0 == 'ROTATION_VALUE': if tok0 == 'ROTATION_VALUE':
self.NextToken()
return {'nt':CONST, 't':'rotation', 'value':val} return {'nt':CONST, 't':'rotation', 'value':val}
if tok0 == 'LIST_VALUE': if tok0 == 'LIST_VALUE':
self.NextToken()
return {'nt':CONST, 't':'list', 'value':val} return {'nt':CONST, 't':'list', 'value':val}
if tok0 in ('TRUE', 'FALSE'): if tok0 in ('TRUE', 'FALSE'):
self.NextToken()
return {'nt':CONST, 't':'integer', 'value':int(tok0 == 'TRUE')} return {'nt':CONST, 't':'integer', 'value':int(tok0 == 'TRUE')}
if tok0 == '<': if tok0 == '<':
self.NextToken()
val = [self.Parse_expression()] val = [self.Parse_expression()]
self.expect(',') self.expect(',')
self.NextToken() self.NextToken()
@ -709,11 +718,13 @@ class parser(object):
return {'nt':'ROTATION', 't':'rotation', 'ch':val} return {'nt':'ROTATION', 't':'rotation', 'ch':val}
if tok0 == '[': if tok0 == '[':
self.NextToken()
val = self.Parse_optional_expression_list() val = self.Parse_optional_expression_list()
self.expect(']') self.expect(']')
self.NextToken() self.NextToken()
return {'nt':'LIST', 't':'list', 'ch':val} return {'nt':'LIST', 't':'list', 'ch':val}
if tok0 == 'PRINT': if tok0 == 'PRINT':
self.NextToken()
self.expect('(') self.expect('(')
self.NextToken() self.NextToken()
expr = self.Parse_expression() expr = self.Parse_expression()
@ -728,6 +739,7 @@ class parser(object):
raise EParseUEOF(self) raise EParseUEOF(self)
raise EParseSyntax(self) raise EParseSyntax(self)
name = val name = val
self.NextToken()
# Course of action decided here. # Course of action decided here.
tok0 = self.tok[0] tok0 = self.tok[0]

View file

@ -467,6 +467,17 @@ class Test03_Optimizer(UnitTestCase):
self.assertRaises(EParseAlreadyDefined, self.parser.parse, self.assertRaises(EParseAlreadyDefined, self.parser.parse,
'default { timer() {} timer() {} }') 'default { timer() {} timer() {} }')
try:
self.parser.parse('default { timer() { return } }')
# should raise EParseSyntax, so it should never get here
self.assertFalse(True)
except EParseSyntax as e:
# should err before first closing brace
self.assertEqual(e.cno, 27)
except:
# should raise no other exception
self.assertFalse(True)
def tearDown(self): def tearDown(self):
del self.parser del self.parser
del self.opt del self.opt