@@ -14,6 +14,33 @@ use crate::{
14
14
symboltable:: { self , SymbolFlags , SymbolScope , SymbolTable , SymbolTableType } ,
15
15
unparse:: unparse_expr,
16
16
} ;
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
+ }
17
44
use itertools:: Itertools ;
18
45
use malachite_bigint:: BigInt ;
19
46
use num_complex:: Complex ;
@@ -323,6 +350,7 @@ impl<'src> Compiler<'src> {
323
350
} ,
324
351
static_attributes : None ,
325
352
in_inlined_comp : false ,
353
+ fblock : Vec :: with_capacity ( MAXBLOCKS ) ,
326
354
} ;
327
355
Compiler {
328
356
code_stack : vec ! [ module_code] ,
@@ -442,6 +470,7 @@ impl Compiler<'_> {
442
470
None
443
471
} ,
444
472
in_inlined_comp : false ,
473
+ fblock : Vec :: with_capacity ( MAXBLOCKS ) ,
445
474
} ;
446
475
self . code_stack . push ( info) ;
447
476
}
@@ -454,6 +483,37 @@ impl Compiler<'_> {
454
483
unwrap_internal ( self , stack_top. finalize_code ( self . opts . optimize ) )
455
484
}
456
485
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
+
457
517
// could take impl Into<Cow<str>>, but everything is borrowed from ast structs; we never
458
518
// actually have a `String` to pass
459
519
fn name ( & mut self , name : & str ) -> bytecode:: NameIdx {
@@ -1086,26 +1146,62 @@ impl Compiler<'_> {
1086
1146
self . switch_to_block ( after_block) ;
1087
1147
}
1088
1148
}
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
+ }
1102
1175
}
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
+ }
1107
1203
}
1108
- } ,
1204
+ }
1109
1205
Stmt :: Return ( StmtReturn { value, .. } ) => {
1110
1206
if !self . ctx . in_func ( ) {
1111
1207
return Err (
@@ -2028,6 +2124,9 @@ impl Compiler<'_> {
2028
2124
emit ! ( self , Instruction :: SetupLoop ) ;
2029
2125
self . switch_to_block ( while_block) ;
2030
2126
2127
+ // Push fblock for while loop
2128
+ self . push_fblock ( FBlockType :: WhileLoop , while_block, after_block) ?;
2129
+
2031
2130
self . compile_jump_if ( test, false , else_block) ?;
2032
2131
2033
2132
let was_in_loop = self . ctx . loop_data . replace ( ( while_block, after_block) ) ;
@@ -2040,6 +2139,9 @@ impl Compiler<'_> {
2040
2139
}
2041
2140
) ;
2042
2141
self . switch_to_block ( else_block) ;
2142
+
2143
+ // Pop fblock
2144
+ self . pop_fblock ( FBlockType :: WhileLoop ) ;
2043
2145
emit ! ( self , Instruction :: PopBlock ) ;
2044
2146
self . compile_statements ( orelse) ?;
2045
2147
self . switch_to_block ( after_block) ;
@@ -2150,6 +2252,10 @@ impl Compiler<'_> {
2150
2252
emit ! ( self , Instruction :: GetAIter ) ;
2151
2253
2152
2254
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
+
2153
2259
emit ! (
2154
2260
self ,
2155
2261
Instruction :: SetupExcept {
@@ -2172,6 +2278,10 @@ impl Compiler<'_> {
2172
2278
emit ! ( self , Instruction :: GetIter ) ;
2173
2279
2174
2280
self . switch_to_block ( for_block) ;
2281
+
2282
+ // Push fblock for for loop
2283
+ self . push_fblock ( FBlockType :: ForLoop , for_block, after_block) ?;
2284
+
2175
2285
emit ! ( self , Instruction :: ForIter { target: else_block } ) ;
2176
2286
2177
2287
// Start of loop iteration, set targets:
@@ -2184,6 +2294,10 @@ impl Compiler<'_> {
2184
2294
emit ! ( self , Instruction :: Jump { target: for_block } ) ;
2185
2295
2186
2296
self . switch_to_block ( else_block) ;
2297
+
2298
+ // Pop fblock
2299
+ self . pop_fblock ( FBlockType :: ForLoop ) ;
2300
+
2187
2301
if is_async {
2188
2302
emit ! ( self , Instruction :: EndAsyncFor ) ;
2189
2303
}
@@ -4162,6 +4276,9 @@ impl Compiler<'_> {
4162
4276
// Create magnificent function <listcomp>:
4163
4277
self . push_output ( flags, 1 , 1 , 0 , name. to_owned ( ) ) ;
4164
4278
4279
+ // Mark that we're in an inlined comprehension
4280
+ self . current_code_info ( ) . in_inlined_comp = true ;
4281
+
4165
4282
// Set qualname for comprehension
4166
4283
self . set_qualname ( ) ;
4167
4284
0 commit comments