Add support for polymorphic enum builds (used for suffix operators).

This commit is contained in:
Jesse Brault 2025-11-15 18:13:25 -06:00
parent 7439ca554c
commit f21128fd68
20 changed files with 590 additions and 45 deletions

View File

@ -1,6 +1,7 @@
mod enum_ast_node;
mod leaf_enum_ast_node;
mod leaf_struct_ast_node;
mod polymorphic_enum_inner_build_ast_node;
mod polymorphic_enum_loop_ast_node;
mod polymorphic_type_ast_node;
mod struct_ast_node;
@ -8,6 +9,7 @@ mod struct_ast_node;
use crate::ast_node::enum_ast_node::make_enum_ast_node_impl;
use crate::ast_node::leaf_enum_ast_node::make_leaf_enum_ast_node_impl;
use crate::ast_node::leaf_struct_ast_node::make_leaf_struct_ast_node_impl;
use crate::ast_node::polymorphic_enum_inner_build_ast_node::make_polymorphic_enum_inner_build_ast_node_impl;
use crate::ast_node::polymorphic_enum_loop_ast_node::make_polymorphic_enum_loop_ast_node_impl;
use crate::ast_node::polymorphic_type_ast_node::make_polymorphic_type_ast_node_impl;
use crate::ast_node::struct_ast_node::make_struct_ast_node_impl;
@ -30,6 +32,11 @@ pub fn make_ast_node_impl(build_spec: &BuildSpec) -> Option<TokenStream> {
make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop),
),
BuildSpec::PolymorphicPassThrough(_) => None,
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build) => Some(
make_polymorphic_enum_inner_build_ast_node_impl(polymorphic_enum_inner_build),
),
BuildSpec::PolymorphicLeafEnum(_) => None,
BuildSpec::PolymorphicTreeEnum(_) => None,
}
}
@ -48,6 +55,11 @@ fn make_type_ident(build_spec: &BuildSpec) -> Option<Ident> {
BuildSpec::PolymorphicPassThrough(_) => None,
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build) => {
Some(format_ident!("{}", polymorphic_enum_inner_build.name()))
}
BuildSpec::PolymorphicLeafEnum(_) => None,
BuildSpec::PolymorphicTreeEnum(_) => None,
}
}
@ -81,4 +93,4 @@ pub fn make_ast_node_ref_mut_unwrapper(build_spec: &BuildSpec) -> Option<TokenSt
AstNodeRefMut::#type_ident(inner) => *inner
}
})
}
}

View File

@ -0,0 +1,76 @@
use convert_case::{Case, Casing};
use crate::spec::polymorphic_enum_inner_build::{PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMemberKind};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_enum_inner_build_ast_node_impl(
spec: &PolymorphicEnumInnerBuild,
) -> TokenStream {
let type_ident = format_ident!("{}", spec.name());
let match_arms = spec.members()
.map(|member| {
let member_ident = format_ident!("{}", member.name());
match member.kind() {
PolymorphicEnumInnerBuildMemberKind::Leaf => {
quote! {
#type_ident::#member_ident => vec![]
}
}
PolymorphicEnumInnerBuildMemberKind::Struct => {
let child_ident = format_ident!("{}", member.name().to_case(Case::Snake));
quote! {
#type_ident::#member_ident(#child_ident) => vec![
#child_ident
]
}
}
}
})
.collect::<Vec<_>>();
let mut_match_arms = spec.members()
.map(|member| {
let member_ident = format_ident!("{}", member.name());
match member.kind() {
PolymorphicEnumInnerBuildMemberKind::Leaf => {
quote! {
#type_ident::#member_ident => {}
}
}
PolymorphicEnumInnerBuildMemberKind::Struct => {
let child_ident = format_ident!("{}", member.name().to_case(Case::Snake));
quote! {
#type_ident::#member_ident(#child_ident) => {
f(#child_ident as &'a mut dyn AstNode<'a>)
}
}
}
}
})
.collect::<Vec<_>>();
quote! {
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
match self {
#(#match_arms,)*
}
}
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {
match self {
#(#mut_match_arms,)*
}
}
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
}
}
}

View File

@ -1,20 +1,26 @@
use crate::build_fn::leaf_enum_build_fn::make_leaf_enum_build_fn;
use crate::build_fn::leaf_struct_build_fn::make_leaf_struct_build_fn;
use crate::build_fn::node_production_build_fn::make_node_production_build_fn;
use crate::build_fn::polymorphic_enum_loop_build_fn::make_polymorphic_enum_loop_build_fn;
use crate::build_fn::polymorphic_pass_through_build_fn::make_polymorphic_pass_through_build_fn;
use crate::build_fn::polymorphic_type_build_fn::make_polymorphic_type_build_fn;
use crate::build_fn::production_build_fn::make_production_build_fn;
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 leaf_enum_build_fn::make_leaf_enum_build_fn;
use leaf_struct_build_fn::make_leaf_struct_build_fn;
use node_production_build_fn::make_node_production_build_fn;
use polymorphic_enum_inner_build_build_fn::make_polymorphic_enum_inner_build_build_fn;
use polymorphic_enum_loop_build_fn::make_polymorphic_enum_loop_build_fn;
use polymorphic_leaf_enum_build_fn::make_polymorphic_leaf_enum_build_fn;
use polymorphic_pass_through_build_fn::make_polymorphic_pass_through_build_fn;
use polymorphic_tree_enum_build_fn::make_polymorphic_tree_enum_build_fn;
use polymorphic_type_build_fn::make_polymorphic_type_build_fn;
use proc_macro2::TokenStream;
use production_build_fn::make_production_build_fn;
use struct_build_fn::make_struct_build_fn;
use tree_enum_build_fn::make_enum_build_fn;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod node_production_build_fn;
mod polymorphic_enum_inner_build_build_fn;
mod polymorphic_enum_loop_build_fn;
mod polymorphic_leaf_enum_build_fn;
mod polymorphic_pass_through_build_fn;
mod polymorphic_tree_enum_build_fn;
mod polymorphic_type_build_fn;
mod production_build_fn;
mod struct_build_fn;
@ -39,5 +45,14 @@ pub fn make_build_fn(build_spec: &BuildSpec) -> TokenStream {
BuildSpec::PolymorphicPassThrough(polymorphic_pass_through_spec) => {
make_polymorphic_pass_through_build_fn(polymorphic_pass_through_spec)
}
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build_spec) => {
make_polymorphic_enum_inner_build_build_fn(polymorphic_enum_inner_build_spec)
}
BuildSpec::PolymorphicLeafEnum(polymorphic_leaf_enum_spec) => {
make_polymorphic_leaf_enum_build_fn(polymorphic_leaf_enum_spec)
}
BuildSpec::PolymorphicTreeEnum(polymorphic_tree_enum_spec) => {
make_polymorphic_tree_enum_build_fn(polymorphic_tree_enum_spec)
}
}
}

View File

@ -0,0 +1,30 @@
use crate::spec::polymorphic_enum_inner_build::PolymorphicEnumInnerBuild;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
pub fn make_polymorphic_enum_inner_build_build_fn(spec: &PolymorphicEnumInnerBuild) -> 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.name());
let rule_branches = spec.rules()
.map(|rule| {
let rule_ident = format_ident!("{}", rule.name());
let rule_build_fn_ident = format_ident!("{}", rule.with());
quote! {
Rule::#rule_ident => #rule_build_fn_ident(file_id, inner_pair)
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#rule_branches,)*
_ => unreachable!()
}
}
}
}

View File

@ -0,0 +1,29 @@
use crate::spec::polymorphic_leaf_enum::PolymorphicLeafEnum;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_leaf_enum_build_fn(spec: &PolymorphicLeafEnum) -> TokenStream {
let build_fn_ident = format_ident!("build_{}", spec.name().to_case(Case::Snake));
let pair_ident = format_ident!("{}_pair", spec.name().to_case(Case::Snake));
let return_type_ident = format_ident!("{}", spec.kind());
let child_matchers = spec.rules()
.map(|rule| {
let rule_ident = format_ident!("{}", rule);
quote! {
Rule::#rule_ident => #return_type_ident::#rule_ident
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#child_matchers,)*
_ => unreachable!()
}
}
}
}

View File

@ -0,0 +1,33 @@
use crate::spec::polymorphic_tree_enum_spec::PolymorphicTreeEnumSpec;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_tree_enum_build_fn(spec: &PolymorphicTreeEnumSpec) -> TokenStream {
let build_fn_ident = format_ident!("build_{}", spec.name().to_case(Case::Snake));
let pair_ident = format_ident!("{}_pair", spec.name().to_case(Case::Snake));
let return_type_ident = format_ident!("{}", spec.kind());
let rule_matchers = spec
.rules()
.map(|rule| {
let rule_ident = format_ident!("{}", rule);
let inner_build_fn_ident = format_ident!("build_{}", rule.to_case(Case::Snake));
quote! {
Rule::#rule_ident => #return_type_ident::#rule_ident(
#inner_build_fn_ident(file_id, inner_pair)
)
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#rule_matchers,)*
_ => unreachable!(),
}
}
}
}

View File

@ -1,8 +1,11 @@
mod leaf_enum_spec;
mod leaf_struct_spec;
mod node_production_spec;
mod polymorphic_enum_build_inner;
mod polymorphic_enum_loop_spec;
mod polymorphic_leaf_enum;
mod polymorphic_pass_through_spec;
mod polymorphic_tree_enum;
mod polymorphic_type_spec;
mod production_spec;
mod struct_spec;
@ -12,14 +15,17 @@ pub(crate) mod util;
use crate::deserialize::leaf_enum_spec::deserialize_leaf_enum;
use crate::deserialize::leaf_struct_spec::deserialize_leaf_struct;
use crate::deserialize::node_production_spec::deserialize_node_production;
use crate::deserialize::polymorphic_enum_build_inner::deserialize_polymorphic_enum_inner_build;
use crate::deserialize::polymorphic_enum_loop_spec::deserialize_polymorphic_enum_loop;
use crate::deserialize::polymorphic_leaf_enum::deserialize_polymorphic_leaf_enum;
use crate::deserialize::polymorphic_pass_through_spec::deserialize_polymorphic_pass_through;
use crate::deserialize::polymorphic_type_spec::deserialize_polymorphic_type;
use crate::deserialize::production_spec::deserialize_production;
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;
use crate::deserialize::polymorphic_tree_enum::deserialize_polymorphic_tree_enum;
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
if build_spec["struct"].is_hash() {
@ -67,6 +73,21 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
build_spec_name,
&build_spec["polymorphic_pass_through"],
))
} else if build_spec["polymorphic_enum_inner_build"].is_hash() {
BuildSpec::PolymorphicEnumInnerBuild(deserialize_polymorphic_enum_inner_build(
build_spec_name,
&build_spec["polymorphic_enum_inner_build"],
))
} else if build_spec["polymorphic_leaf_enum"].is_hash() {
BuildSpec::PolymorphicLeafEnum(deserialize_polymorphic_leaf_enum(
build_spec_name,
&build_spec["polymorphic_leaf_enum"],
))
} else if build_spec["polymorphic_tree_enum"].is_hash() {
BuildSpec::PolymorphicTreeEnum(deserialize_polymorphic_tree_enum(
build_spec_name,
&build_spec["polymorphic_tree_enum"],
))
} else {
panic!("Missing or incorrect build type for {}", build_spec_name);
}

View File

@ -0,0 +1,59 @@
use crate::deserialize::util::{make_build_fn_name, unwrap_single_member_hash};
use crate::spec::polymorphic_enum_inner_build::{
PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMember,
PolymorphicEnumInnerBuildMemberKind, PolymorphicEnumInnerBuildRule,
};
use yaml_rust2::Yaml;
pub fn deserialize_polymorphic_enum_inner_build(
name: &str,
props: &Yaml,
) -> PolymorphicEnumInnerBuild {
let members = props["members"]
.as_vec()
.unwrap()
.iter()
.map(|member| {
if let Some(name) = member.as_str() {
PolymorphicEnumInnerBuildMember::new(
name,
PolymorphicEnumInnerBuildMemberKind::Struct,
)
} else if member.is_hash() {
let (name, props) = unwrap_single_member_hash(member);
if let Some(kind) = props["kind"].as_str() {
match kind {
"leaf" => PolymorphicEnumInnerBuildMember::new(
&name,
PolymorphicEnumInnerBuildMemberKind::Leaf,
),
"struct" => PolymorphicEnumInnerBuildMember::new(
&name,
PolymorphicEnumInnerBuildMemberKind::Struct,
),
_ => panic!(),
}
} else {
panic!()
}
} else {
panic!()
}
})
.collect::<Vec<_>>();
let rules = props["rules"]
.as_vec()
.unwrap()
.iter()
.map(|rule| {
let rule_as_string = rule.as_str().unwrap().to_string();
PolymorphicEnumInnerBuildRule::new(
&rule_as_string,
&make_build_fn_name(&rule_as_string),
)
})
.collect::<Vec<_>>();
PolymorphicEnumInnerBuild::new(name, members, rules)
}

View File

@ -0,0 +1,13 @@
use yaml_rust2::Yaml;
use crate::spec::polymorphic_leaf_enum::PolymorphicLeafEnum;
pub fn deserialize_polymorphic_leaf_enum(name: &str, props: &Yaml) -> PolymorphicLeafEnum {
let kind = props["kind"].as_str().unwrap();
let rules = props["rules"].as_vec().unwrap()
.iter()
.map(|rule| {
rule.as_str().unwrap().to_string()
})
.collect::<Vec<_>>();
PolymorphicLeafEnum::new(name, kind, rules)
}

View File

@ -0,0 +1,12 @@
use yaml_rust2::Yaml;
use crate::spec::polymorphic_tree_enum_spec::PolymorphicTreeEnumSpec;
pub fn deserialize_polymorphic_tree_enum(name: &str, props: &Yaml) -> PolymorphicTreeEnumSpec {
let kind = props["kind"].as_str().unwrap();
let rules = props["rules"].as_vec().unwrap()
.iter()
.map(|rule| rule.as_str().unwrap())
.collect::<Vec<_>>();
PolymorphicTreeEnumSpec::new(name, kind, &rules)
}

View File

@ -65,6 +65,24 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
pass_through_build_spec.name()
);
}
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build_spec) => {
println!(
"Polymorphic Enum Inner Build Spec - name: {}",
polymorphic_enum_inner_build_spec.name()
);
}
BuildSpec::PolymorphicLeafEnum(polymorphic_leaf_enum) => {
println!(
"Polymorphic Leaf Enum Build Spec - name: {}",
polymorphic_leaf_enum.name()
);
}
BuildSpec::PolymorphicTreeEnum(polymorphic_tree_enum) => {
println!(
"Polymorphic Tree Enum Build Spec - name: {}",
polymorphic_tree_enum.name()
);
}
}
println!("{:#?}", token_stream);
let parsed: File = syn::parse2(token_stream.clone()).unwrap();

View File

@ -10,11 +10,56 @@ use crate::spec::BuildSpec;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::polymorphic_enum_inner_build::{PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMember, PolymorphicEnumInnerBuildMemberKind};
fn make_result() -> TokenStream {
quote! { std::fmt::Result }
}
fn make_polymorphic_enum_inner_build_p2_impl(spec: &PolymorphicEnumInnerBuild) -> TokenStream {
let type_ident = format_ident!("{}", spec.name());
let result = make_result();
let type_string = spec.name();
let child_matchers = spec.members()
.map(|member| {
let variant_ident = format_ident!("{}", member.name());
match member.kind() {
PolymorphicEnumInnerBuildMemberKind::Leaf => {
let variant_string = member.name();
quote! {
#type_ident::#variant_ident => writer.writeln_indented(#variant_string)?
}
}
PolymorphicEnumInnerBuildMemberKind::Struct => {
let child_ident = format_ident!("{}", member.name().to_case(Case::Snake));
quote! {
#type_ident::#variant_ident(#child_ident) => {
#child_ident.pretty_print(writer)?;
}
}
}
}
})
.collect::<Vec<_>>();
quote! {
impl PrettyPrint for #type_ident {
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
writer.writeln_indented(#type_string)?;
writer.increase_indent();
match self {
#(#child_matchers,)*
_ => {}
}
writer.decrease_indent();
Ok(())
}
}
}
}
fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.name());
let type_string = spec.name();
@ -285,5 +330,10 @@ pub fn make_pretty_print_impl(build_spec: &BuildSpec) -> Option<TokenStream> {
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
Some(make_polymorphic_enum_loop_p2_impl(polymorphic_enum_loop))
}
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build) => {
Some(make_polymorphic_enum_inner_build_p2_impl(polymorphic_enum_inner_build))
}
BuildSpec::PolymorphicLeafEnum(_) => None,
BuildSpec::PolymorphicTreeEnum(_) => None,
}
}

View File

@ -1,18 +1,24 @@
use crate::spec::node_production_spec::NodeProductionBuildSpec;
use crate::spec::polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use polymorphic_leaf_enum::PolymorphicLeafEnum;
use leaf_enum_spec::LeafEnumBuildSpec;
use leaf_struct_spec::LeafStructBuildSpec;
use node_production_spec::NodeProductionBuildSpec;
use polymorphic_enum_inner_build::PolymorphicEnumInnerBuild;
use polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use polymorphic_pass_through_spec::PolymorphicPassThroughBuildSpec;
use polymorphic_type_spec::PolymorphicTypeBuildSpec;
use production_spec::ProductionBuildSpec;
use struct_spec::StructSpec;
use tree_enum_spec::TreeEnumBuildSpec;
use crate::spec::polymorphic_pass_through_spec::PolymorphicPassThroughBuildSpec;
use polymorphic_tree_enum_spec::PolymorphicTreeEnumSpec;
pub(crate) mod leaf_enum_spec;
pub(crate) mod leaf_struct_spec;
pub(crate) mod node_production_spec;
pub(crate) mod polymorphic_enum_inner_build;
pub(crate) mod polymorphic_enum_loop_spec;
pub(crate) mod polymorphic_leaf_enum;
pub(crate) mod polymorphic_pass_through_spec;
pub(crate) mod polymorphic_tree_enum_spec;
pub(crate) mod polymorphic_type_spec;
pub(crate) mod production_spec;
pub(crate) mod struct_spec;
@ -27,5 +33,8 @@ pub enum BuildSpec {
NodeProduction(NodeProductionBuildSpec),
PolymorphicType(PolymorphicTypeBuildSpec),
PolymorphicEnumLoop(PolymorphicEnumLoopBuildSpec),
PolymorphicPassThrough(PolymorphicPassThroughBuildSpec)
PolymorphicPassThrough(PolymorphicPassThroughBuildSpec),
PolymorphicEnumInnerBuild(PolymorphicEnumInnerBuild),
PolymorphicLeafEnum(PolymorphicLeafEnum),
PolymorphicTreeEnum(PolymorphicTreeEnumSpec),
}

View File

@ -0,0 +1,76 @@
pub struct PolymorphicEnumInnerBuild {
name: String,
members: Vec<PolymorphicEnumInnerBuildMember>,
rules: Vec<PolymorphicEnumInnerBuildRule>,
}
impl PolymorphicEnumInnerBuild {
pub fn new(name: &str, members: Vec<PolymorphicEnumInnerBuildMember>, rules: Vec<PolymorphicEnumInnerBuildRule>) -> Self {
Self {
name: name.to_string(),
members,
rules,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn members(&self) -> impl Iterator<Item = &PolymorphicEnumInnerBuildMember> {
self.members.iter()
}
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumInnerBuildRule> {
self.rules.iter()
}
}
pub struct PolymorphicEnumInnerBuildMember {
name: String,
kind: PolymorphicEnumInnerBuildMemberKind
}
impl PolymorphicEnumInnerBuildMember {
pub fn new(name: &str, kind: PolymorphicEnumInnerBuildMemberKind) -> Self {
Self {
name: name.to_string(),
kind
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &PolymorphicEnumInnerBuildMemberKind {
&self.kind
}
}
pub enum PolymorphicEnumInnerBuildMemberKind {
Leaf,
Struct
}
pub struct PolymorphicEnumInnerBuildRule {
name: String,
with: String,
}
impl PolymorphicEnumInnerBuildRule {
pub fn new(name: &str, with: &str) -> Self {
Self {
name: name.to_string(),
with: with.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn with(&self) -> &str {
&self.with
}
}

View File

@ -0,0 +1,27 @@
pub struct PolymorphicLeafEnum {
name: String,
kind: String,
rules: Vec<String>,
}
impl PolymorphicLeafEnum {
pub fn new(name: &str, kind: &str, rules: Vec<String>) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
rules,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn rules(&self) -> impl Iterator<Item = &str> {
self.rules.iter().map(AsRef::as_ref)
}
}

View File

@ -0,0 +1,27 @@
pub struct PolymorphicTreeEnumSpec {
name: String,
kind: String,
rules: Vec<String>,
}
impl PolymorphicTreeEnumSpec {
pub fn new(name: &str, kind: &str, rules: &[&str]) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
rules: rules.iter().map(ToString::to_string).collect(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn rules(&self) -> impl Iterator<Item = &str> {
self.rules.iter().map(AsRef::as_ref)
}
}

View File

@ -1,6 +1,7 @@
mod enum_type;
mod leaf_enum_type;
mod leaf_struct_type;
mod polymorphic_enum_inner_build_type;
mod polymorphic_enum_loop_type;
mod polymorphic_type_type;
mod struct_type;
@ -9,10 +10,11 @@ use crate::spec::BuildSpec;
use crate::type_gen::enum_type::make_enum_type;
use crate::type_gen::leaf_enum_type::make_leaf_enum_type;
use crate::type_gen::leaf_struct_type::make_leaf_struct_type;
use crate::type_gen::polymorphic_enum_inner_build_type::make_polymorphic_enum_inner_build_type;
use crate::type_gen::polymorphic_enum_loop_type::make_polymorphic_enum_loop_type;
use crate::type_gen::polymorphic_type_type::make_polymorphic_type_type;
use crate::type_gen::struct_type::make_struct_type;
use proc_macro2::TokenStream;
use crate::type_gen::polymorphic_enum_loop_type::make_polymorphic_enum_loop_type;
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
match build_spec {
@ -31,7 +33,12 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
}
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_spec) => {
Some(make_polymorphic_enum_loop_type(polymorphic_enum_loop_spec))
},
}
BuildSpec::PolymorphicPassThrough(_) => None,
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build_spec) => Some(
make_polymorphic_enum_inner_build_type(polymorphic_enum_inner_build_spec),
),
BuildSpec::PolymorphicLeafEnum(_) => None,
BuildSpec::PolymorphicTreeEnum(_) => None,
}
}

View File

@ -0,0 +1,25 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::polymorphic_enum_inner_build::{PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMemberKind};
pub fn make_polymorphic_enum_inner_build_type(spec: &PolymorphicEnumInnerBuild) -> TokenStream {
let members = spec.members()
.map(|member| {
let name_ident = format_ident!("{}", member.name());
match member.kind() {
PolymorphicEnumInnerBuildMemberKind::Leaf => {
quote! { #name_ident }
}
PolymorphicEnumInnerBuildMemberKind::Struct => {
quote! { #name_ident(#name_ident) }
}
}
})
.collect::<Vec<_>>();
let type_name_ident = format_ident!("{}", spec.name());
quote! {
pub enum #type_name_ident {
#(#members,)*
}
}
}

View File

@ -1,4 +1,13 @@
use crate::ast::node::{AnySpaceSuffixOperator, AssignmentStatement, BacktickString, BoundSuffixOperator, Call, Closure, ClosureParameters, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, DString, Expression, ExpressionList, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody, FunctionBody, FunctionEqualsBody, GenericParameters, Identifier, IdentifierExpression, IdentifierOrFqn, LValue, LValueSuffix, Literal, ModuleLevelDeclaration, NoNewlineSuffixOperator, ObjectIndex, Parameter, Parameters, PlatformFunction, PrimitiveType, ReturnType, StarUseStatement, Statement, SuffixExpression, SuffixOperator, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, UseStatementPrefix, VariableDeclaration};
use crate::ast::node::{
AssignmentStatement, BacktickString, Call, Closure, ClosureParameters,
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, DString, Expression,
ExpressionList, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody,
FunctionBody, FunctionEqualsBody, GenericParameters, Identifier, IdentifierExpression,
IdentifierOrFqn, LValue, LValueSuffix, Literal, ModuleLevelDeclaration
, ObjectIndex, Parameter, Parameters, PlatformFunction, PrimitiveType,
ReturnType, StarUseStatement, Statement, SuffixExpression, SuffixOperator, TypeUse, TypedArray,
UseStatement, UseStatementIdentifier, UseStatementPrefix, VariableDeclaration,
};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
@ -668,30 +677,16 @@ fn na_p2_suffix_operator(
diagnostics: &mut Vec<DmDiagnostic>,
) {
match suffix_operator {
SuffixOperator::BoundSuffixOperator(bound_suffix) => {
match bound_suffix {
BoundSuffixOperator::PlusPlus => {
// no-op
}
BoundSuffixOperator::MinusMinus => {
// no-op
}
}
SuffixOperator::PlusPlus => {}
SuffixOperator::MinusMinus => {}
SuffixOperator::ObjectIndex(object_index) => {
na_p2_object_index(object_index, symbol_table, diagnostics);
}
SuffixOperator::NoNewlineSuffixOperator(no_newline_suffix) => match no_newline_suffix {
NoNewlineSuffixOperator::ObjectIndex(object_index) => {
na_p2_object_index(object_index, symbol_table, diagnostics);
}
NoNewlineSuffixOperator::Call(call) => {
na_p2_call(call, symbol_table, diagnostics);
}
},
SuffixOperator::AnySpaceSuffixOperator(any_space_suffix) => {
match any_space_suffix {
AnySpaceSuffixOperator::ObjectProperty(_) => {
// no-op; this is checked during type checking
}
}
SuffixOperator::Call(call) => {
na_p2_call(call, symbol_table, diagnostics);
}
SuffixOperator::ObjectProperty(object_property) => {
todo!()
}
}
}

View File

@ -1158,23 +1158,34 @@ SuffixExpression:
on_each:
rule: SuffixOperator
SuffixOperator:
tree_enum:
polymorphic_enum_inner_build:
members:
- PlusPlus:
kind: leaf
- MinusMinus:
kind: leaf
- ObjectIndex
- Call
- ObjectProperty
rules:
- BoundSuffixOperator
- NoNewlineSuffixOperator
- AnySpaceSuffixOperator
BoundSuffixOperator:
leaf_enum:
polymorphic_leaf_enum:
kind: SuffixOperator
rules:
- PlusPlus
- MinusMinus
NoNewlineSuffixOperator:
tree_enum:
polymorphic_tree_enum:
kind: SuffixOperator
rules:
- ObjectIndex
- Call
AnySpaceSuffixOperator:
tree_enum:
polymorphic_tree_enum:
kind: SuffixOperator
rules:
- ObjectProperty
ObjectProperty: