Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,70 +1,4 @@
use emmylua_parser::{BinaryOperator, LuaAst, LuaBinaryExpr, LuaExpr, UnaryOperator};

use crate::{
FlowId,
compilation::analyzer::flow::{
bind_analyze::{bind_each_child, exprs::bind_condition_expr, finish_flow_label},
binder::FlowBinder,
},
};

pub fn bind_binary_expr(
binder: &mut FlowBinder,
binary_expr: LuaBinaryExpr,
current: FlowId,
) -> Option<()> {
let op_token = binary_expr.get_op_token()?;

match op_token.get_op() {
BinaryOperator::OpAnd => bind_and_expr(binder, binary_expr, current),
BinaryOperator::OpOr => bind_or_expr(binder, binary_expr, current),
BinaryOperator::OpNilCoalescing => bind_or_expr(binder, binary_expr, current),
_ => {
bind_each_child(binder, LuaAst::LuaBinaryExpr(binary_expr.clone()), current);
Some(())
}
}
}

fn bind_and_expr(
binder: &mut FlowBinder,
binary_expr: LuaBinaryExpr,
current: FlowId,
) -> Option<()> {
let (left, right) = binary_expr.get_exprs()?;

let pre_right = binder.create_branch_label();
bind_condition_expr(binder, left, current, pre_right, binder.false_target);
let current = finish_flow_label(binder, pre_right, current);
bind_condition_expr(
binder,
right,
current,
binder.true_target,
binder.false_target,
);

Some(())
}

fn bind_or_expr(
binder: &mut FlowBinder,
binary_expr: LuaBinaryExpr,
current: FlowId,
) -> Option<()> {
let (left, right) = binary_expr.get_exprs()?;
let pre_right = binder.create_branch_label();
bind_condition_expr(binder, left, current, binder.true_target, pre_right);
let current = finish_flow_label(binder, pre_right, current);
bind_condition_expr(
binder,
right,
current,
binder.true_target,
binder.false_target,
);
Some(())
}
use emmylua_parser::{BinaryOperator, LuaExpr, UnaryOperator};

pub fn is_binary_logical(expr: &LuaExpr) -> bool {
match expr {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,212 +1,12 @@
mod bind_binary_expr;

use emmylua_parser::{
LuaAst, LuaAstNode, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaIndexExpr, LuaNameExpr,
LuaTableExpr, LuaTernaryExpr, LuaUnaryExpr, UnaryOperator,
};
use emmylua_parser::LuaExpr;

use crate::{
FlowId, FlowNodeKind,
compilation::analyzer::flow::{
bind_analyze::{
bind_each_child, exprs::bind_binary_expr::is_binary_logical, finish_flow_label,
},
binder::FlowBinder,
},
};
pub use bind_binary_expr::bind_binary_expr;
use crate::{FlowId, compilation::analyzer::flow::binder::FlowBinder};

pub fn bind_condition_expr(
binder: &mut FlowBinder,
condition_expr: LuaExpr,
current: FlowId,
true_target: FlowId,
false_target: FlowId,
) {
let old_true_target = binder.true_target;
let old_false_target = binder.false_target;

binder.true_target = true_target;
binder.false_target = false_target;
bind_expr(binder, condition_expr.clone(), current);
binder.true_target = old_true_target;
binder.false_target = old_false_target;

if !is_binary_logical(&condition_expr) {
let true_condition =
binder.create_node(FlowNodeKind::TrueCondition(condition_expr.to_ptr()));
binder.add_antecedent(true_condition, current);
binder.add_antecedent(true_target, true_condition);

let false_condition =
binder.create_node(FlowNodeKind::FalseCondition(condition_expr.to_ptr()));
binder.add_antecedent(false_condition, current);
binder.add_antecedent(false_target, false_condition);
}
}
pub use bind_binary_expr::is_binary_logical;

/// Bind an expression (explicit task stack engine; the result always equals the input current)
pub fn bind_expr(binder: &mut FlowBinder, expr: LuaExpr, current: FlowId) -> FlowId {
match expr {
LuaExpr::NameExpr(name_expr) => bind_name_expr(binder, name_expr, current),
LuaExpr::CallExpr(call_expr) => bind_call_expr(binder, call_expr, current),
LuaExpr::TableExpr(table_expr) => bind_table_expr(binder, table_expr, current),
LuaExpr::LiteralExpr(_) => Some(()), // Literal expressions do not need binding
LuaExpr::ClosureExpr(closure_expr) => bind_closure_expr(binder, closure_expr, current),
LuaExpr::ParenExpr(paren_expr) => bind_paren_expr(binder, paren_expr, current),
LuaExpr::IndexExpr(index_expr) => bind_index_expr(binder, index_expr, current),
LuaExpr::BinaryExpr(binary_expr) => bind_binary_expr(binder, binary_expr, current),
LuaExpr::UnaryExpr(unary_expr) => bind_unary_expr(binder, unary_expr, current),
LuaExpr::TernaryExpr(ternary_expr) => bind_ternary_expr(binder, ternary_expr, current),
};

current
}

pub fn bind_name_expr(
binder: &mut FlowBinder,
name_expr: LuaNameExpr,
current: FlowId,
) -> Option<()> {
binder.bind_syntax_node(name_expr.get_syntax_id(), current);
Some(())
}

pub fn bind_table_expr(
binder: &mut FlowBinder,
table_expr: LuaTableExpr,
current: FlowId,
) -> Option<()> {
bind_each_child(binder, LuaAst::LuaTableExpr(table_expr), current);
Some(())
}

pub fn bind_closure_expr(
binder: &mut FlowBinder,
closure_expr: LuaClosureExpr,
current: FlowId,
) -> Option<()> {
bind_each_child(binder, LuaAst::LuaClosureExpr(closure_expr), current);
Some(())
}

pub fn bind_index_expr(
binder: &mut FlowBinder,
index_expr: LuaIndexExpr,
current: FlowId,
) -> Option<()> {
binder.bind_syntax_node(index_expr.get_syntax_id(), current);
if index_expr.is_safe_index() {
return bind_safe_index_expr(binder, index_expr, current);
}
bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr.clone()), current);
Some(())
}

fn bind_safe_index_expr(
binder: &mut FlowBinder,
index_expr: LuaIndexExpr,
current: FlowId,
) -> Option<()> {
let prefix_expr = index_expr.get_prefix_expr()?;

let pre_access = binder.create_branch_label();
bind_condition_expr(
binder,
prefix_expr,
current,
pre_access,
binder.false_target,
);
let current = finish_flow_label(binder, pre_access, current);

bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr), current);
Some(())
}

pub fn bind_paren_expr(
binder: &mut FlowBinder,
paren_expr: emmylua_parser::LuaParenExpr,
current: FlowId,
) -> Option<()> {
let inner_expr = paren_expr.get_expr()?;

bind_expr(binder, inner_expr, current);
Some(())
}

pub fn bind_unary_expr(
binder: &mut FlowBinder,
unary_expr: LuaUnaryExpr,
current: FlowId,
) -> Option<()> {
let inner_expr = unary_expr.get_expr()?;

if unary_expr
.get_op_token()
.is_some_and(|op| op.get_op() == UnaryOperator::OpNot)
{
let old_true_target = binder.true_target;
let old_false_target = binder.false_target;

// not 会反转条件出口, 内层 and/or 的短路分支也要落到反转后的路径.
binder.true_target = old_false_target;
binder.false_target = old_true_target;
bind_expr(binder, inner_expr, current);
binder.true_target = old_true_target;
binder.false_target = old_false_target;

return Some(());
}

bind_expr(binder, inner_expr, current);
Some(())
}

pub fn bind_call_expr(
binder: &mut FlowBinder,
call_expr: LuaCallExpr,
current: FlowId,
) -> Option<()> {
bind_each_child(binder, LuaAst::LuaCallExpr(call_expr.clone()), current);
Some(())
}

fn bind_ternary_expr(
binder: &mut FlowBinder,
ternary_expr: LuaTernaryExpr,
current: FlowId,
) -> Option<()> {
let condition = ternary_expr.get_condition_expr()?;
let (true_expr, false_expr) = ternary_expr.get_true_false_exprs()?;

let true_branch_label = binder.create_branch_label();
let false_branch_label = binder.create_branch_label();

bind_condition_expr(
binder,
condition,
current,
true_branch_label,
false_branch_label,
);

let true_branch_start = finish_flow_label(binder, true_branch_label, binder.unreachable);
bind_condition_expr(
binder,
true_expr,
true_branch_start,
binder.true_target,
binder.false_target,
);

let false_branch_start = finish_flow_label(binder, false_branch_label, binder.unreachable);
bind_condition_expr(
binder,
false_expr,
false_branch_start,
binder.true_target,
binder.false_target,
);

Some(())
super::engine::run_bind_expr(binder, expr, current)
}
Loading
Loading