Fill out build-fn generation for ast nodes.

This commit is contained in:
Jesse Brault 2025-09-14 15:40:39 -05:00
parent 968b950436
commit b75e51ee41
7 changed files with 164 additions and 49 deletions

View File

@ -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<TokenStream> {
match child_spec {
ChildSpec::SkipChild(_) => None,
@ -50,10 +60,30 @@ fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> {
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<TokenStream> {
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! {

View File

@ -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<LeafEnumRule> {
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);

View File

@ -88,7 +88,7 @@ impl LeafEnumBuildSpec {
Self {
name: name.to_string(),
build: name.to_string(),
rules
rules,
}
}
@ -107,14 +107,14 @@ 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,
}
}
@ -128,12 +128,8 @@ impl LeafEnumRule {
}
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
}
}

View File

@ -136,6 +136,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
&mut accessors,
);
}
_ => todo!()
};
}
}

View File

@ -1 +0,0 @@
include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs"));

View File

@ -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;

View File

@ -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: