use emmylua_parser::{
LuaAssignStat, LuaAstNode, LuaAstPtr, LuaChunk, LuaClosureExpr, LuaDocTagCast, LuaExpr,
LuaForStat, LuaFuncStat, LuaSyntaxKind, LuaSyntaxNode,
};
use internment::ArcIntern;
use rowan::{TextRange, TextSize};
use smol_str::SmolStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct FlowId(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FlowAntecedent {
Single(FlowId),
Multiple(u32),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FlowNode {
pub id: FlowId,
pub kind: FlowNodeKind,
pub antecedent: Option<FlowAntecedent>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FlowNodeKind {
Start,
Unreachable,
BranchLabel,
LoopLabel,
NamedLabel(ArcIntern<SmolStr>),
DeclPosition(TextSize),
Assignment(LuaAstPtr<LuaAssignStat>),
TrueCondition(LuaAstPtr<LuaExpr>),
FalseCondition(LuaAstPtr<LuaExpr>),
ImplFunc(LuaAstPtr<LuaFuncStat>),
ForIStat(LuaAstPtr<LuaForStat>),
TagCast(LuaAstPtr<LuaDocTagCast>),
Break,
Return,
}
#[allow(unused)]
impl FlowNodeKind {
pub fn is_branch_label(&self) -> bool {
matches!(self, FlowNodeKind::BranchLabel)
}
pub fn is_loop_label(&self) -> bool {
matches!(self, FlowNodeKind::LoopLabel)
}
pub fn is_named_label(&self) -> bool {
matches!(self, FlowNodeKind::NamedLabel(_))
}
pub fn is_change_flow(&self) -> bool {
matches!(self, FlowNodeKind::Break | FlowNodeKind::Return)
}
pub fn is_assignment(&self) -> bool {
matches!(self, FlowNodeKind::Assignment(_))
}
pub fn is_conditional(&self) -> bool {
matches!(
self,
FlowNodeKind::TrueCondition(_) | FlowNodeKind::FalseCondition(_)
)
}
pub fn is_unreachable(&self) -> bool {
matches!(self, FlowNodeKind::Unreachable)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LuaClosureId(TextRange);
impl LuaClosureId {
pub fn from_closure(closure_expr: LuaClosureExpr) -> Self {
Self(closure_expr.get_range())
}
pub fn from_chunk(chunk: LuaChunk) -> Self {
Self(chunk.get_range())
}
pub fn from_node(node: &LuaSyntaxNode) -> Self {
let flow_id = node.ancestors().find_map(|node| match node.kind().into() {
LuaSyntaxKind::ClosureExpr => {
LuaClosureExpr::cast(node).map(LuaClosureId::from_closure)
}
LuaSyntaxKind::Chunk => LuaChunk::cast(node).map(LuaClosureId::from_chunk),
_ => None,
});
flow_id.unwrap_or_else(|| LuaClosureId(TextRange::default()))
}
pub fn get_position(&self) -> TextSize {
self.0.start()
}
pub fn get_range(&self) -> TextRange {
self.0
}
}