60 lines
2.2 KiB
Rust
60 lines
2.2 KiB
Rust
use crate::spec::struct_spec::{MemberChildBuild, StructChild, StructSpec, VecChildBuild};
|
|
use proc_macro2::TokenStream;
|
|
use quote::{format_ident, quote};
|
|
|
|
pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", spec.build());
|
|
let child_adders = spec
|
|
.children()
|
|
.map(|child| match child {
|
|
StructChild::SkipChild(_) => None,
|
|
StructChild::VecChild(vec_child) => match vec_child.build() {
|
|
VecChildBuild::String(_) => None,
|
|
VecChildBuild::Node(_) => {
|
|
let child_ident = format_ident!("{}", vec_child.name());
|
|
let children_stream = quote! {
|
|
for child in self.#child_ident() {
|
|
children.push(child as &dyn AstNode);
|
|
}
|
|
};
|
|
Some(children_stream)
|
|
}
|
|
},
|
|
StructChild::MemberChild(member_child) => match member_child.build() {
|
|
MemberChildBuild::Node(_) => {
|
|
let child_ident = format_ident!("{}", member_child.name());
|
|
if member_child.optional() {
|
|
Some(quote! {
|
|
if let Some(#child_ident) = self.#child_ident() {
|
|
children.push(#child_ident as &dyn AstNode);
|
|
}
|
|
})
|
|
} else {
|
|
Some(quote! {
|
|
children.push(self.#child_ident() as &dyn AstNode)
|
|
})
|
|
}
|
|
}
|
|
MemberChildBuild::Boolean(_) => None,
|
|
},
|
|
StructChild::Special(_) => None,
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
quote! {
|
|
impl<'a> AstNode<'a> for #type_ident {
|
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
|
let mut children = vec![];
|
|
#(#child_adders;)*
|
|
children
|
|
}
|
|
|
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
|
AstNodeRef::#type_ident(&self)
|
|
}
|
|
}
|
|
}
|
|
}
|