Add polymorphic build types gen.
This commit is contained in:
parent
a7eabae3e3
commit
7399a8748c
@ -1,4 +1,4 @@
|
|||||||
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NodeChildToBuild, PolymorphicBuildSpec, PolymorphicEnumMember, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
|
use crate::spec::{AlternativeAction, AlternativeBuild, AlternativeBuildChild, AlternativeChild, AlternativeTest, BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NameAndKind, NodeChildToBuild, PolymorphicBuildAlternative, PolymorphicBuildBuildSpec, PolymorphicEnumBuildSpec, PolymorphicEnumMember, PolymorphicEnumRule, PolymorphicTypeBuildSpec, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use yaml_rust2::{Yaml, YamlLoader};
|
use yaml_rust2::{Yaml, YamlLoader};
|
||||||
|
|
||||||
@ -18,7 +18,87 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
|||||||
(key_as_string, member_value)
|
(key_as_string, member_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_polymorphic_enum_members(enum_members_yaml: &Yaml) -> Vec<Box<PolymorphicEnumMember>> {
|
fn deserialize_polymorphic_enum_build_spec(name: &str, build_spec: &Yaml) -> PolymorphicEnumBuildSpec {
|
||||||
|
let return_type = build_spec["return_type"].as_str().unwrap();
|
||||||
|
let rules = build_spec["rules"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|rule_yaml| {
|
||||||
|
let (rule_name, props) = unwrap_single_member_hash(rule_yaml);
|
||||||
|
if props["wrap"].is_hash() {
|
||||||
|
PolymorphicEnumRule::Wrap(NameAndKind::new(
|
||||||
|
&rule_name,
|
||||||
|
props["wrap"]["enum_variant"].as_str().unwrap()
|
||||||
|
))
|
||||||
|
} else if props["return_build"].is_hash() {
|
||||||
|
PolymorphicEnumRule::ReturnBuild(NameAndKind::new(
|
||||||
|
&rule_name,
|
||||||
|
props["return_build"]["kind"].as_str().unwrap()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
PolymorphicEnumBuildSpec::new(name, return_type, rules)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_polymorphic_action(action_yaml: &Yaml) -> AlternativeAction {
|
||||||
|
if action_yaml["return_build"].is_hash() {
|
||||||
|
let kind = action_yaml["return_build"]["kind"].as_str().unwrap();
|
||||||
|
AlternativeAction::ReturnBuild(kind.to_string())
|
||||||
|
} else if action_yaml["build"].is_hash() {
|
||||||
|
let build_children = action_yaml["build"]["children"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|child_yaml| {
|
||||||
|
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
|
||||||
|
if get_as_bool(&child_props["skip"]) {
|
||||||
|
AlternativeChild::Skip
|
||||||
|
} else {
|
||||||
|
let kind = child_props["kind"].as_str().unwrap();
|
||||||
|
let rule = child_props["rule"].as_str().unwrap();
|
||||||
|
AlternativeChild::Build(AlternativeBuildChild::new(&child_name, kind, rule))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
let enum_variant = action_yaml["build"]["enum_variant"].as_str().unwrap();
|
||||||
|
let build = AlternativeBuild::new(enum_variant, build_children);
|
||||||
|
AlternativeAction::Build(build)
|
||||||
|
} else {
|
||||||
|
panic!("return_build or build is required for an alternative")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_polymorphic_build_build_spec(
|
||||||
|
name: &str,
|
||||||
|
polymorphic_build_yaml: &Yaml
|
||||||
|
) -> PolymorphicBuildBuildSpec {
|
||||||
|
let return_type = polymorphic_build_yaml["return_type"].as_str().unwrap();
|
||||||
|
let alternatives = polymorphic_build_yaml["alternatives"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|alternative_yaml| {
|
||||||
|
let number_of_pairs = alternative_yaml["test"]["number_of_pairs"].as_i64().unwrap();
|
||||||
|
let action = deserialize_polymorphic_action(&alternative_yaml["action"]);
|
||||||
|
PolymorphicBuildAlternative::new(
|
||||||
|
AlternativeTest::NumberOfPairs(number_of_pairs),
|
||||||
|
action
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
PolymorphicBuildBuildSpec::new(name, return_type, alternatives)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_polymorphic_enum_members(
|
||||||
|
enum_members_yaml: &Yaml,
|
||||||
|
) -> Vec<Box<PolymorphicEnumMember>> {
|
||||||
enum_members_yaml
|
enum_members_yaml
|
||||||
.as_vec()
|
.as_vec()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -32,27 +112,38 @@ fn deserialize_polymorphic_enum_members(enum_members_yaml: &Yaml) -> Vec<Box<Pol
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicBuildSpec {
|
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicTypeBuildSpec {
|
||||||
let enum_members = deserialize_polymorphic_enum_members(&spec_props["enum_members"]);
|
let enum_members = deserialize_polymorphic_enum_members(&spec_props["enum_members"]);
|
||||||
let build_kind = spec_props["build"]["kind"].as_str().unwrap();
|
let build_kind = spec_props["build"]["kind"].as_str().unwrap();
|
||||||
PolymorphicBuildSpec::new(name, enum_members, build_kind)
|
PolymorphicTypeBuildSpec::new(name, enum_members, build_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
||||||
let kind = match production_yaml["kind"].as_str().unwrap() {
|
let kind = if production_yaml["kind"].is_hash() {
|
||||||
"int" => ProductionKind::Int,
|
let node = production_yaml["kind"]["node"].as_str().unwrap();
|
||||||
"long" => ProductionKind::Long,
|
ProductionKind::Node(node.to_string())
|
||||||
"double" => ProductionKind::Double,
|
} else {
|
||||||
"boolean" => ProductionKind::Boolean,
|
match production_yaml["kind"].as_str().unwrap() {
|
||||||
"string" => {
|
"int" => ProductionKind::Int,
|
||||||
let from = match production_yaml["from"].as_str().unwrap() {
|
"long" => ProductionKind::Long,
|
||||||
"string_inner" => ProductionStringFrom::StringInner,
|
"double" => ProductionKind::Double,
|
||||||
"whole_pair" => ProductionStringFrom::WholePair,
|
"boolean" => ProductionKind::Boolean,
|
||||||
_ => panic!("invalid from: {}", production_yaml["from"].as_str().unwrap()),
|
"string" => {
|
||||||
};
|
let from = match production_yaml["from"].as_str().unwrap() {
|
||||||
ProductionKind::String(from)
|
"string_inner" => ProductionStringFrom::StringInner,
|
||||||
},
|
"whole_pair" => ProductionStringFrom::WholePair,
|
||||||
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()),
|
_ => panic!(
|
||||||
|
"invalid from: {}",
|
||||||
|
production_yaml["from"].as_str().unwrap()
|
||||||
|
),
|
||||||
|
};
|
||||||
|
ProductionKind::String(from)
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"invalid kind: {}",
|
||||||
|
production_yaml["kind"].as_str().unwrap()
|
||||||
|
),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ProductionBuildSpec::new(rule, kind)
|
ProductionBuildSpec::new(rule, kind)
|
||||||
}
|
}
|
||||||
@ -66,9 +157,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
|
|||||||
.as_vec()
|
.as_vec()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|rule_yaml| {
|
.map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
|
||||||
deserialize_leaf_enum_rule(rule_yaml)
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,16 +172,19 @@ fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleC
|
|||||||
"usize" => EnumRuleChildKind::USize,
|
"usize" => EnumRuleChildKind::USize,
|
||||||
"string" => EnumRuleChildKind::String,
|
"string" => EnumRuleChildKind::String,
|
||||||
"boolean" => EnumRuleChildKind::Boolean,
|
"boolean" => EnumRuleChildKind::Boolean,
|
||||||
_ => panic!("unsupported enum rule kind: {}", rule_props["kind"].as_str().unwrap()),
|
_ => panic!(
|
||||||
|
"unsupported enum rule kind: {}",
|
||||||
|
rule_props["kind"].as_str().unwrap()
|
||||||
|
),
|
||||||
};
|
};
|
||||||
Some(Box::new(EnumRuleChild::new(Box::new(kind))))
|
Some(Box::new(EnumRuleChild::new(Box::new(kind))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
|
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
|
||||||
Box::new(EnumRuleChild::new(Box::new(
|
Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
|
||||||
EnumRuleChildKind::Node(EnumRuleNodeChild::new(rule)),
|
EnumRuleNodeChild::new(rule),
|
||||||
)))
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
|
fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
|
||||||
@ -100,7 +192,7 @@ fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
|
|||||||
let (rule, rule_props) = unwrap_single_member_hash(rule_yaml);
|
let (rule, rule_props) = unwrap_single_member_hash(rule_yaml);
|
||||||
Box::new(EnumRule::new(
|
Box::new(EnumRule::new(
|
||||||
&rule,
|
&rule,
|
||||||
deserialize_enum_rule_custom_child(rule_props)
|
deserialize_enum_rule_custom_child(rule_props),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
let rule_as_str = rule_yaml.as_str().unwrap();
|
let rule_as_str = rule_yaml.as_str().unwrap();
|
||||||
@ -184,7 +276,9 @@ fn deserialize_member_child_to_build(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let optional = get_as_bool(&props["optional"]);
|
let optional = get_as_bool(&props["optional"]);
|
||||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(rule, None, optional)))
|
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
|
||||||
|
rule, None, optional,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,11 +391,29 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
|
|||||||
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
|
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
|
||||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
||||||
} else if build_spec["produce"].is_hash() {
|
} else if build_spec["produce"].is_hash() {
|
||||||
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
|
BuildSpec::Production(deserialize_production_spec(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["produce"],
|
||||||
|
))
|
||||||
} else if build_spec["polymorphic_type"].is_hash() {
|
} else if build_spec["polymorphic_type"].is_hash() {
|
||||||
BuildSpec::Polymorphic(deserialize_polymorphic_spec(build_spec_name, &build_spec["polymorphic_type"]))
|
BuildSpec::Polymorphic(deserialize_polymorphic_spec(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["polymorphic_type"],
|
||||||
|
))
|
||||||
|
} else if build_spec["polymorphic_build"].is_hash() {
|
||||||
|
BuildSpec::PolymorphicBuild(deserialize_polymorphic_build_build_spec(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["polymorphic_build"],
|
||||||
|
))
|
||||||
|
} else if build_spec["polymorphic_enum"].is_hash() {
|
||||||
|
BuildSpec::PolymorphicEnum(deserialize_polymorphic_enum_build_spec(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["polymorphic_enum"],
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
|
panic!(
|
||||||
|
"Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, production, polymorphic type, or polymorphic build type."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,9 @@ pub mod deserialize;
|
|||||||
mod enum_build_fn;
|
mod enum_build_fn;
|
||||||
mod leaf_enum_build_fn;
|
mod leaf_enum_build_fn;
|
||||||
mod leaf_struct_build_fn;
|
mod leaf_struct_build_fn;
|
||||||
|
mod polymorphic_build_build_fn;
|
||||||
mod polymorphic_build_fn;
|
mod polymorphic_build_fn;
|
||||||
|
mod polymorphic_enum_build_fn;
|
||||||
mod production_build_fn;
|
mod production_build_fn;
|
||||||
mod spec;
|
mod spec;
|
||||||
mod struct_build_fn;
|
mod struct_build_fn;
|
||||||
@ -12,6 +14,9 @@ mod util;
|
|||||||
use crate::enum_build_fn::make_enum_build_fn;
|
use crate::enum_build_fn::make_enum_build_fn;
|
||||||
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn;
|
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn;
|
||||||
use crate::leaf_struct_build_fn::make_leaf_struct_build_fn;
|
use crate::leaf_struct_build_fn::make_leaf_struct_build_fn;
|
||||||
|
use crate::polymorphic_build_build_fn::make_polymorphic_build_build_fn;
|
||||||
|
use crate::polymorphic_build_fn::make_polymorphic_build_fn;
|
||||||
|
use crate::polymorphic_enum_build_fn::make_polymorphic_enum_build_fn;
|
||||||
use crate::production_build_fn::make_production_build_fn;
|
use crate::production_build_fn::make_production_build_fn;
|
||||||
use crate::struct_build_fn::make_struct_build_fn;
|
use crate::struct_build_fn::make_struct_build_fn;
|
||||||
use crate::type_gen::make_type;
|
use crate::type_gen::make_type;
|
||||||
@ -19,7 +24,6 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
use spec::BuildSpec;
|
use spec::BuildSpec;
|
||||||
use syn::File;
|
use syn::File;
|
||||||
use crate::polymorphic_build_fn::make_polymorphic_build_fn;
|
|
||||||
|
|
||||||
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
||||||
println!("*** BuildSpec ***");
|
println!("*** BuildSpec ***");
|
||||||
@ -43,7 +47,22 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
|||||||
println!("Production Spec - rule: {}", production_build_spec.rule());
|
println!("Production Spec - rule: {}", production_build_spec.rule());
|
||||||
}
|
}
|
||||||
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
||||||
println!("Polymorphic Spec - name: {}", polymorphic_build_spec.name());
|
println!(
|
||||||
|
"Polymorphic Type Spec - name: {}",
|
||||||
|
polymorphic_build_spec.name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
|
||||||
|
println!(
|
||||||
|
"Polymorphic Build Spec - name: {}",
|
||||||
|
polymorphic_build_build_spec.name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
BuildSpec::PolymorphicEnum(polymorphic_enum_build_spec) => {
|
||||||
|
println!(
|
||||||
|
"Polymorphic Enum Spec - name: {}",
|
||||||
|
polymorphic_enum_build_spec.name()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{:#?}", token_stream);
|
println!("{:#?}", token_stream);
|
||||||
@ -95,6 +114,16 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|||||||
debug_built_spec(build_spec, &stream);
|
debug_built_spec(build_spec, &stream);
|
||||||
stream
|
stream
|
||||||
}
|
}
|
||||||
|
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
|
||||||
|
let stream = make_polymorphic_build_build_fn(polymorphic_build_build_spec);
|
||||||
|
debug_built_spec(build_spec, &stream);
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
BuildSpec::PolymorphicEnum(polymorphic_enum_build_spec) => {
|
||||||
|
let stream = make_polymorphic_enum_build_fn(polymorphic_enum_build_spec);
|
||||||
|
debug_built_spec(build_spec, &stream);
|
||||||
|
stream
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let combined = quote! {
|
let combined = quote! {
|
||||||
|
|||||||
134
ast-generator/src/polymorphic_build_build_fn.rs
Normal file
134
ast-generator/src/polymorphic_build_build_fn.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use convert_case::{Case, Casing};
|
||||||
|
use crate::spec::{AlternativeAction, AlternativeBuild, AlternativeBuildChild, AlternativeChild, AlternativeTest, PolymorphicBuildBuildSpec};
|
||||||
|
use crate::util::{make_build_fn_name, make_build_pair};
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
|
fn make_build_child(build_child: &AlternativeBuildChild) -> TokenStream {
|
||||||
|
let rule_ident = format_ident!("{}", build_child.rule());
|
||||||
|
let child_ident = format_ident!("{}", build_child.name());
|
||||||
|
let child_build_fn_ident = format_ident!("{}", make_build_fn_name(build_child.rule()));
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
Rule::#rule_ident => {
|
||||||
|
#child_ident = Some(#child_build_fn_ident(inner_pair));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_build_action(
|
||||||
|
spec: &PolymorphicBuildBuildSpec,
|
||||||
|
alternative_build: &AlternativeBuild,
|
||||||
|
) -> TokenStream {
|
||||||
|
let enum_type_ident = format_ident!("{}", spec.return_type());
|
||||||
|
let enum_variant_ident = format_ident!("{}", alternative_build.enum_variant());
|
||||||
|
|
||||||
|
let child_holders = alternative_build
|
||||||
|
.children()
|
||||||
|
.map(|child| {
|
||||||
|
match child {
|
||||||
|
AlternativeChild::Skip => None,
|
||||||
|
AlternativeChild::Build(build_child) => {
|
||||||
|
let child_ident = format_ident!("{}", build_child.name());
|
||||||
|
let child_type_ident = format_ident!("{}", build_child.kind());
|
||||||
|
Some(quote! {
|
||||||
|
let mut #child_ident: Option<#child_type_ident> = None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
|
||||||
|
|
||||||
|
let rule_matchers = alternative_build
|
||||||
|
.children()
|
||||||
|
.map(|child| {
|
||||||
|
match child {
|
||||||
|
AlternativeChild::Skip => None,
|
||||||
|
AlternativeChild::Build(build_child) => {
|
||||||
|
Some(make_build_child(build_child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let built_ident = format_ident!("{}", spec.name().to_case(Case::Snake));
|
||||||
|
let inner_type_ident = format_ident!("{}", spec.name());
|
||||||
|
let child_args = alternative_build.children()
|
||||||
|
.map(|child| {
|
||||||
|
match child {
|
||||||
|
AlternativeChild::Skip => None,
|
||||||
|
AlternativeChild::Build(child_build) => {
|
||||||
|
let child_ident = format_ident!("{}", child_build.name());
|
||||||
|
Some(quote! {
|
||||||
|
Box::new(#child_ident.unwrap())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#(#child_holders;)*
|
||||||
|
|
||||||
|
for inner_pair in #pair_ident.into_inner() {
|
||||||
|
match inner_pair.as_rule() {
|
||||||
|
#(#rule_matchers),*
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let #built_ident = #inner_type_ident::new(#(#child_args),*);
|
||||||
|
|
||||||
|
#enum_type_ident::#enum_variant_ident(#built_ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_polymorphic_build_build_fn(spec: &PolymorphicBuildBuildSpec) -> TokenStream {
|
||||||
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
|
||||||
|
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
|
||||||
|
let return_type_ident = format_ident!("{}", spec.return_type());
|
||||||
|
|
||||||
|
let alternatives = spec
|
||||||
|
.alternatives()
|
||||||
|
.map(|alternative| {
|
||||||
|
let count_to_match: usize = match alternative.test() {
|
||||||
|
AlternativeTest::NumberOfPairs(count) => count.clone().try_into().unwrap(),
|
||||||
|
};
|
||||||
|
let action = match alternative.action() {
|
||||||
|
AlternativeAction::ReturnBuild(kind) => {
|
||||||
|
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(kind));
|
||||||
|
quote! {
|
||||||
|
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||||
|
#inner_build_fn_ident(inner_pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AlternativeAction::Build(alternative_build) => {
|
||||||
|
make_build_action(spec, alternative_build)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
#count_to_match => {
|
||||||
|
#action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||||
|
let count = #pair_ident.clone().into_inner().count();
|
||||||
|
match count {
|
||||||
|
#(#alternatives,)*
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +1,18 @@
|
|||||||
|
use crate::spec::PolymorphicTypeBuildSpec;
|
||||||
|
use crate::util::{make_build_fn_name, make_build_pair};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use crate::spec::PolymorphicBuildSpec;
|
|
||||||
use crate::token_stream_to_string;
|
|
||||||
use crate::util::{make_build_fn_name, make_build_pair};
|
|
||||||
|
|
||||||
pub fn make_polymorphic_build_fn(build_spec: &PolymorphicBuildSpec) -> TokenStream {
|
pub fn make_polymorphic_build_fn(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
|
||||||
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.name()));
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.name()));
|
||||||
let pair_ident = format_ident!("{}", make_build_pair(&build_spec.name()));
|
let pair_ident = format_ident!("{}", make_build_pair(&build_spec.name()));
|
||||||
let return_type_ident = format_ident!("{}", build_spec.name());
|
let return_type_ident = format_ident!("{}", build_spec.name());
|
||||||
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind()));
|
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind()));
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||||
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||||
#inner_build_fn_ident(inner_pair)
|
#inner_build_fn_ident(inner_pair)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
42
ast-generator/src/polymorphic_enum_build_fn.rs
Normal file
42
ast-generator/src/polymorphic_enum_build_fn.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use crate::spec::{PolymorphicEnumBuildSpec, PolymorphicEnumRule};
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use crate::util::{make_build_fn_name, make_build_pair};
|
||||||
|
|
||||||
|
pub fn make_polymorphic_enum_build_fn(spec: &PolymorphicEnumBuildSpec) -> TokenStream {
|
||||||
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
|
||||||
|
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
|
||||||
|
let return_type_ident = format_ident!("{}", spec.return_type());
|
||||||
|
|
||||||
|
let match_arms = spec.rules()
|
||||||
|
.map(|rule| {
|
||||||
|
match rule {
|
||||||
|
PolymorphicEnumRule::Wrap(name_and_kind) => {
|
||||||
|
let rule_ident = format_ident!("{}", name_and_kind.name());
|
||||||
|
let enum_variant_ident = format_ident!("{}", name_and_kind.kind());
|
||||||
|
let rule_build_fn = format_ident!("{}", make_build_fn_name(name_and_kind.name()));
|
||||||
|
quote! {
|
||||||
|
Rule::#rule_ident => #return_type_ident::#enum_variant_ident(#rule_build_fn(inner_pair))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PolymorphicEnumRule::ReturnBuild(name_and_kind) => {
|
||||||
|
let rule_ident = format_ident!("{}", name_and_kind.name());
|
||||||
|
let rule_build_fn = format_ident!("{}", make_build_fn_name(name_and_kind.kind()));
|
||||||
|
quote! {
|
||||||
|
Rule::#rule_ident => #rule_build_fn(inner_pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||||
|
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||||
|
match inner_pair.as_rule() {
|
||||||
|
#(#match_arms,)*
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
|
|||||||
ProductionKind::Double => format_ident!("f64"),
|
ProductionKind::Double => format_ident!("f64"),
|
||||||
ProductionKind::String(_) => format_ident!("String"),
|
ProductionKind::String(_) => format_ident!("String"),
|
||||||
ProductionKind::Boolean => format_ident!("bool"),
|
ProductionKind::Boolean => format_ident!("bool"),
|
||||||
|
ProductionKind::Node(node_type) => format_ident!("{}", node_type),
|
||||||
};
|
};
|
||||||
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule()));
|
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule()));
|
||||||
|
|
||||||
@ -77,6 +78,13 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
|
|||||||
ProductionKind::Boolean => quote! {
|
ProductionKind::Boolean => quote! {
|
||||||
#pair_ident.as_str().parse::<bool>().unwrap()
|
#pair_ident.as_str().parse::<bool>().unwrap()
|
||||||
},
|
},
|
||||||
|
ProductionKind::Node(node_type) => {
|
||||||
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(node_type));
|
||||||
|
quote! {
|
||||||
|
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||||
|
#build_fn_ident(inner_pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
|||||||
@ -4,7 +4,9 @@ pub enum BuildSpec {
|
|||||||
Struct(StructBuildSpec),
|
Struct(StructBuildSpec),
|
||||||
LeafStruct(LeafStructBuildSpec),
|
LeafStruct(LeafStructBuildSpec),
|
||||||
Production(ProductionBuildSpec),
|
Production(ProductionBuildSpec),
|
||||||
Polymorphic(PolymorphicBuildSpec),
|
Polymorphic(PolymorphicTypeBuildSpec),
|
||||||
|
PolymorphicBuild(PolymorphicBuildBuildSpec),
|
||||||
|
PolymorphicEnum(PolymorphicEnumBuildSpec),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum build spec
|
// Enum build spec
|
||||||
@ -35,14 +37,14 @@ impl EnumBuildSpec {
|
|||||||
|
|
||||||
pub struct EnumRule {
|
pub struct EnumRule {
|
||||||
rule: String,
|
rule: String,
|
||||||
child: Option<Box<EnumRuleChild>>
|
child: Option<Box<EnumRuleChild>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumRule {
|
impl EnumRule {
|
||||||
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rule: rule.to_string(),
|
rule: rule.to_string(),
|
||||||
child
|
child,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ impl EnumRule {
|
|||||||
pub fn rule(&self) -> &str {
|
pub fn rule(&self) -> &str {
|
||||||
&self.rule
|
&self.rule
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child(&self) -> Option<&EnumRuleChild> {
|
pub fn child(&self) -> Option<&EnumRuleChild> {
|
||||||
if let Some(child) = &self.child {
|
if let Some(child) = &self.child {
|
||||||
Some(child.as_ref())
|
Some(child.as_ref())
|
||||||
@ -61,14 +63,14 @@ impl EnumRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct EnumRuleChild {
|
pub struct EnumRuleChild {
|
||||||
kind: Box<EnumRuleChildKind>
|
kind: Box<EnumRuleChildKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumRuleChild {
|
impl EnumRuleChild {
|
||||||
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
|
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
|
||||||
Self { kind }
|
Self { kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> &EnumRuleChildKind {
|
pub fn kind(&self) -> &EnumRuleChildKind {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
@ -81,11 +83,11 @@ pub enum EnumRuleChildKind {
|
|||||||
Double,
|
Double,
|
||||||
USize,
|
USize,
|
||||||
String,
|
String,
|
||||||
Boolean
|
Boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EnumRuleNodeChild {
|
pub struct EnumRuleNodeChild {
|
||||||
build: String
|
build: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumRuleNodeChild {
|
impl EnumRuleNodeChild {
|
||||||
@ -94,7 +96,7 @@ impl EnumRuleNodeChild {
|
|||||||
build: build.to_string(),
|
build: build.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(&self) -> &str {
|
pub fn build(&self) -> &str {
|
||||||
&self.build
|
&self.build
|
||||||
}
|
}
|
||||||
@ -111,7 +113,7 @@ impl LeafEnumBuildSpec {
|
|||||||
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
|
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
build: build.to_string(),
|
build: build.to_string(),
|
||||||
rules
|
rules,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +153,7 @@ impl StructBuildSpec {
|
|||||||
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
|
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
build: build.to_string(),
|
build: build.to_string(),
|
||||||
children
|
children,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +161,7 @@ impl StructBuildSpec {
|
|||||||
pub fn build(&self) -> &str {
|
pub fn build(&self) -> &str {
|
||||||
&self.build
|
&self.build
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The children for this build spec.
|
/// The children for this build spec.
|
||||||
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
|
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
|
||||||
self.children.iter().map(Box::as_ref)
|
self.children.iter().map(Box::as_ref)
|
||||||
@ -230,7 +232,7 @@ impl VecChild {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VecChildToBuild {
|
pub enum VecChildToBuild {
|
||||||
Node(VecNodeChildToBuild),
|
Node(VecNodeChildToBuild),
|
||||||
String
|
String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -240,7 +242,9 @@ pub struct VecNodeChildToBuild {
|
|||||||
|
|
||||||
impl VecNodeChildToBuild {
|
impl VecNodeChildToBuild {
|
||||||
pub fn new(build: &str) -> Self {
|
pub fn new(build: &str) -> Self {
|
||||||
Self { build: build.to_string() }
|
Self {
|
||||||
|
build: build.to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type to build, in Pascal case.
|
/// The type to build, in Pascal case.
|
||||||
@ -295,11 +299,7 @@ pub struct NodeChildToBuild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NodeChildToBuild {
|
impl NodeChildToBuild {
|
||||||
pub fn new(
|
pub fn new(build: &str, or_else: Option<String>, optional: bool) -> Self {
|
||||||
build: &str,
|
|
||||||
or_else: Option<String>,
|
|
||||||
optional: bool,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
build: build.to_string(),
|
build: build.to_string(),
|
||||||
or_else,
|
or_else,
|
||||||
@ -325,13 +325,13 @@ impl NodeChildToBuild {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BooleanChildToBuild {
|
pub struct BooleanChildToBuild {
|
||||||
name: String
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BooleanChildToBuild {
|
impl BooleanChildToBuild {
|
||||||
pub fn new(name: &str) -> Self {
|
pub fn new(name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string()
|
name: name.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,11 +402,11 @@ impl ProductionBuildSpec {
|
|||||||
kind,
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rule(&self) -> &str {
|
pub fn rule(&self) -> &str {
|
||||||
&self.rule
|
&self.rule
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> &ProductionKind {
|
pub fn kind(&self) -> &ProductionKind {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
@ -417,39 +417,44 @@ pub enum ProductionKind {
|
|||||||
Long,
|
Long,
|
||||||
Double,
|
Double,
|
||||||
String(ProductionStringFrom),
|
String(ProductionStringFrom),
|
||||||
Boolean
|
Boolean,
|
||||||
|
Node(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ProductionStringFrom {
|
pub enum ProductionStringFrom {
|
||||||
StringInner,
|
StringInner,
|
||||||
WholePair
|
WholePair,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polymorphic build spec
|
// Polymorphic build spec
|
||||||
|
|
||||||
pub struct PolymorphicBuildSpec {
|
pub struct PolymorphicTypeBuildSpec {
|
||||||
name: String,
|
name: String,
|
||||||
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
||||||
build_kind: String
|
build_kind: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PolymorphicBuildSpec {
|
impl PolymorphicTypeBuildSpec {
|
||||||
pub fn new(name: &str, enum_members: Vec<Box<PolymorphicEnumMember>>, build_kind: &str) -> Self {
|
pub fn new(
|
||||||
|
name: &str,
|
||||||
|
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
||||||
|
build_kind: &str,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
enum_members,
|
enum_members,
|
||||||
build_kind: build_kind.to_string()
|
build_kind: build_kind.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
|
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
|
||||||
self.enum_members.iter().map(Box::as_ref)
|
self.enum_members.iter().map(Box::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_kind(&self) -> &str {
|
pub fn build_kind(&self) -> &str {
|
||||||
self.build_kind.as_str()
|
self.build_kind.as_str()
|
||||||
}
|
}
|
||||||
@ -457,22 +462,192 @@ impl PolymorphicBuildSpec {
|
|||||||
|
|
||||||
pub struct PolymorphicEnumMember {
|
pub struct PolymorphicEnumMember {
|
||||||
name: String,
|
name: String,
|
||||||
inner_kind: String
|
inner_kind: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PolymorphicEnumMember {
|
impl PolymorphicEnumMember {
|
||||||
pub fn new(name: &str, inner_kind: &str) -> Self {
|
pub fn new(name: &str, inner_kind: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
inner_kind: inner_kind.to_string()
|
inner_kind: inner_kind.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_kind(&self) -> &str {
|
pub fn inner_kind(&self) -> &str {
|
||||||
&self.inner_kind
|
&self.inner_kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicBuildBuildSpec {
|
||||||
|
name: String,
|
||||||
|
return_type: String,
|
||||||
|
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicBuildBuildSpec {
|
||||||
|
pub fn new(
|
||||||
|
name: &str,
|
||||||
|
return_type: &str,
|
||||||
|
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
return_type: return_type.to_string(),
|
||||||
|
alternatives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn return_type(&self) -> &str {
|
||||||
|
&self.return_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alternatives(&self) -> impl Iterator<Item = &PolymorphicBuildAlternative> {
|
||||||
|
self.alternatives.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicBuildAlternative {
|
||||||
|
test: AlternativeTest,
|
||||||
|
action: AlternativeAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicBuildAlternative {
|
||||||
|
pub fn new(test: AlternativeTest, action: AlternativeAction) -> Self {
|
||||||
|
Self { test, action }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test(&self) -> &AlternativeTest {
|
||||||
|
&self.test
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn action(&self) -> &AlternativeAction {
|
||||||
|
&self.action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AlternativeTest {
|
||||||
|
NumberOfPairs(i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AlternativeAction {
|
||||||
|
ReturnBuild(String),
|
||||||
|
Build(AlternativeBuild),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AlternativeBuild {
|
||||||
|
enum_variant: String,
|
||||||
|
children: Vec<Box<AlternativeChild>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlternativeBuild {
|
||||||
|
pub fn new(enum_variant: &str, children: Vec<Box<AlternativeChild>>) -> Self {
|
||||||
|
Self {
|
||||||
|
enum_variant: enum_variant.to_string(),
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enum_variant(&self) -> &str {
|
||||||
|
&self.enum_variant
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self) -> impl Iterator<Item = &AlternativeChild> {
|
||||||
|
self.children.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AlternativeChild {
|
||||||
|
Skip,
|
||||||
|
Build(AlternativeBuildChild),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AlternativeBuildChild {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
rule: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlternativeBuildChild {
|
||||||
|
pub fn new(name: &str, kind: &str, rule: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
rule: rule.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumBuildSpec {
|
||||||
|
name: String,
|
||||||
|
return_type: String,
|
||||||
|
rules: Vec<Box<PolymorphicEnumRule>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumBuildSpec {
|
||||||
|
pub fn new(name: &str, return_type: &str, rules: Vec<Box<PolymorphicEnumRule>>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
return_type: return_type.to_string(),
|
||||||
|
rules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn return_type(&self) -> &str {
|
||||||
|
&self.return_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumRule> {
|
||||||
|
self.rules.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PolymorphicEnumRule {
|
||||||
|
Wrap(NameAndKind),
|
||||||
|
ReturnBuild(NameAndKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NameAndKind {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameAndKind {
|
||||||
|
pub fn new(name: &str, kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,12 +1,75 @@
|
|||||||
use crate::spec::{
|
use crate::spec::{
|
||||||
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
|
AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec,
|
||||||
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
|
EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind,
|
||||||
PolymorphicBuildSpec, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec,
|
||||||
|
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
||||||
};
|
};
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
fn make_polymorphic_type(build_spec: &PolymorphicBuildSpec) -> TokenStream {
|
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(|build_child| match build_child {
|
||||||
|
AlternativeChild::Skip => None,
|
||||||
|
AlternativeChild::Build(build_child) => Some(format_ident!("{}", build_child.name())),
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.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),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_polymorphic_type(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
|
||||||
let members = build_spec
|
let members = build_spec
|
||||||
.enum_members()
|
.enum_members()
|
||||||
.map(|enum_member| {
|
.map(|enum_member| {
|
||||||
@ -370,5 +433,9 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
|
|||||||
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
||||||
Some(make_polymorphic_type(polymorphic_build_spec))
|
Some(make_polymorphic_type(polymorphic_build_spec))
|
||||||
}
|
}
|
||||||
|
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
|
||||||
|
Some(make_polymorphic_build_type(polymorphic_build_build_spec))
|
||||||
|
}
|
||||||
|
BuildSpec::PolymorphicEnum(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -605,50 +605,109 @@ Expression:
|
|||||||
build:
|
build:
|
||||||
kind: TernaryExpression
|
kind: TernaryExpression
|
||||||
TernaryExpression:
|
TernaryExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- or_expression
|
return_type: Expression
|
||||||
- ternary_alternatives:
|
alternatives:
|
||||||
optional: true
|
- test:
|
||||||
TernaryAlternatives:
|
number_of_pairs: 1
|
||||||
children:
|
action:
|
||||||
- ternary_true_alternative
|
return_build:
|
||||||
- ternary_false_alternative
|
kind: OrExpression
|
||||||
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Ternary
|
||||||
|
children:
|
||||||
|
- test:
|
||||||
|
kind: Expression
|
||||||
|
rule: OrExpression
|
||||||
|
- on_true:
|
||||||
|
kind: Expression
|
||||||
|
rule: TernaryTrueAlternative
|
||||||
|
- on_false:
|
||||||
|
kind: Expression
|
||||||
|
rule: TernaryFalseAlternative
|
||||||
TernaryTrueAlternative:
|
TernaryTrueAlternative:
|
||||||
children:
|
produce:
|
||||||
- expression
|
kind:
|
||||||
|
node: Expression
|
||||||
TernaryFalseAlternative:
|
TernaryFalseAlternative:
|
||||||
children:
|
produce:
|
||||||
- expression
|
kind:
|
||||||
|
node: Expression
|
||||||
OrExpression:
|
OrExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: AndExpression
|
alternatives:
|
||||||
- or_sym:
|
- test:
|
||||||
rule: Or
|
number_of_pairs: 1
|
||||||
skip: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: AndExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Or
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: AndExpression
|
||||||
|
- or_sym:
|
||||||
|
rule: Or
|
||||||
|
skip: true
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
AndExpression:
|
AndExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: ComparisonExpression
|
alternatives:
|
||||||
- and_sym:
|
- test:
|
||||||
rule: And
|
number_of_pairs: 1
|
||||||
skip: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: ComparisonExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: And
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: ComparisonExpression
|
||||||
|
- and_sym:
|
||||||
|
rule: And
|
||||||
|
skip: true
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
ComparisonExpression:
|
ComparisonExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: ShiftExpression
|
alternatives:
|
||||||
- operator:
|
- test:
|
||||||
rule: ComparisonOperator
|
number_of_pairs: 1
|
||||||
optional: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: ShiftExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Comparison
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: ShiftExpression
|
||||||
|
- operator:
|
||||||
|
kind: ComparisonOperator
|
||||||
|
rule: ComparisonOperator
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
ComparisonOperator:
|
ComparisonOperator:
|
||||||
leaf_rules:
|
leaf_rules:
|
||||||
- Greater
|
- Greater
|
||||||
@ -658,64 +717,144 @@ ComparisonOperator:
|
|||||||
- EqualTo
|
- EqualTo
|
||||||
- NotEqualTo
|
- NotEqualTo
|
||||||
ShiftExpression:
|
ShiftExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: AdditiveExpression
|
alternatives:
|
||||||
- operator:
|
- test:
|
||||||
rule: ShiftOperator
|
number_of_pairs: 1
|
||||||
optional: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: AdditiveExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Shift
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: AdditiveExpression
|
||||||
|
- operator:
|
||||||
|
kind: ShiftOperator
|
||||||
|
rule: ShiftOperator
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
ShiftOperator:
|
ShiftOperator:
|
||||||
leaf_rules:
|
leaf_rules:
|
||||||
- LeftShift
|
- LeftShift
|
||||||
- RightShift
|
- RightShift
|
||||||
AdditiveExpression:
|
AdditiveExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: MultiplicativeExpression
|
alternatives:
|
||||||
- operator:
|
- test:
|
||||||
rule: AdditiveOperator
|
number_of_pairs: 1
|
||||||
optional: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: MultiplicativeExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Additive
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: MultiplicativeExpression
|
||||||
|
- operator:
|
||||||
|
kind: AdditiveOperator
|
||||||
|
rule: AdditiveOperator
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
AdditiveOperator:
|
AdditiveOperator:
|
||||||
leaf_rules:
|
leaf_rules:
|
||||||
- Add
|
- Add
|
||||||
- Subtract
|
- Subtract
|
||||||
MultiplicativeExpression:
|
MultiplicativeExpression:
|
||||||
children:
|
polymorphic_build:
|
||||||
- left:
|
return_type: Expression
|
||||||
rule: PrefixExpression
|
alternatives:
|
||||||
- operator:
|
- test:
|
||||||
rule: MultiplicativeOperator
|
number_of_pairs: 1
|
||||||
optional: true
|
action:
|
||||||
- right:
|
return_build:
|
||||||
rule: Expression
|
kind: PrefixExpression
|
||||||
optional: true
|
- test:
|
||||||
|
number_of_pairs: 3
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Multiplicative
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: PrefixExpression
|
||||||
|
- operator:
|
||||||
|
kind: MultiplicativeOperator
|
||||||
|
rule: MultiplicativeOperator
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: Expression
|
||||||
MultiplicativeOperator:
|
MultiplicativeOperator:
|
||||||
leaf_rules:
|
leaf_rules:
|
||||||
- Multiply
|
- Multiply
|
||||||
- Divide
|
- Divide
|
||||||
- Modulo
|
- Modulo
|
||||||
PrefixExpression:
|
PrefixExpression:
|
||||||
|
polymorphic_build:
|
||||||
|
return_type: Expression
|
||||||
|
alternatives:
|
||||||
|
- test:
|
||||||
|
number_of_pairs: 1
|
||||||
|
action:
|
||||||
|
return_build:
|
||||||
|
kind: SuffixExpression
|
||||||
|
- test:
|
||||||
|
number_of_pairs: 2
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Prefix
|
||||||
|
children:
|
||||||
|
- prefix_operators:
|
||||||
|
kind: PrefixOperators
|
||||||
|
rule: PrefixOperators
|
||||||
|
- right:
|
||||||
|
kind: Expression
|
||||||
|
rule: SuffixExpression
|
||||||
|
PrefixOperators:
|
||||||
children:
|
children:
|
||||||
- operators:
|
- operators:
|
||||||
rule: PrefixOperator
|
rule: PrefixOperator
|
||||||
vec: true
|
vec: true
|
||||||
- right:
|
|
||||||
rule: SuffixExpression
|
|
||||||
PrefixOperator:
|
PrefixOperator:
|
||||||
leaf_rules:
|
leaf_rules:
|
||||||
- Spread
|
- Spread
|
||||||
- Not
|
- Not
|
||||||
- Negative
|
- Negative
|
||||||
SuffixExpression:
|
SuffixExpression:
|
||||||
|
polymorphic_build:
|
||||||
|
return_type: Expression
|
||||||
|
alternatives:
|
||||||
|
- test:
|
||||||
|
number_of_pairs: 1
|
||||||
|
action:
|
||||||
|
return_build:
|
||||||
|
kind: PrimaryExpression
|
||||||
|
- test:
|
||||||
|
number_of_pairs: 2
|
||||||
|
action:
|
||||||
|
build:
|
||||||
|
enum_variant: Suffix
|
||||||
|
children:
|
||||||
|
- left:
|
||||||
|
kind: Expression
|
||||||
|
rule: PrimaryExpression
|
||||||
|
- suffix_operators:
|
||||||
|
kind: SuffixOperators
|
||||||
|
rule: SuffixOperators
|
||||||
|
SuffixOperators:
|
||||||
children:
|
children:
|
||||||
- left:
|
|
||||||
rule: PrimaryExpression
|
|
||||||
- operators:
|
- operators:
|
||||||
rule: SuffixOperator
|
rule: SuffixOperator
|
||||||
vec: true
|
vec: true
|
||||||
@ -735,11 +874,21 @@ ObjectIndex:
|
|||||||
children:
|
children:
|
||||||
- expression
|
- expression
|
||||||
PrimaryExpression:
|
PrimaryExpression:
|
||||||
rules:
|
polymorphic_enum:
|
||||||
- Literal
|
return_type: Expression
|
||||||
- FullyQualifiedName
|
rules:
|
||||||
- Closure
|
- Literal:
|
||||||
- ParenthesizedExpression
|
wrap:
|
||||||
|
enum_variant: Literal
|
||||||
|
- FullyQualifiedName:
|
||||||
|
wrap:
|
||||||
|
enum_variant: Fqn
|
||||||
|
- Closure:
|
||||||
|
wrap:
|
||||||
|
enum_variant: Closure
|
||||||
|
- ParenthesizedExpression:
|
||||||
|
return_build:
|
||||||
|
kind: Expression
|
||||||
ParenthesizedExpression:
|
ParenthesizedExpression:
|
||||||
children:
|
children:
|
||||||
- expression
|
- expression
|
||||||
|
|||||||
@ -596,12 +596,10 @@ Expression = {
|
|||||||
|
|
||||||
TernaryExpression = {
|
TernaryExpression = {
|
||||||
OrExpression
|
OrExpression
|
||||||
~ ( TernaryAlternatives )?
|
~ (
|
||||||
}
|
TernaryTrueAlternative
|
||||||
|
~ TernaryFalseAlternative
|
||||||
TernaryAlternatives = {
|
)?
|
||||||
TernaryTrueAlternative
|
|
||||||
~ TernaryFalseAlternative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TernaryTrueAlternative = {
|
TernaryTrueAlternative = {
|
||||||
@ -682,10 +680,14 @@ MultiplicativeOperator = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrefixExpression = {
|
PrefixExpression = {
|
||||||
PrefixOperator*
|
PrefixOperators?
|
||||||
~ SuffixExpression
|
~ SuffixExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrefixOperators = {
|
||||||
|
PrefixOperator+
|
||||||
|
}
|
||||||
|
|
||||||
PrefixOperator = {
|
PrefixOperator = {
|
||||||
Spread
|
Spread
|
||||||
| Not
|
| Not
|
||||||
@ -694,7 +696,11 @@ PrefixOperator = {
|
|||||||
|
|
||||||
SuffixExpression = {
|
SuffixExpression = {
|
||||||
PrimaryExpression
|
PrimaryExpression
|
||||||
~ SuffixOperator*
|
~ SuffixOperators?
|
||||||
|
}
|
||||||
|
|
||||||
|
SuffixOperators = {
|
||||||
|
SuffixOperator+
|
||||||
}
|
}
|
||||||
|
|
||||||
SuffixOperator = {
|
SuffixOperator = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user