diff --git a/ast-generator/src/build_fn_gen.rs b/ast-generator/src/build_fn_gen.rs index ab5f2e7..37ccb89 100644 --- a/ast-generator/src/build_fn_gen.rs +++ b/ast-generator/src/build_fn_gen.rs @@ -1,5 +1,6 @@ use crate::spec::{ - BuildBooleanOn, ChildSpec, SingleChildToBuild, StructBuildSpec, VecChildToBuild, + BuildBooleanOn, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild, + SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild, }; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; @@ -9,33 +10,45 @@ pub fn make_build_fn_name(s: &str) -> String { format!("build_{}", 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::Type(vec_type_child) => ( + format_ident!("{}", vec_type_child.var_name()), + format_ident!("{}", vec_type_child.build()), + ), + }; + quote! { + let mut #child_ident: Vec> = vec![] + } +} + +fn make_single_type_child_holder(single_type_child: &SingleTypeChildToBuild) -> TokenStream { + let child_ident = format_ident!("{}", single_type_child.var_name()); + let child_type_ident = format_ident!("{}", single_type_child.build()); + quote! { + let mut #child_ident: Option> = None + } +} + +fn make_single_boolean_child_holder( + single_boolean_child: &SingleBooleanChildToBuild, +) -> TokenStream { + let child_ident = format_ident!("{}", single_boolean_child.var_name()); + quote! { + let mut #child_ident: bool = false + } +} + fn make_child_holder(child_spec: &ChildSpec) -> Option { match child_spec { ChildSpec::SkipChild(_) => None, - ChildSpec::VecChild(vec_child) => { - let (child_ident, child_type_ident) = match vec_child.build() { - VecChildToBuild::Type(vec_type_child) => ( - format_ident!("{}", vec_type_child.var_name()), - format_ident!("{}", vec_type_child.build()), - ), - }; - Some(quote! { - let mut #child_ident: Vec> = vec![] - }) - } + ChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)), ChildSpec::SingleChild(single_child) => match single_child.build() { SingleChildToBuild::Type(single_type_child) => { - let child_ident = format_ident!("{}", single_type_child.var_name()); - let child_type_ident = format_ident!("{}", single_type_child.build()); - Some(quote! { - let mut #child_ident: Option> = None; - }) + Some(make_single_type_child_holder(single_type_child)) } SingleChildToBuild::Boolean(boolean_child) => { - let child_ident = format_ident!("{}", boolean_child.var_name()); - Some(quote! { - let #child_ident: bool = false - }) + Some(make_single_boolean_child_holder(boolean_child)) } }, } @@ -95,32 +108,32 @@ fn make_child_arg(child_spec: &ChildSpec) -> Option { ChildSpec::SkipChild(_) => None, ChildSpec::VecChild(vec_child) => { let child_ident = match vec_child.build() { - VecChildToBuild::Type(vec_type_child) => format_ident!("{}", vec_type_child.var_name()) + VecChildToBuild::Type(vec_type_child) => { + format_ident!("{}", vec_type_child.var_name()) + } }; Some(quote! { #child_ident }) - }, - ChildSpec::SingleChild(single_child) => { - match single_child.build() { - SingleChildToBuild::Type(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() }) - } - }, - SingleChildToBuild::Boolean(single_boolean_child) => { - let child_ident = format_ident!("{}", single_boolean_child.var_name()); + } + ChildSpec::SingleChild(single_child) => match single_child.build() { + SingleChildToBuild::Type(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() }) } } - } + SingleChildToBuild::Boolean(single_boolean_child) => { + let child_ident = format_ident!("{}", single_boolean_child.var_name()); + Some(quote! { #child_ident }) + } + }, } } @@ -180,3 +193,54 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::spec::VecTypeChildToBuild; + + #[test] + fn vec_child_holder() { + let vec_child = VecChild::new( + "test_child", + "Test", + VecChildToBuild::Type(VecTypeChildToBuild::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 = SingleTypeChildToBuild::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 = + SingleBooleanChildToBuild::new("test_child", BuildBooleanOn::RulePresent); + assert_eq!( + make_single_boolean_child_holder(&single_boolean_child).to_string(), + quote! { + let mut test_child: bool = false + } + .to_string() + ); + } +}