Skip to content

refactor flow algorithm #523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ use emmylua_parser::{
};

use crate::{
compilation::analyzer::{
bind_type::bind_type, flow::CastAction, unresolve::UnResolveModuleRef,
},
compilation::analyzer::{bind_type::bind_type, unresolve::UnResolveModuleRef},
db_index::{
LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaMemberId, LuaOperator, LuaSemanticDeclId,
LuaSignatureId, LuaType,
},
InFiled, InferFailReason, LuaOperatorMetaMethod, LuaTypeCache, OperatorFunction,
SignatureReturnStatus, TypeAssertion, TypeOps,
InFiled, InferFailReason, LuaOperatorMetaMethod, LuaTypeCache, LuaTypeOwner, OperatorFunction,
SignatureReturnStatus, TypeOps,
};

use super::{
Expand Down Expand Up @@ -188,6 +186,13 @@ pub fn analyze_return(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturn) -> Optio
Some(())
}

enum CastAction {
Add,
Remove,
Force,
}

#[allow(unused)]
pub fn analyze_return_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturnCast) -> Option<()> {
if let Some(LuaSemanticDeclId::Signature(signature_id)) = get_owner_id(analyzer) {
let name_token = tag.get_name_token()?;
Expand All @@ -205,48 +210,48 @@ pub fn analyze_return_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturnCast)
};

if cast_op_type.is_nullable() {
match action {
CastAction::Add => {
analyzer.db.get_flow_index_mut().add_call_cast(
signature_id,
name,
TypeAssertion::Add(LuaType::Nil),
);
}
CastAction::Remove => {
analyzer.db.get_flow_index_mut().add_call_cast(
signature_id,
name,
TypeAssertion::Remove(LuaType::Nil),
);
}
_ => {}
}
} else if let Some(doc_type) = cast_op_type.get_type() {
let typ = infer_type(analyzer, doc_type.clone());
match action {
CastAction::Add => {
analyzer.db.get_flow_index_mut().add_call_cast(
signature_id,
name,
TypeAssertion::Add(typ),
);
}
CastAction::Remove => {
analyzer.db.get_flow_index_mut().add_call_cast(
signature_id,
name,
TypeAssertion::Remove(typ),
);
}
CastAction::Force => {
analyzer.db.get_flow_index_mut().add_call_cast(
signature_id,
name,
TypeAssertion::Force(typ),
);
}
}
// match action {
// CastAction::Add => {
// analyzer.db.get_flow_index_mut().add_call_cast(
// signature_id,
// name,
// TypeAssertion::Add(LuaType::Nil),
// );
// }
// CastAction::Remove => {
// analyzer.db.get_flow_index_mut().add_call_cast(
// signature_id,
// name,
// TypeAssertion::Remove(LuaType::Nil),
// );
// }
// _ => {}
// }
// } else if let Some(doc_type) = cast_op_type.get_type() {
// let typ = infer_type(analyzer, doc_type.clone());
// match action {
// CastAction::Add => {
// analyzer.db.get_flow_index_mut().add_call_cast(
// signature_id,
// name,
// TypeAssertion::Add(typ),
// );
// }
// CastAction::Remove => {
// analyzer.db.get_flow_index_mut().add_call_cast(
// signature_id,
// name,
// TypeAssertion::Remove(typ),
// );
// }
// CastAction::Force => {
// analyzer.db.get_flow_index_mut().add_call_cast(
// signature_id,
// name,
// TypeAssertion::Force(typ),
// );
// }
// }
}
}

Expand Down Expand Up @@ -354,13 +359,12 @@ pub fn analyze_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagCast) -> Option<()
for op in tag.get_op_types() {
if let Some(doc_type) = op.get_type() {
let typ = infer_type(analyzer, doc_type.clone());
analyzer.context.cast_flow.insert(
InFiled {
file_id: analyzer.file_id,
value: doc_type.get_syntax_id(),
},
typ,
);
let type_owner =
LuaTypeOwner::SyntaxId(InFiled::new(analyzer.file_id, doc_type.get_syntax_id()));
analyzer
.db
.get_type_index_mut()
.bind_type(type_owner, LuaTypeCache::DocType(typ));
}
}
Some(())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use emmylua_parser::{LuaAstNode, LuaComment, LuaDocTag};

use crate::{compilation::analyzer::flow::binder::FlowBinder, FlowId, FlowNodeKind};

pub fn bind_comment(binder: &mut FlowBinder, lua_comment: LuaComment, current: FlowId) -> FlowId {
let cast_tags = lua_comment.get_doc_tags().filter_map(|it| match it {
LuaDocTag::Cast(cast) => Some(cast),
_ => None,
});

let mut parent = current;
for cast in cast_tags {
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
binder.add_antecedent(flow_id, parent);
parent = flow_id;
}

parent
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use emmylua_parser::{BinaryOperator, LuaAst, LuaBinaryExpr, LuaExpr};

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

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),
_ => {
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(())
}

pub fn is_binary_logical(expr: &LuaExpr) -> bool {
if let LuaExpr::BinaryExpr(binary_expr) = expr {
let Some(op_token) = binary_expr.get_op_token() else {
return false;
};

return match op_token.get_op() {
BinaryOperator::OpAnd | BinaryOperator::OpOr => true,
_ => false,
};
}

false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
mod bind_binary_expr;

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

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

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 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),
};

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<()> {
bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr.clone()), current);
Some(())
}

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

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

pub fn bind_unary_expr(
binder: &mut FlowBinder,
unary_expr: LuaUnaryExpr,
current: FlowId,
) -> Option<()> {
let Some(inner_expr) = unary_expr.get_expr() else {
return None;
};
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(())
}
Loading
Loading