Big refactor of ast gen.

This commit is contained in:
Jesse Brault 2025-09-15 21:12:38 -05:00
parent 5d640ca585
commit f3c3e40eb2
9 changed files with 121 additions and 121 deletions

View File

@ -53,7 +53,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
} }
fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> { fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> {
if !rule_props["child"].as_bool().unwrap() { if !rule_props["child"].as_bool().unwrap_or(true) {
None None
} else { } else {
let kind = match rule_props["kind"].as_str().unwrap() { let kind = match rule_props["kind"].as_str().unwrap() {
@ -163,7 +163,8 @@ fn deserialize_member_child_to_build(
panic!("unsupported kind: {}", kind) panic!("unsupported kind: {}", kind)
} }
} else { } 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"]); let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules)) BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
} else if build_spec["produce"].is_hash() { } 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 { } else {
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type."); panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
} }

View File

@ -1,4 +1,4 @@
use crate::spec::EnumBuildSpec; use crate::spec::{EnumBuildSpec, EnumRuleChildKind};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; 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 let rule_branches = enum_build_spec
.rules() .rules()
.iter()
.map(|enum_rule| { .map(|enum_rule| {
let rule_ident = format_ident!("{}", enum_rule.rule()); let rule_ident = format_ident!("{}", enum_rule.rule());
let build_rule_ident = format_ident!("{}", enum_rule.with()); if let Some(child) = enum_rule.child() {
quote! { let inner_builder = match child.kind() {
Rule::#rule_ident => #build_rule_ident(inner_pair) 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::<Vec<_>>(); .collect::<Vec<_>>();
@ -24,7 +40,8 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident { fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap(); let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() { match inner_pair.as_rule() {
#(#rule_branches),* #(#rule_branches,)*
_ => unreachable!()
} }
} }
} }

View File

@ -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 return_type_ident = format_ident!("{}", leaf_enum_build_spec.build());
let rule_branches = leaf_enum_build_spec.rules() let rule_branches = leaf_enum_build_spec.rules()
.iter()
.map(|leaf_enum_rule| { .map(|leaf_enum_rule| {
let rule_ident = format_ident!("{}", leaf_enum_rule.rule()); let rule_ident = format_ident!("{}", leaf_enum_rule.rule());
if leaf_enum_rule.build().child().is_some() { quote! {
let child_build_fn_ident = format_ident!("{}", leaf_enum_rule.build().child().unwrap().with()); Rule::#rule_ident => #return_type_ident::#rule_ident
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
}
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -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(); let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() { match inner_pair.as_rule() {
#(#rule_branches,)* #(#rule_branches,)*
_ => panic!("Unexpected rule: {:?}", inner_pair.as_rule()) _ => unreachable!()
} }
} }
} }

View File

@ -10,10 +10,9 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea
let child_builders = build_spec let child_builders = build_spec
.members() .members()
.iter() .map(|member| {
.map(|leaf_struct_child| { let child_ident = format_ident!("{}", member.name());
let child_ident = format_ident!("{}", leaf_struct_child.name()); match member.kind() {
match leaf_struct_child.r#type() {
LeafStructMemberKind::String => { LeafStructMemberKind::String => {
quote! { quote! {
let #child_ident = #pair_ident.as_str() 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 let child_args = build_spec
.members() .members()
.iter() .map(|member| format_ident!("{}", member.name()))
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { quote! {

View File

@ -100,6 +100,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
let types = build_specs let types = build_specs
.iter() .iter()
.map(|build_spec| make_type(build_spec)) .map(|build_spec| make_type(build_spec))
.filter(Option::is_some)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let combined = quote! { let combined = quote! {
#(#types)* #(#types)*

View File

@ -1,6 +0,0 @@
use ast_generator::test_dump;
fn main() {
let s = test_dump();
println!("{}", s);
}

View File

@ -1,7 +1,7 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom}; use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom};
use crate::util::{make_build_fn_name, make_build_pair}; 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 { 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())); 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"), ProductionKind::Boolean => format_ident!("bool"),
}; };
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule())); let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule()));
let pair_mapper = match production_build_spec.kind() { let pair_mapper = match production_build_spec.kind() {
ProductionKind::Int => quote! { ProductionKind::Int => quote! {
let number_base_pair = #pair_ident.to_inner() let number_base_pair = #pair_ident.into_inner()
.next() .next()
.unwrap(); .unwrap();
let inner_number_base_pair = number_base_pair.to_inner() let inner_number_base_pair = number_base_pair.into_inner()
.next() .next()
.unwrap(); .unwrap();
match inner_number_base_pair.as_rule() { match inner_number_base_pair.as_rule() {
@ -36,10 +36,10 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
} }
}, },
ProductionKind::Long => quote! { ProductionKind::Long => quote! {
let number_base_pair = #pair_ident.to_inner() let number_base_pair = #pair_ident.into_inner()
.next() .next()
.unwrap(); .unwrap();
let inner_number_base_pair = number_base_pair.to_inner() let inner_number_base_pair = number_base_pair.into_inner()
.next() .next()
.unwrap(); .unwrap();
match inner_number_base_pair.as_rule() { match inner_number_base_pair.as_rule() {
@ -58,33 +58,30 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
ProductionKind::Double => quote! { ProductionKind::Double => quote! {
#pair_ident.as_str().parse::<f64>().unwrap() #pair_ident.as_str().parse::<f64>().unwrap()
}, },
ProductionKind::String(from) => { ProductionKind::String(from) => match from {
match from { ProductionStringFrom::StringInner => {
ProductionStringFrom::StringInner => { quote! {
quote! { #pair_ident.into_inner()
#pair_ident.to_inner() .next()
.iter() .unwrap()
.next() .as_str()
.unwrap() .to_string()
.as_str()
.to_string()
}
} }
ProductionStringFrom::WholePair => { }
quote! { ProductionStringFrom::WholePair => {
#pair_ident.as_string().to_string() quote! {
} #pair_ident.as_str().to_string()
} }
} }
}, },
ProductionKind::Boolean => quote! { ProductionKind::Boolean => quote! {
#pair_ident.as_str().parse::<bool>().unwrap() #pair_ident.as_str().parse::<bool>().unwrap()
} },
}; };
quote! { quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident { fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
#pair_mapper #pair_mapper
} }
} }
} }

View File

@ -1,6 +1,3 @@
use crate::util::make_build_fn_name;
use convert_case::{Case, Casing};
pub enum BuildSpec { pub enum BuildSpec {
Enum(EnumBuildSpec), Enum(EnumBuildSpec),
LeafEnum(LeafEnumBuildSpec), LeafEnum(LeafEnumBuildSpec),

View File

@ -1,20 +1,32 @@
use crate::spec::{ use convert_case::{Case, Casing};
BooleanChildToBuild, BuildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec, use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild};
LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec,
VecChild, VecChildToBuild,
};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream { fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
let children: Vec<TokenStream> = build_spec let children: Vec<TokenStream> = build_spec
.rules() .rules()
.iter() .map(|enum_rule| {
.map(|rule| { let member_name_ident = format_ident!("{}", enum_rule.rule());
let member_name_ident = format_ident!("{}", rule.rule()); if let Some(enum_rule_child) = enum_rule.child() {
let child_name_ident = format_ident!("{}", rule.build()); let child_type_ident = match enum_rule_child.kind() {
quote! { EnumRuleChildKind::Node(node_child) => {
#member_name_ident(#child_name_ident) 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(); .collect();
@ -30,19 +42,10 @@ fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream {
let type_name_ident = format_ident!("{}", build_spec.build()); let type_name_ident = format_ident!("{}", build_spec.build());
let children = build_spec let children = build_spec
.rules() .rules()
.iter()
.map(|leaf_enum_rule| { .map(|leaf_enum_rule| {
let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule()); let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule());
if leaf_enum_rule.build().child().is_some() { quote! {
let child_type_ident = #rule_name_ident
format_ident!("{}", leaf_enum_rule.build().child().unwrap().build());
quote! {
#rule_name_ident(#child_type_ident)
}
} else {
quote! {
#rule_name_ident
}
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -60,12 +63,13 @@ fn handle_vec_child(
annotated_members: &mut Vec<TokenStream>, annotated_members: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>, accessors: &mut Vec<TokenStream>,
) { ) {
let (child_ident, child_ident_mut, child_type_ident) = match vec_child.build() { let (child_ident, child_ident_mut) = (
VecChildToBuild::Node(vec_type_child) => ( format_ident!("{}", vec_child.name()),
format_ident!("{}", vec_type_child.var_name()), format_ident!("{}", vec_child.name()),
format_ident!("{}_mut", vec_type_child.var_name()), );
format_ident!("{}", vec_type_child.build()), 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()); member_names.push(child_ident.clone());
@ -83,17 +87,19 @@ fn handle_vec_child(
}); });
} }
fn handle_single_type_child( fn handle_node_child(
single_type_child: &NodeChildToBuild, node_child: &NodeChildToBuild,
member_names: &mut Vec<Ident>, member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>, annotated_members: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>, accessors: &mut Vec<TokenStream>,
) { ) {
let child_ident = format_ident!("{}", single_type_child.var_name()); let child_ident = format_ident!("{}", node_child.build().to_case(Case::Snake));
let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name()); let child_ident_mut = format_ident!("{}_mut", child_ident);
let child_type_ident = format_ident!("{}", single_type_child.build()); let child_type_ident = format_ident!("{}", node_child.build());
member_names.push(child_ident.clone()); member_names.push(child_ident.clone());
if single_type_child.optional() {
if node_child.optional() {
annotated_members.push(quote! { annotated_members.push(quote! {
#child_ident: Option<Box<#child_type_ident>> #child_ident: Option<Box<#child_type_ident>>
}); });
@ -102,7 +108,7 @@ fn handle_single_type_child(
#child_ident: Box<#child_type_ident> #child_ident: Box<#child_type_ident>
}) })
} }
if single_type_child.optional() { if node_child.optional() {
accessors.push(quote! { accessors.push(quote! {
pub fn #child_ident(&self) -> Option<&#child_type_ident> { pub fn #child_ident(&self) -> Option<&#child_type_ident> {
if let Some(#child_ident) = &self.#child_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, single_boolean_child: &BooleanChildToBuild,
member_names: &mut Vec<Ident>, member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>, annotated_members: &mut Vec<TokenStream>,
@ -156,7 +162,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
let mut annotated_members: Vec<TokenStream> = vec![]; let mut annotated_members: Vec<TokenStream> = vec![];
let mut accessors: Vec<TokenStream> = vec![]; let mut accessors: Vec<TokenStream> = vec![];
for child_spec in build_spec.children().iter() { for child_spec in build_spec.children() {
match child_spec { match child_spec {
StructChildSpec::SkipChild(_) => {} StructChildSpec::SkipChild(_) => {}
StructChildSpec::VecChild(vec_child) => { StructChildSpec::VecChild(vec_child) => {
@ -167,25 +173,24 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
&mut accessors, &mut accessors,
); );
} }
StructChildSpec::MemberChild(single_child) => { StructChildSpec::MemberChild(member_child) => {
match single_child.build() { match member_child.build() {
MemberChildToBuild::Node(single_type_child) => { MemberChildToBuild::Node(node_child) => {
handle_single_type_child( handle_node_child(
single_type_child, node_child,
&mut member_names, &mut member_names,
&mut annotated_members, &mut annotated_members,
&mut accessors, &mut accessors,
); );
} }
MemberChildToBuild::Boolean(single_boolean_child) => { MemberChildToBuild::Boolean(boolean_child) => {
handle_single_boolean_child( handle_boolean_child(
single_boolean_child, boolean_child,
&mut member_names, &mut member_names,
&mut annotated_members, &mut annotated_members,
&mut accessors, &mut accessors,
); );
} }
_ => {}
}; };
} }
} }
@ -215,10 +220,9 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
let annotated_members = build_spec let annotated_members = build_spec
.members() .members()
.iter() .map(|member| {
.map(|leaf_struct_child| { let name_ident = format_ident!("{}", member.name());
let name_ident = format_ident!("{}", leaf_struct_child.name()); let type_ident = match member.kind() {
let type_ident = match leaf_struct_child.r#type() {
LeafStructMemberKind::String => format_ident!("{}", "String"), LeafStructMemberKind::String => format_ident!("{}", "String"),
}; };
quote! { quote! {
@ -229,16 +233,14 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
let member_names = build_spec let member_names = build_spec
.members() .members()
.iter()
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name())) .map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let accessors = build_spec let accessors = build_spec
.members() .members()
.iter() .map(|member| {
.map(|leaf_struct_child| { let name_ident = format_ident!("{}", member.name());
let name_ident = format_ident!("{}", leaf_struct_child.name()); match member.kind() {
match leaf_struct_child.r#type() {
LeafStructMemberKind::String => { LeafStructMemberKind::String => {
quote! { quote! {
pub fn #name_ident(&self) -> &str { 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<TokenStream> {
match build_spec { match build_spec {
BuildSpec::Enum(enum_build_spec) => make_enum_type(enum_build_spec), BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)),
BuildSpec::LeafEnum(leaf_enum_build_spec) => make_leaf_enum_type(leaf_enum_build_spec), BuildSpec::LeafEnum(leaf_enum_build_spec) => Some(make_leaf_enum_type(leaf_enum_build_spec)),
BuildSpec::Struct(struct_build_spec) => make_struct_type(struct_build_spec), BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)),
BuildSpec::LeafStruct(leaf_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
} }
} }