Refactor struct type.

This commit is contained in:
Jesse Brault 2025-09-23 18:07:04 -05:00
parent 1565abace5
commit 2986bbe37e
2 changed files with 213 additions and 451 deletions

View File

@ -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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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<TokenStream> = 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::<Vec<_>>();
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}
fn handle_vec_child(
vec_child: &VecChild,
member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
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<Box<#child_type_ident>>
});
member_args.push(quote! {
#child_ident: Vec<Box<#child_type_ident>>
});
}
VecChildToBuild::String => {
annotated_members.push(quote! {
#child_ident: Vec<String>
});
member_args.push(quote! {
#child_ident: Vec<String>
})
}
}
match vec_child.build() {
VecChildToBuild::Node(_) => {
accessors.push(quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &#child_type_ident> {
self.#child_ident.iter().map(Box::as_ref)
}
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut #child_type_ident> {
self.#child_ident.iter_mut().map(Box::as_mut)
}
});
}
VecChildToBuild::String => accessors.push(quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &str> {
self.#child_ident.iter().map(String::as_str)
}
}),
}
}
fn handle_node_child(
name: &str,
node_child: &NodeChildToBuild,
member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
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<Box<#child_type_ident>>
});
member_args.push(quote! {
#child_ident: Option<Box<#child_type_ident>>
});
} 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<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
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<Ident> = vec![];
let mut annotated_members: Vec<TokenStream> = vec![];
let mut member_args: Vec<TokenStream> = vec![];
let mut accessors: Vec<TokenStream> = 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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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<TokenStream> {
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,
}
}

View File

@ -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<Item = &str> {
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<Item = &#child_type_ident> {
self.#child_ident.iter().map(Box::as_ref)
}
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut child_type_ident> {
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<TokenStream> {
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<Ident> {
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<TokenStream> {
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::<Vec<_>>();
let member_names = build_spec.children()
.map(|child| {
make_member_ident(child)
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let accessors = build_spec.children()
.map(|child| {
make_accessors(child)
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
quote! {
pub struct #type_ident {
#(#annotated_members),*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#member_names),*
}
}
#(#accessors)*
}
}
}