From 5d640ca5857f0e3ead02406358b15635bb2458e7 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 15 Sep 2025 20:10:59 -0500 Subject: [PATCH] Refactor struct build-fn gen. --- ast-generator/src/struct_build_fn.rs | 283 +++++++++------------------ 1 file changed, 89 insertions(+), 194 deletions(-) diff --git a/ast-generator/src/struct_build_fn.rs b/ast-generator/src/struct_build_fn.rs index fad891b..bfbebc4 100644 --- a/ast-generator/src/struct_build_fn.rs +++ b/ast-generator/src/struct_build_fn.rs @@ -1,141 +1,98 @@ -use crate::spec::{ - BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, - StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, -}; -use crate::util::make_build_pair; -use proc_macro2::{Ident, TokenStream}; +use crate::spec::{BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild}; +use crate::util::{make_build_fn_name, make_build_pair}; +use convert_case::{Case, Casing}; +use proc_macro2::TokenStream; use quote::{format_ident, quote}; +fn make_var_name(s: &str) -> String { + s.to_case(Case::Snake) +} + fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream { - let (child_ident, child_type_ident) = match vec_child.build() { - VecChildToBuild::Node(vec_type_child) => ( - format_ident!("{}", vec_type_child.var_name()), - format_ident!("{}", vec_type_child.build()), - ), + let child_ident = format_ident!("{}", vec_child.name()); + let child_type_ident = match vec_child.build() { + VecChildToBuild::Node(node_child) => { + format_ident!("{}", node_child.build()) + }, + VecChildToBuild::String => format_ident!("{}", "String") }; quote! { let mut #child_ident: Vec> = vec![] } } -fn make_single_type_child_holder(single_type_child: &NodeChildToBuild) -> TokenStream { - let child_ident = format_ident!("{}", single_type_child.var_name()); - let child_type_ident = format_ident!("{}", single_type_child.build()); +fn make_node_child_holder(node_child: &NodeChildToBuild) -> TokenStream { + let child_ident = format_ident!("{}", make_var_name(node_child.build())); + let child_type_ident = format_ident!("{}", node_child.build()); quote! { let mut #child_ident: Option> = None } } -fn make_single_boolean_child_holder(single_boolean_child: &BooleanChildToBuild) -> TokenStream { - let child_ident = format_ident!("{}", single_boolean_child.name()); +fn make_boolean_child_holder(boolean_child: &BooleanChildToBuild) -> TokenStream { + let child_ident = format_ident!("{}", boolean_child.name()); quote! { let mut #child_ident: bool = false } } -fn make_literal_child_holder( - literal_child: &SingleLiteralChildToBuild, - literal_type_ident: Ident, -) -> TokenStream { - let child_ident = format_ident!("{}", literal_child.var_name()); - quote! { - let mut #child_ident: Option<#literal_type_ident> = None - } -} - fn make_child_holder(child_spec: &StructChildSpec) -> Option { match child_spec { StructChildSpec::SkipChild(_) => None, StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)), - StructChildSpec::MemberChild(single_child) => match single_child.build() { - MemberChildToBuild::Node(single_type_child) => { - Some(make_single_type_child_holder(single_type_child)) + StructChildSpec::MemberChild(member_child) => match member_child.build() { + MemberChildToBuild::Node(node_child) => { + Some(make_node_child_holder(node_child)) } MemberChildToBuild::Boolean(boolean_child) => { - Some(make_single_boolean_child_holder(boolean_child)) + Some(make_boolean_child_holder(boolean_child)) } - MemberChildToBuild::Int(literal_child) => Some(make_literal_child_holder( - literal_child, - format_ident!("i32"), - )), - MemberChildToBuild::Long(literal_child) => Some(make_literal_child_holder( - literal_child, - format_ident!("i64"), - )), - MemberChildToBuild::Double(literal_child) => Some(make_literal_child_holder( - literal_child, - format_ident!("f64"), - )), - MemberChildToBuild::String(literal_child) => Some(make_literal_child_holder( - literal_child, - format_ident!("String"), - )), }, } } -fn get_literal_child_ident(literal_child: &SingleLiteralChildToBuild) -> Ident { - format_ident!("{}", literal_child.var_name()) +fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream { + let child_name_ident = format_ident!("{}", vec_child.name()); + let build_fn_ident = match vec_child.build() { + VecChildToBuild::Node(vec_node_child) => { + format_ident!("{}", make_build_fn_name(vec_node_child.build())) + }, + VecChildToBuild::String => { + format_ident!("{}", make_build_fn_name(vec_child.rule())) + } + }; + quote! { + #child_name_ident.push(Box::new(#build_fn_ident(inner_pair))) + } +} + +fn make_node_member_child_match_action(node_child: &NodeChildToBuild) -> TokenStream { + let child_name_ident = format_ident!("{}", make_var_name(node_child.build())); + let build_fn_ident = format_ident!("{}", make_build_fn_name(node_child.build())); + quote! { + #child_name_ident = Some(Box::new(#build_fn_ident(inner_pair))) + } +} + +fn make_boolean_member_child_match_action(boolean_child: &BooleanChildToBuild) -> TokenStream { + let child_name_ident = format_ident!("{}", make_var_name(boolean_child.name())); + quote! { + #child_name_ident = true + } } fn make_match_action(child_spec: &StructChildSpec) -> TokenStream { match child_spec { StructChildSpec::SkipChild(_) => quote! {}, StructChildSpec::VecChild(vec_child) => { - let (child_name_ident, build_fn_ident) = match vec_child.build() { - VecChildToBuild::Node(vec_type_child) => ( - format_ident!("{}", vec_type_child.var_name()), - format_ident!("{}", vec_type_child.with()), - ), - }; - quote! { - #child_name_ident.push(Box::new(#build_fn_ident(inner_pair))) - } + make_vec_child_match_action(vec_child) } StructChildSpec::MemberChild(single_child) => match single_child.build() { - MemberChildToBuild::Node(single_type_child) => { - let child_name_ident = format_ident!("{}", single_type_child.var_name()); - let build_fn_ident = format_ident!("{}", single_type_child.with()); - quote! { - #child_name_ident = Some(Box::new(#build_fn_ident(inner_pair))) - } + MemberChildToBuild::Node(node_child) => { + make_node_member_child_match_action(node_child) } - MemberChildToBuild::Boolean(single_boolean_child) => { - let child_name_ident = format_ident!("{}", single_boolean_child.name()); - match single_boolean_child.build() { - BooleanBuild::RulePresent => quote! { - #child_name_ident = true - }, - BooleanBuild::ParseWholePair => quote! { - #child_name_ident = Some(inner_pair.as_str().parse().unwrap()) - }, - } - } - MemberChildToBuild::Int(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - quote! { - #child_ident = Some(inner_pair.as_str().parse().unwrap()) - } - } - MemberChildToBuild::Long(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - quote! { - let as_string = inner_pair.as_str(); - let without_el = &as_string[0..(as_string.len() - 1)]; - #child_ident = Some(without_el.parse().unwrap()) - } - } - MemberChildToBuild::Double(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - quote! { - #child_ident = Some(inner_pair.as_str().parse().unwrap()) - } - } - MemberChildToBuild::String(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - quote! { - #child_ident = Some(inner_pair.as_str().to_string()) - } + MemberChildToBuild::Boolean(boolean_child) => { + make_boolean_member_child_match_action(boolean_child) } }, } @@ -156,51 +113,43 @@ fn make_rule_matcher(child_spec: &StructChildSpec) -> TokenStream { } } +fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream { + let child_ident = format_ident!("{}", vec_child.name()); + quote! { #child_ident } +} + +fn make_node_member_child_arg(name: &str, node_child: &NodeChildToBuild) -> TokenStream { + let child_ident = format_ident!("{}", name); + if node_child.optional() { + quote! { #child_ident } + } else if let Some(or_else) = node_child.or_else() { + let child_type_ident = format_ident!("{}", node_child.build()); + let or_else_ident = format_ident!("{}", or_else); + quote! { + #child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident())) + } + } else { + quote! { #child_ident.unwrap() } + } +} + +fn make_boolean_member_child_arg(boolean_child: &BooleanChildToBuild) -> TokenStream { + let child_ident = format_ident!("{}", boolean_child.name()); + quote! { #child_ident } +} + fn make_child_arg(child_spec: &StructChildSpec) -> Option { match child_spec { StructChildSpec::SkipChild(_) => None, StructChildSpec::VecChild(vec_child) => { - let child_ident = match vec_child.build() { - VecChildToBuild::Node(vec_type_child) => { - format_ident!("{}", vec_type_child.var_name()) - } - }; - Some(quote! { #child_ident }) + Some(make_vec_child_arg(vec_child)) } - StructChildSpec::MemberChild(single_child) => match single_child.build() { + StructChildSpec::MemberChild(member_child) => match member_child.build() { MemberChildToBuild::Node(single_type_child) => { - let child_ident = format_ident!("{}", single_type_child.var_name()); - if single_type_child.optional() { - Some(quote! { #child_ident }) - } else if let Some(or_else) = single_type_child.or_else() { - let child_type_ident = format_ident!("{}", single_type_child.build()); - let or_else_ident = format_ident!("{}", or_else); - Some(quote! { - #child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident())) - }) - } else { - Some(quote! { #child_ident.unwrap() }) - } + Some(make_node_member_child_arg(member_child.name(), single_type_child)) } - MemberChildToBuild::Boolean(single_boolean_child) => { - let child_ident = format_ident!("{}", single_boolean_child.name()); - Some(quote! { #child_ident }) - } - MemberChildToBuild::Int(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - Some(quote! { #child_ident.unwrap() }) - } - MemberChildToBuild::Long(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - Some(quote! { #child_ident.unwrap() }) - } - MemberChildToBuild::Double(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - Some(quote! { #child_ident.unwrap() }) - } - MemberChildToBuild::String(literal_child) => { - let child_ident = get_literal_child_ident(literal_child); - Some(quote! { #child_ident.unwrap() }) + MemberChildToBuild::Boolean(boolean_child) => { + Some(make_boolean_member_child_arg(boolean_child)) } }, } @@ -210,7 +159,6 @@ fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream { let type_ident = format_ident!("{}", build_spec.build()); let child_args = build_spec .children() - .iter() .map(|child| make_child_arg(child)) .filter(|child_arg| child_arg.is_some()) .map(|child_arg| child_arg.unwrap()) @@ -224,13 +172,12 @@ fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream { } pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { - let build_fn_ident = format_ident!("{}", build_spec.with()); // TODO: get rid of with - let pair_ident = format_ident!("{}", make_build_pair(build_spec.var_name())); // TODO: get rid of var_name + let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build())); + let pair_ident = format_ident!("{}", make_build_pair(build_spec.build())); let return_type_ident = format_ident!("{}", build_spec.build()); let child_holders = build_spec .children() - .iter() .map(|child_spec| make_child_holder(child_spec)) .filter(|child_holder| child_holder.is_some()) .map(|child_holder| child_holder.unwrap()) @@ -238,7 +185,6 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { let rule_matchers = build_spec .children() - .iter() .map(|child_spec| make_rule_matcher(child_spec)) .collect::>(); @@ -262,55 +208,4 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { #new_stream } } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::spec::VecNodeChildToBuild; - - #[test] - fn vec_child_holder() { - let vec_child = VecChild::new( - "test_child", - "Test", - VecChildToBuild::Node(VecNodeChildToBuild::new( - "TestType", - "test_child", - "build_test_child", - )), - ); - assert_eq!( - make_vec_child_holder(&vec_child).to_string(), - quote! { - let mut test_child: Vec> = vec![] - } - .to_string() - ); - } - - #[test] - fn single_type_child_holder() { - let single_type_child = NodeChildToBuild::from_build_or_rule("TestType", None, false); - assert_eq!( - make_single_type_child_holder(&single_type_child).to_string(), - quote! { - let mut test_type: Option> = None - } - .to_string() - ); - } - - #[test] - fn single_boolean_child_holder() { - let single_boolean_child = - BooleanChildToBuild::new("test_child", BooleanBuild::RulePresent); - assert_eq!( - make_single_boolean_child_holder(&single_boolean_child).to_string(), - quote! { - let mut test_child: bool = false - } - .to_string() - ); - } -} +} \ No newline at end of file