WIP polymorphic building.

This commit is contained in:
Jesse Brault 2025-09-16 10:59:38 -05:00
parent c94a698a52
commit a7eabae3e3
7 changed files with 169 additions and 32 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, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
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 convert_case::{Case, Casing};
use yaml_rust2::{Yaml, YamlLoader};
@ -18,6 +18,26 @@ 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>> {
enum_members_yaml
.as_vec()
.unwrap()
.iter()
.map(|enum_member_yaml| {
let (member_name, member_hash) = unwrap_single_member_hash(enum_member_yaml);
let inner_kind = member_hash["inner"]["kind"].as_str().unwrap();
PolymorphicEnumMember::new(&member_name, inner_kind)
})
.map(Box::new)
.collect()
}
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicBuildSpec {
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)
}
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
let kind = match production_yaml["kind"].as_str().unwrap() {
"int" => ProductionKind::Int,
@ -278,6 +298,8 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
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"]))
} else if build_spec["polymorphic_type"].is_hash() {
BuildSpec::Polymorphic(deserialize_polymorphic_spec(build_spec_name, &build_spec["polymorphic_type"]))
} else {
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
}

View File

@ -2,6 +2,7 @@ pub mod deserialize;
mod enum_build_fn;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod polymorphic_build_fn;
mod production_build_fn;
mod spec;
mod struct_build_fn;
@ -18,6 +19,7 @@ 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 ***");
@ -38,7 +40,10 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
);
}
BuildSpec::Production(production_build_spec) => {
println!("Production Spec - rule: {}", production_build_spec.rule())
println!("Production Spec - rule: {}", production_build_spec.rule());
}
BuildSpec::Polymorphic(polymorphic_build_spec) => {
println!("Polymorphic Spec - name: {}", polymorphic_build_spec.name());
}
}
println!("{:#?}", token_stream);
@ -85,6 +90,11 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
debug_built_spec(build_spec, &stream);
stream
}
BuildSpec::Polymorphic(polymorphic_build_spec) => {
let stream = make_polymorphic_build_fn(polymorphic_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
})
.collect::<Vec<_>>();
let combined = quote! {

View File

@ -0,0 +1,19 @@
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 {
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());
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind()));
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
#inner_build_fn_ident(inner_pair)
}
}
}

View File

@ -4,6 +4,7 @@ pub enum BuildSpec {
Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec),
Polymorphic(PolymorphicBuildSpec),
}
// Enum build spec
@ -423,3 +424,55 @@ pub enum ProductionStringFrom {
StringInner,
WholePair
}
// Polymorphic build spec
pub struct PolymorphicBuildSpec {
name: String,
enum_members: Vec<Box<PolymorphicEnumMember>>,
build_kind: String
}
impl PolymorphicBuildSpec {
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()
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
self.enum_members.iter().map(Box::as_ref)
}
pub fn build_kind(&self) -> &str {
self.build_kind.as_str()
}
}
pub struct PolymorphicEnumMember {
name: 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()
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn inner_kind(&self) -> &str {
&self.inner_kind
}
}

View File

@ -1,11 +1,30 @@
use crate::spec::{
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
PolymorphicBuildSpec, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
fn make_polymorphic_type(build_spec: &PolymorphicBuildSpec) -> TokenStream {
let members = build_spec
.enum_members()
.map(|enum_member| {
let member_ident = format_ident!("{}", enum_member.name());
let inner_type_ident = format_ident!("{}", enum_member.inner_kind());
quote! {
#member_ident(#inner_type_ident)
}
})
.collect::<Vec<_>>();
let type_name_ident = format_ident!("{}", build_spec.name());
quote! {
pub enum #type_name_ident {
#(#members),*
}
}
}
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
let children: Vec<TokenStream> = build_spec
.rules()
@ -348,5 +367,8 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
Some(make_leaf_struct_type(leaf_struct_build_spec))
}
BuildSpec::Production(_) => None,
BuildSpec::Polymorphic(polymorphic_build_spec) => {
Some(make_polymorphic_type(polymorphic_build_spec))
}
}
}

View File

@ -42,31 +42,6 @@ pub mod node {
Self::new(vec![])
}
}
impl Expression {
pub fn unwrap_identifier(&self) -> &Identifier {
let primary = self.ternary_expression()
.or_expression()
.left()
.left()
.left()
.left()
.left()
.left()
.right()
.left();
match primary {
PrimaryExpression::FullyQualifiedName(fqn) => {
if fqn.identifiers().count() == 1 {
fqn.identifiers().next().unwrap()
} else {
panic!()
}
}
_ => panic!(),
}
}
}
}
pub mod build {
@ -133,8 +108,6 @@ pub mod build {
fn d_string_expression_simple() {
let pair = parse(Rule::DStringExpression, "${thing}");
let d_string_expression = build_d_string_expression(pair);
let identifier = d_string_expression.expression().unwrap_identifier();
assert_eq!("thing", identifier.name());
}
}
}

View File

@ -564,8 +564,46 @@ ForStatement:
# Expressions
Expression:
children:
- ternary_expression
polymorphic_type:
enum_members:
- Ternary:
inner:
kind: TernaryExpression
- Or:
inner:
kind: OrExpression
- And:
inner:
kind: AndExpression
- Comparison:
inner:
kind: ComparisonExpression
- Shift:
inner:
kind: ShiftExpression
- Additive:
inner:
kind: AdditiveExpression
- Multiplicative:
inner:
kind: MultiplicativeExpression
- Prefix:
inner:
kind: PrefixExpression
- Suffix:
inner:
kind: SuffixExpression
- Literal:
inner:
kind: Literal
- Fqn:
inner:
kind: FullyQualifiedName
- Closure:
inner:
kind: Closure
build:
kind: TernaryExpression
TernaryExpression:
children:
- or_expression