Add polymorphic pass through.

This commit is contained in:
Jesse Brault 2025-09-23 17:34:03 -05:00
parent 4b59abc989
commit 13e2ae6b0c
6 changed files with 132 additions and 1 deletions

View File

@ -8,6 +8,7 @@ use crate::build_fn::struct_build_fn::make_struct_build_fn;
use crate::build_fn::tree_enum_build_fn::make_enum_build_fn;
use crate::spec::BuildSpec;
use proc_macro2::TokenStream;
use crate::build_fn::polymorphic_pass_through_build_fn::make_polymorphic_pass_through_build_fn;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
@ -15,6 +16,7 @@ mod node_production_build_fn;
mod polymorphic_build_build_fn;
mod polymorphic_enum_build_fn;
mod polymorphic_enum_loop_build_fn;
mod polymorphic_pass_through_build_fn;
mod polymorphic_type_build_fn;
mod production_build_fn;
mod struct_build_fn;
@ -36,5 +38,8 @@ pub fn make_build_fn(build_spec: &BuildSpec) -> TokenStream {
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_spec) => {
make_polymorphic_enum_loop_build_fn(polymorphic_enum_loop_spec)
}
BuildSpec::PolymorphicPassThrough(polymorphic_pass_through_spec) => {
make_polymorphic_pass_through_build_fn(polymorphic_pass_through_spec)
}
}
}

View File

@ -0,0 +1,50 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::polymorphic_pass_through_spec::{PolymorphicPassThroughBuildSpec, PolymorphicPassThroughVariant};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_pass_through_build_fn(
spec: &PolymorphicPassThroughBuildSpec,
) -> 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.build_kind());
let match_arms = spec.variants()
.map(|variant| {
match variant {
PolymorphicPassThroughVariant::Inner { name, kind} => {
let rule_ident = format_ident!("{}", kind);
let variant_ident = format_ident!("{}", name);
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(kind));
quote! {
Rule::#rule_ident => {
#return_type_ident::#variant_ident(
#inner_build_fn_ident(inner_pair)
)
}
}
}
PolymorphicPassThroughVariant::PassThrough { name, kind: _kind } => {
let rule_ident = format_ident!("{}", name);
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(name));
quote! {
Rule::#rule_ident => #inner_build_fn_ident(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

@ -2,6 +2,7 @@ mod leaf_enum_spec;
mod leaf_struct_spec;
mod node_production_spec;
mod polymorphic_enum_loop_spec;
mod polymorphic_pass_through_spec;
mod polymorphic_type_spec;
mod production_spec;
mod struct_spec;
@ -18,6 +19,7 @@ use crate::deserialize::struct_spec::deserialize_struct_spec;
use crate::deserialize::tree_enum_spec::deserialize_tree_enum;
use crate::spec::BuildSpec;
use yaml_rust2::{Yaml, YamlLoader};
use crate::deserialize::polymorphic_pass_through_spec::deserialize_polymorphic_pass_through;
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
if build_spec["struct"].is_hash() {
@ -60,6 +62,11 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
build_spec_name,
&build_spec["polymorphic_enum_loop_build"],
))
} else if build_spec["polymorphic_pass_through"].is_hash() {
BuildSpec::PolymorphicPassThrough(deserialize_polymorphic_pass_through(
build_spec_name,
&build_spec["polymorphic_pass_through"],
))
} else {
panic!("Missing or incorrect build type for {}", build_spec_name);
}

View File

@ -0,0 +1,30 @@
use crate::deserialize::util::unwrap_single_member_hash;
use crate::spec::polymorphic_pass_through_spec::{PolymorphicPassThroughBuildSpec, PolymorphicPassThroughVariant};
use yaml_rust2::Yaml;
pub fn deserialize_polymorphic_pass_through(name: &str, props: &Yaml) -> PolymorphicPassThroughBuildSpec {
let build_kind = props["build"]["kind"].as_str().unwrap();
let variants = props["variants"].as_vec().unwrap()
.iter()
.map(|variant_yaml| {
let (variant_name, variant_props) = unwrap_single_member_hash(variant_yaml);
if variant_props["inner"].is_hash() {
let inner_kind = variant_props["inner"]["kind"].as_str().unwrap();
PolymorphicPassThroughVariant::Inner {
name: variant_name,
kind: inner_kind.to_string(),
}
} else if variant_props["pass_through"].is_hash() {
let pass_through_kind = variant_props["pass_through"]["kind"].is_hash();
PolymorphicPassThroughVariant::PassThrough {
name: variant_name,
kind: pass_through_kind.to_string(),
}
} else {
panic!()
}
})
.map(Box::new)
.collect();
PolymorphicPassThroughBuildSpec::new(name, build_kind, variants)
}

View File

@ -1,16 +1,18 @@
use crate::spec::node_production_spec::NodeProductionBuildSpec;
use crate::spec::polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use leaf_enum_spec::LeafEnumBuildSpec;
use leaf_struct_spec::LeafStructBuildSpec;
use polymorphic_type_spec::PolymorphicTypeBuildSpec;
use production_spec::ProductionBuildSpec;
use struct_spec::StructSpec;
use tree_enum_spec::TreeEnumBuildSpec;
use crate::spec::polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use crate::spec::polymorphic_pass_through_spec::PolymorphicPassThroughBuildSpec;
pub(crate) mod leaf_enum_spec;
pub(crate) mod leaf_struct_spec;
pub(crate) mod node_production_spec;
pub(crate) mod polymorphic_enum_loop_spec;
pub(crate) mod polymorphic_pass_through_spec;
pub(crate) mod polymorphic_type_spec;
pub(crate) mod production_spec;
pub(crate) mod struct_spec;
@ -25,4 +27,5 @@ pub enum BuildSpec {
NodeProduction(NodeProductionBuildSpec),
PolymorphicType(PolymorphicTypeBuildSpec),
PolymorphicEnumLoop(PolymorphicEnumLoopBuildSpec),
PolymorphicPassThrough(PolymorphicPassThroughBuildSpec)
}

View File

@ -0,0 +1,36 @@
pub struct PolymorphicPassThroughBuildSpec {
name: String,
build_kind: String,
variants: Vec<Box<PolymorphicPassThroughVariant>>,
}
impl PolymorphicPassThroughBuildSpec {
pub fn new(
name: &str,
build_kind: &str,
variants: Vec<Box<PolymorphicPassThroughVariant>>,
) -> Self {
Self {
name: name.to_string(),
build_kind: build_kind.to_string(),
variants,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn build_kind(&self) -> &str {
&self.build_kind
}
pub fn variants(&self) -> impl Iterator<Item = &PolymorphicPassThroughVariant> {
self.variants.iter().map(Box::as_ref)
}
}
pub enum PolymorphicPassThroughVariant {
Inner { name: String, kind: String },
PassThrough { name: String, kind: String },
}