mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +00:00
Fix rare bug with breakcont and label scope.
This caused "Label not defined within scope" when breakcont was active: default{timer(){jump x;while(0)@x;}} The problem was that breakcont opens a new scope for the case where it has to deal with a loop which is the single statement of an outer statement, e.g. default{timer(){if(1)while(1)break;}} would add braces to jump to the correct break point: default{timer(){if(1){while(1)jump brk;@brk;}} To avoid excessive complication, a new scope was always opened for the whole statement in each of the loops, regardless of whether we needed braces later on or not. That should be transparent most of the time, but then if the statement was a label declaration, the label would be in a new scope that would be invisible outside the loop. Fix that by checking explicitly for a label to temporarily get rid of the new scope in that case, and add a test case for it.
This commit is contained in:
parent
9d0eb307e1
commit
e60457f00e
2 changed files with 33 additions and 7 deletions
|
@ -1659,9 +1659,6 @@ list lazy_list_set(list L, integer i, list v)
|
|||
# This works by adding braces around the while and the newly
|
||||
# added label, like this:
|
||||
# if (a) { while (b) { ... jump label; } @label; }
|
||||
#
|
||||
# FIXME: This causes issues with this code that should work:
|
||||
# default{timer(){ jump x; while(1) @x; }}
|
||||
self.PushScope()
|
||||
|
||||
self.breakstack.append([self.GenerateLabel(), self.scopeindex, False])
|
||||
|
@ -1671,8 +1668,22 @@ list lazy_list_set(list L, integer i, list v)
|
|||
condition = self.Parse_expression()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
ret = {'nt':'WHILE', 't':None, 'ch':[condition,
|
||||
self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)]}
|
||||
# To fix a problem with a corner case (LSL allows defining a label
|
||||
# in a single statement, at the same scope as the loop, breaking
|
||||
# some of our logic), we check if the statement is a label. If so,
|
||||
# we pop the scope to parse the statement and push it again.
|
||||
# It won't cause scope problems in turn because we won't add any
|
||||
# break or continue labels if no break or continue statement is
|
||||
# present, which it can't because the statement is a label.
|
||||
if self.breakcont and self.tok[0] == '@':
|
||||
self.PopScope()
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
self.PushScope()
|
||||
else:
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
|
||||
ret = {'nt':'WHILE', 't':None, 'ch':[condition, stmt]}
|
||||
|
||||
if self.breakcont:
|
||||
last = self.continuestack.pop()
|
||||
if last[2]:
|
||||
|
@ -1694,7 +1705,12 @@ list lazy_list_set(list L, integer i, list v)
|
|||
|
||||
self.breakstack.append([self.GenerateLabel(), self.scopeindex, False])
|
||||
self.continuestack.append([self.GenerateLabel(), None, False])
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
if self.breakcont and self.tok[0] == '@':
|
||||
self.PopScope()
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
self.PushScope()
|
||||
else:
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
self.expect('WHILE')
|
||||
self.NextToken()
|
||||
self.expect('(')
|
||||
|
@ -1737,7 +1753,12 @@ list lazy_list_set(list L, integer i, list v)
|
|||
iterator = self.Parse_optional_expression_list()
|
||||
self.expect(')')
|
||||
self.NextToken()
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
if self.breakcont and self.tok[0] == '@':
|
||||
self.PopScope()
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
self.PushScope()
|
||||
else:
|
||||
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
||||
ret = {'nt':'FOR', 't':None,
|
||||
'ch':[{'nt':'EXPRLIST','t':None, 'ch':initializer},
|
||||
condition,
|
||||
|
|
|
@ -229,6 +229,11 @@ class Test02_Parser(UnitTestCase):
|
|||
|
||||
# Check for exceptions only
|
||||
p = self.parser.parse('default{timer(){jump x;while(1)@x;}}')
|
||||
p = self.parser.parse('default{timer(){jump x;do@x;while(1);}}')
|
||||
p = self.parser.parse('default{timer(){jump x;for(;1;)@x;}}')
|
||||
p = self.parser.parse('default{timer(){jump x;while(1)@x;}}', ('breakcont',))
|
||||
p = self.parser.parse('default{timer(){jump x;do@x;while(1);}}', ('breakcont',))
|
||||
p = self.parser.parse('default{timer(){jump x;for(;1;)@x;}}', ('breakcont',))
|
||||
self.outscript.output(p)
|
||||
|
||||
self.assertRaises(EParseUndefined, self.parser.parse,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue