#![allow(clippy::all)]
mod node_id_walk;
#[cfg(test)]
pub(crate) mod render_skeleton;
pub(crate) mod size_asserts;
mod spanned;
pub mod visit;
pub use node_id_walk::NodeIdWalk;
pub use visit::{Visit, VisitMut};
#[cfg(test)]
mod tests {
use crate::ast::*;
use crate::generated::visit::{self, Visit, VisitMut};
use crate::vocab::{Meta, NodeId, Span, Symbol};
fn meta(start: u32, end: u32) -> Meta {
Meta::new(
Span::new(start, end),
NodeId::new(1).expect("non-zero node id"),
)
}
fn ident(sym: u32, start: u32, end: u32) -> Ident {
Ident {
sym: Symbol::new(sym).expect("non-zero symbol"),
quote: QuoteStyle::None,
meta: meta(start, end),
}
}
fn literal_expr(start: u32, end: u32) -> Expr {
Expr::Literal {
literal: Literal {
kind: LiteralKind::Integer,
meta: meta(start, end),
},
meta: meta(start, end),
}
}
#[test]
fn struct_node_span_is_its_meta_span() {
assert_eq!(ident(1, 3, 8).span(), Span::new(3, 8));
}
#[test]
fn enum_node_span_is_its_meta_span() {
let binary_op: Expr = Expr::BinaryOp {
left: Box::new(literal_expr(0, 1)),
op: BinaryOperator::Plus,
right: Box::new(literal_expr(4, 5)),
meta: meta(10, 12),
};
assert_eq!(binary_op.span(), Span::new(10, 12));
}
#[test]
fn object_name_span_unions_its_idents() {
let name = ObjectName(vec![ident(1, 2, 6), ident(2, 7, 12)].into());
assert_eq!(name.span(), Span::new(2, 12));
}
#[test]
fn field_less_variant_span_is_its_meta_span() {
let wildcard: SelectItem = SelectItem::Wildcard {
options: None,
alias: None,
alias_spelling: AliasSpelling::As,
meta: meta(7, 8),
};
assert_eq!(wildcard.span(), Span::new(7, 8));
}
#[test]
fn visit_threads_extension_nodes() {
let expr = Expr::Other {
ext: TestExt::default(),
meta: meta(0, 0),
};
let mut visitor = CountingVisit::default();
visitor.visit_expr(&expr);
assert_eq!(visitor.exprs, 1);
assert_eq!(visitor.extensions, 1);
}
#[test]
fn visit_mut_threads_extension_nodes() {
let mut expr = Expr::Other {
ext: TestExt::default(),
meta: meta(0, 0),
};
let mut visitor = TouchingVisitMut;
visitor.visit_expr_mut(&mut expr);
let Expr::Other { ext, .. } = expr else {
panic!("test expression stays an extension node");
};
assert!(ext.touched);
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
struct TestExt {
touched: bool,
}
impl Spanned for TestExt {
fn span(&self) -> Span {
Span::SYNTHETIC
}
}
#[derive(Default)]
struct CountingVisit {
exprs: usize,
extensions: usize,
}
impl<'ast> Visit<'ast, TestExt> for CountingVisit {
fn visit_expr(&mut self, node: &'ast Expr<TestExt>) {
self.exprs += 1;
visit::walk_expr(self, node);
}
fn visit_extension(&mut self, _node: &'ast TestExt) {
self.extensions += 1;
}
}
struct TouchingVisitMut;
impl VisitMut<TestExt> for TouchingVisitMut {
fn visit_extension_mut(&mut self, node: &mut TestExt) {
node.touched = true;
}
}
}