Add polymorphic build types gen.

This commit is contained in:
Jesse Brault 2025-09-17 17:21:37 -05:00
parent a7eabae3e3
commit 7399a8748c
10 changed files with 885 additions and 164 deletions

View File

@ -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 yaml_rust2::{Yaml, YamlLoader};
@ -18,7 +18,87 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
(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
.as_vec()
.unwrap()
@ -32,14 +112,18 @@ fn deserialize_polymorphic_enum_members(enum_members_yaml: &Yaml) -> Vec<Box<Pol
.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 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 {
let kind = match production_yaml["kind"].as_str().unwrap() {
let kind = if production_yaml["kind"].is_hash() {
let node = production_yaml["kind"]["node"].as_str().unwrap();
ProductionKind::Node(node.to_string())
} else {
match production_yaml["kind"].as_str().unwrap() {
"int" => ProductionKind::Int,
"long" => ProductionKind::Long,
"double" => ProductionKind::Double,
@ -48,11 +132,18 @@ fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> Production
let from = match production_yaml["from"].as_str().unwrap() {
"string_inner" => ProductionStringFrom::StringInner,
"whole_pair" => ProductionStringFrom::WholePair,
_ => panic!("invalid from: {}", production_yaml["from"].as_str().unwrap()),
_ => panic!(
"invalid from: {}",
production_yaml["from"].as_str().unwrap()
),
};
ProductionKind::String(from)
},
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()),
}
_ => panic!(
"invalid kind: {}",
production_yaml["kind"].as_str().unwrap()
),
}
};
ProductionBuildSpec::new(rule, kind)
}
@ -66,9 +157,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
deserialize_leaf_enum_rule(rule_yaml)
})
.map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
.collect()
}
@ -83,16 +172,19 @@ fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleC
"usize" => EnumRuleChildKind::USize,
"string" => EnumRuleChildKind::String,
"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))))
}
}
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
Box::new(EnumRuleChild::new(Box::new(
EnumRuleChildKind::Node(EnumRuleNodeChild::new(rule)),
)))
Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
EnumRuleNodeChild::new(rule),
))))
}
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);
Box::new(EnumRule::new(
&rule,
deserialize_enum_rule_custom_child(rule_props)
deserialize_enum_rule_custom_child(rule_props),
))
} else {
let rule_as_str = rule_yaml.as_str().unwrap();
@ -184,7 +276,9 @@ fn deserialize_member_child_to_build(
}
} else {
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"]);
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
} 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() {
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 {
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."
);
}
}

View File

@ -2,7 +2,9 @@ pub mod deserialize;
mod enum_build_fn;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod polymorphic_build_build_fn;
mod polymorphic_build_fn;
mod polymorphic_enum_build_fn;
mod production_build_fn;
mod spec;
mod struct_build_fn;
@ -12,6 +14,9 @@ mod util;
use crate::enum_build_fn::make_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::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::struct_build_fn::make_struct_build_fn;
use crate::type_gen::make_type;
@ -19,7 +24,6 @@ use proc_macro2::TokenStream;
use quote::quote;
use spec::BuildSpec;
use syn::File;
use crate::polymorphic_build_fn::make_polymorphic_build_fn;
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
println!("*** BuildSpec ***");
@ -43,7 +47,22 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
println!("Production Spec - rule: {}", production_build_spec.rule());
}
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);
@ -95,6 +114,16 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
debug_built_spec(build_spec, &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<_>>();
let combined = quote! {

View 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!()
}
}
}
}

View File

@ -1,10 +1,9 @@
use crate::spec::PolymorphicTypeBuildSpec;
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
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 pair_ident = format_ident!("{}", make_build_pair(&build_spec.name()));
let return_type_ident = format_ident!("{}", build_spec.name());

View 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!()
}
}
}
}

View File

@ -11,6 +11,7 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
ProductionKind::Double => format_ident!("f64"),
ProductionKind::String(_) => format_ident!("String"),
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()));
@ -77,6 +78,13 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
ProductionKind::Boolean => quote! {
#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! {

View File

@ -4,7 +4,9 @@ pub enum BuildSpec {
Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec),
Polymorphic(PolymorphicBuildSpec),
Polymorphic(PolymorphicTypeBuildSpec),
PolymorphicBuild(PolymorphicBuildBuildSpec),
PolymorphicEnum(PolymorphicEnumBuildSpec),
}
// Enum build spec
@ -35,14 +37,14 @@ impl EnumBuildSpec {
pub struct EnumRule {
rule: String,
child: Option<Box<EnumRuleChild>>
child: Option<Box<EnumRuleChild>>,
}
impl EnumRule {
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
Self {
rule: rule.to_string(),
child
child,
}
}
@ -61,7 +63,7 @@ impl EnumRule {
}
pub struct EnumRuleChild {
kind: Box<EnumRuleChildKind>
kind: Box<EnumRuleChildKind>,
}
impl EnumRuleChild {
@ -81,11 +83,11 @@ pub enum EnumRuleChildKind {
Double,
USize,
String,
Boolean
Boolean,
}
pub struct EnumRuleNodeChild {
build: String
build: String,
}
impl EnumRuleNodeChild {
@ -111,7 +113,7 @@ impl LeafEnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
Self {
build: build.to_string(),
rules
rules,
}
}
@ -151,7 +153,7 @@ impl StructBuildSpec {
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
Self {
build: build.to_string(),
children
children,
}
}
@ -230,7 +232,7 @@ impl VecChild {
#[derive(Debug)]
pub enum VecChildToBuild {
Node(VecNodeChildToBuild),
String
String,
}
#[derive(Debug)]
@ -240,7 +242,9 @@ pub struct VecNodeChildToBuild {
impl VecNodeChildToBuild {
pub fn new(build: &str) -> Self {
Self { build: build.to_string() }
Self {
build: build.to_string(),
}
}
/// The type to build, in Pascal case.
@ -295,11 +299,7 @@ pub struct NodeChildToBuild {
}
impl NodeChildToBuild {
pub fn new(
build: &str,
or_else: Option<String>,
optional: bool,
) -> Self {
pub fn new(build: &str, or_else: Option<String>, optional: bool) -> Self {
Self {
build: build.to_string(),
or_else,
@ -325,13 +325,13 @@ impl NodeChildToBuild {
#[derive(Debug)]
pub struct BooleanChildToBuild {
name: String
name: String,
}
impl BooleanChildToBuild {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string()
name: name.to_string(),
}
}
@ -417,28 +417,33 @@ pub enum ProductionKind {
Long,
Double,
String(ProductionStringFrom),
Boolean
Boolean,
Node(String),
}
pub enum ProductionStringFrom {
StringInner,
WholePair
WholePair,
}
// Polymorphic build spec
pub struct PolymorphicBuildSpec {
pub struct PolymorphicTypeBuildSpec {
name: String,
enum_members: Vec<Box<PolymorphicEnumMember>>,
build_kind: String
build_kind: String,
}
impl PolymorphicBuildSpec {
pub fn new(name: &str, enum_members: Vec<Box<PolymorphicEnumMember>>, build_kind: &str) -> Self {
impl PolymorphicTypeBuildSpec {
pub fn new(
name: &str,
enum_members: Vec<Box<PolymorphicEnumMember>>,
build_kind: &str,
) -> Self {
Self {
name: name.to_string(),
enum_members,
build_kind: build_kind.to_string()
build_kind: build_kind.to_string(),
}
}
@ -457,14 +462,14 @@ impl PolymorphicBuildSpec {
pub struct PolymorphicEnumMember {
name: String,
inner_kind: String
inner_kind: String,
}
impl PolymorphicEnumMember {
pub fn new(name: &str, inner_kind: &str) -> Self {
Self {
name: name.to_string(),
inner_kind: inner_kind.to_string()
inner_kind: inner_kind.to_string(),
}
}
@ -476,3 +481,173 @@ impl PolymorphicEnumMember {
&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
}
}

View File

@ -1,12 +1,75 @@
use crate::spec::{
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
PolymorphicBuildSpec, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec,
EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind,
MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec,
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
};
use proc_macro2::{Ident, TokenStream};
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
.enum_members()
.map(|enum_member| {
@ -370,5 +433,9 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
BuildSpec::Polymorphic(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,
}
}

View File

@ -605,50 +605,109 @@ Expression:
build:
kind: TernaryExpression
TernaryExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: OrExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Ternary
children:
- or_expression
- ternary_alternatives:
optional: true
TernaryAlternatives:
children:
- ternary_true_alternative
- ternary_false_alternative
- test:
kind: Expression
rule: OrExpression
- on_true:
kind: Expression
rule: TernaryTrueAlternative
- on_false:
kind: Expression
rule: TernaryFalseAlternative
TernaryTrueAlternative:
children:
- expression
produce:
kind:
node: Expression
TernaryFalseAlternative:
children:
- expression
produce:
kind:
node: Expression
OrExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: AndExpression
- 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
optional: true
AndExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: ComparisonExpression
- 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
optional: true
ComparisonExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: ShiftExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Comparison
children:
- left:
kind: Expression
rule: ShiftExpression
- operator:
kind: ComparisonOperator
rule: ComparisonOperator
optional: true
- right:
kind: Expression
rule: Expression
optional: true
ComparisonOperator:
leaf_rules:
- Greater
@ -658,64 +717,144 @@ ComparisonOperator:
- EqualTo
- NotEqualTo
ShiftExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: AdditiveExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Shift
children:
- left:
kind: Expression
rule: AdditiveExpression
- operator:
kind: ShiftOperator
rule: ShiftOperator
optional: true
- right:
kind: Expression
rule: Expression
optional: true
ShiftOperator:
leaf_rules:
- LeftShift
- RightShift
AdditiveExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: MultiplicativeExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Additive
children:
- left:
kind: Expression
rule: MultiplicativeExpression
- operator:
kind: AdditiveOperator
rule: AdditiveOperator
optional: true
- right:
kind: Expression
rule: Expression
optional: true
AdditiveOperator:
leaf_rules:
- Add
- Subtract
MultiplicativeExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: PrefixExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Multiplicative
children:
- left:
kind: Expression
rule: PrefixExpression
- operator:
kind: MultiplicativeOperator
rule: MultiplicativeOperator
optional: true
- right:
kind: Expression
rule: Expression
optional: true
MultiplicativeOperator:
leaf_rules:
- Multiply
- Divide
- Modulo
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:
- operators:
rule: PrefixOperator
vec: true
- right:
rule: SuffixExpression
PrefixOperator:
leaf_rules:
- Spread
- Not
- Negative
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:
- operators:
rule: SuffixOperator
vec: true
@ -735,11 +874,21 @@ ObjectIndex:
children:
- expression
PrimaryExpression:
polymorphic_enum:
return_type: Expression
rules:
- Literal
- FullyQualifiedName
- Closure
- ParenthesizedExpression
- Literal:
wrap:
enum_variant: Literal
- FullyQualifiedName:
wrap:
enum_variant: Fqn
- Closure:
wrap:
enum_variant: Closure
- ParenthesizedExpression:
return_build:
kind: Expression
ParenthesizedExpression:
children:
- expression

View File

@ -596,12 +596,10 @@ Expression = {
TernaryExpression = {
OrExpression
~ ( TernaryAlternatives )?
}
TernaryAlternatives = {
~ (
TernaryTrueAlternative
~ TernaryFalseAlternative
)?
}
TernaryTrueAlternative = {
@ -682,10 +680,14 @@ MultiplicativeOperator = {
}
PrefixExpression = {
PrefixOperator*
PrefixOperators?
~ SuffixExpression
}
PrefixOperators = {
PrefixOperator+
}
PrefixOperator = {
Spread
| Not
@ -694,7 +696,11 @@ PrefixOperator = {
SuffixExpression = {
PrimaryExpression
~ SuffixOperator*
~ SuffixOperators?
}
SuffixOperators = {
SuffixOperator+
}
SuffixOperator = {