deimos-lang/ast-generator/src/build_fn/tree_enum_build_fn.rs
2025-09-25 18:43:05 -05:00

64 lines
3.0 KiB
Rust

use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_enum_build_fn(enum_build_spec: &TreeEnumBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(enum_build_spec.build()));
let pair_ident = format_ident!("{}", make_build_pair(enum_build_spec.build()));
let return_type_ident = format_ident!("{}", enum_build_spec.build());
let rule_branches = enum_build_spec
.rules()
.map(|enum_rule| {
let rule_ident = format_ident!("{}", enum_rule.rule());
if let Some(child) = enum_rule.child() {
let inner_builder = match child.kind() {
EnumRuleChildKind::Node(node_child) => {
let inner_build_fn_ident =
format_ident!("{}", node_child.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
EnumRuleChildKind::Int(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
EnumRuleChildKind::Long(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
EnumRuleChildKind::Double(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
EnumRuleChildKind::String(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
EnumRuleChildKind::Boolean(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(file_id, inner_pair) }
}
};
quote! {
Rule::#rule_ident => #return_type_ident::#rule_ident(#inner_builder)
}
} else {
quote! {
Rule::#rule_ident => #return_type_ident::#rule_ident
}
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#rule_branches,)*
_ => unreachable!()
}
}
}
}