@@ -93,7 +93,9 @@ def visit_Break(self, node):
9393 if not self .block .loop_stack :
9494 raise util .ParseError (node , "'break' not in loop" )
9595 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 )
9799
98100 def visit_ClassDef (self , node ):
99101 # Since we only care about global vars, we end up throwing away the locals
@@ -166,7 +168,7 @@ def visit_Continue(self, node):
166168 if not self .block .loop_stack :
167169 raise util .ParseError (node , "'continue' not in loop" )
168170 self ._write_py_context (node .lineno )
169- self .writer .write ('goto Label{}' . format ( self . block . top_loop (). start_label ) )
171+ self .writer .write ('continue' )
170172
171173 def visit_Delete (self , node ):
172174 self ._write_py_context (node .lineno )
@@ -192,40 +194,27 @@ def visit_Expr(self, node):
192194 self .visit_expr (node .value ).free ()
193195
194196 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 )
229218
230219 def visit_FunctionDef (self , node ):
231220 self ._write_py_context (node .lineno + len (node .decorator_list ))
@@ -357,6 +346,8 @@ def visit_Return(self, node):
357346 if node .value :
358347 with self .visit_expr (node .value ) as value :
359348 self .writer .write ('πR = {}' .format (value .expr ))
349+ else :
350+ self .writer .write ('πR = πg.None' )
360351 self .writer .write ('continue' )
361352
362353 def visit_Try (self , node ):
@@ -439,26 +430,12 @@ def visit_Try(self, node):
439430 }""" ), exc = exc .expr , tb = tb .expr )
440431
441432 def visit_While (self , node ):
442- loop = self .block .push_loop ()
443433 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 )
462439
463440 def visit_With (self , node ):
464441 assert len (node .items ) == 1 , 'multiple items in a with not yet supported'
@@ -739,6 +716,44 @@ def _visit_each(self, nodes):
739716 for node in nodes :
740717 self .visit (node )
741718
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+
742757 def _write_except_block (self , label , exc , except_node ):
743758 self ._write_py_context (except_node .lineno )
744759 self .writer .write_label (label )
0 commit comments