From b75e51ee41ff1cdd7bc017cd6deb713dcd341ba8 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sun, 14 Sep 2025 15:40:39 -0500 Subject: [PATCH] Fill out build-fn generation for ast nodes. --- ast-generator/src/build_fn_gen.rs | 87 ++++++++++++++++++++++++++++--- ast-generator/src/deserialize.rs | 49 ++++++++++++----- ast-generator/src/spec.rs | 58 ++++++++++++++------- ast-generator/src/type_gen.rs | 1 + src/ast/build.rs | 1 - src/ast/mod.rs | 8 ++- src/parser/ast.yaml | 9 ---- 7 files changed, 164 insertions(+), 49 deletions(-) delete mode 100644 src/ast/build.rs diff --git a/ast-generator/src/build_fn_gen.rs b/ast-generator/src/build_fn_gen.rs index 37ccb89..a39151f 100644 --- a/ast-generator/src/build_fn_gen.rs +++ b/ast-generator/src/build_fn_gen.rs @@ -1,9 +1,9 @@ use crate::spec::{ - BuildBooleanOn, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild, - SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild, + BooleanBuild, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild, + SingleLiteralChildToBuild, SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild, }; use convert_case::{Case, Casing}; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; pub fn make_build_fn_name(s: &str) -> String { @@ -39,6 +39,16 @@ fn make_single_boolean_child_holder( } } +fn make_literal_child_holder( + literal_child: &SingleLiteralChildToBuild, + literal_type_ident: Ident, +) -> TokenStream { + let child_ident = format_ident!("{}", literal_child.var_name()); + quote! { + let mut #child_ident: Option<#literal_type_ident> = None + } +} + fn make_child_holder(child_spec: &ChildSpec) -> Option { match child_spec { ChildSpec::SkipChild(_) => None, @@ -50,10 +60,30 @@ fn make_child_holder(child_spec: &ChildSpec) -> Option { SingleChildToBuild::Boolean(boolean_child) => { Some(make_single_boolean_child_holder(boolean_child)) } + SingleChildToBuild::Int(literal_child) => Some(make_literal_child_holder( + literal_child, + format_ident!("i32"), + )), + SingleChildToBuild::Long(literal_child) => Some(make_literal_child_holder( + literal_child, + format_ident!("i64"), + )), + SingleChildToBuild::Double(literal_child) => Some(make_literal_child_holder( + literal_child, + format_ident!("f64"), + )), + SingleChildToBuild::String(literal_child) => Some(make_literal_child_holder( + literal_child, + format_ident!("String"), + )), }, } } +fn get_literal_child_ident(literal_child: &SingleLiteralChildToBuild) -> Ident { + format_ident!("{}", literal_child.var_name()) +} + fn make_match_action(child_spec: &ChildSpec) -> TokenStream { match child_spec { ChildSpec::SkipChild(_) => quote! {}, @@ -78,10 +108,39 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream { } SingleChildToBuild::Boolean(single_boolean_child) => { let child_name_ident = format_ident!("{}", single_boolean_child.var_name()); - match single_boolean_child.on() { - BuildBooleanOn::RulePresent => quote! { + match single_boolean_child.build() { + BooleanBuild::RulePresent => quote! { #child_name_ident = true }, + BooleanBuild::ParseWholePair => quote! { + #child_name_ident = Some(inner_pair.as_str().parse().unwrap()) + }, + } + } + SingleChildToBuild::Int(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + quote! { + #child_ident = Some(inner_pair.as_str().parse().unwrap()) + } + } + SingleChildToBuild::Long(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + quote! { + let as_string = inner_pair.as_str(); + let without_el = &as_string[0..(as_string.len() - 1)]; + #child_ident = Some(without_el.parse().unwrap()) + } + } + SingleChildToBuild::Double(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + quote! { + #child_ident = Some(inner_pair.as_str().parse().unwrap()) + } + } + SingleChildToBuild::String(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + quote! { + #child_ident = Some(inner_pair.as_str().to_string()) } } }, @@ -133,6 +192,22 @@ fn make_child_arg(child_spec: &ChildSpec) -> Option { let child_ident = format_ident!("{}", single_boolean_child.var_name()); Some(quote! { #child_ident }) } + SingleChildToBuild::Int(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + Some(quote! { #child_ident.unwrap() }) + } + SingleChildToBuild::Long(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + Some(quote! { #child_ident.unwrap() }) + }, + SingleChildToBuild::Double(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + Some(quote! { #child_ident.unwrap() }) + } + SingleChildToBuild::String(literal_child) => { + let child_ident = get_literal_child_ident(literal_child); + Some(quote! { #child_ident.unwrap() }) + } }, } } @@ -234,7 +309,7 @@ mod tests { #[test] fn single_boolean_child_holder() { let single_boolean_child = - SingleBooleanChildToBuild::new("test_child", BuildBooleanOn::RulePresent); + SingleBooleanChildToBuild::new("test_child", BooleanBuild::RulePresent); assert_eq!( make_single_boolean_child_holder(&single_boolean_child).to_string(), quote! { diff --git a/ast-generator/src/deserialize.rs b/ast-generator/src/deserialize.rs index 93bf24e..8b2e00f 100644 --- a/ast-generator/src/deserialize.rs +++ b/ast-generator/src/deserialize.rs @@ -1,5 +1,10 @@ use crate::build_fn_gen::make_build_fn_name; -use crate::spec::{BuildBooleanOn, BuildSpec, ChildSpec, EnumBuildSpec, EnumRule, LeafEnumBuildSpec, LeafEnumRule, LeafEnumRuleBuild, SingleBooleanChildToBuild, SingleChild, SingleChildToBuild, SingleTypeChildToBuild, SkipChild, StructBuildSpec, VecChild, VecChildToBuild, VecTypeChildToBuild}; +use crate::spec::{ + BooleanBuild, BuildSpec, ChildSpec, EnumBuildSpec, EnumRule, LeafEnumBuildSpec, LeafEnumRule, + LeafEnumRuleBuild, SingleBooleanChildToBuild, SingleChild, SingleChildToBuild, + SingleLiteralChildToBuild, SingleTypeChildToBuild, SkipChild, StructBuildSpec, VecChild, + VecChildToBuild, VecTypeChildToBuild, +}; use convert_case::{Case, Casing}; use yaml_rust2::{Yaml, YamlLoader}; @@ -51,14 +56,29 @@ fn get_single_child_to_build( .as_str() .map(|s| s.to_string()) .unwrap_or(name.to_string()); - let on = build["on"].as_str().unwrap(); - if r#type.eq("boolean") && on.eq("rule_present") { - SingleChildToBuild::Boolean(SingleBooleanChildToBuild::new( - &var_name, - BuildBooleanOn::RulePresent, - )) - } else { - todo!("currently on boolean types with on: rule_present are supported") + match r#type { + "boolean" => { + if yaml_is_string(&build["on"], "rule_present") { + SingleChildToBuild::Boolean(SingleBooleanChildToBuild::new( + &var_name, + BooleanBuild::RulePresent, + )) + } else if yaml_is_string(&build["from"], "parse_whole_pair") { + SingleChildToBuild::Boolean(SingleBooleanChildToBuild::new( + &var_name, + BooleanBuild::ParseWholePair, + )) + } else { + panic!("invalid build on/from with type boolean"); + } + } + "i32" => SingleChildToBuild::Int(SingleLiteralChildToBuild::new(&var_name)), + "i64" => SingleChildToBuild::Long(SingleLiteralChildToBuild::new(&var_name)), + "f64" => SingleChildToBuild::Double(SingleLiteralChildToBuild::new(&var_name)), + "string" => { + SingleChildToBuild::String(SingleLiteralChildToBuild::new(&var_name)) + } + _ => panic!("unsupported build type: {}", r#type), } } None => { @@ -160,11 +180,13 @@ fn get_leaf_enum_rules(rules: &Yaml) -> Vec { let (rule_as_string, rule_hash) = unwrap_single_member_hash(rule); if get_as_bool(&rule_hash["child"]) { let build = LeafEnumRuleBuild::Child { - with: make_build_fn_name(&rule_as_string) + with: make_build_fn_name(&rule_as_string), }; LeafEnumRule::new(&rule_as_string, build) } else { - panic!("if a leaf_enum rule is a hash, its child prop must be present and true"); + panic!( + "if a leaf_enum rule is a hash, its child prop must be present and true" + ); } } else { let rule_as_str = rule.as_str().unwrap(); @@ -221,7 +243,10 @@ fn deserialize_build_spec(build_spec_name: &Yaml, build_spec: &Yaml) -> BuildSpe )) } else if yaml_is_string(node_type, "leaf_enum") && rules.is_array() { let leaf_enum_rules = get_leaf_enum_rules(rules); - BuildSpec::LeafEnum(LeafEnumBuildSpec::from_name(build_spec_name_pascal, leaf_enum_rules)) + BuildSpec::LeafEnum(LeafEnumBuildSpec::from_name( + build_spec_name_pascal, + leaf_enum_rules, + )) } else if rules.is_array() { // enum node let enum_rules = get_enum_rules(rules); diff --git a/ast-generator/src/spec.rs b/ast-generator/src/spec.rs index 0972882..5830d3d 100644 --- a/ast-generator/src/spec.rs +++ b/ast-generator/src/spec.rs @@ -88,18 +88,18 @@ impl LeafEnumBuildSpec { Self { name: name.to_string(), build: name.to_string(), - rules + rules, } } - + pub fn name(&self) -> &str { &self.name } - + pub fn build(&self) -> &str { &self.build } - + pub fn rules(&self) -> &[LeafEnumRule] { &self.rules } @@ -107,33 +107,29 @@ impl LeafEnumBuildSpec { pub struct LeafEnumRule { rule: String, - build: LeafEnumRuleBuild + build: LeafEnumRuleBuild, } impl LeafEnumRule { pub fn new(rule: &str, build: LeafEnumRuleBuild) -> Self { Self { rule: rule.to_string(), - build + build, } } - + pub fn rule(&self) -> &str { &self.rule } - + pub fn build(&self) -> &LeafEnumRuleBuild { &self.build } } pub enum LeafEnumRuleBuild { - EnumRule { - rule: String, - }, - Child { - with: String - } + EnumRule { rule: String }, + Child { with: String }, } pub struct StructBuildSpec { @@ -327,6 +323,10 @@ impl SingleChild { pub enum SingleChildToBuild { Type(SingleTypeChildToBuild), Boolean(SingleBooleanChildToBuild), + Int(SingleLiteralChildToBuild), + Long(SingleLiteralChildToBuild), + Double(SingleLiteralChildToBuild), + String(SingleLiteralChildToBuild), } #[derive(Debug)] @@ -382,14 +382,14 @@ impl SingleTypeChildToBuild { #[derive(Debug)] pub struct SingleBooleanChildToBuild { var_name: String, - on: BuildBooleanOn, + build: BooleanBuild, } impl SingleBooleanChildToBuild { - pub fn new(var_name: &str, on: BuildBooleanOn) -> Self { + pub fn new(var_name: &str, build: BooleanBuild) -> Self { Self { var_name: var_name.to_string(), - on, + build, } } @@ -397,12 +397,30 @@ impl SingleBooleanChildToBuild { &self.var_name } - pub fn on(&self) -> &BuildBooleanOn { - &self.on + pub fn build(&self) -> &BooleanBuild { + &self.build } } #[derive(Debug)] -pub enum BuildBooleanOn { +pub enum BooleanBuild { RulePresent, + ParseWholePair, +} + +#[derive(Debug)] +pub struct SingleLiteralChildToBuild { + var_name: String, +} + +impl SingleLiteralChildToBuild { + pub fn new(var_name: &str) -> Self { + Self { + var_name: var_name.to_string(), + } + } + + pub fn var_name(&self) -> &str { + &self.var_name + } } diff --git a/ast-generator/src/type_gen.rs b/ast-generator/src/type_gen.rs index b244077..95e1ffa 100644 --- a/ast-generator/src/type_gen.rs +++ b/ast-generator/src/type_gen.rs @@ -136,6 +136,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream { &mut accessors, ); } + _ => todo!() }; } } diff --git a/src/ast/build.rs b/src/ast/build.rs deleted file mode 100644 index 4be5b6a..0000000 --- a/src/ast/build.rs +++ /dev/null @@ -1 +0,0 @@ -include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs")); diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9636c8b..557ec4d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,4 +1,10 @@ -pub mod build; +pub mod build { + //noinspection RsUnusedImport + use crate::parser::Rule; + + include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs")); +} + pub mod children; pub mod node; pub mod pretty_print; diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 6854b31..544deaa 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -625,20 +625,17 @@ IntLiteral: - literal: build: type: i32 - from: parse_number_base LongLiteral: children: - number_base - literal: build: type: i64 - from: parse_number_base DoubleLiteral: children: - literal: build: type: f64 - from: parse_whole_pair NumberBase: rules: - BinaryBase @@ -649,7 +646,6 @@ DecimalBase: - literal: build: type: string - from: whole_pair BinaryBase: children: - binary_digits @@ -658,7 +654,6 @@ BinaryDigits: - literal: build: type: string - from: whole_pair HexadecimalBase: children: - hexadecimal_digits @@ -667,7 +662,6 @@ HexadecimalDigits: - literal: build: type: string - from: whole_pair StringLiteral: rules: - SingleQuoteString @@ -690,13 +684,11 @@ StringInner: - literal: build: type: string - from: whole_pair DStringInner: children: - literal: build: type: string - from: whole_pair DStringExpression: children: - expression @@ -713,7 +705,6 @@ BacktickInner: - literal: build: type: string - from: whole_pair BooleanLiteral: children: - literal: