diff --git a/ast-generator/src/type_gen/mod.rs b/ast-generator/src/type_gen/mod.rs index aac4858..f218bbd 100644 --- a/ast-generator/src/type_gen/mod.rs +++ b/ast-generator/src/type_gen/mod.rs @@ -1,6 +1,7 @@ mod enum_type; mod leaf_enum_type; mod leaf_struct_type; +mod polymorphic_enum_loop_type; mod polymorphic_type_type; mod struct_type; @@ -11,6 +12,7 @@ use crate::type_gen::leaf_struct_type::make_leaf_struct_type; use crate::type_gen::polymorphic_type_type::make_polymorphic_type_type; use crate::type_gen::struct_type::make_struct_type; use proc_macro2::TokenStream; +use crate::type_gen::polymorphic_enum_loop_type::make_polymorphic_enum_loop_type; pub fn make_type(build_spec: &BuildSpec) -> Option { match build_spec { @@ -27,7 +29,9 @@ pub fn make_type(build_spec: &BuildSpec) -> Option { BuildSpec::PolymorphicType(polymorphic_build_spec) => { Some(make_polymorphic_type_type(polymorphic_build_spec)) } - BuildSpec::PolymorphicEnumLoop(_) => None, + BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_spec) => { + Some(make_polymorphic_enum_loop_type(polymorphic_enum_loop_spec)) + }, BuildSpec::PolymorphicPassThrough(_) => None, } } diff --git a/ast-generator/src/type_gen/polymorphic_enum_loop_type.rs b/ast-generator/src/type_gen/polymorphic_enum_loop_type.rs new file mode 100644 index 0000000..d8466a3 --- /dev/null +++ b/ast-generator/src/type_gen/polymorphic_enum_loop_type.rs @@ -0,0 +1,96 @@ +use crate::spec::polymorphic_enum_loop_spec::{PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuildChild}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub fn make_polymorphic_enum_loop_type(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream { + let type_ident = format_ident!("{}", spec.name()); + + let build = spec.rules() + .find(|rule| { + match rule { + PolymorphicEnumLoopRule::Build(_) => true, + _ => false + } + }) + .map(|rule| { + match rule { + PolymorphicEnumLoopRule::Build(build) => build, + _ => unreachable!() + } + }) + .unwrap(); + + let annotated_members = build.children() + .map(|child| { + match child { + PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => { + let child_ident = format_ident!("{}", use_current.name()); + let child_type_ident = format_ident!("{}", use_current.kind()); + quote! { + #child_ident: Box<#child_type_ident> + } + } + PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => { + let child_ident = format_ident!("{}", on_each.name()); + let child_type_ident = format_ident!("{}", on_each.rule()); + quote! { + #child_ident: Box<#child_type_ident> + } + } + } + }) + .collect::>(); + + let member_names = build.children() + .map(|child| { + match child { + PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => { + format_ident!("{}", use_current.name()) + } + PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => { + format_ident!("{}", on_each.name()) + } + } + }) + .collect::>(); + + let accessors = build.children() + .map(|child| { + let (child_ident, child_type_ident) = match child { + PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => { + (format_ident!("{}", use_current.name()), format_ident!("{}", use_current.kind())) + } + PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => { + (format_ident!("{}", on_each.name()), format_ident!("{}", on_each.rule())) + } + }; + let child_mut_ident = format_ident!("{}_mut", child_ident); + + quote! { + pub fn #child_ident(&self) -> &#child_type_ident { + self.#child_ident.as_ref() + } + + pub fn #child_mut_ident(&mut self) -> &mut #child_type_ident { + self.#child_ident.as_mut() + } + } + }) + .collect::>(); + + quote! { + pub struct #type_ident { + #(#annotated_members),* + } + + impl #type_ident { + pub fn new(#(#annotated_members),*) -> Self { + Self { + #(#member_names),* + } + } + + #(#accessors)* + } + } +}