From 9f3f3e0f0d85567b30a1d83e09b76bd8d9f8868d Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Wed, 3 Sep 2025 17:12:19 -0500 Subject: [PATCH] Implement optionality for types. --- ast-generator/src/deserialize.rs | 13 ++++++------- ast-generator/src/spec.rs | 15 ++++++++++----- ast-generator/src/type_gen.rs | 12 +++++++++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ast-generator/src/deserialize.rs b/ast-generator/src/deserialize.rs index a4d95e7..74a49dc 100644 --- a/ast-generator/src/deserialize.rs +++ b/ast-generator/src/deserialize.rs @@ -46,7 +46,7 @@ fn get_vec_child(name: &str, rule: &str, build: &Yaml) -> ChildSpec { )) } -fn get_single_child_to_build(name: &str, rule: &str, build: &Yaml) -> SingleChildToBuild { +fn get_single_child_to_build(name: &str, rule: &str, optional: bool, build: &Yaml) -> SingleChildToBuild { if build.is_hash() { let r#type = build["type"].as_str().unwrap(); let var_name = build["var"] @@ -64,18 +64,17 @@ fn get_single_child_to_build(name: &str, rule: &str, build: &Yaml) -> SingleChil } } else { match build.as_str() { - Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s)), - None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule)), + Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s, optional)), + None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule, optional)), } } } -fn get_single_child(name: &str, rule: &str, build: &Yaml, optional: bool) -> ChildSpec { +fn get_single_child(name: &str, rule: &str, optional: bool, build: &Yaml) -> ChildSpec { ChildSpec::SingleChild(SingleChild::new( name, rule, - get_single_child_to_build(name, rule, build), - optional + get_single_child_to_build(name, rule, optional, build), )) } @@ -111,7 +110,7 @@ fn get_child_specs(children: &Yaml) -> Vec { .as_bool() .unwrap_or_else(|| false); - get_single_child(name, &rule, build, optional) + get_single_child(name, &rule, optional, build) } } else { ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap())) diff --git a/ast-generator/src/spec.rs b/ast-generator/src/spec.rs index 5211799..e21cbee 100644 --- a/ast-generator/src/spec.rs +++ b/ast-generator/src/spec.rs @@ -224,7 +224,6 @@ pub struct SingleChild { name: String, rule: String, build: SingleChildToBuild, - optional: bool } impl SingleChild { @@ -234,17 +233,16 @@ impl SingleChild { rule: name.to_case(Case::Pascal), build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule( &name.to_case(Case::Pascal), + false, )), - optional: false, } } - pub fn new(name: &str, rule: &str, build: SingleChildToBuild, optional: bool) -> Self { + pub fn new(name: &str, rule: &str, build: SingleChildToBuild) -> Self { Self { name: name.to_string(), rule: rule.to_string(), build, - optional } } @@ -275,14 +273,16 @@ pub struct SingleTypeChildToBuild { build: String, var_name: String, with: String, + optional: bool, } impl SingleTypeChildToBuild { - pub fn from_build_or_rule(build_or_rule: &str) -> Self { + pub fn from_build_or_rule(build_or_rule: &str, optional: bool) -> Self { Self { build: build_or_rule.to_string(), var_name: build_or_rule.to_case(Case::Snake), with: make_build_fn_name(build_or_rule), + optional, } } @@ -300,6 +300,11 @@ impl SingleTypeChildToBuild { pub fn with(&self) -> &str { &self.with } + + /// If the type should be wrapped in an Option. + pub fn optional(&self) -> bool { + self.optional + } } #[derive(Debug)] diff --git a/ast-generator/src/type_gen.rs b/ast-generator/src/type_gen.rs index 62f2abb..c8d5ea7 100644 --- a/ast-generator/src/type_gen.rs +++ b/ast-generator/src/type_gen.rs @@ -64,9 +64,15 @@ fn handle_single_type_child( let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name()); let child_type_ident = format_ident!("{}", single_type_child.build()); member_names.push(child_ident.clone()); - annotated_members.push(quote! { - #child_ident: Box<#child_type_ident> - }); + if single_type_child.optional() { + annotated_members.push(quote! { + #child_ident: Option> + }); + } else { + annotated_members.push(quote! { + #child_ident: Box<#child_type_ident> + }) + } accessors.push(quote! { pub fn #child_ident(&self) -> &#child_type_ident { self.#child_ident.as_ref()