|
| 1 | +mod bind_binary_expr; |
| 2 | + |
| 3 | +use emmylua_parser::{ |
| 4 | + LuaAst, LuaAstNode, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaIndexExpr, LuaNameExpr, |
| 5 | + LuaTableExpr, LuaUnaryExpr, UnaryOperator, |
| 6 | +}; |
| 7 | + |
| 8 | +use crate::compilation::analyzer::flow::{ |
| 9 | + bind_analyze::bind_each_child, |
| 10 | + binder::FlowBinder, |
| 11 | + flow_node::{FlowId, FlowNodeKind}, |
| 12 | +}; |
| 13 | +pub use bind_binary_expr::bind_binary_expr; |
| 14 | + |
| 15 | +pub fn bind_condition_expr( |
| 16 | + binder: &mut FlowBinder, |
| 17 | + condition_expr: LuaExpr, |
| 18 | + current: FlowId, |
| 19 | + true_target: FlowId, |
| 20 | + false_target: FlowId, |
| 21 | +) { |
| 22 | + let old_true_target = binder.true_target; |
| 23 | + let old_false_target = binder.false_target; |
| 24 | + binder.true_target = true_target; |
| 25 | + binder.false_target = false_target; |
| 26 | + bind_expr(binder, condition_expr.clone(), current); |
| 27 | + binder.true_target = old_true_target; |
| 28 | + binder.false_target = old_false_target; |
| 29 | + |
| 30 | + let true_condition = binder.create_node(FlowNodeKind::TrueCondition(condition_expr.to_ptr())); |
| 31 | + binder.add_antecedent(true_condition, current); |
| 32 | + let false_condition = binder.create_node(FlowNodeKind::FalseCondition(condition_expr.to_ptr())); |
| 33 | + binder.add_antecedent(false_condition, current); |
| 34 | + |
| 35 | + binder.add_antecedent(true_condition, true_target); |
| 36 | + binder.add_antecedent(false_condition, false_target); |
| 37 | +} |
| 38 | + |
| 39 | +pub fn bind_expr(binder: &mut FlowBinder, expr: LuaExpr, current: FlowId) -> FlowId { |
| 40 | + match expr { |
| 41 | + LuaExpr::NameExpr(name_expr) => bind_name_expr(binder, name_expr, current), |
| 42 | + LuaExpr::CallExpr(call_expr) => bind_call_expr(binder, call_expr, current), |
| 43 | + LuaExpr::TableExpr(table_expr) => bind_table_expr(binder, table_expr, current), |
| 44 | + LuaExpr::LiteralExpr(_) => current, |
| 45 | + LuaExpr::ClosureExpr(closure_expr) => bind_closure_expr(binder, closure_expr, current), |
| 46 | + LuaExpr::ParenExpr(paren_expr) => bind_paren_expr(binder, paren_expr, current), |
| 47 | + LuaExpr::IndexExpr(index_expr) => bind_index_expr(binder, index_expr, current), |
| 48 | + LuaExpr::BinaryExpr(binary_expr) => bind_binary_expr(binder, binary_expr, current), |
| 49 | + LuaExpr::UnaryExpr(unary_expr) => bind_unary_expr(binder, unary_expr, current), |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +pub fn bind_name_expr(binder: &mut FlowBinder, name_expr: LuaNameExpr, current: FlowId) -> FlowId { |
| 54 | + binder.bind_syntax_node(name_expr.get_syntax_id(), current); |
| 55 | + |
| 56 | + if let Some(parent) = name_expr.get_parent::<LuaExpr>() { |
| 57 | + match parent { |
| 58 | + LuaExpr::IndexExpr(_) | LuaExpr::CallExpr(_) => { |
| 59 | + // If the name is part of an index or call expression, we don't create a true condition |
| 60 | + // node here, as it will be handled by the index or call binding. |
| 61 | + return current; |
| 62 | + } |
| 63 | + _ => {} |
| 64 | + } |
| 65 | + } |
| 66 | + let expr = LuaExpr::NameExpr(name_expr.clone()); |
| 67 | + let true_condition = binder.create_node(FlowNodeKind::TrueCondition(expr.to_ptr())); |
| 68 | + binder.add_antecedent(true_condition, current); |
| 69 | + true_condition |
| 70 | +} |
| 71 | + |
| 72 | +pub fn bind_table_expr( |
| 73 | + binder: &mut FlowBinder, |
| 74 | + table_expr: LuaTableExpr, |
| 75 | + current: FlowId, |
| 76 | +) -> FlowId { |
| 77 | + bind_each_child(binder, LuaAst::LuaTableExpr(table_expr), current); |
| 78 | + current |
| 79 | +} |
| 80 | + |
| 81 | +pub fn bind_closure_expr( |
| 82 | + binder: &mut FlowBinder, |
| 83 | + closure_expr: LuaClosureExpr, |
| 84 | + current: FlowId, |
| 85 | +) -> FlowId { |
| 86 | + bind_each_child(binder, LuaAst::LuaClosureExpr(closure_expr), current); |
| 87 | + current |
| 88 | +} |
| 89 | + |
| 90 | +pub fn bind_index_expr( |
| 91 | + binder: &mut FlowBinder, |
| 92 | + index_expr: LuaIndexExpr, |
| 93 | + current: FlowId, |
| 94 | +) -> FlowId { |
| 95 | + bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr.clone()), current); |
| 96 | + |
| 97 | + if let Some(parent) = index_expr.get_parent::<LuaExpr>() { |
| 98 | + match parent { |
| 99 | + LuaExpr::IndexExpr(_) | LuaExpr::CallExpr(_) => { |
| 100 | + // If the name is part of an index or call expression, we don't create a true condition |
| 101 | + // node here, as it will be handled by the index or call binding. |
| 102 | + return current; |
| 103 | + } |
| 104 | + _ => {} |
| 105 | + } |
| 106 | + } |
| 107 | + let expr = LuaExpr::IndexExpr(index_expr.clone()); |
| 108 | + let true_condition = binder.create_node(FlowNodeKind::TrueCondition(expr.to_ptr())); |
| 109 | + binder.add_antecedent(true_condition, current); |
| 110 | + true_condition |
| 111 | +} |
| 112 | + |
| 113 | +pub fn bind_paren_expr( |
| 114 | + binder: &mut FlowBinder, |
| 115 | + paren_expr: emmylua_parser::LuaParenExpr, |
| 116 | + current: FlowId, |
| 117 | +) -> FlowId { |
| 118 | + let Some(inner_expr) = paren_expr.get_expr() else { |
| 119 | + return current; |
| 120 | + }; |
| 121 | + |
| 122 | + bind_expr(binder, inner_expr, current) |
| 123 | +} |
| 124 | + |
| 125 | +pub fn bind_unary_expr( |
| 126 | + binder: &mut FlowBinder, |
| 127 | + unary_expr: LuaUnaryExpr, |
| 128 | + current: FlowId, |
| 129 | +) -> FlowId { |
| 130 | + let Some(inner_expr) = unary_expr.get_expr() else { |
| 131 | + return current; |
| 132 | + }; |
| 133 | + let inner_flow = bind_expr(binder, inner_expr, current); |
| 134 | + |
| 135 | + let Some(op) = unary_expr.get_op_token() else { |
| 136 | + return current; |
| 137 | + }; |
| 138 | + match op.get_op() { |
| 139 | + UnaryOperator::OpNot => { |
| 140 | + // If it's a not operator, we create a false condition node |
| 141 | + if let Some(flow_node) = binder.get_flow(inner_flow) { |
| 142 | + if flow_node.kind.is_conditional() { |
| 143 | + // If the inner flow is already a conditional, we can just negate it |
| 144 | + let Some(negated_condition) = flow_node.kind.get_negation_condition() else { |
| 145 | + return current; |
| 146 | + }; |
| 147 | + |
| 148 | + let negated_flow = binder.create_node(negated_condition); |
| 149 | + binder.add_antecedent(negated_flow, current); |
| 150 | + return negated_flow; |
| 151 | + } |
| 152 | + } |
| 153 | + } |
| 154 | + _ => {} |
| 155 | + } |
| 156 | + |
| 157 | + current |
| 158 | +} |
| 159 | + |
| 160 | +pub fn bind_call_expr(binder: &mut FlowBinder, call_expr: LuaCallExpr, current: FlowId) -> FlowId { |
| 161 | + bind_each_child(binder, LuaAst::LuaCallExpr(call_expr.clone()), current); |
| 162 | + |
| 163 | + if let Some(parent) = call_expr.get_parent::<LuaExpr>() { |
| 164 | + match parent { |
| 165 | + LuaExpr::IndexExpr(_) | LuaExpr::CallExpr(_) => { |
| 166 | + // If the name is part of an index or call expression, we don't create a true condition |
| 167 | + // node here, as it will be handled by the index or call binding. |
| 168 | + return current; |
| 169 | + } |
| 170 | + _ => {} |
| 171 | + } |
| 172 | + } |
| 173 | + let expr = LuaExpr::CallExpr(call_expr.clone()); |
| 174 | + let true_condition = binder.create_node(FlowNodeKind::TrueCondition(expr.to_ptr())); |
| 175 | + binder.add_antecedent(true_condition, current); |
| 176 | + true_condition |
| 177 | +} |
0 commit comments