1
1
use emmylua_parser:: {
2
- LuaAssignStat , LuaAst , LuaAstNode , LuaBreakStat , LuaCallExprStat , LuaDoStat , LuaForRangeStat ,
3
- LuaFuncStat , LuaGotoStat , LuaIfStat , LuaLabelStat , LuaLocalStat , LuaRepeatStat , LuaReturnStat ,
4
- LuaVarExpr , LuaWhileStat , PathTrait ,
2
+ LuaAssignStat , LuaAst , LuaAstNode , LuaBreakStat , LuaCallExprStat , LuaDoStat , LuaExpr , LuaForRangeStat , LuaForStat , LuaFuncStat , LuaGotoStat , LuaIfStat , LuaLabelStat , LuaLocalStat , LuaRepeatStat , LuaReturnStat , LuaUnaryExpr , LuaVarExpr , LuaWhileStat , PathTrait , UnaryOperator
5
3
} ;
6
4
7
5
use crate :: {
8
6
compilation:: analyzer:: flow:: {
9
7
bind_analyze:: { bind_block, bind_each_child, exprs:: bind_expr} ,
10
8
binder:: FlowBinder ,
11
- flow_node:: { FlowAssignment , FlowId , FlowNodeKind } ,
9
+ flow_node:: { FlowAssertion , FlowAssignment , FlowId , FlowNodeKind } ,
12
10
} ,
13
11
LuaClosureId , LuaDeclId , LuaVarRefId ,
14
12
} ;
@@ -331,16 +329,75 @@ pub fn bind_for_range_stat(
331
329
for_range_stat : LuaForRangeStat ,
332
330
current : FlowId ,
333
331
) -> FlowId {
334
- bind_each_child ( binder, LuaAst :: LuaForRangeStat ( for_range_stat) , current) ;
332
+ let loop_label = binder. create_loop_label ( ) ;
333
+ binder. add_antecedent ( loop_label, current) ;
334
+ let old_loop_label = binder. loop_label ;
335
+ binder. loop_label = loop_label;
336
+ bind_each_child ( binder, LuaAst :: LuaForRangeStat ( for_range_stat) , loop_label) ;
337
+ binder. loop_label = old_loop_label;
335
338
current
336
339
}
337
340
338
- pub fn bind_for_stat (
339
- binder : & mut FlowBinder ,
340
- _for_stat : emmylua_parser:: LuaForStat ,
341
- current : FlowId ,
342
- ) -> FlowId {
343
- // For loops are not yet implemented
344
- // For now, we just return the current flow
341
+ pub fn bind_for_stat ( binder : & mut FlowBinder , for_stat : LuaForStat , current : FlowId ) -> FlowId {
342
+ let loop_label = binder. create_loop_label ( ) ;
343
+ binder. add_antecedent ( loop_label, current) ;
344
+ let old_loop_label = binder. loop_label ;
345
+ binder. loop_label = loop_label;
346
+
347
+ let Some ( var_name_token) = for_stat. get_var_name ( ) else {
348
+ binder. loop_label = old_loop_label;
349
+ return current;
350
+ } ;
351
+
352
+ let var_name = var_name_token. get_name_text ( ) ;
353
+ let var_list = for_stat. get_iter_expr ( ) . collect :: < Vec < _ > > ( ) ;
354
+ for expr in & var_list {
355
+ bind_expr ( binder, expr. clone ( ) , loop_label) ;
356
+ }
357
+
358
+ if var_list. len ( ) < 2 {
359
+ binder. loop_label = old_loop_label;
360
+ return current;
361
+ }
362
+
363
+ let mut parent_flow_id = loop_label;
364
+ let second_expr = var_list[ 1 ] . clone ( ) ;
365
+ if let LuaExpr :: UnaryExpr ( unary_expr) = second_expr {
366
+ if let Some ( length_var_name) = get_for_length_name ( unary_expr) {
367
+ let var_ref_id = LuaVarRefId :: Name ( format ! ( "{}.[{}]" , length_var_name, var_name) . into ( ) ) ;
368
+ let flow_id = binder. create_node ( FlowNodeKind :: Assertion (
369
+ FlowAssertion :: Truthy ( var_ref_id) . into ( ) ,
370
+ ) ) ;
371
+ binder. add_antecedent ( flow_id, loop_label) ;
372
+ parent_flow_id = flow_id;
373
+ }
374
+ }
375
+
376
+ if let Some ( block) = for_stat. get_block ( ) {
377
+ bind_block ( binder, block, parent_flow_id) ;
378
+ }
379
+
380
+ binder. loop_label = old_loop_label;
345
381
current
346
382
}
383
+
384
+ fn get_for_length_name ( unary_expr : LuaUnaryExpr ) -> Option < String > {
385
+ let op_token = unary_expr. get_op_token ( ) ?;
386
+ if op_token. get_op ( ) == UnaryOperator :: OpLen {
387
+ if let Some ( inner) = unary_expr. get_expr ( ) {
388
+ match inner {
389
+ LuaExpr :: IndexExpr ( index_expr) => {
390
+ if let Some ( access_path) = index_expr. get_access_path ( ) {
391
+ return Some ( access_path. into ( ) ) ;
392
+ }
393
+ }
394
+ LuaExpr :: NameExpr ( name_expr) => {
395
+ return Some ( name_expr. get_name_text ( ) ?) ;
396
+ }
397
+ _ => { }
398
+ }
399
+ }
400
+ }
401
+
402
+ None
403
+ }
0 commit comments