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!("{}", make_build_fn_name(node_child.build())); quote! { #inner_build_fn_ident(inner_pair) } } _ => { let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(enum_rule.rule())); quote! { #inner_build_fn_ident(inner_pair) } } }; quote! { Rule::#rule_ident => #return_type_ident::#rule_ident(#inner_builder) } } else { quote! { Rule::#rule_ident => #return_type_ident::#rule_ident } } }) .collect::>(); quote! { fn #build_fn_ident(#pair_ident: Pair) -> #return_type_ident { let inner_pair = #pair_ident.into_inner().next().unwrap(); match inner_pair.as_rule() { #(#rule_branches,)* _ => unreachable!() } } } }