deimos-lang/ast-generator/src/ast_node/struct_ast_node.rs

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)
}
}
}
}