use std::collections::HashMap;
use crate::placeholder_order_collector::PlaceholderOrderCollector;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LiteralKind {
Int,
Float,
Str,
ByteStr,
CStr,
Byte,
Char,
Bool,
Null,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PlaceholderKind {
Variable,
Function,
Type,
Lifetime,
Label,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum BinOpKind {
Add,
Sub,
Mul,
Div,
Rem,
And,
Or,
BitXor,
BitAnd,
BitOr,
Shl,
Shr,
Eq,
Lt,
Le,
Ne,
Ge,
Gt,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
RemAssign,
BitXorAssign,
BitAndAssign,
BitOrAssign,
ShlAssign,
ShrAssign,
FloorDiv,
Pow,
In,
NotIn,
Is,
IsNot,
FloorDivAssign,
PowAssign,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum UnOpKind {
Deref,
Not,
Neg,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NodeKind {
Block,
LetBinding,
Semi,
Paren,
Literal(LiteralKind),
Placeholder(PlaceholderKind, usize),
BinaryOp(BinOpKind),
UnaryOp(UnOpKind),
Range,
Call,
MethodCall,
FieldAccess,
Index,
Path,
Closure,
FnSignature,
Return,
Break,
Continue,
Assign,
Reference {
mutable: bool,
},
Tuple,
Array,
Set,
Repeat,
Cast,
StructInit,
Await,
Yield,
Try,
If,
Match,
MatchArm,
Loop,
While,
ForLoop,
LetExpr,
PatWild,
PatPlaceholder(PlaceholderKind, usize),
PatTuple,
PatStruct,
PatOr,
PatLiteral,
PatReference {
mutable: bool,
},
PatSlice,
PatRest,
PatRange,
TypePlaceholder(PlaceholderKind, usize),
TypeReference {
mutable: bool,
},
TypeTuple,
TypeSlice,
TypeArray,
TypePath,
TypeImplTrait,
TypeInfer,
TypeUnit,
TypeNever,
FieldValue,
MacroCall {
name: String,
},
Opaque,
None,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NormalizedNode {
pub kind: NodeKind,
pub children: Vec<Self>,
}
impl NormalizedNode {
#[must_use]
pub const fn leaf(kind: NodeKind) -> Self {
Self {
kind,
children: vec![],
}
}
#[must_use]
pub const fn with_children(kind: NodeKind, children: Vec<Self>) -> Self {
Self { kind, children }
}
#[must_use]
pub const fn none() -> Self {
Self::leaf(NodeKind::None)
}
pub fn opt(node: Option<Self>) -> Self {
node.unwrap_or_else(Self::none)
}
#[must_use]
pub const fn is_none(&self) -> bool {
matches!(self.kind, NodeKind::None)
}
}
fn apply_reindex(
node: &NormalizedNode,
mapping: &HashMap<(PlaceholderKind, usize), usize>,
) -> NormalizedNode {
let kind = match &node.kind {
NodeKind::Placeholder(kind, idx) => {
let new_idx = mapping.get(&(*kind, *idx)).copied().unwrap_or(*idx);
NodeKind::Placeholder(*kind, new_idx)
}
NodeKind::PatPlaceholder(kind, idx) => {
let new_idx = mapping.get(&(*kind, *idx)).copied().unwrap_or(*idx);
NodeKind::PatPlaceholder(*kind, new_idx)
}
NodeKind::TypePlaceholder(kind, idx) => {
let new_idx = mapping.get(&(*kind, *idx)).copied().unwrap_or(*idx);
NodeKind::TypePlaceholder(*kind, new_idx)
}
other => other.clone(),
};
let children = node
.children
.iter()
.map(|c| apply_reindex(c, mapping))
.collect();
NormalizedNode { kind, children }
}
#[must_use]
pub fn reindex_placeholders(node: &NormalizedNode) -> NormalizedNode {
let mut collector = PlaceholderOrderCollector::new();
collector.collect(node);
let order = collector.into_order();
let mut counters: HashMap<PlaceholderKind, usize> = HashMap::new();
let mut mapping: HashMap<(PlaceholderKind, usize), usize> = HashMap::new();
for (kind, old_idx) in order {
let counter = counters.entry(kind).or_insert(0);
mapping.insert((kind, old_idx), *counter);
*counter += 1;
}
apply_reindex(node, &mapping)
}
pub fn count_nodes(node: &NormalizedNode) -> usize {
if node.is_none() {
return 0;
}
1 + node.children.iter().map(count_nodes).sum::<usize>()
}