@@ -93,7 +93,9 @@ def visit_Break(self, node):
93
93
if not self .block .loop_stack :
94
94
raise util .ParseError (node , "'break' not in loop" )
95
95
self ._write_py_context (node .lineno )
96
- self .writer .write ('goto Label{}' .format (self .block .top_loop ().end_label ))
96
+ self .writer .write_tmpl (textwrap .dedent ("""\
97
+ $breakvar = true
98
+ continue""" ), breakvar = self .block .top_loop ().breakvar .name )
97
99
98
100
def visit_ClassDef (self , node ):
99
101
# Since we only care about global vars, we end up throwing away the locals
@@ -166,7 +168,7 @@ def visit_Continue(self, node):
166
168
if not self .block .loop_stack :
167
169
raise util .ParseError (node , "'continue' not in loop" )
168
170
self ._write_py_context (node .lineno )
169
- self .writer .write ('goto Label{}' . format ( self . block . top_loop (). start_label ) )
171
+ self .writer .write ('continue' )
170
172
171
173
def visit_Delete (self , node ):
172
174
self ._write_py_context (node .lineno )
@@ -192,40 +194,27 @@ def visit_Expr(self, node):
192
194
self .visit_expr (node .value ).free ()
193
195
194
196
def visit_For (self , node ):
195
- loop = self .block .push_loop ()
196
- orelse_label = self .block .genlabel () if node .orelse else loop .end_label
197
- self ._write_py_context (node .lineno )
198
- with self .visit_expr (node .iter ) as iter_expr , \
199
- self .block .alloc_temp () as i , \
200
- self .block .alloc_temp () as n :
201
- self .writer .write_checked_call2 (i , 'πg.Iter(πF, {})' , iter_expr .expr )
202
- self .writer .write_label (loop .start_label )
203
- tmpl = textwrap .dedent ("""\
204
- if $n, πE = πg.Next(πF, $i); πE != nil {
205
- \t isStop, exc := πg.IsInstance(πF, πE.ToObject(), πg.StopIterationType.ToObject())
206
- \t if exc != nil {
207
- \t \t πE = exc
208
- \t \t continue
209
- \t }
210
- \t if !isStop {
211
- \t \t continue
212
- \t }
213
- \t πE = nil
214
- \t πF.RestoreExc(nil, nil)
215
- \t goto Label$orelse
216
- }""" )
217
- self .writer .write_tmpl (tmpl , n = n .name , i = i .expr , orelse = orelse_label )
218
- self ._tie_target (node .target , n .expr )
219
- self ._visit_each (node .body )
220
- self .writer .write ('goto Label{}' .format (loop .start_label ))
221
-
222
- self .block .pop_loop ()
223
- if node .orelse :
224
- self .writer .write_label (orelse_label )
225
- self ._visit_each (node .orelse )
226
- # Avoid label "defined and not used" in case there's no break statements.
227
- self .writer .write ('goto Label{}' .format (loop .end_label ))
228
- self .writer .write_label (loop .end_label )
197
+ with self .block .alloc_temp () as i :
198
+ with self .visit_expr (node .iter ) as iter_expr :
199
+ self .writer .write_checked_call2 (i , 'πg.Iter(πF, {})' , iter_expr .expr )
200
+ def testfunc (testvar ):
201
+ with self .block .alloc_temp () as n :
202
+ self .writer .write_tmpl (textwrap .dedent ("""\
203
+ if $n, πE = πg.Next(πF, $i); πE != nil {
204
+ \t isStop, exc := πg.IsInstance(πF, πE.ToObject(), πg.StopIterationType.ToObject())
205
+ \t if exc != nil {
206
+ \t \t πE = exc
207
+ \t } else if isStop {
208
+ \t \t πE = nil
209
+ \t \t πF.RestoreExc(nil, nil)
210
+ \t }
211
+ \t $testvar = !isStop
212
+ } else {
213
+ \t $testvar = true""" ), n = n .name , i = i .expr , testvar = testvar .name )
214
+ with self .writer .indent_block ():
215
+ self ._tie_target (node .target , n .expr )
216
+ self .writer .write ('}' )
217
+ self ._visit_loop (testfunc , node )
229
218
230
219
def visit_FunctionDef (self , node ):
231
220
self ._write_py_context (node .lineno + len (node .decorator_list ))
@@ -357,6 +346,8 @@ def visit_Return(self, node):
357
346
if node .value :
358
347
with self .visit_expr (node .value ) as value :
359
348
self .writer .write ('πR = {}' .format (value .expr ))
349
+ else :
350
+ self .writer .write ('πR = πg.None' )
360
351
self .writer .write ('continue' )
361
352
362
353
def visit_Try (self , node ):
@@ -439,26 +430,12 @@ def visit_Try(self, node):
439
430
}""" ), exc = exc .expr , tb = tb .expr )
440
431
441
432
def visit_While (self , node ):
442
- loop = self .block .push_loop ()
443
433
self ._write_py_context (node .lineno )
444
- self .writer .write_label (loop .start_label )
445
- orelse_label = self .block .genlabel () if node .orelse else loop .end_label
446
- with self .visit_expr (node .test ) as cond ,\
447
- self .block .alloc_temp ('bool' ) as is_true :
448
- self .writer .write_checked_call2 (is_true , 'πg.IsTrue(πF, {})' , cond .expr )
449
- self .writer .write_tmpl (textwrap .dedent ("""\
450
- if !$is_true {
451
- \t goto Label$orelse_label
452
- }""" ), is_true = is_true .expr , orelse_label = orelse_label )
453
- self ._visit_each (node .body )
454
- self .writer .write ('goto Label{}' .format (loop .start_label ))
455
- if node .orelse :
456
- self .writer .write_label (orelse_label )
457
- self ._visit_each (node .orelse )
458
- # Avoid label "defined and not used" in case there's no break statements.
459
- self .writer .write ('goto Label{}' .format (loop .end_label ))
460
- self .writer .write_label (loop .end_label )
461
- self .block .pop_loop ()
434
+ def testfunc (testvar ):
435
+ with self .visit_expr (node .test ) as cond :
436
+ self .writer .write_checked_call2 (
437
+ testvar , 'πg.IsTrue(πF, {})' , cond .expr )
438
+ self ._visit_loop (testfunc , node )
462
439
463
440
def visit_With (self , node ):
464
441
assert len (node .items ) == 1 , 'multiple items in a with not yet supported'
@@ -739,6 +716,44 @@ def _visit_each(self, nodes):
739
716
for node in nodes :
740
717
self .visit (node )
741
718
719
+ def _visit_loop (self , testfunc , node ):
720
+ start_label = self .block .genlabel (is_checkpoint = True )
721
+ else_label = self .block .genlabel (is_checkpoint = True )
722
+ end_label = self .block .genlabel ()
723
+ with self .block .alloc_temp ('bool' ) as breakvar :
724
+ self .block .push_loop (breakvar )
725
+ self .writer .write ('πF.PushCheckpoint({})' .format (else_label ))
726
+ self .writer .write ('{} = false' .format (breakvar .name ))
727
+ self .writer .write_label (start_label )
728
+ self .writer .write_tmpl (textwrap .dedent ("""\
729
+ if πE != nil || πR != nil {
730
+ \t continue
731
+ }
732
+ if $breakvar {
733
+ \t πF.PopCheckpoint()
734
+ \t goto Label$end_label
735
+ }""" ), breakvar = breakvar .expr , end_label = end_label )
736
+ with self .block .alloc_temp ('bool' ) as testvar :
737
+ testfunc (testvar )
738
+ self .writer .write_tmpl (textwrap .dedent ("""\
739
+ if πE != nil || !$testvar {
740
+ \t continue
741
+ }
742
+ πF.PushCheckpoint($start_label)\
743
+ """ ), testvar = testvar .name , start_label = start_label )
744
+ self ._visit_each (node .body )
745
+ self .writer .write ('continue' )
746
+ # End the loop so that break applies to an outer loop if present.
747
+ self .block .pop_loop ()
748
+ self .writer .write_label (else_label )
749
+ self .writer .write (textwrap .dedent ("""\
750
+ if πE != nil || πR != nil {
751
+ \t continue
752
+ }""" ))
753
+ if node .orelse :
754
+ self ._visit_each (node .orelse )
755
+ self .writer .write_label (end_label )
756
+
742
757
def _write_except_block (self , label , exc , except_node ):
743
758
self ._write_py_context (except_node .lineno )
744
759
self .writer .write_label (label )
0 commit comments