Much work on ast gen, leaf enums and leaf structs.

This commit is contained in:
Jesse Brault 2025-09-14 19:34:38 -05:00
parent 42cc6720d1
commit 434df5642a
10 changed files with 369 additions and 39 deletions

View File

@ -1,9 +1,4 @@
use crate::spec::{ use crate::spec::{BooleanBuild, BuildSpec, ChildSpec, EnumBuildSpec, EnumRule, LeafEnumBuildSpec, LeafEnumRule, LeafEnumRuleBuild, LeafEnumRuleBuildChild, LeafStructBuildSpec, LeafStructChild, LeafStructChildType, SingleBooleanChildToBuild, SingleChild, SingleChildToBuild, SingleLiteralChildToBuild, SingleTypeChildToBuild, SkipChild, StructBuildSpec, VecChild, VecChildToBuild, VecTypeChildToBuild};
BooleanBuild, BuildSpec, ChildSpec, EnumBuildSpec, EnumRule, LeafEnumBuildSpec, LeafEnumRule,
LeafEnumRuleBuild, SingleBooleanChildToBuild, SingleChild, SingleChildToBuild,
SingleLiteralChildToBuild, SingleTypeChildToBuild, SkipChild, StructBuildSpec, VecChild,
VecChildToBuild, VecTypeChildToBuild,
};
use crate::util::make_build_fn_name; use crate::util::make_build_fn_name;
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use yaml_rust2::{Yaml, YamlLoader}; use yaml_rust2::{Yaml, YamlLoader};
@ -177,9 +172,13 @@ fn get_leaf_enum_rules(rules: &Yaml) -> Vec<LeafEnumRule> {
if rule.is_hash() { if rule.is_hash() {
let (rule_as_string, rule_hash) = unwrap_single_member_hash(rule); let (rule_as_string, rule_hash) = unwrap_single_member_hash(rule);
if get_as_bool(&rule_hash["child"]) { if get_as_bool(&rule_hash["child"]) {
let build = LeafEnumRuleBuild::Child { let build = LeafEnumRuleBuild::new(
with: make_build_fn_name(&rule_as_string), &rule_as_string,
}; Some(LeafEnumRuleBuildChild::new(
&rule_as_string,
&make_build_fn_name(&rule_as_string),
)),
);
LeafEnumRule::new(&rule_as_string, build) LeafEnumRule::new(&rule_as_string, build)
} else { } else {
panic!( panic!(
@ -188,9 +187,7 @@ fn get_leaf_enum_rules(rules: &Yaml) -> Vec<LeafEnumRule> {
} }
} else { } else {
let rule_as_str = rule.as_str().unwrap(); let rule_as_str = rule.as_str().unwrap();
let build = LeafEnumRuleBuild::EnumRule { let build = LeafEnumRuleBuild::new(rule_as_str, None);
rule: rule_as_str.to_string(),
};
LeafEnumRule::new(rule_as_str, build) LeafEnumRule::new(rule_as_str, build)
} }
}) })
@ -220,6 +217,20 @@ fn get_enum_rules(rule_specs: &Yaml) -> Vec<EnumRule> {
.collect() .collect()
} }
fn get_leaf_struct_child_specs(children: &Yaml) -> Vec<LeafStructChild> {
children.as_vec()
.unwrap()
.iter()
.map(|child_spec| {
let (name, hash) = unwrap_single_member_hash(child_spec);
LeafStructChild::new(
&name,
LeafStructChildType::String
)
})
.collect::<Vec<_>>()
}
fn yaml_is_string(yaml: &Yaml, test: &str) -> bool { fn yaml_is_string(yaml: &Yaml, test: &str) -> bool {
match yaml.as_str() { match yaml.as_str() {
Some(s) => s == test, Some(s) => s == test,
@ -233,7 +244,14 @@ fn deserialize_build_spec(build_spec_name: &Yaml, build_spec: &Yaml) -> BuildSpe
let children = &build_spec["children"]; let children = &build_spec["children"];
let rules = &build_spec["rules"]; let rules = &build_spec["rules"];
if yaml_is_string(node_type, "struct") || children.is_array() { if yaml_is_string(node_type, "leaf_struct") && children.is_array() {
let child_specs = get_leaf_struct_child_specs(children);
BuildSpec::LeafStruct(LeafStructBuildSpec::new(
build_spec_name_pascal,
build_spec_name_pascal,
child_specs,
))
} else if children.is_array() {
let child_specs = get_child_specs(children); let child_specs = get_child_specs(children);
BuildSpec::Struct(StructBuildSpec::from_name( BuildSpec::Struct(StructBuildSpec::from_name(
build_spec_name_pascal, build_spec_name_pascal,
@ -250,7 +268,7 @@ fn deserialize_build_spec(build_spec_name: &Yaml, build_spec: &Yaml) -> BuildSpe
let enum_rules = get_enum_rules(rules); let enum_rules = get_enum_rules(rules);
BuildSpec::Enum(EnumBuildSpec::from_name(build_spec_name_pascal, enum_rules)) BuildSpec::Enum(EnumBuildSpec::from_name(build_spec_name_pascal, enum_rules))
} else { } else {
panic!("Expected a node spec for either a struct, enum, or leaf_enum node type."); panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type.");
} }
} }

View File

@ -1,6 +1,31 @@
use proc_macro2::TokenStream;
use crate::spec::EnumBuildSpec; use crate::spec::EnumBuildSpec;
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream { pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream {
todo!() let build_fn_ident = format_ident!("{}", make_build_fn_name(enum_build_spec.build()));
} let pair_ident = format_ident!("{}", make_build_pair(enum_build_spec.build()));
let return_type_ident = format_ident!("{}", enum_build_spec.build());
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)
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#rule_branches),*
}
}
}
}

View File

@ -0,0 +1,36 @@
use crate::spec::LeafEnumBuildSpec;
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(leaf_enum_build_spec.build()));
let pair_ident = format_ident!("{}", make_build_pair(leaf_enum_build_spec.build()));
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
}
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
match inner_pair.as_rule() {
#(#rule_branches),*
}
}
}
}

View File

@ -0,0 +1,40 @@
use crate::spec::{LeafStructBuildSpec, LeafStructChildType};
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build()));
let pair_ident = format_ident!("{}", make_build_pair(build_spec.build()));
let return_type_ident = format_ident!("{}", build_spec.build());
let child_builders = build_spec
.children()
.iter()
.map(|leaf_struct_child| {
let child_ident = format_ident!("{}", leaf_struct_child.name());
match leaf_struct_child.r#type() {
LeafStructChildType::String => {
quote! {
let #child_ident = #pair_ident.as_str()
}
}
}
})
.collect::<Vec<_>>();
let child_args = build_spec
.children()
.iter()
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
#(#child_builders;)*
#return_type_ident::new(
#(#child_args,)*
)
}
}
}

View File

@ -1,17 +1,21 @@
pub mod deserialize; pub mod deserialize;
mod enum_build_fn; mod enum_build_fn;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod spec; mod spec;
mod struct_build_fn; mod struct_build_fn;
mod type_gen; mod type_gen;
mod util; mod util;
use crate::enum_build_fn::make_enum_build_fn;
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn;
use crate::struct_build_fn::make_struct_build_fn; use crate::struct_build_fn::make_struct_build_fn;
use crate::type_gen::make_type; use crate::type_gen::make_type;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use spec::BuildSpec; use spec::BuildSpec;
use syn::File; use syn::File;
use crate::enum_build_fn::make_enum_build_fn; use crate::leaf_struct_build_fn::make_leaf_struct_build_fn;
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) { fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
println!("*** BuildSpec ***"); println!("*** BuildSpec ***");
@ -25,6 +29,9 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
BuildSpec::Struct(struct_build_spec) => { BuildSpec::Struct(struct_build_spec) => {
println!("Spec name: {}", struct_build_spec.name()); println!("Spec name: {}", struct_build_spec.name());
} }
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
println!("Spec name: {}", leaf_struct_build_spec.name());
}
} }
println!("{:#?}", token_stream); println!("{:#?}", token_stream);
let parsed: File = syn::parse2(token_stream.clone()).unwrap(); let parsed: File = syn::parse2(token_stream.clone()).unwrap();
@ -51,12 +58,19 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
stream stream
} }
BuildSpec::LeafEnum(leaf_enum_build_spec) => { BuildSpec::LeafEnum(leaf_enum_build_spec) => {
todo!() let stream = make_leaf_enum_build_fn(leaf_enum_build_spec);
debug_built_spec(build_spec, &stream);
stream
} }
BuildSpec::Struct(struct_build_spec) => { BuildSpec::Struct(struct_build_spec) => {
let struct_build_fn_stream = make_struct_build_fn(struct_build_spec); let stream = make_struct_build_fn(struct_build_spec);
debug_built_spec(build_spec, &struct_build_fn_stream); debug_built_spec(build_spec, &stream);
struct_build_fn_stream stream
}
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
let stream = make_leaf_struct_build_fn(leaf_struct_build_spec);
debug_built_spec(build_spec, &stream);
stream
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -109,6 +123,7 @@ pub fn test_dump() -> String {
debug_built_spec(build_spec, &struct_build_fn_stream); debug_built_spec(build_spec, &struct_build_fn_stream);
streams.push(struct_build_fn_stream); streams.push(struct_build_fn_stream);
} }
BuildSpec::LeafStruct(_) => {}
} }
} }

View File

@ -5,6 +5,7 @@ pub enum BuildSpec {
Enum(EnumBuildSpec), Enum(EnumBuildSpec),
LeafEnum(LeafEnumBuildSpec), LeafEnum(LeafEnumBuildSpec),
Struct(StructBuildSpec), Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec),
} }
pub struct EnumBuildSpec { pub struct EnumBuildSpec {
@ -127,9 +128,48 @@ impl LeafEnumRule {
} }
} }
pub enum LeafEnumRuleBuild { pub struct LeafEnumRuleBuild {
EnumRule { rule: String }, rule: String,
Child { with: String }, child: Option<LeafEnumRuleBuildChild>,
}
impl LeafEnumRuleBuild {
pub fn new(rule: &str, child: Option<LeafEnumRuleBuildChild>) -> Self {
Self {
rule: rule.to_string(),
child,
}
}
pub fn rule(&self) -> &str {
&self.rule
}
pub fn child(&self) -> Option<&LeafEnumRuleBuildChild> {
self.child.as_ref()
}
}
pub struct LeafEnumRuleBuildChild {
build: String,
with: String,
}
impl LeafEnumRuleBuildChild {
pub fn new(build: &str, with: &str) -> Self {
Self {
build: build.to_string(),
with: with.to_string(),
}
}
pub fn build(&self) -> &str {
&self.build
}
pub fn with(&self) -> &str {
&self.with
}
} }
pub struct StructBuildSpec { pub struct StructBuildSpec {
@ -440,3 +480,57 @@ impl SingleLiteralChildToBuild {
&self.var_name &self.var_name
} }
} }
pub struct LeafStructBuildSpec {
name: String,
build: String,
children: Vec<LeafStructChild>,
}
impl LeafStructBuildSpec {
pub fn new(name: &str, build: &str, children: Vec<LeafStructChild>) -> Self {
Self {
name: name.to_string(),
build: build.to_string(),
children,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn build(&self) -> &str {
&self.build
}
pub fn children(&self) -> &[LeafStructChild] {
&self.children
}
}
pub struct LeafStructChild {
name: String,
r#type: LeafStructChildType,
}
impl LeafStructChild {
pub fn new(name: &str, r#type: LeafStructChildType) -> Self {
Self {
name: name.to_string(),
r#type
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn r#type(&self) -> &LeafStructChildType {
&self.r#type
}
}
pub enum LeafStructChildType {
String,
}

View File

@ -5,6 +5,7 @@ use crate::spec::{
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use crate::util::make_build_pair;
fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream { fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
let (child_ident, child_type_ident) = match vec_child.build() { let (child_ident, child_type_ident) = match vec_child.build() {
@ -226,8 +227,8 @@ fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream {
} }
pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", build_spec.with()); let build_fn_ident = format_ident!("{}", build_spec.with()); // TODO: get rid of with
let pair_ident = format_ident!("{}_pair", build_spec.build().to_case(Case::Snake)); let pair_ident = format_ident!("{}", make_build_pair(build_spec.var_name())); // TODO: get rid of var_name
let return_type_ident = format_ident!("{}", build_spec.build()); let return_type_ident = format_ident!("{}", build_spec.build());
let child_holders = build_spec let child_holders = build_spec

View File

@ -1,6 +1,7 @@
use crate::spec::{ use crate::spec::{
BuildSpec, ChildSpec, EnumBuildSpec, SingleBooleanChildToBuild, SingleChildToBuild, BuildSpec, ChildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec,
SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild, LeafStructChildType, SingleBooleanChildToBuild, SingleChildToBuild, SingleTypeChildToBuild,
StructBuildSpec, VecChild, VecChildToBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -25,6 +26,34 @@ fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
} }
} }
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
}
}
})
.collect::<Vec<_>>();
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}
fn handle_vec_child( fn handle_vec_child(
vec_child: &VecChild, vec_child: &VecChild,
member_names: &mut Vec<Ident>, member_names: &mut Vec<Ident>,
@ -161,10 +190,70 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
} }
} }
fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec
.children()
.iter()
.map(|leaf_struct_child| {
let name_ident = format_ident!("{}", leaf_struct_child.name());
let type_ident = match leaf_struct_child.r#type() {
LeafStructChildType::String => format_ident!("{}", "String"),
};
quote! {
#name_ident: #type_ident
}
})
.collect::<Vec<_>>();
let member_names = build_spec
.children()
.iter()
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
.collect::<Vec<_>>();
let accessors = build_spec
.children()
.iter()
.map(|leaf_struct_child| {
let name_ident = format_ident!("{}", leaf_struct_child.name());
match leaf_struct_child.r#type() {
LeafStructChildType::String => {
quote! {
pub fn #name_ident(&self) -> &str {
&self.#name_ident
}
}
}
}
})
.collect::<Vec<_>>();
quote! {
pub struct #type_ident {
#(#annotated_members),*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#member_names),*
}
}
#(#accessors)*
}
}
}
pub fn make_type(build_spec: &BuildSpec) -> TokenStream { pub fn make_type(build_spec: &BuildSpec) -> TokenStream {
match build_spec { match build_spec {
BuildSpec::Enum(enum_build_spec) => make_enum_type(enum_build_spec), BuildSpec::Enum(enum_build_spec) => make_enum_type(enum_build_spec),
BuildSpec::LeafEnum(leaf_enum_build_spec) => todo!(), 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::Struct(struct_build_spec) => make_struct_type(struct_build_spec),
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
make_leaf_struct_type(leaf_struct_build_spec)
}
} }
} }

View File

@ -3,3 +3,7 @@ use convert_case::{Case, Casing};
pub fn make_build_fn_name(s: &str) -> String { pub fn make_build_fn_name(s: &str) -> String {
format!("build_{}", s.to_case(Case::Snake)) format!("build_{}", s.to_case(Case::Snake))
} }
pub fn make_build_pair(s: &str) -> String {
format!("{}_pair", s.to_case(Case::Snake))
}

View File

@ -15,7 +15,7 @@ Operator:
- Subtract - Subtract
- Multiply - Multiply
- Divide - Divide
- Moduolo - Modulo
- LeftShift - LeftShift
- RightShift - RightShift
- Spread - Spread
@ -29,11 +29,11 @@ Operator:
# Names # Names
Identifier: Identifier:
type: leaf_struct
children: children:
- name: - name:
build: build:
type: string type: string
from: parse_whole_pair
FullyQualifiedName: FullyQualifiedName:
children: children:
- identifiers: - identifiers:
@ -174,11 +174,13 @@ UseStatementPrefix:
children: children:
- identifier - identifier
UseStatementSuffix: UseStatementSuffix:
type: leaf_enum
rules: rules:
- Identifier - Identifier:
- rule: Star child: true
build: UseStatementStarSuffix - Star
- UseList - UseList:
child: true
UseList: UseList:
children: children:
- identifiers: - identifiers:
@ -463,8 +465,7 @@ Statement:
- AssignmentStatement - AssignmentStatement
- ExpressionStatement - ExpressionStatement
- UseStatement - UseStatement
- IfElseStatement - IfStatement
- IfStatementStatement
- WhileStatement - WhileStatement
- ForStatement - ForStatement
VariableDeclaration: VariableDeclaration:
@ -560,7 +561,7 @@ ForStatement:
vec: true vec: true
- end_kw: - end_kw:
rule: End rule: End
vec: true skip: true
# Expressions # Expressions
Expression: Expression:
@ -612,6 +613,7 @@ ComparisonExpression:
rule: Expression rule: Expression
optional: true optional: true
ComparisonOperator: ComparisonOperator:
type: leaf_enum
rules: rules:
- Greater - Greater
- Less - Less
@ -629,6 +631,7 @@ ShiftExpression:
- right: - right:
rule: Expression rule: Expression
ShiftOperator: ShiftOperator:
type: leaf_enum
rules: rules:
- LeftShift - LeftShift
- RightShift - RightShift
@ -642,6 +645,11 @@ AdditiveExpression:
- right: - right:
rule: Expression rule: Expression
optional: true optional: true
AdditiveOperator:
type: leaf_enum
rules:
- Add
- Subtract
MultiplicativeExpression: MultiplicativeExpression:
children: children:
- left: - left: