Refactor struct build-fn gen.
This commit is contained in:
parent
b5cdb8dd29
commit
5d640ca585
@ -1,141 +1,98 @@
|
|||||||
use crate::spec::{
|
use crate::spec::{BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild};
|
||||||
BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild,
|
use crate::util::{make_build_fn_name, make_build_pair};
|
||||||
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
use convert_case::{Case, Casing};
|
||||||
};
|
use proc_macro2::TokenStream;
|
||||||
use crate::util::make_build_pair;
|
|
||||||
use proc_macro2::{Ident, 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, child_type_ident) = match vec_child.build() {
|
let child_ident = format_ident!("{}", vec_child.name());
|
||||||
VecChildToBuild::Node(vec_type_child) => (
|
let child_type_ident = match vec_child.build() {
|
||||||
format_ident!("{}", vec_type_child.var_name()),
|
VecChildToBuild::Node(node_child) => {
|
||||||
format_ident!("{}", vec_type_child.build()),
|
format_ident!("{}", node_child.build())
|
||||||
),
|
},
|
||||||
|
VecChildToBuild::String => format_ident!("{}", "String")
|
||||||
};
|
};
|
||||||
quote! {
|
quote! {
|
||||||
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
|
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_single_type_child_holder(single_type_child: &NodeChildToBuild) -> TokenStream {
|
fn make_node_child_holder(node_child: &NodeChildToBuild) -> TokenStream {
|
||||||
let child_ident = format_ident!("{}", single_type_child.var_name());
|
let child_ident = format_ident!("{}", make_var_name(node_child.build()));
|
||||||
let child_type_ident = format_ident!("{}", single_type_child.build());
|
let child_type_ident = format_ident!("{}", node_child.build());
|
||||||
quote! {
|
quote! {
|
||||||
let mut #child_ident: Option<Box<#child_type_ident>> = None
|
let mut #child_ident: Option<Box<#child_type_ident>> = None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_single_boolean_child_holder(single_boolean_child: &BooleanChildToBuild) -> TokenStream {
|
fn make_boolean_child_holder(boolean_child: &BooleanChildToBuild) -> TokenStream {
|
||||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
let child_ident = format_ident!("{}", boolean_child.name());
|
||||||
quote! {
|
quote! {
|
||||||
let mut #child_ident: bool = false
|
let mut #child_ident: bool = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_literal_child_holder(
|
|
||||||
literal_child: &SingleLiteralChildToBuild,
|
|
||||||
literal_type_ident: Ident,
|
|
||||||
) -> TokenStream {
|
|
||||||
let child_ident = format_ident!("{}", literal_child.var_name());
|
|
||||||
quote! {
|
|
||||||
let mut #child_ident: Option<#literal_type_ident> = None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
||||||
match child_spec {
|
match child_spec {
|
||||||
StructChildSpec::SkipChild(_) => None,
|
StructChildSpec::SkipChild(_) => None,
|
||||||
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
|
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
|
||||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
StructChildSpec::MemberChild(member_child) => match member_child.build() {
|
||||||
MemberChildToBuild::Node(single_type_child) => {
|
MemberChildToBuild::Node(node_child) => {
|
||||||
Some(make_single_type_child_holder(single_type_child))
|
Some(make_node_child_holder(node_child))
|
||||||
}
|
}
|
||||||
MemberChildToBuild::Boolean(boolean_child) => {
|
MemberChildToBuild::Boolean(boolean_child) => {
|
||||||
Some(make_single_boolean_child_holder(boolean_child))
|
Some(make_boolean_child_holder(boolean_child))
|
||||||
}
|
}
|
||||||
MemberChildToBuild::Int(literal_child) => Some(make_literal_child_holder(
|
|
||||||
literal_child,
|
|
||||||
format_ident!("i32"),
|
|
||||||
)),
|
|
||||||
MemberChildToBuild::Long(literal_child) => Some(make_literal_child_holder(
|
|
||||||
literal_child,
|
|
||||||
format_ident!("i64"),
|
|
||||||
)),
|
|
||||||
MemberChildToBuild::Double(literal_child) => Some(make_literal_child_holder(
|
|
||||||
literal_child,
|
|
||||||
format_ident!("f64"),
|
|
||||||
)),
|
|
||||||
MemberChildToBuild::String(literal_child) => Some(make_literal_child_holder(
|
|
||||||
literal_child,
|
|
||||||
format_ident!("String"),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_literal_child_ident(literal_child: &SingleLiteralChildToBuild) -> Ident {
|
fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream {
|
||||||
format_ident!("{}", literal_child.var_name())
|
let child_name_ident = format_ident!("{}", vec_child.name());
|
||||||
|
let build_fn_ident = match vec_child.build() {
|
||||||
|
VecChildToBuild::Node(vec_node_child) => {
|
||||||
|
format_ident!("{}", make_build_fn_name(vec_node_child.build()))
|
||||||
|
},
|
||||||
|
VecChildToBuild::String => {
|
||||||
|
format_ident!("{}", make_build_fn_name(vec_child.rule()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_node_member_child_match_action(node_child: &NodeChildToBuild) -> TokenStream {
|
||||||
|
let child_name_ident = format_ident!("{}", make_var_name(node_child.build()));
|
||||||
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(node_child.build()));
|
||||||
|
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()));
|
||||||
|
quote! {
|
||||||
|
#child_name_ident = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream {
|
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream {
|
||||||
match child_spec {
|
match child_spec {
|
||||||
StructChildSpec::SkipChild(_) => quote! {},
|
StructChildSpec::SkipChild(_) => quote! {},
|
||||||
StructChildSpec::VecChild(vec_child) => {
|
StructChildSpec::VecChild(vec_child) => {
|
||||||
let (child_name_ident, build_fn_ident) = match vec_child.build() {
|
make_vec_child_match_action(vec_child)
|
||||||
VecChildToBuild::Node(vec_type_child) => (
|
|
||||||
format_ident!("{}", vec_type_child.var_name()),
|
|
||||||
format_ident!("{}", vec_type_child.with()),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
||||||
MemberChildToBuild::Node(single_type_child) => {
|
MemberChildToBuild::Node(node_child) => {
|
||||||
let child_name_ident = format_ident!("{}", single_type_child.var_name());
|
make_node_member_child_match_action(node_child)
|
||||||
let build_fn_ident = format_ident!("{}", single_type_child.with());
|
|
||||||
quote! {
|
|
||||||
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
MemberChildToBuild::Boolean(boolean_child) => {
|
||||||
let child_name_ident = format_ident!("{}", single_boolean_child.name());
|
make_boolean_member_child_match_action(boolean_child)
|
||||||
match single_boolean_child.build() {
|
|
||||||
BooleanBuild::RulePresent => quote! {
|
|
||||||
#child_name_ident = true
|
|
||||||
},
|
|
||||||
BooleanBuild::ParseWholePair => quote! {
|
|
||||||
#child_name_ident = Some(inner_pair.as_str().parse().unwrap())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Int(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
quote! {
|
|
||||||
#child_ident = Some(inner_pair.as_str().parse().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Long(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
quote! {
|
|
||||||
let as_string = inner_pair.as_str();
|
|
||||||
let without_el = &as_string[0..(as_string.len() - 1)];
|
|
||||||
#child_ident = Some(without_el.parse().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Double(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
quote! {
|
|
||||||
#child_ident = Some(inner_pair.as_str().parse().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberChildToBuild::String(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
quote! {
|
|
||||||
#child_ident = Some(inner_pair.as_str().to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -156,51 +113,43 @@ fn make_rule_matcher(child_spec: &StructChildSpec) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", vec_child.name());
|
||||||
|
quote! { #child_ident }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_node_member_child_arg(name: &str, node_child: &NodeChildToBuild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", name);
|
||||||
|
if node_child.optional() {
|
||||||
|
quote! { #child_ident }
|
||||||
|
} else if let Some(or_else) = node_child.or_else() {
|
||||||
|
let child_type_ident = format_ident!("{}", node_child.build());
|
||||||
|
let or_else_ident = format_ident!("{}", or_else);
|
||||||
|
quote! {
|
||||||
|
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! { #child_ident.unwrap() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_boolean_member_child_arg(boolean_child: &BooleanChildToBuild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", boolean_child.name());
|
||||||
|
quote! { #child_ident }
|
||||||
|
}
|
||||||
|
|
||||||
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
||||||
match child_spec {
|
match child_spec {
|
||||||
StructChildSpec::SkipChild(_) => None,
|
StructChildSpec::SkipChild(_) => None,
|
||||||
StructChildSpec::VecChild(vec_child) => {
|
StructChildSpec::VecChild(vec_child) => {
|
||||||
let child_ident = match vec_child.build() {
|
Some(make_vec_child_arg(vec_child))
|
||||||
VecChildToBuild::Node(vec_type_child) => {
|
|
||||||
format_ident!("{}", vec_type_child.var_name())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(quote! { #child_ident })
|
|
||||||
}
|
}
|
||||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
StructChildSpec::MemberChild(member_child) => match member_child.build() {
|
||||||
MemberChildToBuild::Node(single_type_child) => {
|
MemberChildToBuild::Node(single_type_child) => {
|
||||||
let child_ident = format_ident!("{}", single_type_child.var_name());
|
Some(make_node_member_child_arg(member_child.name(), single_type_child))
|
||||||
if single_type_child.optional() {
|
|
||||||
Some(quote! { #child_ident })
|
|
||||||
} else if let Some(or_else) = single_type_child.or_else() {
|
|
||||||
let child_type_ident = format_ident!("{}", single_type_child.build());
|
|
||||||
let or_else_ident = format_ident!("{}", or_else);
|
|
||||||
Some(quote! {
|
|
||||||
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Some(quote! { #child_ident.unwrap() })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
MemberChildToBuild::Boolean(boolean_child) => {
|
||||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
Some(make_boolean_member_child_arg(boolean_child))
|
||||||
Some(quote! { #child_ident })
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Int(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
Some(quote! { #child_ident.unwrap() })
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Long(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
Some(quote! { #child_ident.unwrap() })
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Double(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
Some(quote! { #child_ident.unwrap() })
|
|
||||||
}
|
|
||||||
MemberChildToBuild::String(literal_child) => {
|
|
||||||
let child_ident = get_literal_child_ident(literal_child);
|
|
||||||
Some(quote! { #child_ident.unwrap() })
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -210,7 +159,6 @@ fn make_return_value_stream(build_spec: &StructBuildSpec) -> 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()
|
||||||
.iter()
|
|
||||||
.map(|child| make_child_arg(child))
|
.map(|child| make_child_arg(child))
|
||||||
.filter(|child_arg| child_arg.is_some())
|
.filter(|child_arg| child_arg.is_some())
|
||||||
.map(|child_arg| child_arg.unwrap())
|
.map(|child_arg| child_arg.unwrap())
|
||||||
@ -224,13 +172,12 @@ 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: &StructBuildSpec) -> TokenStream {
|
||||||
let build_fn_ident = format_ident!("{}", build_spec.with()); // TODO: get rid of with
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build()));
|
||||||
let pair_ident = format_ident!("{}", make_build_pair(build_spec.var_name())); // TODO: get rid of var_name
|
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());
|
||||||
|
|
||||||
let child_holders = build_spec
|
let child_holders = build_spec
|
||||||
.children()
|
.children()
|
||||||
.iter()
|
|
||||||
.map(|child_spec| make_child_holder(child_spec))
|
.map(|child_spec| make_child_holder(child_spec))
|
||||||
.filter(|child_holder| child_holder.is_some())
|
.filter(|child_holder| child_holder.is_some())
|
||||||
.map(|child_holder| child_holder.unwrap())
|
.map(|child_holder| child_holder.unwrap())
|
||||||
@ -238,7 +185,6 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
|
|||||||
|
|
||||||
let rule_matchers = build_spec
|
let rule_matchers = build_spec
|
||||||
.children()
|
.children()
|
||||||
.iter()
|
|
||||||
.map(|child_spec| make_rule_matcher(child_spec))
|
.map(|child_spec| make_rule_matcher(child_spec))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@ -262,55 +208,4 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
|
|||||||
#new_stream
|
#new_stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::spec::VecNodeChildToBuild;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn vec_child_holder() {
|
|
||||||
let vec_child = VecChild::new(
|
|
||||||
"test_child",
|
|
||||||
"Test",
|
|
||||||
VecChildToBuild::Node(VecNodeChildToBuild::new(
|
|
||||||
"TestType",
|
|
||||||
"test_child",
|
|
||||||
"build_test_child",
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
make_vec_child_holder(&vec_child).to_string(),
|
|
||||||
quote! {
|
|
||||||
let mut test_child: Vec<Box<TestType>> = vec![]
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_type_child_holder() {
|
|
||||||
let single_type_child = NodeChildToBuild::from_build_or_rule("TestType", None, false);
|
|
||||||
assert_eq!(
|
|
||||||
make_single_type_child_holder(&single_type_child).to_string(),
|
|
||||||
quote! {
|
|
||||||
let mut test_type: Option<Box<TestType>> = None
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_boolean_child_holder() {
|
|
||||||
let single_boolean_child =
|
|
||||||
BooleanChildToBuild::new("test_child", BooleanBuild::RulePresent);
|
|
||||||
assert_eq!(
|
|
||||||
make_single_boolean_child_holder(&single_boolean_child).to_string(),
|
|
||||||
quote! {
|
|
||||||
let mut test_child: bool = false
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user