Refactor build fn for struct nodes.

This commit is contained in:
Jesse Brault 2025-09-22 20:56:24 -05:00
parent 63643d86ba
commit 4d2e76338a
3 changed files with 86 additions and 72 deletions

View File

@ -1,8 +1,8 @@
pub(crate) mod enum_build_fn; pub mod enum_build_fn;
pub(crate) mod leaf_enum_build_fn; pub mod leaf_enum_build_fn;
pub(crate) mod leaf_struct_build_fn; pub mod leaf_struct_build_fn;
pub(crate) mod polymorphic_build_build_fn; pub mod polymorphic_build_build_fn;
pub(crate) mod polymorphic_build_fn; pub mod polymorphic_build_fn;
pub(crate) mod polymorphic_enum_build_fn; pub mod polymorphic_enum_build_fn;
pub(crate) mod production_build_fn; pub mod production_build_fn;
pub(crate) mod struct_build_fn; pub mod struct_build_fn;

View File

@ -1,32 +1,28 @@
use crate::spec::{ use crate::deserialize::util::{make_build_fn_name, make_build_pair};
BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, use crate::spec::struct_spec::{
VecChild, VecChildToBuild, MemberChildBuild, NodeMemberBuild, StructChild, StructSpec, VecChild, VecChildBuild,
}; };
use crate::util::{make_build_fn_name, make_build_pair};
use convert_case::{Case, Casing};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; 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 { fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name()); let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() { match vec_child.build() {
VecChildToBuild::Node(node_child) => { VecChildBuild::String(_) => {
let child_type_ident = format_ident!("{}", node_child.build());
quote! { quote! {
let mut #child_ident: Vec<Box<#child_type_ident >> = vec![] let mut #child_ident: Vec<String> = vec![]
}
}
VecChildBuild::Node(node_build) => {
let child_type_ident = format_ident!("{}", node_build.kind());
quote! {
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
} }
} }
VecChildToBuild::String => quote! {
let mut #child_ident: Vec<String> = vec![]
},
} }
} }
fn make_node_child_holder(name: &str, node_child: &NodeChildToBuild) -> TokenStream { fn make_node_child_holder(name: &str, node_child: &NodeMemberBuild) -> TokenStream {
let child_ident = format_ident!("{}", name); let child_ident = format_ident!("{}", name);
let child_type_ident = format_ident!("{}", node_child.kind()); let child_type_ident = format_ident!("{}", node_child.kind());
quote! { quote! {
@ -34,24 +30,22 @@ fn make_node_child_holder(name: &str, node_child: &NodeChildToBuild) -> TokenStr
} }
} }
fn make_boolean_child_holder(boolean_child: &BooleanChildToBuild) -> TokenStream { fn make_boolean_child_holder(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", boolean_child.name()); let child_ident = format_ident!("{}", name);
quote! { quote! {
let mut #child_ident: bool = false let mut #child_ident: bool = false
} }
} }
fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> { fn make_child_holder(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec { match child_spec {
StructChildSpec::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)), StructChild::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
StructChildSpec::MemberChild(member_child) => match member_child.build() { StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => { MemberChildBuild::Node(node_child) => {
Some(make_node_child_holder(member_child.name(), node_child)) Some(make_node_child_holder(member_child.name(), node_child))
} }
MemberChildToBuild::Boolean(boolean_child) => { MemberChildBuild::Boolean(_) => Some(make_boolean_child_holder(member_child.name())),
Some(make_boolean_child_holder(boolean_child))
}
}, },
} }
} }
@ -59,56 +53,56 @@ fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream { fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream {
let child_name_ident = format_ident!("{}", vec_child.name()); let child_name_ident = format_ident!("{}", vec_child.name());
match vec_child.build() { match vec_child.build() {
VecChildToBuild::Node(vec_node_child) => { VecChildBuild::String(string_build) => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(vec_node_child.build())); let build_fn_ident = format_ident!("{}", string_build.with());
quote! {
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
}
}
VecChildToBuild::String => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(vec_child.rule()));
quote! { quote! {
#child_name_ident.push(#build_fn_ident(inner_pair)) #child_name_ident.push(#build_fn_ident(inner_pair))
} }
} }
VecChildBuild::Node(node_build) => {
let build_fn_ident = format_ident!("{}", node_build.with());
quote! {
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
}
}
} }
} }
fn make_node_member_child_match_action(name: &str, node_child: &NodeChildToBuild) -> TokenStream { fn make_node_member_child_match_action(name: &str, node_child: &NodeMemberBuild) -> TokenStream {
let child_name_ident = format_ident!("{}", name); let child_name_ident = format_ident!("{}", name);
let build_fn_ident = format_ident!("{}", make_build_fn_name(node_child.kind())); let build_fn_ident = format_ident!("{}", node_child.with());
quote! { quote! {
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair))) #child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
} }
} }
fn make_boolean_member_child_match_action(boolean_child: &BooleanChildToBuild) -> TokenStream { fn make_boolean_member_child_match_action(name: &str) -> TokenStream {
let child_name_ident = format_ident!("{}", make_var_name(boolean_child.name())); let child_name_ident = format_ident!("{}", name);
quote! { quote! {
#child_name_ident = true #child_name_ident = true
} }
} }
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream { fn make_match_action(child_spec: &StructChild) -> TokenStream {
match child_spec { match child_spec {
StructChildSpec::SkipChild(_) => quote! {}, StructChild::SkipChild(_) => quote! {},
StructChildSpec::VecChild(vec_child) => make_vec_child_match_action(vec_child), StructChild::VecChild(vec_child) => make_vec_child_match_action(vec_child),
StructChildSpec::MemberChild(member_child) => match member_child.build() { StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => { MemberChildBuild::Node(node_child) => {
make_node_member_child_match_action(member_child.name(), node_child) make_node_member_child_match_action(member_child.name(), node_child)
} }
MemberChildToBuild::Boolean(boolean_child) => { MemberChildBuild::Boolean(_) => {
make_boolean_member_child_match_action(boolean_child) make_boolean_member_child_match_action(member_child.name())
} }
}, },
} }
} }
fn make_rule_matcher(child_spec: &StructChildSpec) -> TokenStream { fn make_rule_matcher(child_spec: &StructChild) -> TokenStream {
let rule_ident = match child_spec { let rule_ident = match child_spec {
StructChildSpec::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()), StructChild::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
StructChildSpec::VecChild(vec_child) => format_ident!("{}", vec_child.rule()), StructChild::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
StructChildSpec::MemberChild(single_child) => format_ident!("{}", single_child.rule()), StructChild::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
}; };
let action = make_match_action(child_spec); let action = make_match_action(child_spec);
@ -124,9 +118,13 @@ fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream {
quote! { #child_ident } quote! { #child_ident }
} }
fn make_node_member_child_arg(name: &str, node_child: &NodeChildToBuild) -> TokenStream { fn make_node_member_child_arg(
name: &str,
optional: bool,
node_child: &NodeMemberBuild,
) -> TokenStream {
let child_ident = format_ident!("{}", name); let child_ident = format_ident!("{}", name);
if node_child.optional() { if optional {
quote! { #child_ident } quote! { #child_ident }
} else if let Some(or_else) = node_child.or_else() { } else if let Some(or_else) = node_child.or_else() {
let child_type_ident = format_ident!("{}", node_child.kind()); let child_type_ident = format_ident!("{}", node_child.kind());
@ -139,28 +137,29 @@ fn make_node_member_child_arg(name: &str, node_child: &NodeChildToBuild) -> Toke
} }
} }
fn make_boolean_member_child_arg(boolean_child: &BooleanChildToBuild) -> TokenStream { fn make_boolean_member_child_arg(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", boolean_child.name()); let child_ident = format_ident!("{}", name);
quote! { #child_ident } quote! { #child_ident }
} }
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> { fn make_child_arg(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec { match child_spec {
StructChildSpec::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)), StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
StructChildSpec::MemberChild(member_child) => match member_child.build() { StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(single_type_child) => Some(make_node_member_child_arg( MemberChildBuild::Node(node_member_build) => Some(make_node_member_child_arg(
member_child.name(), member_child.name(),
single_type_child, member_child.optional(),
node_member_build,
)), )),
MemberChildToBuild::Boolean(boolean_child) => { MemberChildBuild::Boolean(_) => {
Some(make_boolean_member_child_arg(boolean_child)) Some(make_boolean_member_child_arg(member_child.name()))
} }
}, },
} }
} }
fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream { fn make_return_value_stream(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build()); let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec let child_args = build_spec
.children() .children()
@ -176,7 +175,7 @@ fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream {
} }
} }
pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { pub fn make_struct_build_fn(build_spec: &StructSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build())); 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 pair_ident = format_ident!("{}", make_build_pair(build_spec.build()));
let return_type_ident = format_ident!("{}", build_spec.build()); let return_type_ident = format_ident!("{}", build_spec.build());

View File

@ -14,7 +14,22 @@ fn deserialize_vec_child(child_name: &str, props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap(); let rule = props["rule"].as_str().unwrap();
let kind = props["kind"].as_str() let kind = props["kind"].as_str()
.unwrap_or(rule); .unwrap_or(rule);
StructChild::VecChild(VecChild::new(child_name, rule, kind)) if kind == "string" {
let build = VecChildBuild::String(VecChildStringBuild::new(
&make_build_fn_name(rule)
));
StructChild::VecChild(VecChild::new(
child_name,
rule,
Box::new(build),
))
} else {
let build = VecChildBuild::Node(VecChildNodeBuild::new(
rule,
&make_build_fn_name(rule)
));
StructChild::VecChild(VecChild::new(child_name, rule, Box::new(build)))
}
} }
fn deserialize_member_build(child_name: &str, rule: &str, props: &Yaml) -> MemberChildBuild { fn deserialize_member_build(child_name: &str, rule: &str, props: &Yaml) -> MemberChildBuild {