use crate::node::{NodeKind, NormalizedNode, PlaceholderKind};
use crate::normalization_context::NormalizationContext;
use super::helpers::{
member_to_string, normalize_bin_op, normalize_lit, normalize_macro, normalize_un_op,
};
use super::pat::{normalize_pat, normalize_type};
use syn::Block;
use syn::Expr;
use syn::Stmt;
#[allow(clippy::too_many_lines)]
pub fn normalize_expr(expr: &Expr, ctx: &mut NormalizationContext) -> NormalizedNode {
match expr {
Expr::Lit(el) => normalize_lit(&el.lit),
Expr::Path(ep) => {
if ep.path.segments.len() == 1 {
let seg = &ep.path.segments[0];
let ident = seg.ident.to_string();
let kind = if ident.chars().next().is_some_and(char::is_uppercase) {
PlaceholderKind::Type
} else {
PlaceholderKind::Variable
};
let idx = ctx.placeholder(&ident, kind);
NormalizedNode::leaf(NodeKind::Placeholder(kind, idx))
} else {
let segments: Vec<NormalizedNode> = ep
.path
.segments
.iter()
.map(|seg| {
let ident = seg.ident.to_string();
let kind = if ident.chars().next().is_some_and(char::is_uppercase) {
PlaceholderKind::Type
} else {
PlaceholderKind::Variable
};
let idx = ctx.placeholder(&ident, kind);
NormalizedNode::leaf(NodeKind::Placeholder(kind, idx))
})
.collect();
NormalizedNode::with_children(NodeKind::Path, segments)
}
}
Expr::Binary(eb) => NormalizedNode::with_children(
NodeKind::BinaryOp(normalize_bin_op(&eb.op)),
vec![
normalize_expr(&eb.left, ctx),
normalize_expr(&eb.right, ctx),
],
),
Expr::Unary(eu) => NormalizedNode::with_children(
NodeKind::UnaryOp(normalize_un_op(&eu.op)),
vec![normalize_expr(&eu.expr, ctx)],
),
Expr::Call(ec) => {
let mut children = vec![normalize_expr(&ec.func, ctx)];
children.extend(ec.args.iter().map(|a| normalize_expr(a, ctx)));
NormalizedNode::with_children(NodeKind::Call, children)
}
Expr::MethodCall(emc) => {
let method_idx = ctx.placeholder(&emc.method.to_string(), PlaceholderKind::Function);
let mut children = vec![
normalize_expr(&emc.receiver, ctx),
NormalizedNode::leaf(NodeKind::Placeholder(PlaceholderKind::Function, method_idx)),
];
children.extend(emc.args.iter().map(|a| normalize_expr(a, ctx)));
NormalizedNode::with_children(NodeKind::MethodCall, children)
}
Expr::Field(ef) => {
let field_idx =
ctx.placeholder(&member_to_string(&ef.member), PlaceholderKind::Variable);
NormalizedNode::with_children(
NodeKind::FieldAccess,
vec![
normalize_expr(&ef.base, ctx),
NormalizedNode::leaf(NodeKind::Placeholder(
PlaceholderKind::Variable,
field_idx,
)),
],
)
}
Expr::Index(ei) => NormalizedNode::with_children(
NodeKind::Index,
vec![
normalize_expr(&ei.expr, ctx),
normalize_expr(&ei.index, ctx),
],
),
Expr::Closure(ec) => {
let mut children = vec![normalize_expr(&ec.body, ctx)];
children.extend(ec.inputs.iter().map(|p| normalize_pat(p, ctx)));
NormalizedNode::with_children(NodeKind::Closure, children)
}
Expr::Return(er) => {
let children: Vec<_> = er
.expr
.as_ref()
.map(|e| vec![normalize_expr(e, ctx)])
.unwrap_or_default();
NormalizedNode::with_children(NodeKind::Return, children)
}
Expr::Break(eb) => {
let children: Vec<_> = eb
.expr
.as_ref()
.map(|e| vec![normalize_expr(e, ctx)])
.unwrap_or_default();
NormalizedNode::with_children(NodeKind::Break, children)
}
Expr::Continue(_) => NormalizedNode::leaf(NodeKind::Continue),
Expr::Assign(ea) => NormalizedNode::with_children(
NodeKind::Assign,
vec![
normalize_expr(&ea.left, ctx),
normalize_expr(&ea.right, ctx),
],
),
Expr::Reference(er) => NormalizedNode::with_children(
NodeKind::Reference {
mutable: er.mutability.is_some(),
},
vec![normalize_expr(&er.expr, ctx)],
),
Expr::Tuple(et) => NormalizedNode::with_children(
NodeKind::Tuple,
et.elems.iter().map(|e| normalize_expr(e, ctx)).collect(),
),
Expr::Array(ea) => NormalizedNode::with_children(
NodeKind::Array,
ea.elems.iter().map(|e| normalize_expr(e, ctx)).collect(),
),
Expr::Repeat(er) => NormalizedNode::with_children(
NodeKind::Repeat,
vec![normalize_expr(&er.expr, ctx), normalize_expr(&er.len, ctx)],
),
Expr::Cast(ec) => NormalizedNode::with_children(
NodeKind::Cast,
vec![normalize_expr(&ec.expr, ctx), normalize_type(&ec.ty, ctx)],
),
Expr::Struct(es) => {
let mut children = vec![NormalizedNode::opt(
es.rest.as_ref().map(|e| normalize_expr(e, ctx)),
)];
children.extend(es.fields.iter().map(|f| {
let field_idx =
ctx.placeholder(&member_to_string(&f.member), PlaceholderKind::Variable);
NormalizedNode::with_children(
NodeKind::FieldValue,
vec![
NormalizedNode::leaf(NodeKind::Placeholder(
PlaceholderKind::Variable,
field_idx,
)),
normalize_expr(&f.expr, ctx),
],
)
}));
NormalizedNode::with_children(NodeKind::StructInit, children)
}
Expr::Await(ea) => {
NormalizedNode::with_children(NodeKind::Await, vec![normalize_expr(&ea.base, ctx)])
}
Expr::Try(et) => {
NormalizedNode::with_children(NodeKind::Try, vec![normalize_expr(&et.expr, ctx)])
}
Expr::If(ei) => NormalizedNode::with_children(
NodeKind::If,
vec![
normalize_expr(&ei.cond, ctx),
normalize_block(&ei.then_branch, ctx),
NormalizedNode::opt(ei.else_branch.as_ref().map(|(_, e)| normalize_expr(e, ctx))),
],
),
Expr::Match(em) => {
let mut children = vec![normalize_expr(&em.expr, ctx)];
children.extend(em.arms.iter().map(|arm| {
NormalizedNode::with_children(
NodeKind::MatchArm,
vec![
normalize_pat(&arm.pat, ctx),
NormalizedNode::opt(
arm.guard.as_ref().map(|(_, g)| normalize_expr(g, ctx)),
),
normalize_expr(&arm.body, ctx),
],
)
}));
NormalizedNode::with_children(NodeKind::Match, children)
}
Expr::Loop(el) => {
NormalizedNode::with_children(NodeKind::Loop, vec![normalize_block(&el.body, ctx)])
}
Expr::While(ew) => NormalizedNode::with_children(
NodeKind::While,
vec![
normalize_expr(&ew.cond, ctx),
normalize_block(&ew.body, ctx),
],
),
Expr::ForLoop(ef) => NormalizedNode::with_children(
NodeKind::ForLoop,
vec![
normalize_pat(&ef.pat, ctx),
normalize_expr(&ef.expr, ctx),
normalize_block(&ef.body, ctx),
],
),
Expr::Block(eb) => normalize_block(&eb.block, ctx),
Expr::Paren(ep) => {
NormalizedNode::with_children(NodeKind::Paren, vec![normalize_expr(&ep.expr, ctx)])
}
Expr::Range(er) => NormalizedNode::with_children(
NodeKind::Range,
vec![
NormalizedNode::opt(er.start.as_ref().map(|e| normalize_expr(e, ctx))),
NormalizedNode::opt(er.end.as_ref().map(|e| normalize_expr(e, ctx))),
],
),
Expr::Let(el) => NormalizedNode::with_children(
NodeKind::LetExpr,
vec![normalize_pat(&el.pat, ctx), normalize_expr(&el.expr, ctx)],
),
Expr::Macro(em) => normalize_macro(&em.mac, ctx),
Expr::Group(eg) => normalize_expr(&eg.expr, ctx),
Expr::Unsafe(eu) => normalize_block(&eu.block, ctx),
Expr::Const(ec) => normalize_block(&ec.block, ctx),
_ => NormalizedNode::leaf(NodeKind::Opaque),
}
}
pub fn normalize_stmt(stmt: &Stmt, ctx: &mut NormalizationContext) -> NormalizedNode {
match stmt {
Stmt::Local(local) => NormalizedNode::with_children(
NodeKind::LetBinding,
vec![
normalize_pat(&local.pat, ctx),
NormalizedNode::none(), NormalizedNode::opt(
local
.init
.as_ref()
.map(|init| normalize_expr(&init.expr, ctx)),
),
NormalizedNode::opt(
local
.init
.as_ref()
.and_then(|init| init.diverge.as_ref())
.map(|(_, expr)| normalize_expr(expr, ctx)),
),
],
),
Stmt::Expr(expr, semi) => {
let normalized = normalize_expr(expr, ctx);
if semi.is_some() {
NormalizedNode::with_children(NodeKind::Semi, vec![normalized])
} else {
normalized
}
}
Stmt::Item(_) => NormalizedNode::leaf(NodeKind::Opaque),
Stmt::Macro(sm) => {
let normalized = normalize_macro(&sm.mac, ctx);
if sm.semi_token.is_some() {
NormalizedNode::with_children(NodeKind::Semi, vec![normalized])
} else {
normalized
}
}
}
}
pub fn normalize_block(block: &Block, ctx: &mut NormalizationContext) -> NormalizedNode {
NormalizedNode::with_children(
NodeKind::Block,
block.stmts.iter().map(|s| normalize_stmt(s, ctx)).collect(),
)
}