@@ -14,6 +14,33 @@ use crate::{
1414 symboltable:: { self , SymbolFlags , SymbolScope , SymbolTable , SymbolTableType } ,
1515 unparse:: unparse_expr,
1616} ;
17+
18+ const MAXBLOCKS : usize = 20 ;
19+
20+ #[ derive( Debug , Clone , Copy ) ]
21+ pub enum FBlockType {
22+ WhileLoop ,
23+ ForLoop ,
24+ TryExcept ,
25+ FinallyTry ,
26+ FinallyEnd ,
27+ With ,
28+ AsyncWith ,
29+ HandlerCleanup ,
30+ PopValue ,
31+ ExceptionHandler ,
32+ ExceptionGroupHandler ,
33+ AsyncComprehensionGenerator ,
34+ StopIteration ,
35+ }
36+
37+ #[ derive( Debug , Clone ) ]
38+ pub struct FBlockInfo {
39+ pub fb_type : FBlockType ,
40+ pub fb_block : BlockIdx ,
41+ pub fb_exit : BlockIdx ,
42+ // fb_datum is not needed in RustPython
43+ }
1744use itertools:: Itertools ;
1845use malachite_bigint:: BigInt ;
1946use num_complex:: Complex ;
@@ -315,14 +342,15 @@ impl<'src> Compiler<'src> {
315342 varnames : IndexSet :: default ( ) ,
316343 cellvars : IndexSet :: default ( ) ,
317344 freevars : IndexSet :: default ( ) ,
318- fasthidden : IndexMap :: default ( ) ,
345+ fast_hidden : IndexMap :: default ( ) ,
319346 argcount : 0 ,
320347 posonlyargcount : 0 ,
321348 kwonlyargcount : 0 ,
322349 firstlineno : OneIndexed :: MIN ,
323350 } ,
324351 static_attributes : None ,
325352 in_inlined_comp : false ,
353+ fblock : Vec :: with_capacity ( MAXBLOCKS ) ,
326354 } ;
327355 Compiler {
328356 code_stack : vec ! [ module_code] ,
@@ -430,7 +458,7 @@ impl Compiler<'_> {
430458 varnames : varname_cache,
431459 cellvars : cellvar_cache,
432460 freevars : freevar_cache,
433- fasthidden : IndexMap :: default ( ) ,
461+ fast_hidden : IndexMap :: default ( ) ,
434462 argcount : arg_count,
435463 posonlyargcount : posonlyarg_count,
436464 kwonlyargcount : kwonlyarg_count,
@@ -442,6 +470,7 @@ impl Compiler<'_> {
442470 None
443471 } ,
444472 in_inlined_comp : false ,
473+ fblock : Vec :: with_capacity ( MAXBLOCKS ) ,
445474 } ;
446475 self . code_stack . push ( info) ;
447476 }
@@ -454,6 +483,37 @@ impl Compiler<'_> {
454483 unwrap_internal ( self , stack_top. finalize_code ( self . opts . optimize ) )
455484 }
456485
486+ /// Push a new fblock
487+ // = compiler_push_fblock
488+ fn push_fblock (
489+ & mut self ,
490+ fb_type : FBlockType ,
491+ fb_block : BlockIdx ,
492+ fb_exit : BlockIdx ,
493+ ) -> CompileResult < ( ) > {
494+ let code = self . current_code_info ( ) ;
495+ if code. fblock . len ( ) >= MAXBLOCKS {
496+ return Err ( self . error ( CodegenErrorType :: SyntaxError (
497+ "too many statically nested blocks" . to_owned ( ) ,
498+ ) ) ) ;
499+ }
500+ code. fblock . push ( FBlockInfo {
501+ fb_type,
502+ fb_block,
503+ fb_exit,
504+ } ) ;
505+ Ok ( ( ) )
506+ }
507+
508+ /// Pop an fblock
509+ // = compiler_pop_fblock
510+ fn pop_fblock ( & mut self , _expected_type : FBlockType ) -> FBlockInfo {
511+ let code = self . current_code_info ( ) ;
512+ // TODO: Add assertion to check expected type matches
513+ // assert!(matches!(fblock.fb_type, expected_type));
514+ code. fblock . pop ( ) . expect ( "fblock stack underflow" )
515+ }
516+
457517 // could take impl Into<Cow<str>>, but everything is borrowed from ast structs; we never
458518 // actually have a `String` to pass
459519 fn name ( & mut self , name : & str ) -> bytecode:: NameIdx {
@@ -1086,26 +1146,62 @@ impl Compiler<'_> {
10861146 self . switch_to_block ( after_block) ;
10871147 }
10881148 }
1089- Stmt :: Break ( _) => match self . ctx . loop_data {
1090- Some ( ( _, end) ) => {
1091- emit ! ( self , Instruction :: Break { target: end } ) ;
1092- }
1093- None => {
1094- return Err (
1095- self . error_ranged ( CodegenErrorType :: InvalidBreak , statement. range ( ) )
1096- ) ;
1097- }
1098- } ,
1099- Stmt :: Continue ( _) => match self . ctx . loop_data {
1100- Some ( ( start, _) ) => {
1101- emit ! ( self , Instruction :: Continue { target: start } ) ;
1149+ Stmt :: Break ( _) => {
1150+ // Find the innermost loop in fblock stack
1151+ let found_loop = {
1152+ let code = self . current_code_info ( ) ;
1153+ let mut result = None ;
1154+ for i in ( 0 ..code. fblock . len ( ) ) . rev ( ) {
1155+ match code. fblock [ i] . fb_type {
1156+ FBlockType :: WhileLoop | FBlockType :: ForLoop => {
1157+ result = Some ( code. fblock [ i] . fb_exit ) ;
1158+ break ;
1159+ }
1160+ _ => continue ,
1161+ }
1162+ }
1163+ result
1164+ } ;
1165+
1166+ match found_loop {
1167+ Some ( exit_block) => {
1168+ emit ! ( self , Instruction :: Break { target: exit_block } ) ;
1169+ }
1170+ None => {
1171+ return Err (
1172+ self . error_ranged ( CodegenErrorType :: InvalidBreak , statement. range ( ) )
1173+ ) ;
1174+ }
11021175 }
1103- None => {
1104- return Err (
1105- self . error_ranged ( CodegenErrorType :: InvalidContinue , statement. range ( ) )
1106- ) ;
1176+ }
1177+ Stmt :: Continue ( _) => {
1178+ // Find the innermost loop in fblock stack
1179+ let found_loop = {
1180+ let code = self . current_code_info ( ) ;
1181+ let mut result = None ;
1182+ for i in ( 0 ..code. fblock . len ( ) ) . rev ( ) {
1183+ match code. fblock [ i] . fb_type {
1184+ FBlockType :: WhileLoop | FBlockType :: ForLoop => {
1185+ result = Some ( code. fblock [ i] . fb_block ) ;
1186+ break ;
1187+ }
1188+ _ => continue ,
1189+ }
1190+ }
1191+ result
1192+ } ;
1193+
1194+ match found_loop {
1195+ Some ( loop_block) => {
1196+ emit ! ( self , Instruction :: Continue { target: loop_block } ) ;
1197+ }
1198+ None => {
1199+ return Err (
1200+ self . error_ranged ( CodegenErrorType :: InvalidContinue , statement. range ( ) )
1201+ ) ;
1202+ }
11071203 }
1108- } ,
1204+ }
11091205 Stmt :: Return ( StmtReturn { value, .. } ) => {
11101206 if !self . ctx . in_func ( ) {
11111207 return Err (
@@ -2028,6 +2124,9 @@ impl Compiler<'_> {
20282124 emit ! ( self , Instruction :: SetupLoop ) ;
20292125 self . switch_to_block ( while_block) ;
20302126
2127+ // Push fblock for while loop
2128+ self . push_fblock ( FBlockType :: WhileLoop , while_block, after_block) ?;
2129+
20312130 self . compile_jump_if ( test, false , else_block) ?;
20322131
20332132 let was_in_loop = self . ctx . loop_data . replace ( ( while_block, after_block) ) ;
@@ -2040,6 +2139,9 @@ impl Compiler<'_> {
20402139 }
20412140 ) ;
20422141 self . switch_to_block ( else_block) ;
2142+
2143+ // Pop fblock
2144+ self . pop_fblock ( FBlockType :: WhileLoop ) ;
20432145 emit ! ( self , Instruction :: PopBlock ) ;
20442146 self . compile_statements ( orelse) ?;
20452147 self . switch_to_block ( after_block) ;
@@ -2150,6 +2252,10 @@ impl Compiler<'_> {
21502252 emit ! ( self , Instruction :: GetAIter ) ;
21512253
21522254 self . switch_to_block ( for_block) ;
2255+
2256+ // Push fblock for async for loop
2257+ self . push_fblock ( FBlockType :: ForLoop , for_block, after_block) ?;
2258+
21532259 emit ! (
21542260 self ,
21552261 Instruction :: SetupExcept {
@@ -2172,6 +2278,10 @@ impl Compiler<'_> {
21722278 emit ! ( self , Instruction :: GetIter ) ;
21732279
21742280 self . switch_to_block ( for_block) ;
2281+
2282+ // Push fblock for for loop
2283+ self . push_fblock ( FBlockType :: ForLoop , for_block, after_block) ?;
2284+
21752285 emit ! ( self , Instruction :: ForIter { target: else_block } ) ;
21762286
21772287 // Start of loop iteration, set targets:
@@ -2184,6 +2294,10 @@ impl Compiler<'_> {
21842294 emit ! ( self , Instruction :: Jump { target: for_block } ) ;
21852295
21862296 self . switch_to_block ( else_block) ;
2297+
2298+ // Pop fblock
2299+ self . pop_fblock ( FBlockType :: ForLoop ) ;
2300+
21872301 if is_async {
21882302 emit ! ( self , Instruction :: EndAsyncFor ) ;
21892303 }
@@ -4162,6 +4276,9 @@ impl Compiler<'_> {
41624276 // Create magnificent function <listcomp>:
41634277 self . push_output ( flags, 1 , 1 , 0 , name. to_owned ( ) ) ;
41644278
4279+ // Mark that we're in an inlined comprehension
4280+ self . current_code_info ( ) . in_inlined_comp = true ;
4281+
41654282 // Set qualname for comprehension
41664283 self . set_qualname ( ) ;
41674284
0 commit comments