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(crate) mod leaf_enum_build_fn;
pub(crate) mod leaf_struct_build_fn;
pub(crate) mod polymorphic_build_build_fn;
pub(crate) mod polymorphic_build_fn;
pub(crate) mod polymorphic_enum_build_fn;
pub(crate) mod production_build_fn;
pub(crate) mod struct_build_fn;
pub mod enum_build_fn;
pub mod leaf_enum_build_fn;
pub mod leaf_struct_build_fn;
pub mod polymorphic_build_build_fn;
pub mod polymorphic_build_fn;
pub mod polymorphic_enum_build_fn;
pub mod production_build_fn;
pub mod struct_build_fn;

View File

@ -1,32 +1,28 @@
use crate::spec::{
BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec,
VecChild, VecChildToBuild,
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::struct_spec::{
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 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 {
let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildToBuild::Node(node_child) => {
let child_type_ident = format_ident!("{}", node_child.build());
VecChildBuild::String(_) => {
quote! {
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_type_ident = format_ident!("{}", node_child.kind());
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 {
let child_ident = format_ident!("{}", boolean_child.name());
fn make_boolean_child_holder(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", name);
quote! {
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 {
StructChildSpec::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_child) => {
Some(make_node_child_holder(member_child.name(), node_child))
}
MemberChildToBuild::Boolean(boolean_child) => {
Some(make_boolean_child_holder(boolean_child))
}
MemberChildBuild::Boolean(_) => Some(make_boolean_child_holder(member_child.name())),
},
}
}
@ -59,56 +53,56 @@ fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream {
let child_name_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildToBuild::Node(vec_node_child) => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(vec_node_child.build()));
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()));
VecChildBuild::String(string_build) => {
let build_fn_ident = format_ident!("{}", string_build.with());
quote! {
#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 build_fn_ident = format_ident!("{}", make_build_fn_name(node_child.kind()));
let build_fn_ident = format_ident!("{}", node_child.with());
quote! {
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
}
}
fn make_boolean_member_child_match_action(boolean_child: &BooleanChildToBuild) -> TokenStream {
let child_name_ident = format_ident!("{}", make_var_name(boolean_child.name()));
fn make_boolean_member_child_match_action(name: &str) -> TokenStream {
let child_name_ident = format_ident!("{}", name);
quote! {
#child_name_ident = true
}
}
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream {
fn make_match_action(child_spec: &StructChild) -> TokenStream {
match child_spec {
StructChildSpec::SkipChild(_) => quote! {},
StructChildSpec::VecChild(vec_child) => make_vec_child_match_action(vec_child),
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => {
StructChild::SkipChild(_) => quote! {},
StructChild::VecChild(vec_child) => make_vec_child_match_action(vec_child),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_child) => {
make_node_member_child_match_action(member_child.name(), node_child)
}
MemberChildToBuild::Boolean(boolean_child) => {
make_boolean_member_child_match_action(boolean_child)
MemberChildBuild::Boolean(_) => {
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 {
StructChildSpec::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
StructChildSpec::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
StructChildSpec::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
StructChild::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
StructChild::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
StructChild::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
};
let action = make_match_action(child_spec);
@ -124,9 +118,13 @@ fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream {
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);
if node_child.optional() {
if optional {
quote! { #child_ident }
} else if let Some(or_else) = node_child.or_else() {
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 {
let child_ident = format_ident!("{}", boolean_child.name());
fn make_boolean_member_child_arg(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", name);
quote! { #child_ident }
}
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> {
fn make_child_arg(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec {
StructChildSpec::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(single_type_child) => Some(make_node_member_child_arg(
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_member_build) => Some(make_node_member_child_arg(
member_child.name(),
single_type_child,
member_child.optional(),
node_member_build,
)),
MemberChildToBuild::Boolean(boolean_child) => {
Some(make_boolean_member_child_arg(boolean_child))
MemberChildBuild::Boolean(_) => {
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 child_args = build_spec
.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 pair_ident = format_ident!("{}", make_build_pair(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 kind = props["kind"].as_str()
.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 {