From f3c3e40eb2c87159b8419cc9a2b6f8cabfa42587 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 15 Sep 2025 21:12:38 -0500 Subject: [PATCH] Big refactor of ast gen. --- ast-generator/src/deserialize.rs | 7 +- ast-generator/src/enum_build_fn.rs | 29 +++-- ast-generator/src/leaf_enum_build_fn.rs | 14 +-- ast-generator/src/leaf_struct_build_fn.rs | 10 +- ast-generator/src/lib.rs | 1 + ast-generator/src/main.rs | 6 -- ast-generator/src/production_build_fn.rs | 47 ++++---- ast-generator/src/spec.rs | 3 - ast-generator/src/type_gen.rs | 125 +++++++++++----------- 9 files changed, 121 insertions(+), 121 deletions(-) delete mode 100644 ast-generator/src/main.rs diff --git a/ast-generator/src/deserialize.rs b/ast-generator/src/deserialize.rs index cc1a504..a13cddd 100644 --- a/ast-generator/src/deserialize.rs +++ b/ast-generator/src/deserialize.rs @@ -53,7 +53,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec> { } fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option> { - if !rule_props["child"].as_bool().unwrap() { + if !rule_props["child"].as_bool().unwrap_or(true) { None } else { let kind = match rule_props["kind"].as_str().unwrap() { @@ -163,7 +163,8 @@ fn deserialize_member_child_to_build( panic!("unsupported kind: {}", kind) } } else { - panic!("build is required for a member child") + let optional = get_as_bool(&props["optional"]); + Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(rule, None, optional))) } } @@ -276,7 +277,7 @@ 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 { panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type."); } diff --git a/ast-generator/src/enum_build_fn.rs b/ast-generator/src/enum_build_fn.rs index 906dd4d..296f6e4 100644 --- a/ast-generator/src/enum_build_fn.rs +++ b/ast-generator/src/enum_build_fn.rs @@ -1,4 +1,4 @@ -use crate::spec::EnumBuildSpec; +use crate::spec::{EnumBuildSpec, EnumRuleChildKind}; use crate::util::{make_build_fn_name, make_build_pair}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -10,12 +10,28 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream { let rule_branches = enum_build_spec .rules() - .iter() .map(|enum_rule| { let rule_ident = format_ident!("{}", enum_rule.rule()); - let build_rule_ident = format_ident!("{}", enum_rule.with()); - quote! { - Rule::#rule_ident => #build_rule_ident(inner_pair) + if let Some(child) = enum_rule.child() { + let inner_builder = match child.kind() { + EnumRuleChildKind::Node(node_child) => { + let inner_build_fn_ident = + format_ident!("{}", make_build_fn_name(node_child.build())); + quote! { #inner_build_fn_ident(inner_pair) } + } + _ => { + let inner_build_fn_ident = + format_ident!("{}", make_build_fn_name(enum_rule.rule())); + quote! { #inner_build_fn_ident(inner_pair) } + } + }; + quote! { + Rule::#rule_ident => #return_type_ident::#rule_ident(#inner_builder) + } + } else { + quote! { + Rule::#rule_ident => #return_type_ident::#rule_ident + } } }) .collect::>(); @@ -24,7 +40,8 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream { fn #build_fn_ident(#pair_ident: Pair) -> #return_type_ident { let inner_pair = #pair_ident.into_inner().next().unwrap(); match inner_pair.as_rule() { - #(#rule_branches),* + #(#rule_branches,)* + _ => unreachable!() } } } diff --git a/ast-generator/src/leaf_enum_build_fn.rs b/ast-generator/src/leaf_enum_build_fn.rs index 9ff9813..8ee0648 100644 --- a/ast-generator/src/leaf_enum_build_fn.rs +++ b/ast-generator/src/leaf_enum_build_fn.rs @@ -9,18 +9,10 @@ pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> Toke let return_type_ident = format_ident!("{}", leaf_enum_build_spec.build()); let rule_branches = leaf_enum_build_spec.rules() - .iter() .map(|leaf_enum_rule| { let rule_ident = format_ident!("{}", leaf_enum_rule.rule()); - if leaf_enum_rule.build().child().is_some() { - let child_build_fn_ident = format_ident!("{}", leaf_enum_rule.build().child().unwrap().with()); - quote! { - Rule::#rule_ident => #return_type_ident::#rule_ident(#child_build_fn_ident(inner_pair)) - } - } else { - quote! { - Rule::#rule_ident => #return_type_ident::#rule_ident - } + quote! { + Rule::#rule_ident => #return_type_ident::#rule_ident } }) .collect::>(); @@ -30,7 +22,7 @@ pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> Toke let inner_pair = #pair_ident.into_inner().next().unwrap(); match inner_pair.as_rule() { #(#rule_branches,)* - _ => panic!("Unexpected rule: {:?}", inner_pair.as_rule()) + _ => unreachable!() } } } diff --git a/ast-generator/src/leaf_struct_build_fn.rs b/ast-generator/src/leaf_struct_build_fn.rs index 71f1f2d..7746d9e 100644 --- a/ast-generator/src/leaf_struct_build_fn.rs +++ b/ast-generator/src/leaf_struct_build_fn.rs @@ -10,10 +10,9 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea let child_builders = build_spec .members() - .iter() - .map(|leaf_struct_child| { - let child_ident = format_ident!("{}", leaf_struct_child.name()); - match leaf_struct_child.r#type() { + .map(|member| { + let child_ident = format_ident!("{}", member.name()); + match member.kind() { LeafStructMemberKind::String => { quote! { let #child_ident = #pair_ident.as_str() @@ -25,8 +24,7 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea let child_args = build_spec .members() - .iter() - .map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name())) + .map(|member| format_ident!("{}", member.name())) .collect::>(); quote! { diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index 0a4269d..50fb8e1 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -100,6 +100,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { let types = build_specs .iter() .map(|build_spec| make_type(build_spec)) + .filter(Option::is_some) .collect::>(); let combined = quote! { #(#types)* diff --git a/ast-generator/src/main.rs b/ast-generator/src/main.rs deleted file mode 100644 index 1ba4f81..0000000 --- a/ast-generator/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -use ast_generator::test_dump; - -fn main() { - let s = test_dump(); - println!("{}", s); -} diff --git a/ast-generator/src/production_build_fn.rs b/ast-generator/src/production_build_fn.rs index cba13eb..57ad1b1 100644 --- a/ast-generator/src/production_build_fn.rs +++ b/ast-generator/src/production_build_fn.rs @@ -1,7 +1,7 @@ -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom}; use crate::util::{make_build_fn_name, make_build_pair}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> TokenStream { let build_fn_ident = format_ident!("{}", make_build_fn_name(production_build_spec.rule())); @@ -13,13 +13,13 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> ProductionKind::Boolean => format_ident!("bool"), }; let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule())); - + let pair_mapper = match production_build_spec.kind() { ProductionKind::Int => quote! { - let number_base_pair = #pair_ident.to_inner() + let number_base_pair = #pair_ident.into_inner() .next() .unwrap(); - let inner_number_base_pair = number_base_pair.to_inner() + let inner_number_base_pair = number_base_pair.into_inner() .next() .unwrap(); match inner_number_base_pair.as_rule() { @@ -36,10 +36,10 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> } }, ProductionKind::Long => quote! { - let number_base_pair = #pair_ident.to_inner() + let number_base_pair = #pair_ident.into_inner() .next() .unwrap(); - let inner_number_base_pair = number_base_pair.to_inner() + let inner_number_base_pair = number_base_pair.into_inner() .next() .unwrap(); match inner_number_base_pair.as_rule() { @@ -58,33 +58,30 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> ProductionKind::Double => quote! { #pair_ident.as_str().parse::().unwrap() }, - ProductionKind::String(from) => { - match from { - ProductionStringFrom::StringInner => { - quote! { - #pair_ident.to_inner() - .iter() - .next() - .unwrap() - .as_str() - .to_string() - } + ProductionKind::String(from) => match from { + ProductionStringFrom::StringInner => { + quote! { + #pair_ident.into_inner() + .next() + .unwrap() + .as_str() + .to_string() } - ProductionStringFrom::WholePair => { - quote! { - #pair_ident.as_string().to_string() - } + } + ProductionStringFrom::WholePair => { + quote! { + #pair_ident.as_str().to_string() } } }, ProductionKind::Boolean => quote! { #pair_ident.as_str().parse::().unwrap() - } + }, }; - + quote! { fn #build_fn_ident(#pair_ident: Pair) -> #return_type_ident { #pair_mapper } } -} \ No newline at end of file +} diff --git a/ast-generator/src/spec.rs b/ast-generator/src/spec.rs index 9fb47e0..22da2c3 100644 --- a/ast-generator/src/spec.rs +++ b/ast-generator/src/spec.rs @@ -1,6 +1,3 @@ -use crate::util::make_build_fn_name; -use convert_case::{Case, Casing}; - pub enum BuildSpec { Enum(EnumBuildSpec), LeafEnum(LeafEnumBuildSpec), diff --git a/ast-generator/src/type_gen.rs b/ast-generator/src/type_gen.rs index 9d9b28f..3a479d4 100644 --- a/ast-generator/src/type_gen.rs +++ b/ast-generator/src/type_gen.rs @@ -1,20 +1,32 @@ -use crate::spec::{ - BooleanChildToBuild, BuildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec, - LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, - VecChild, VecChildToBuild, -}; +use convert_case::{Case, Casing}; +use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream { let children: Vec = build_spec .rules() - .iter() - .map(|rule| { - let member_name_ident = format_ident!("{}", rule.rule()); - let child_name_ident = format_ident!("{}", rule.build()); - quote! { - #member_name_ident(#child_name_ident) + .map(|enum_rule| { + let member_name_ident = format_ident!("{}", enum_rule.rule()); + if let Some(enum_rule_child) = enum_rule.child() { + let child_type_ident = match enum_rule_child.kind() { + EnumRuleChildKind::Node(node_child) => { + format_ident!("{}", node_child.build()) + }, + EnumRuleChildKind::Int => format_ident!("i32"), + EnumRuleChildKind::Long => format_ident!("i64"), + EnumRuleChildKind::Double => format_ident!("f64"), + EnumRuleChildKind::USize => format_ident!("usize"), + EnumRuleChildKind::String => format_ident!("String"), + EnumRuleChildKind::Boolean => format_ident!("bool"), + }; + quote! { + #member_name_ident(#child_type_ident) + } + } else { + quote! { + #member_name_ident + } } }) .collect(); @@ -30,19 +42,10 @@ fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream { let type_name_ident = format_ident!("{}", build_spec.build()); let children = build_spec .rules() - .iter() .map(|leaf_enum_rule| { let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule()); - if leaf_enum_rule.build().child().is_some() { - let child_type_ident = - format_ident!("{}", leaf_enum_rule.build().child().unwrap().build()); - quote! { - #rule_name_ident(#child_type_ident) - } - } else { - quote! { - #rule_name_ident - } + quote! { + #rule_name_ident } }) .collect::>(); @@ -60,12 +63,13 @@ fn handle_vec_child( annotated_members: &mut Vec, accessors: &mut Vec, ) { - let (child_ident, child_ident_mut, child_type_ident) = match vec_child.build() { - VecChildToBuild::Node(vec_type_child) => ( - format_ident!("{}", vec_type_child.var_name()), - format_ident!("{}_mut", vec_type_child.var_name()), - format_ident!("{}", vec_type_child.build()), - ), + let (child_ident, child_ident_mut) = ( + format_ident!("{}", vec_child.name()), + format_ident!("{}", vec_child.name()), + ); + let child_type_ident = match vec_child.build() { + VecChildToBuild::Node(vec_node_child) => format_ident!("{}", vec_node_child.build()), + VecChildToBuild::String => format_ident!("{}", "String"), }; member_names.push(child_ident.clone()); @@ -83,17 +87,19 @@ fn handle_vec_child( }); } -fn handle_single_type_child( - single_type_child: &NodeChildToBuild, +fn handle_node_child( + node_child: &NodeChildToBuild, member_names: &mut Vec, annotated_members: &mut Vec, accessors: &mut Vec, ) { - let child_ident = format_ident!("{}", single_type_child.var_name()); - let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name()); - let child_type_ident = format_ident!("{}", single_type_child.build()); + let child_ident = format_ident!("{}", node_child.build().to_case(Case::Snake)); + let child_ident_mut = format_ident!("{}_mut", child_ident); + let child_type_ident = format_ident!("{}", node_child.build()); + member_names.push(child_ident.clone()); - if single_type_child.optional() { + + if node_child.optional() { annotated_members.push(quote! { #child_ident: Option> }); @@ -102,7 +108,7 @@ fn handle_single_type_child( #child_ident: Box<#child_type_ident> }) } - if single_type_child.optional() { + if node_child.optional() { accessors.push(quote! { pub fn #child_ident(&self) -> Option<&#child_type_ident> { if let Some(#child_ident) = &self.#child_ident { @@ -133,7 +139,7 @@ fn handle_single_type_child( } } -fn handle_single_boolean_child( +fn handle_boolean_child( single_boolean_child: &BooleanChildToBuild, member_names: &mut Vec, annotated_members: &mut Vec, @@ -156,7 +162,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream { let mut annotated_members: Vec = vec![]; let mut accessors: Vec = vec![]; - for child_spec in build_spec.children().iter() { + for child_spec in build_spec.children() { match child_spec { StructChildSpec::SkipChild(_) => {} StructChildSpec::VecChild(vec_child) => { @@ -167,25 +173,24 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream { &mut accessors, ); } - StructChildSpec::MemberChild(single_child) => { - match single_child.build() { - MemberChildToBuild::Node(single_type_child) => { - handle_single_type_child( - single_type_child, + StructChildSpec::MemberChild(member_child) => { + match member_child.build() { + MemberChildToBuild::Node(node_child) => { + handle_node_child( + node_child, &mut member_names, &mut annotated_members, &mut accessors, ); } - MemberChildToBuild::Boolean(single_boolean_child) => { - handle_single_boolean_child( - single_boolean_child, + MemberChildToBuild::Boolean(boolean_child) => { + handle_boolean_child( + boolean_child, &mut member_names, &mut annotated_members, &mut accessors, ); } - _ => {} }; } } @@ -215,10 +220,9 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream { let annotated_members = build_spec .members() - .iter() - .map(|leaf_struct_child| { - let name_ident = format_ident!("{}", leaf_struct_child.name()); - let type_ident = match leaf_struct_child.r#type() { + .map(|member| { + let name_ident = format_ident!("{}", member.name()); + let type_ident = match member.kind() { LeafStructMemberKind::String => format_ident!("{}", "String"), }; quote! { @@ -229,16 +233,14 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream { let member_names = build_spec .members() - .iter() .map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name())) .collect::>(); let accessors = build_spec .members() - .iter() - .map(|leaf_struct_child| { - let name_ident = format_ident!("{}", leaf_struct_child.name()); - match leaf_struct_child.r#type() { + .map(|member| { + let name_ident = format_ident!("{}", member.name()); + match member.kind() { LeafStructMemberKind::String => { quote! { pub fn #name_ident(&self) -> &str { @@ -267,13 +269,14 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream { } } -pub fn make_type(build_spec: &BuildSpec) -> TokenStream { +pub fn make_type(build_spec: &BuildSpec) -> Option { match build_spec { - BuildSpec::Enum(enum_build_spec) => make_enum_type(enum_build_spec), - BuildSpec::LeafEnum(leaf_enum_build_spec) => make_leaf_enum_type(leaf_enum_build_spec), - BuildSpec::Struct(struct_build_spec) => make_struct_type(struct_build_spec), + BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)), + BuildSpec::LeafEnum(leaf_enum_build_spec) => Some(make_leaf_enum_type(leaf_enum_build_spec)), + BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)), BuildSpec::LeafStruct(leaf_struct_build_spec) => { - make_leaf_struct_type(leaf_struct_build_spec) - } + Some(make_leaf_struct_type(leaf_struct_build_spec)) + }, + BuildSpec::Production(production_build_spec) => None } }