Add return value to build fn.
This commit is contained in:
parent
0adb4bbe0e
commit
0a97cc01b9
@ -90,6 +90,57 @@ fn make_rule_matcher(child_spec: &ChildSpec) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_child_arg(child_spec: &ChildSpec) -> Option<TokenStream> {
|
||||||
|
match child_spec {
|
||||||
|
ChildSpec::SkipChild(_) => None,
|
||||||
|
ChildSpec::VecChild(vec_child) => {
|
||||||
|
let child_ident = match vec_child.build() {
|
||||||
|
VecChildToBuild::Type(vec_type_child) => format_ident!("{}", vec_type_child.var_name())
|
||||||
|
};
|
||||||
|
Some(quote! { #child_ident })
|
||||||
|
},
|
||||||
|
ChildSpec::SingleChild(single_child) => {
|
||||||
|
match single_child.build() {
|
||||||
|
SingleChildToBuild::Type(single_type_child) => {
|
||||||
|
let child_ident = format_ident!("{}", single_type_child.var_name());
|
||||||
|
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() })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SingleChildToBuild::Boolean(single_boolean_child) => {
|
||||||
|
let child_ident = format_ident!("{}", single_boolean_child.var_name());
|
||||||
|
Some(quote! { #child_ident })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream {
|
||||||
|
let type_ident = format_ident!("{}", build_spec.build());
|
||||||
|
let child_args = build_spec
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.map(|child| make_child_arg(child))
|
||||||
|
.filter(|child_arg| child_arg.is_some())
|
||||||
|
.map(|child_arg| child_arg.unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#type_ident::new(
|
||||||
|
#(#child_args,)*
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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());
|
let build_fn_ident = format_ident!("{}", build_spec.with());
|
||||||
let pair_ident = format_ident!("{}_pair", build_spec.build().to_case(Case::Snake));
|
let pair_ident = format_ident!("{}_pair", build_spec.build().to_case(Case::Snake));
|
||||||
@ -117,11 +168,15 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let new_stream = make_return_value_stream(build_spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||||
#(#child_holders;)*
|
#(#child_holders;)*
|
||||||
|
|
||||||
#iter_stream
|
#iter_stream
|
||||||
|
|
||||||
|
#new_stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,8 @@ fn get_vec_child(name: &str, rule: &str, build: &Yaml) -> ChildSpec {
|
|||||||
|
|
||||||
fn get_single_child_to_build(name: &str, rule: &str, optional: bool, build: &Yaml) -> SingleChildToBuild {
|
fn get_single_child_to_build(name: &str, rule: &str, optional: bool, build: &Yaml) -> SingleChildToBuild {
|
||||||
if build.is_hash() {
|
if build.is_hash() {
|
||||||
let r#type = build["type"].as_str().unwrap();
|
match build["type"].as_str() {
|
||||||
|
Some(r#type) => {
|
||||||
let var_name = build["var"]
|
let var_name = build["var"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
@ -62,20 +63,41 @@ fn get_single_child_to_build(name: &str, rule: &str, optional: bool, build: &Yam
|
|||||||
} else {
|
} else {
|
||||||
todo!("currently on boolean types with on: rule_present are supported")
|
todo!("currently on boolean types with on: rule_present are supported")
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let or_else = build["or_else"]
|
||||||
|
.as_str()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.or_else(|| {
|
||||||
|
let or_else_default = build["or_else_default"]
|
||||||
|
.as_bool()
|
||||||
|
.unwrap_or_else(|| false);
|
||||||
|
if or_else_default {
|
||||||
|
Some(String::from("default"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
||||||
|
rule,
|
||||||
|
or_else,
|
||||||
|
optional,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match build.as_str() {
|
match build.as_str() {
|
||||||
Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s, optional)),
|
Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s, None, optional)),
|
||||||
None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule, optional)),
|
None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule, None, optional)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_single_child(name: &str, rule: &str, optional: bool, or_else: Option<String>, build: &Yaml) -> ChildSpec {
|
fn get_single_child(name: &str, rule: &str, optional: bool, build: &Yaml) -> ChildSpec {
|
||||||
ChildSpec::SingleChild(SingleChild::new(
|
ChildSpec::SingleChild(SingleChild::new(
|
||||||
name,
|
name,
|
||||||
rule,
|
rule,
|
||||||
get_single_child_to_build(name, rule, optional, build),
|
get_single_child_to_build(name, rule, optional, build),
|
||||||
or_else
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,21 +132,8 @@ fn get_child_specs(children: &Yaml) -> Vec<ChildSpec> {
|
|||||||
let optional = props["optional"]
|
let optional = props["optional"]
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or_else(|| false);
|
.unwrap_or_else(|| false);
|
||||||
let or_else = props["or_else"]
|
|
||||||
.as_str()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.or_else(|| {
|
|
||||||
let or_else_default = props["or_else_default"]
|
|
||||||
.as_bool()
|
|
||||||
.unwrap_or_else(|| false);
|
|
||||||
if or_else_default {
|
|
||||||
Some(String::from("default"))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
get_single_child(name, &rule, optional, or_else, build)
|
get_single_child(name, &rule, optional, build)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap()))
|
ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap()))
|
||||||
|
@ -9,6 +9,7 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
use spec::BuildSpec;
|
use spec::BuildSpec;
|
||||||
use syn::File;
|
use syn::File;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
||||||
println!("*** BuildSpec ***");
|
println!("*** BuildSpec ***");
|
||||||
|
@ -224,7 +224,6 @@ pub struct SingleChild {
|
|||||||
name: String,
|
name: String,
|
||||||
rule: String,
|
rule: String,
|
||||||
build: SingleChildToBuild,
|
build: SingleChildToBuild,
|
||||||
or_else: Option<String>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleChild {
|
impl SingleChild {
|
||||||
@ -234,18 +233,17 @@ impl SingleChild {
|
|||||||
rule: name.to_case(Case::Pascal),
|
rule: name.to_case(Case::Pascal),
|
||||||
build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
||||||
&name.to_case(Case::Pascal),
|
&name.to_case(Case::Pascal),
|
||||||
|
None,
|
||||||
false,
|
false,
|
||||||
)),
|
)),
|
||||||
or_else: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(name: &str, rule: &str, build: SingleChildToBuild, or_else: Option<String>) -> Self {
|
pub fn new(name: &str, rule: &str, build: SingleChildToBuild) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
rule: rule.to_string(),
|
rule: rule.to_string(),
|
||||||
build,
|
build,
|
||||||
or_else,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,15 +274,21 @@ pub struct SingleTypeChildToBuild {
|
|||||||
build: String,
|
build: String,
|
||||||
var_name: String,
|
var_name: String,
|
||||||
with: String,
|
with: String,
|
||||||
|
or_else: Option<String>,
|
||||||
optional: bool,
|
optional: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleTypeChildToBuild {
|
impl SingleTypeChildToBuild {
|
||||||
pub fn from_build_or_rule(build_or_rule: &str, optional: bool) -> Self {
|
pub fn from_build_or_rule(
|
||||||
|
build_or_rule: &str,
|
||||||
|
or_else: Option<String>,
|
||||||
|
optional: bool,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
build: build_or_rule.to_string(),
|
build: build_or_rule.to_string(),
|
||||||
var_name: build_or_rule.to_case(Case::Snake),
|
var_name: build_or_rule.to_case(Case::Snake),
|
||||||
with: make_build_fn_name(build_or_rule),
|
with: make_build_fn_name(build_or_rule),
|
||||||
|
or_else,
|
||||||
optional,
|
optional,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,6 +308,11 @@ impl SingleTypeChildToBuild {
|
|||||||
&self.with
|
&self.with
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The default fn to call when unwrapping the child (before passing as arg to new).
|
||||||
|
pub fn or_else(&self) -> Option<&str> {
|
||||||
|
self.or_else.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
/// If the type should be wrapped in an Option.
|
/// If the type should be wrapped in an Option.
|
||||||
pub fn optional(&self) -> bool {
|
pub fn optional(&self) -> bool {
|
||||||
self.optional
|
self.optional
|
||||||
|
@ -82,12 +82,6 @@ $defs:
|
|||||||
optional:
|
optional:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If true, this child will be stored as an Option.
|
description: If true, this child will be stored as an Option.
|
||||||
or_else:
|
|
||||||
type: string
|
|
||||||
description: The method name to call upon the built-type if the rule is not found. Takes precedence over "or_else_default".
|
|
||||||
or_else_default:
|
|
||||||
type: boolean
|
|
||||||
description: Whether to call the default method on the built-type if the rule is not found.
|
|
||||||
build:
|
build:
|
||||||
oneOf:
|
oneOf:
|
||||||
- type: string
|
- type: string
|
||||||
@ -97,7 +91,19 @@ $defs:
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
description: A definition of what exactly to build for a given child rule.
|
description: A definition of what exactly to build for a given child rule.
|
||||||
oneOf:
|
oneOf:
|
||||||
|
- $ref: "#/$defs/BuildSingleTypeChild"
|
||||||
- $ref: "#/$defs/BuildBooleanChild"
|
- $ref: "#/$defs/BuildBooleanChild"
|
||||||
|
BuildSingleTypeChild:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
description: A definition of a single-type child to build.
|
||||||
|
properties:
|
||||||
|
or_else:
|
||||||
|
type: string
|
||||||
|
description: The method name to call upon the built-type if the rule is not found. Takes precedence over "or_else_default".
|
||||||
|
or_else_default:
|
||||||
|
type: boolean
|
||||||
|
description: Whether to call the default method on the built-type if the rule is not found.
|
||||||
BuildBooleanChild:
|
BuildBooleanChild:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
@ -112,8 +112,10 @@ Interface:
|
|||||||
skip: true
|
skip: true
|
||||||
- identifier
|
- identifier
|
||||||
- generic_parameters:
|
- generic_parameters:
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- implements_list:
|
- implements_list:
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- declarations:
|
- declarations:
|
||||||
rule: InterfaceLevelDeclaration
|
rule: InterfaceLevelDeclaration
|
||||||
@ -133,10 +135,13 @@ Class:
|
|||||||
skip: true
|
skip: true
|
||||||
- identifier
|
- identifier
|
||||||
- generic_parameters:
|
- generic_parameters:
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- class_constructor:
|
- class_constructor:
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- implements_list:
|
- implements_list:
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- class_level_declarations:
|
- class_level_declarations:
|
||||||
rule: ClassLevelDeclaration
|
rule: ClassLevelDeclaration
|
||||||
@ -155,10 +160,10 @@ Function:
|
|||||||
skip: true
|
skip: true
|
||||||
- generics:
|
- generics:
|
||||||
rule: GenericParameters
|
rule: GenericParameters
|
||||||
or_else_default: true
|
|
||||||
- identifier
|
- identifier
|
||||||
- parameters
|
- parameters
|
||||||
- return_type:
|
- return_type:
|
||||||
|
build:
|
||||||
or_else: void
|
or_else: void
|
||||||
- function_body
|
- function_body
|
||||||
OperatorFunction:
|
OperatorFunction:
|
||||||
@ -173,10 +178,12 @@ OperatorFunction:
|
|||||||
skip: true
|
skip: true
|
||||||
- generics:
|
- generics:
|
||||||
rule: GenericParameters
|
rule: GenericParameters
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- operator
|
- operator
|
||||||
- parameters
|
- parameters
|
||||||
- return_type:
|
- return_type:
|
||||||
|
build:
|
||||||
or_else: void
|
or_else: void
|
||||||
- function_body
|
- function_body
|
||||||
PlatformFunction:
|
PlatformFunction:
|
||||||
@ -194,6 +201,7 @@ PlatformFunction:
|
|||||||
skip: true
|
skip: true
|
||||||
- generics:
|
- generics:
|
||||||
rule: GenericParameters
|
rule: GenericParameters
|
||||||
|
build:
|
||||||
or_else_default: true
|
or_else_default: true
|
||||||
- identifier
|
- identifier
|
||||||
- parameters
|
- parameters
|
||||||
|
Loading…
Reference in New Issue
Block a user