Skip to content

Commit e9ca3b7

Browse files
committed
update
1 parent 28d2123 commit e9ca3b7

6 files changed

Lines changed: 363 additions & 81 deletions

File tree

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/exprs/bind_call_expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use emmylua_parser::{LuaAst, LuaCallExpr};
22

3-
use crate::compilation::analyzer::flow::{bind_analyze::bind_each_child, binder::FlowBinder, flow_node::{FlowId, FlowNodeType}};
3+
use crate::compilation::analyzer::flow::{bind_analyze::bind_each_child, binder::FlowBinder, flow_node::{FlowId, FlowNodeKind}};
44

55

66
pub fn bind_call_expr(binder: &mut FlowBinder, call_expr: LuaCallExpr) -> Option<FlowId> {

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/exprs/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
compilation::analyzer::flow::{
77
bind_analyze::{bind_each_child, exprs::bind_call_expr::bind_call_expr},
88
binder::FlowBinder,
9-
flow_node::{FlowId, FlowNodeType, LuaFlowCondition},
9+
flow_node::{FlowId, FlowNodeKind, FlowCondition},
1010
},
1111
LuaVarRefId,
1212
};
@@ -40,8 +40,8 @@ fn bind_name_expr(binder: &mut FlowBinder, name_expr: LuaNameExpr) -> Option<Flo
4040
None => LuaVarRefId::Name(name_text.into()),
4141
};
4242

43-
let flow_id = binder.create_node(FlowNodeType::Condition(
44-
LuaFlowCondition::Exist(var_ref_id).into(),
43+
let flow_id = binder.create_node(FlowNodeKind::Condition(
44+
FlowCondition::Truthy(var_ref_id).into(),
4545
));
4646

4747
Some(flow_id)

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod stats;
55
use emmylua_parser::{LuaAst, LuaAstNode, LuaBlock, LuaChunk};
66

77
use crate::compilation::analyzer::flow::{
8-
bind_analyze::{comment::bind_comment, stats::{bind_assign_stat, bind_call_expr_stat, bind_local_stat}},
8+
bind_analyze::{comment::bind_comment, stats::{bind_assign_stat, bind_call_expr_stat, bind_do_stat, bind_goto_stat, bind_if_stat, bind_label_stat, bind_local_stat, bind_repeat_stat, bind_while_stat}},
99
binder::FlowBinder,
1010
};
1111

@@ -33,13 +33,13 @@ fn bind_node(binder: &mut FlowBinder, node: LuaAst) -> Option<()> {
3333
LuaAst::LuaAssignStat(assign_stat) => bind_assign_stat(binder, assign_stat),
3434
LuaAst::LuaLocalStat(local_stat) => bind_local_stat(binder, local_stat),
3535
LuaAst::LuaCallExprStat(call_expr_stat) => bind_call_expr_stat(binder, call_expr_stat),
36-
LuaAst::LuaLabelStat(_) => Some(()),
36+
LuaAst::LuaLabelStat(label_stat) => bind_label_stat(binder, label_stat),
3737
LuaAst::LuaBreakStat(break_stat) => todo!(),
38-
LuaAst::LuaGotoStat(goto_stat) => todo!(),
39-
LuaAst::LuaDoStat(do_stat) => todo!(),
40-
LuaAst::LuaWhileStat(while_stat) => todo!(),
41-
LuaAst::LuaRepeatStat(repeat_stat) => todo!(),
42-
LuaAst::LuaIfStat(if_stat) => todo!(),
38+
LuaAst::LuaGotoStat(goto_stat) => bind_goto_stat(binder, goto_stat),
39+
LuaAst::LuaDoStat(do_stat) => bind_do_stat(binder, do_stat),
40+
LuaAst::LuaWhileStat(while_stat) => bind_while_stat(binder, while_stat),
41+
LuaAst::LuaRepeatStat(repeat_stat) => bind_repeat_stat(binder, repeat_stat),
42+
LuaAst::LuaIfStat(if_stat) => bind_if_stat(binder, if_stat),
4343
LuaAst::LuaForStat(for_stat) => todo!(),
4444
LuaAst::LuaForRangeStat(for_range_stat) => todo!(),
4545
LuaAst::LuaFuncStat(func_stat) => todo!(),

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/stats.rs

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use emmylua_parser::{
2-
LuaAssignStat, LuaAst, LuaAstNode, LuaCallExprStat, LuaLabelStat, LuaLocalStat, LuaVarExpr, PathTrait
2+
LuaAssignStat, LuaAst, LuaAstNode, LuaBreakStat, LuaCallExprStat, LuaDoStat, LuaGotoStat, LuaIfStat, LuaLabelStat, LuaLocalStat, LuaRepeatStat, LuaVarExpr, LuaWhileStat, PathTrait
33
};
44

55
use crate::{
66
compilation::analyzer::flow::{
7-
bind_analyze::{bind_each_child, exprs::bind_condition_expr},
7+
bind_analyze::{bind_block, bind_each_child, exprs::{bind_condition_expr, bind_expr}},
88
binder::FlowBinder,
9-
flow_node::{FlowNodeType, LuaFlowAssignment},
9+
flow_node::{FlowAssignment, FlowNodeKind},
1010
},
11-
LuaDeclId, LuaVarRefId,
11+
LuaClosureId, LuaDeclId, LuaVarRefId,
1212
};
1313

1414
pub fn bind_local_stat(binder: &mut FlowBinder, local_stat: LuaLocalStat) -> Option<()> {
@@ -53,16 +53,14 @@ pub fn bind_assign_stat(binder: &mut FlowBinder, assign_stat: LuaAssignStat) ->
5353

5454
if let Some(var_ref_id) = get_var_ref_id(binder, var.clone()) {
5555
// Create a flow node for the assignment
56-
let flow_id = binder.create_node(
57-
FlowNodeType::Assignment(
58-
LuaFlowAssignment {
59-
var_ref_id,
60-
expr,
61-
idx: idx as u32,
62-
}
63-
.into(),
64-
),
65-
);
56+
let flow_id = binder.create_node(FlowNodeKind::Assignment(
57+
FlowAssignment {
58+
var_ref_id,
59+
expr,
60+
idx: idx as u32,
61+
}
62+
.into(),
63+
));
6664

6765
binder.add_antecedent(flow_id, binder.current);
6866
binder.current = flow_id;
@@ -114,8 +112,157 @@ pub fn bind_call_expr_stat(binder: &mut FlowBinder, call_expr_stat: LuaCallExprS
114112
pub fn bind_label_stat(binder: &mut FlowBinder, label_stat: LuaLabelStat) -> Option<()> {
115113
let label_name_token = label_stat.get_label_name_token()?;
116114
let label_name = label_name_token.get_name_text();
117-
115+
let closure_id = LuaClosureId::from_node(label_stat.syntax());
116+
let name_label = binder.create_name_label(label_name, closure_id);
117+
binder.add_antecedent(name_label, binder.current);
118+
binder.current = name_label;
119+
120+
Some(())
121+
}
122+
123+
pub fn bind_break_stat(binder: &mut FlowBinder, break_stat: LuaBreakStat) -> Option<()> {
124+
// let
125+
// binder.add_antecedent(loop_label, current);
126+
// binder.current = loop_label;
127+
128+
Some(())
129+
}
130+
131+
pub fn bind_goto_stat(binder: &mut FlowBinder, goto_stat: LuaGotoStat) -> Option<()> {
132+
// Goto statements are handled separately in the flow analysis
133+
// They will be processed when we analyze the labels
134+
// For now, we just return None to indicate no flow node is created
135+
let closure_id = LuaClosureId::from_node(goto_stat.syntax());
136+
binder.add_goto_stat(goto_stat, closure_id);
137+
138+
Some(())
139+
}
140+
141+
pub fn bind_do_stat(binder: &mut FlowBinder, do_stat: LuaDoStat) -> Option<()> {
142+
// Do statements are typically used for blocks of code
143+
// We can treat them as a block and bind their contents
144+
bind_each_child(binder, LuaAst::cast(do_stat.syntax().clone())?);
145+
146+
Some(())
147+
}
148+
149+
pub fn bind_while_stat(binder: &mut FlowBinder, while_stat: LuaWhileStat) -> Option<()> {
150+
// While statements are typically used for loops
151+
// We can treat them as a loop and bind their contents
152+
// For now, we just return None to indicate no flow node is created
153+
let current = binder.current;
154+
let old_loop_label = binder.loop_label;
155+
let loop_label = binder.create_loop_label();
156+
binder.add_antecedent(loop_label, current);
157+
158+
binder.loop_label = loop_label;
159+
binder.current = loop_label;
160+
let condition_expr = while_stat.get_condition_expr()?;
161+
if let Some(condition_flow_id) = bind_condition_expr(binder, condition_expr) {
162+
binder.add_antecedent(condition_flow_id, loop_label);
163+
binder.current = condition_flow_id;
164+
binder.loop_label = loop_label;
165+
} else {
166+
binder.current = loop_label;
167+
binder.loop_label = current;
168+
}
118169

170+
if let Some(while_block) = while_stat.get_block() {
171+
bind_block(binder, while_block);
172+
}
173+
174+
binder.current = current;
175+
binder.loop_label = old_loop_label;
119176

177+
Some(())
178+
}
179+
180+
181+
pub fn bind_repeat_stat(binder: &mut FlowBinder, repeat_stat: LuaRepeatStat) -> Option<()> {
182+
let current = binder.current;
183+
let old_loop_label = binder.loop_label;
184+
185+
// Create a loop label for the repeat statement
186+
let loop_label = binder.create_loop_label();
187+
binder.add_antecedent(loop_label, current);
188+
189+
binder.loop_label = loop_label;
190+
binder.current = loop_label;
191+
192+
// Bind the block first (repeat-until executes the block at least once)
193+
if let Some(repeat_block) = repeat_stat.get_block() {
194+
bind_block(binder, repeat_block);
195+
}
196+
197+
let current = binder.current;
198+
bind_expr(binder, repeat_stat.get_condition_expr()?);
199+
200+
// Restore previous state
201+
binder.current = current;
202+
binder.loop_label = old_loop_label;
203+
204+
Some(())
205+
}
206+
207+
pub fn bind_if_stat(binder: &mut FlowBinder, if_stat: LuaIfStat) -> Option<()> {
208+
// let current = binder.current;
209+
// let mut branch_endings = Vec::new();
210+
211+
// // Process the main if condition
212+
// let condition = if_stat.get_condition_expr()?;
213+
// if let Some(condition_flow_id) = bind_condition_expr(binder, condition) {
214+
// binder.add_antecedent(condition_flow_id, current);
215+
// binder.current = condition_flow_id;
216+
// } else {
217+
// binder.current = current;
218+
// }
219+
220+
// // Process the if block (true branch)
221+
// if let Some(if_block) = if_stat.get_block() {
222+
// bind_block(binder, if_block);
223+
// branch_endings.push(binder.current);
224+
// }
225+
226+
// // Process elseif clauses
227+
// for elseif_clause in if_stat.get_else_if_clause_list() {
228+
// binder.current = current; // Reset to the beginning for each elseif
229+
230+
// if let Some(elseif_condition) = elseif_clause.get_condition_expr() {
231+
// if let Some(condition_flow_id) = bind_condition_expr(binder, elseif_condition) {
232+
// binder.add_antecedent(condition_flow_id, current);
233+
// binder.current = condition_flow_id;
234+
// }
235+
// }
236+
237+
// if let Some(elseif_block) = elseif_clause.get_block() {
238+
// bind_block(binder, elseif_block);
239+
// branch_endings.push(binder.current);
240+
// }
241+
// }
242+
243+
// // Process else clause if it exists
244+
// if let Some(else_clause) = if_stat.get_else_clause() {
245+
// binder.current = current; // Reset to the beginning for else
246+
247+
// if let Some(else_block) = else_clause.get_block() {
248+
// bind_block(binder, else_block);
249+
// branch_endings.push(binder.current);
250+
// }
251+
// } else {
252+
// // If there's no else clause, the original flow continues
253+
// branch_endings.push(current);
254+
// }
255+
256+
// // Create a branch label to merge all branches
257+
// if !branch_endings.is_empty() {
258+
// let branch_label = binder.create_branch_label();
259+
// for ending in branch_endings {
260+
// binder.add_antecedent(branch_label, ending);
261+
// }
262+
// binder.current = branch_label;
263+
// } else {
264+
// binder.current = current;
265+
// }
266+
120267
Some(())
121268
}

crates/emmylua_code_analysis/src/compilation/analyzer/flow/binder.rs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
use std::collections::HashMap;
22

3+
use emmylua_parser::{LuaGotoStat, LuaSyntaxId};
34
use internment::ArcIntern;
45
use smol_str::SmolStr;
56

67
use crate::{
7-
compilation::analyzer::flow::flow_node::{FlowAntecedent, FlowId, FlowNode, FlowNodeType},
8-
DbIndex, FileId, LuaDeclId, LuaClosureId,
8+
compilation::analyzer::flow::flow_node::{FlowAntecedent, FlowId, FlowNode, FlowNodeKind},
9+
DbIndex, FileId, LuaClosureId, LuaDeclId,
910
};
1011

1112
#[derive(Debug)]
1213
pub struct FlowBinder<'a> {
1314
pub db: &'a DbIndex,
1415
pub file_id: FileId,
15-
flow_nodes: Vec<FlowNode>,
16-
multiple_antecedents: Vec<Vec<FlowId>>,
17-
labels: HashMap<LuaClosureId, HashMap<SmolStr, FlowId>>,
1816
pub decl_bind_flow_ref: HashMap<LuaDeclId, FlowId>,
19-
pub none_label: FlowId,
2017
pub start: FlowId,
2118
pub unreachable: FlowId,
2219
pub loop_label: FlowId,
2320
pub current: FlowId,
21+
flow_nodes: Vec<FlowNode>,
22+
multiple_antecedents: Vec<Vec<FlowId>>,
23+
labels: HashMap<LuaClosureId, HashMap<SmolStr, FlowId>>,
24+
goto_stats: Vec<(LuaGotoStat, LuaClosureId)>,
25+
bindings: HashMap<LuaSyntaxId, FlowId>,
2426
}
2527

2628
impl<'a> FlowBinder<'a> {
@@ -33,22 +35,22 @@ impl<'a> FlowBinder<'a> {
3335
decl_bind_flow_ref: HashMap::new(),
3436
labels: HashMap::new(),
3537
start: FlowId::default(),
36-
none_label: FlowId::default(),
3738
unreachable: FlowId::default(),
3839
loop_label: FlowId::default(),
3940
current: FlowId::default(),
41+
bindings: HashMap::new(),
42+
goto_stats: Vec::new(),
4043
};
4144

42-
binder.none_label = binder.create_node(FlowNodeType::None);
4345
binder.start = binder.create_start();
4446
binder.unreachable = binder.create_unreachable();
45-
binder.loop_label = binder.none_label;
47+
binder.loop_label = binder.unreachable;
4648
binder.current = binder.start;
4749

4850
binder
4951
}
5052

51-
pub fn create_node(&mut self, kind: FlowNodeType) -> FlowId {
53+
pub fn create_node(&mut self, kind: FlowNodeKind) -> FlowId {
5254
let id = FlowId(self.flow_nodes.len() as u32);
5355
let flow_node = FlowNode {
5456
id,
@@ -58,31 +60,39 @@ impl<'a> FlowBinder<'a> {
5860
self.flow_nodes.push(flow_node);
5961
id
6062
}
61-
63+
6264
pub fn create_branch_label(&mut self) -> FlowId {
63-
self.create_node(FlowNodeType::BranchLabel)
65+
self.create_node(FlowNodeKind::BranchLabel)
6466
}
6567

6668
pub fn create_loop_label(&mut self) -> FlowId {
67-
self.create_node(FlowNodeType::LoopLabel)
69+
self.create_node(FlowNodeKind::LoopLabel)
6870
}
6971

70-
pub fn create_name_label(&mut self, name: String) -> FlowId {
71-
self.create_node(FlowNodeType::NameLabel(ArcIntern::from(SmolStr::new(name))))
72+
pub fn create_name_label(&mut self, name: &str, closure_id: LuaClosureId) -> FlowId {
73+
let label_id = self.create_node(FlowNodeKind::NamedLabel(ArcIntern::from(SmolStr::new(
74+
name,
75+
))));
76+
self.labels
77+
.entry(closure_id)
78+
.or_default()
79+
.insert(SmolStr::new(name), label_id);
80+
81+
label_id
7282
}
7383

7484
pub fn create_start(&mut self) -> FlowId {
75-
self.create_node(FlowNodeType::Start)
85+
self.create_node(FlowNodeKind::Start)
7686
}
7787

7888
pub fn create_unreachable(&mut self) -> FlowId {
79-
self.create_node(FlowNodeType::Unreachable)
89+
self.create_node(FlowNodeKind::Unreachable)
8090
}
8191

8292
pub fn add_antecedent(&mut self, node_id: FlowId, antecedent: FlowId) {
8393
if let Some(existing) = self.flow_nodes.get_mut(node_id.0 as usize) {
8494
match existing.antecedent {
85-
Some(FlowAntecedent::Node(existing_id)) => {
95+
Some(FlowAntecedent::Single(existing_id)) => {
8696
// If the existing antecedent is a single node, convert it to multiple
8797
if existing_id == antecedent {
8898
return; // No change needed if it's the same antecedent
@@ -103,9 +113,17 @@ impl<'a> FlowBinder<'a> {
103113
}
104114
_ => {
105115
// Set new antecedent
106-
existing.antecedent = Some(FlowAntecedent::Node(antecedent));
116+
existing.antecedent = Some(FlowAntecedent::Single(antecedent));
107117
}
108118
};
109119
}
110120
}
121+
122+
pub fn bind_syntax_node(&mut self, syntax_id: LuaSyntaxId, flow_id: FlowId) {
123+
self.bindings.insert(syntax_id, flow_id);
124+
}
125+
126+
pub fn add_goto_stat(&mut self, goto_stat: LuaGotoStat, closure_id: LuaClosureId) {
127+
self.goto_stats.push((goto_stat, closure_id));
128+
}
111129
}

0 commit comments

Comments
 (0)