From 2986bbe37e36454420785021f8f94f3dd42a5312 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Tue, 23 Sep 2025 18:07:04 -0500 Subject: [PATCH] Refactor struct type. --- ast-generator/src/type_gen/mod.rs | 471 +--------------------- ast-generator/src/type_gen/struct_type.rs | 193 +++++++++ 2 files changed, 213 insertions(+), 451 deletions(-) create mode 100644 ast-generator/src/type_gen/struct_type.rs diff --git a/ast-generator/src/type_gen/mod.rs b/ast-generator/src/type_gen/mod.rs index 4b897eb..aac4858 100644 --- a/ast-generator/src/type_gen/mod.rs +++ b/ast-generator/src/type_gen/mod.rs @@ -1,464 +1,33 @@ -use crate::spec::{ - AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec, - EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind, - MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec, - StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, -}; -use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote}; +mod enum_type; +mod leaf_enum_type; +mod leaf_struct_type; +mod polymorphic_type_type; +mod struct_type; -fn make_polymorphic_build_type(build_spec: &PolymorphicBuildBuildSpec) -> TokenStream { - let alternative_action = build_spec - .alternatives() - .find(|alternative| { - if let AlternativeAction::Build(_) = alternative.action() { - true - } else { - false - } - }) - .unwrap(); - - let alternative_build = - if let AlternativeAction::Build(alternative_build) = alternative_action.action() { - alternative_build - } else { - unreachable!() - }; - - let annotated_members = alternative_build - .children() - .map(|child| match child { - AlternativeChild::Skip => None, - AlternativeChild::Build(build_child) => { - let child_name_ident = format_ident!("{}", build_child.name()); - let type_ident = format_ident!("{}", build_child.kind()); - Some(quote! { - #child_name_ident: Box<#type_ident> - }) - } - }) - .filter(Option::is_some) - .map(Option::unwrap) - .collect::>(); - - let initializers = alternative_build - .children() - .map(|child| match child { - AlternativeChild::Skip => None, - AlternativeChild::Build(build_child) => Some(format_ident!("{}", build_child.name())), - }) - .filter(Option::is_some) - .map(Option::unwrap) - .collect::>(); - - let accessors = alternative_build - .children() - .map(|child| match child { - AlternativeChild::Skip => None, - AlternativeChild::Build(build_child) => { - let child_ident = format_ident!("{}", build_child.name()); - let child_ident_mut = format_ident!("{}_mut", build_child.name()); - let child_type_ident = format_ident!("{}", build_child.kind()); - Some(quote! { - pub fn #child_ident(&self) -> &#child_type_ident { - &self.#child_ident - } - - pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident { - &mut self.#child_ident - } - }) - } - }) - .collect::>(); - - let type_ident = format_ident!("{}", build_spec.name()); - - quote! { - pub struct #type_ident { - #(#annotated_members),* - } - - impl #type_ident { - pub fn new(#(#annotated_members),*) -> Self { - Self { - #(#initializers),* - } - } - - #(#accessors)* - } - } -} - -fn make_polymorphic_type_type(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream { - let members = build_spec - .enum_members() - .map(|enum_member| { - let member_ident = format_ident!("{}", enum_member.name()); - let inner_type_ident = format_ident!("{}", enum_member.inner_kind()); - quote! { - #member_ident(#inner_type_ident) - } - }) - .collect::>(); - let type_name_ident = format_ident!("{}", build_spec.name()); - quote! { - pub enum #type_name_ident { - #(#members),* - } - } -} - -fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream { - let children: Vec = build_spec - .rules() - .map(|enum_rule| { - let member_name_ident = format_ident!("{}", enum_rule.rule()); - if let Some(enum_rule_child) = enum_rule.child() { - let child_type_ident = match enum_rule_child.kind() { - EnumRuleChildKind::Node(node_child) => { - format_ident!("{}", node_child.build()) - } - EnumRuleChildKind::Int => format_ident!("i32"), - EnumRuleChildKind::Long => format_ident!("i64"), - EnumRuleChildKind::Double => format_ident!("f64"), - EnumRuleChildKind::USize => format_ident!("usize"), - EnumRuleChildKind::String => format_ident!("String"), - EnumRuleChildKind::Boolean => format_ident!("bool"), - }; - quote! { - #member_name_ident(#child_type_ident) - } - } else { - quote! { - #member_name_ident - } - } - }) - .collect(); - let type_name_ident = format_ident!("{}", build_spec.build()); - quote! { - pub enum #type_name_ident { - #(#children),* - } - } -} - -fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream { - let type_name_ident = format_ident!("{}", build_spec.build()); - let children = build_spec - .rules() - .map(|leaf_enum_rule| { - let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule()); - quote! { - #rule_name_ident - } - }) - .collect::>(); - - quote! { - pub enum #type_name_ident { - #(#children),* - } - } -} - -fn handle_vec_child( - vec_child: &VecChild, - member_names: &mut Vec, - annotated_members: &mut Vec, - member_args: &mut Vec, - accessors: &mut Vec, -) { - let (child_ident, child_ident_mut) = ( - format_ident!("{}", vec_child.name()), - format_ident!("{}_mut", vec_child.name()), - ); - let child_type_ident = match vec_child.build() { - VecChildToBuild::Node(vec_node_child) => format_ident!("{}", vec_node_child.build()), - VecChildToBuild::String => format_ident!("{}", "String"), - }; - - member_names.push(child_ident.clone()); - - match vec_child.build() { - VecChildToBuild::Node(_) => { - annotated_members.push(quote! { - #child_ident: Vec> - }); - member_args.push(quote! { - #child_ident: Vec> - }); - } - VecChildToBuild::String => { - annotated_members.push(quote! { - #child_ident: Vec - }); - member_args.push(quote! { - #child_ident: Vec - }) - } - } - - match vec_child.build() { - VecChildToBuild::Node(_) => { - accessors.push(quote! { - pub fn #child_ident(&self) -> impl Iterator { - self.#child_ident.iter().map(Box::as_ref) - } - - pub fn #child_ident_mut(&mut self) -> impl Iterator { - self.#child_ident.iter_mut().map(Box::as_mut) - } - }); - } - VecChildToBuild::String => accessors.push(quote! { - pub fn #child_ident(&self) -> impl Iterator { - self.#child_ident.iter().map(String::as_str) - } - }), - } -} - -fn handle_node_child( - name: &str, - node_child: &NodeChildToBuild, - member_names: &mut Vec, - annotated_members: &mut Vec, - member_args: &mut Vec, - accessors: &mut Vec, -) { - let child_ident = format_ident!("{}", name); - let child_ident_mut = format_ident!("{}_mut", name); - let child_type_ident = format_ident!("{}", node_child.kind()); - - member_names.push(child_ident.clone()); - - if node_child.optional() { - annotated_members.push(quote! { - #child_ident: Option> - }); - member_args.push(quote! { - #child_ident: Option> - }); - } else { - annotated_members.push(quote! { - #child_ident: Box<#child_type_ident> - }); - member_args.push(quote! { - #child_ident: Box<#child_type_ident> - }) - } - if node_child.optional() { - accessors.push(quote! { - pub fn #child_ident(&self) -> Option<&#child_type_ident> { - if let Some(#child_ident) = &self.#child_ident { - Some(#child_ident.as_ref()) - } else { - None - } - } - - pub fn #child_ident_mut(&mut self) -> Option<&mut #child_type_ident> { - if let Some(#child_ident) = &mut self.#child_ident { - Some(#child_ident.as_mut()) - } else { - None - } - } - }); - } else { - accessors.push(quote! { - pub fn #child_ident(&self) -> &#child_type_ident { - self.#child_ident.as_ref() - } - - pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident { - self.#child_ident.as_mut() - } - }); - } -} - -fn handle_boolean_child( - single_boolean_child: &BooleanChildToBuild, - member_names: &mut Vec, - annotated_members: &mut Vec, - member_args: &mut Vec, - accessors: &mut Vec, -) { - let child_ident = format_ident!("{}", single_boolean_child.name()); - member_names.push(child_ident.clone()); - annotated_members.push(quote! { - #child_ident: bool - }); - member_args.push(quote! { - #child_ident: bool - }); - accessors.push(quote! { - pub fn #child_ident(&self) -> bool { - self.#child_ident - } - }); -} - -fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream { - let mut member_names: Vec = vec![]; - let mut annotated_members: Vec = vec![]; - let mut member_args: Vec = vec![]; - let mut accessors: Vec = vec![]; - - for child_spec in build_spec.children() { - match child_spec { - StructChildSpec::SkipChild(_) => {} - StructChildSpec::VecChild(vec_child) => { - handle_vec_child( - vec_child, - &mut member_names, - &mut annotated_members, - &mut member_args, - &mut accessors, - ); - } - StructChildSpec::MemberChild(member_child) => { - match member_child.build() { - MemberChildToBuild::Node(node_child) => { - handle_node_child( - member_child.name(), - node_child, - &mut member_names, - &mut annotated_members, - &mut member_args, - &mut accessors, - ); - } - MemberChildToBuild::Boolean(boolean_child) => { - handle_boolean_child( - boolean_child, - &mut member_names, - &mut annotated_members, - &mut member_args, - &mut accessors, - ); - } - }; - } - } - } - - let type_ident = format_ident!("{}", build_spec.build()); - - quote! { - pub struct #type_ident { - #(#annotated_members),* - } - - impl #type_ident { - pub fn new(#(#annotated_members),*) -> Self { - Self { - #(#member_names),* - } - } - - #(#accessors)* - } - } -} - -fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream { - let type_ident = format_ident!("{}", build_spec.build()); - - let annotated_members = build_spec - .members() - .map(|member| { - let name_ident = format_ident!("{}", member.name()); - let type_ident = match member.kind() { - LeafStructMemberKind::String => format_ident!("{}", "String"), - }; - quote! { - #name_ident: #type_ident - } - }) - .collect::>(); - - let member_args = build_spec.members().map(|member| { - let name_ident = format_ident!("{}", member.name()); - let type_stream = match member.kind() { - LeafStructMemberKind::String => { - quote! { &str } - } - }; - quote! { - #name_ident: #type_stream - } - }); - - let initializers = build_spec - .members() - .map(|leaf_struct_member| { - let member_ident = format_ident!("{}", leaf_struct_member.name()); - match leaf_struct_member.kind() { - LeafStructMemberKind::String => { - quote! { - #member_ident: #member_ident.to_string() - } - } - } - }) - .collect::>(); - - let accessors = build_spec - .members() - .map(|member| { - let name_ident = format_ident!("{}", member.name()); - match member.kind() { - LeafStructMemberKind::String => { - quote! { - pub fn #name_ident(&self) -> &str { - &self.#name_ident - } - } - } - } - }) - .collect::>(); - - quote! { - pub struct #type_ident { - #(#annotated_members),* - } - - impl #type_ident { - pub fn new(#(#member_args),*) -> Self { - Self { - #(#initializers),* - } - } - - #(#accessors)* - } - } -} +use crate::spec::BuildSpec; +use crate::type_gen::enum_type::make_enum_type; +use crate::type_gen::leaf_enum_type::make_leaf_enum_type; +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; pub fn make_type(build_spec: &BuildSpec) -> Option { match build_spec { - BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)), - BuildSpec::LeafEnum(leaf_enum_build_spec) => { - Some(make_leaf_enum_type(leaf_enum_build_spec)) - } BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)), BuildSpec::LeafStruct(leaf_struct_build_spec) => { Some(make_leaf_struct_type(leaf_struct_build_spec)) } + BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)), + BuildSpec::LeafEnum(leaf_enum_build_spec) => { + Some(make_leaf_enum_type(leaf_enum_build_spec)) + } BuildSpec::Production(_) => None, - BuildSpec::Polymorphic(polymorphic_build_spec) => { + BuildSpec::NodeProduction(_) => None, + BuildSpec::PolymorphicType(polymorphic_build_spec) => { Some(make_polymorphic_type_type(polymorphic_build_spec)) } - BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => { - Some(make_polymorphic_build_type(polymorphic_build_build_spec)) - } - BuildSpec::PolymorphicEnum(_) => None, + BuildSpec::PolymorphicEnumLoop(_) => None, + BuildSpec::PolymorphicPassThrough(_) => None, } } diff --git a/ast-generator/src/type_gen/struct_type.rs b/ast-generator/src/type_gen/struct_type.rs new file mode 100644 index 0000000..c705a94 --- /dev/null +++ b/ast-generator/src/type_gen/struct_type.rs @@ -0,0 +1,193 @@ +use crate::spec::struct_spec::{MemberChild, MemberChildBuild, StructChild, StructSpec, VecChild, VecChildBuild}; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; + +fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream { + let child_ident = format_ident!("{}", vec_child.name()); + match vec_child.build() { + VecChildBuild::String(_) => { + quote! { + pub fn #child_ident(&self) -> impl Iterator { + self.#child_ident.iter().map(String::as_str) + } + } + }, + VecChildBuild::Node(vec_child_node_build) => { + let child_type_ident = format_ident!("{}", vec_child_node_build.kind()); + let child_ident_mut = format_ident!("{}_mut", vec_child.name()); + + quote! { + pub fn #child_ident(&self) -> impl Iterator { + self.#child_ident.iter().map(Box::as_ref) + } + + pub fn #child_ident_mut(&mut self) -> impl Iterator { + self.#child_ident.iter().map(Box::as_mut) + } + } + } + } +} + +fn make_member_child_accessors(member_child: &MemberChild) -> TokenStream { + let child_ident = format_ident!("{}", member_child.name()); + match member_child.build() { + MemberChildBuild::Node(node_member_build) => { + let return_type_ident = format_ident!("{}", node_member_build.kind()); + let child_ident_mut = format_ident!("{}_mut", member_child.name()); + + if member_child.optional() { + quote! { + pub fn #child_ident(&self) -> Option<&#return_type_ident> { + if let Some(#child_ident) = &self.#child_ident { + Some(#child_ident.as_ref()) + } else { + None + } + } + + pub fn #child_ident_mut(&mut self) -> Option<&mut #return_type_ident> { + if let Some(#child_ident) = &mut self.#child_ident { + Some(#child_ident.as_mut()) + } else { + None + } + } + } + } else { + quote! { + pub fn #child_ident(&self) -> &#return_type_ident { + self.#child_ident.as_ref() + } + + pub fn #child_ident_mut(&mut self) -> &mut #return_type_ident { + self.#child_ident.as_mut() + } + } + } + } + MemberChildBuild::Boolean(_) => { + quote! { + pub fn #child_ident(&self) -> bool { + self.#child_ident + } + } + } + } +} + +fn make_accessors(child: &StructChild) -> Option { + match child { + StructChild::SkipChild(_) => None, + StructChild::VecChild(vec_child) => { + Some(make_vec_child_accessors(vec_child)) + } + StructChild::MemberChild(member_child) => { + Some(make_member_child_accessors(member_child)) + } + } +} + +fn make_member_ident(child: &StructChild) -> Option { + match child { + StructChild::SkipChild(_) => None, + StructChild::VecChild(vec_child) => { + Some(format_ident!("{}", vec_child.name())) + }, + StructChild::MemberChild(member_child) => { + Some(format_ident!("{}", member_child.name())) + } + } +} + +fn make_vec_child_annotated_member(vec_child: &VecChild) -> TokenStream { + let child_ident = format_ident!("{}", vec_child.name()); + let type_stream = match vec_child.build() { + VecChildBuild::String(_) => quote! { String }, + VecChildBuild::Node(vec_child_node_build) => { + let type_ident = format_ident!("{}", vec_child_node_build.kind()); + quote! { Box<#type_ident> } + }, + }; + + quote! { + #child_ident: Vec<#type_stream> + } +} + +fn make_member_child_type_ident(member_child: &MemberChild) -> TokenStream { + match member_child.build() { + MemberChildBuild::Node(node_member_build) => { + let type_ident = format_ident!("{}", node_member_build.kind()); + quote! { #type_ident } + }, + MemberChildBuild::Boolean(_) => { + quote! { bool } + } + } +} + +fn make_member_child_annotated_member(member_child: &MemberChild) -> TokenStream { + let child_name_ident = format_ident!("{}", member_child.name()); + let type_ident = make_member_child_type_ident(member_child); + let type_stream = if member_child.optional() { + quote! { Option<#type_ident> } + } else { + type_ident + }; + + quote! { + #child_name_ident: #type_stream + } +} + +fn make_annotated_member(child: &StructChild) -> Option { + match child { + StructChild::SkipChild(_) => None, + StructChild::VecChild(vec_child) => Some(make_vec_child_annotated_member(vec_child)), + StructChild::MemberChild(member_child) => Some(make_member_child_annotated_member(member_child)), + } +} + +pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { + let type_ident = format_ident!("{}", build_spec.build()); + let annotated_members = build_spec.children() + .map(|child| { + make_annotated_member(child) + }) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + + let member_names = build_spec.children() + .map(|child| { + make_member_ident(child) + }) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + + let accessors = build_spec.children() + .map(|child| { + make_accessors(child) + }) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + + quote! { + pub struct #type_ident { + #(#annotated_members),* + } + + impl #type_ident { + pub fn new(#(#annotated_members),*) -> Self { + Self { + #(#member_names),* + } + } + + #(#accessors)* + } + } +}