Make polymorphic enum loop build fn.

This commit is contained in:
Jesse Brault 2025-09-23 10:56:11 -05:00
parent d7b01377d7
commit eb83d1202a
2 changed files with 102 additions and 1 deletions

View File

@ -1,8 +1,9 @@
pub mod leaf_enum_build_fn;
pub mod leaf_struct_build_fn;
mod node_production_build_fn;
pub mod node_production_build_fn;
pub mod polymorphic_build_build_fn;
pub mod polymorphic_enum_build_fn;
pub mod polymorphic_enum_loop_build_fn;
pub mod polymorphic_type_build_fn;
pub mod production_build_fn;
pub mod struct_build_fn;

View File

@ -0,0 +1,100 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule,
PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild,
PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_pass_through(pass_through: &PolymorphicEnumLoopRulePassThrough) -> TokenStream {
let rule_ident = format_ident!("{}", pass_through.name());
let inner_build_fn_ident = format_ident!("{}", pass_through.with());
quote! {
Rule::#rule_ident => {
result = Some(#inner_build_fn_ident(inner_pair))
}
}
}
fn make_on_each_child_build(child: &PolymorphicEnumLoopRuleChildOnEach) -> TokenStream {
let child_build_fn_ident = format_ident!("{}", make_build_fn_name(child.rule()));
quote! {
#child_build_fn_ident(inner_pair)
}
}
fn make_build(
spec: &PolymorphicEnumLoopBuildSpec,
build: &PolymorphicEnumLoopRuleBuild,
) -> TokenStream {
let rule_ident = format_ident!("{}", build.name());
let variant_type_ident = format_ident!("{}", build.name());
let return_type_ident = format_ident!("{}", spec.kind());
let variant_ident = format_ident!("{}", build.variant());
let on_each_child = build
.children()
.find(|child| match child {
PolymorphicEnumLoopRuleBuildChild::OnEach(_) => true,
_ => false,
})
.map(|child| {
match child {
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => on_each,
_ => unreachable!(),
}
})
.unwrap();
let build_on_each_child = make_on_each_child_build(on_each_child);
let child_args = build
.children()
.map(|child| match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(_) => {
quote! { result.unwrap() }
}
PolymorphicEnumLoopRuleBuildChild::OnEach(_) => quote! { on_each_child },
})
.collect::<Vec<_>>();
quote! {
Rule::#rule_ident => {
let on_each_child = #build_on_each_child;
let built = #variant_type_ident::new(#(#child_args),*);
result = Some(#return_type_ident::#variant_ident(built))
}
}
}
fn make_match_arm(spec: &PolymorphicEnumLoopBuildSpec, rule: &PolymorphicEnumLoopRule) -> TokenStream {
match rule {
PolymorphicEnumLoopRule::PassThrough(pass_through) => make_pass_through(pass_through),
PolymorphicEnumLoopRule::Build(build) => make_build(spec, build),
}
}
pub fn make_polymorphic_enum_loop_build_fn(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.kind());
let match_arms = spec
.rules()
.map(|rule| make_match_arm(spec, rule))
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let mut result: Option<#return_type_ident> = None;
for inner_pair in #pair_ident.into_inner() {
match inner_pair.as_rule() {
#(#match_arms,)*,
_ => unreachable!()
}
}
result.unwrap()
}
}
}