From f21128fd6847451b48a32b73ca2181080124ece6 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 15 Nov 2025 18:13:25 -0600 Subject: [PATCH] Add support for polymorphic enum builds (used for suffix operators). --- ast-generator/src/ast_node/mod.rs | 14 +++- .../polymorphic_enum_inner_build_ast_node.rs | 76 +++++++++++++++++++ ast-generator/src/build_fn/mod.rs | 33 +++++--- .../polymorphic_enum_inner_build_build_fn.rs | 30 ++++++++ .../polymorphic_leaf_enum_build_fn.rs | 29 +++++++ .../polymorphic_tree_enum_build_fn.rs | 33 ++++++++ ast-generator/src/deserialize/mod.rs | 23 +++++- .../polymorphic_enum_build_inner.rs | 59 ++++++++++++++ .../src/deserialize/polymorphic_leaf_enum.rs | 13 ++++ .../src/deserialize/polymorphic_tree_enum.rs | 12 +++ ast-generator/src/lib.rs | 18 +++++ ast-generator/src/pretty_print.rs | 50 ++++++++++++ ast-generator/src/spec/mod.rs | 17 ++++- .../src/spec/polymorphic_enum_inner_build.rs | 76 +++++++++++++++++++ .../src/spec/polymorphic_leaf_enum.rs | 27 +++++++ .../src/spec/polymorphic_tree_enum_spec.rs | 27 +++++++ ast-generator/src/type_gen/mod.rs | 11 ++- .../polymorphic_enum_inner_build_type.rs | 25 ++++++ src/name_analysis/second_pass.rs | 43 +++++------ src/parser/ast.yaml | 19 ++++- 20 files changed, 590 insertions(+), 45 deletions(-) create mode 100644 ast-generator/src/ast_node/polymorphic_enum_inner_build_ast_node.rs create mode 100644 ast-generator/src/build_fn/polymorphic_enum_inner_build_build_fn.rs create mode 100644 ast-generator/src/build_fn/polymorphic_leaf_enum_build_fn.rs create mode 100644 ast-generator/src/build_fn/polymorphic_tree_enum_build_fn.rs create mode 100644 ast-generator/src/deserialize/polymorphic_enum_build_inner.rs create mode 100644 ast-generator/src/deserialize/polymorphic_leaf_enum.rs create mode 100644 ast-generator/src/deserialize/polymorphic_tree_enum.rs create mode 100644 ast-generator/src/spec/polymorphic_enum_inner_build.rs create mode 100644 ast-generator/src/spec/polymorphic_leaf_enum.rs create mode 100644 ast-generator/src/spec/polymorphic_tree_enum_spec.rs create mode 100644 ast-generator/src/type_gen/polymorphic_enum_inner_build_type.rs diff --git a/ast-generator/src/ast_node/mod.rs b/ast-generator/src/ast_node/mod.rs index fbbac07..0012148 100644 --- a/ast-generator/src/ast_node/mod.rs +++ b/ast-generator/src/ast_node/mod.rs @@ -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 { 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 { 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 *inner } }) -} \ No newline at end of file +} diff --git a/ast-generator/src/ast_node/polymorphic_enum_inner_build_ast_node.rs b/ast-generator/src/ast_node/polymorphic_enum_inner_build_ast_node.rs new file mode 100644 index 0000000..f8f34b0 --- /dev/null +++ b/ast-generator/src/ast_node/polymorphic_enum_inner_build_ast_node.rs @@ -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::>(); + + 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::>(); + + 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) + } + } + } +} diff --git a/ast-generator/src/build_fn/mod.rs b/ast-generator/src/build_fn/mod.rs index fe71df2..0963148 100644 --- a/ast-generator/src/build_fn/mod.rs +++ b/ast-generator/src/build_fn/mod.rs @@ -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) + } } } diff --git a/ast-generator/src/build_fn/polymorphic_enum_inner_build_build_fn.rs b/ast-generator/src/build_fn/polymorphic_enum_inner_build_build_fn.rs new file mode 100644 index 0000000..5591acc --- /dev/null +++ b/ast-generator/src/build_fn/polymorphic_enum_inner_build_build_fn.rs @@ -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::>(); + + quote! { + fn #build_fn_ident(file_id: usize, #pair_ident: Pair) -> #return_type_ident { + let inner_pair = #pair_ident.into_inner().next().unwrap(); + match inner_pair.as_rule() { + #(#rule_branches,)* + _ => unreachable!() + } + } + } +} diff --git a/ast-generator/src/build_fn/polymorphic_leaf_enum_build_fn.rs b/ast-generator/src/build_fn/polymorphic_leaf_enum_build_fn.rs new file mode 100644 index 0000000..5dad9ad --- /dev/null +++ b/ast-generator/src/build_fn/polymorphic_leaf_enum_build_fn.rs @@ -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::>(); + + quote! { + fn #build_fn_ident(file_id: usize, #pair_ident: Pair) -> #return_type_ident { + let inner_pair = #pair_ident.into_inner().next().unwrap(); + match inner_pair.as_rule() { + #(#child_matchers,)* + _ => unreachable!() + } + } + } +} diff --git a/ast-generator/src/build_fn/polymorphic_tree_enum_build_fn.rs b/ast-generator/src/build_fn/polymorphic_tree_enum_build_fn.rs new file mode 100644 index 0000000..e98bf32 --- /dev/null +++ b/ast-generator/src/build_fn/polymorphic_tree_enum_build_fn.rs @@ -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::>(); + + quote! { + fn #build_fn_ident(file_id: usize, #pair_ident: Pair) -> #return_type_ident { + let inner_pair = #pair_ident.into_inner().next().unwrap(); + match inner_pair.as_rule() { + #(#rule_matchers,)* + _ => unreachable!(), + } + } + } +} diff --git a/ast-generator/src/deserialize/mod.rs b/ast-generator/src/deserialize/mod.rs index f47b1c7..da1f801 100644 --- a/ast-generator/src/deserialize/mod.rs +++ b/ast-generator/src/deserialize/mod.rs @@ -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); } diff --git a/ast-generator/src/deserialize/polymorphic_enum_build_inner.rs b/ast-generator/src/deserialize/polymorphic_enum_build_inner.rs new file mode 100644 index 0000000..08daacb --- /dev/null +++ b/ast-generator/src/deserialize/polymorphic_enum_build_inner.rs @@ -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::>(); + + 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::>(); + + PolymorphicEnumInnerBuild::new(name, members, rules) +} diff --git a/ast-generator/src/deserialize/polymorphic_leaf_enum.rs b/ast-generator/src/deserialize/polymorphic_leaf_enum.rs new file mode 100644 index 0000000..4d31973 --- /dev/null +++ b/ast-generator/src/deserialize/polymorphic_leaf_enum.rs @@ -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::>(); + PolymorphicLeafEnum::new(name, kind, rules) +} \ No newline at end of file diff --git a/ast-generator/src/deserialize/polymorphic_tree_enum.rs b/ast-generator/src/deserialize/polymorphic_tree_enum.rs new file mode 100644 index 0000000..b78c474 --- /dev/null +++ b/ast-generator/src/deserialize/polymorphic_tree_enum.rs @@ -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::>(); + + PolymorphicTreeEnumSpec::new(name, kind, &rules) +} \ No newline at end of file diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index 0566049..201bfc0 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -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(); diff --git a/ast-generator/src/pretty_print.rs b/ast-generator/src/pretty_print.rs index e90106e..06e5f06 100644 --- a/ast-generator/src/pretty_print.rs +++ b/ast-generator/src/pretty_print.rs @@ -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::>(); + + 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 { 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, } } diff --git a/ast-generator/src/spec/mod.rs b/ast-generator/src/spec/mod.rs index ce6929c..83ea54b 100644 --- a/ast-generator/src/spec/mod.rs +++ b/ast-generator/src/spec/mod.rs @@ -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), } diff --git a/ast-generator/src/spec/polymorphic_enum_inner_build.rs b/ast-generator/src/spec/polymorphic_enum_inner_build.rs new file mode 100644 index 0000000..64c7b35 --- /dev/null +++ b/ast-generator/src/spec/polymorphic_enum_inner_build.rs @@ -0,0 +1,76 @@ +pub struct PolymorphicEnumInnerBuild { + name: String, + members: Vec, + rules: Vec, +} + +impl PolymorphicEnumInnerBuild { + pub fn new(name: &str, members: Vec, rules: Vec) -> Self { + Self { + name: name.to_string(), + members, + rules, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn members(&self) -> impl Iterator { + self.members.iter() + } + + pub fn rules(&self) -> impl Iterator { + 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 + } +} \ No newline at end of file diff --git a/ast-generator/src/spec/polymorphic_leaf_enum.rs b/ast-generator/src/spec/polymorphic_leaf_enum.rs new file mode 100644 index 0000000..7f2eeec --- /dev/null +++ b/ast-generator/src/spec/polymorphic_leaf_enum.rs @@ -0,0 +1,27 @@ +pub struct PolymorphicLeafEnum { + name: String, + kind: String, + rules: Vec, +} + +impl PolymorphicLeafEnum { + pub fn new(name: &str, kind: &str, rules: Vec) -> 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 { + self.rules.iter().map(AsRef::as_ref) + } +} diff --git a/ast-generator/src/spec/polymorphic_tree_enum_spec.rs b/ast-generator/src/spec/polymorphic_tree_enum_spec.rs new file mode 100644 index 0000000..c5c2691 --- /dev/null +++ b/ast-generator/src/spec/polymorphic_tree_enum_spec.rs @@ -0,0 +1,27 @@ +pub struct PolymorphicTreeEnumSpec { + name: String, + kind: String, + rules: Vec, +} + +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 { + self.rules.iter().map(AsRef::as_ref) + } +} \ No newline at end of file diff --git a/ast-generator/src/type_gen/mod.rs b/ast-generator/src/type_gen/mod.rs index f218bbd..cbc2103 100644 --- a/ast-generator/src/type_gen/mod.rs +++ b/ast-generator/src/type_gen/mod.rs @@ -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 { match build_spec { @@ -31,7 +33,12 @@ pub fn make_type(build_spec: &BuildSpec) -> Option { } 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, } } diff --git a/ast-generator/src/type_gen/polymorphic_enum_inner_build_type.rs b/ast-generator/src/type_gen/polymorphic_enum_inner_build_type.rs new file mode 100644 index 0000000..57d7d6d --- /dev/null +++ b/ast-generator/src/type_gen/polymorphic_enum_inner_build_type.rs @@ -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::>(); + let type_name_ident = format_ident!("{}", spec.name()); + quote! { + pub enum #type_name_ident { + #(#members,)* + } + } +} \ No newline at end of file diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index bcffad1..142a656 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -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, ) { 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!() } } } diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 375cab4..70cbe7f 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -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: