Add walk impl.

This commit is contained in:
Jesse Brault 2025-09-29 09:10:57 -05:00
parent dd0bee1c91
commit 5b772443f8
3 changed files with 75 additions and 0 deletions

View File

@ -4,6 +4,7 @@ mod deserialize;
mod pretty_print; mod pretty_print;
mod spec; mod spec;
mod type_gen; mod type_gen;
mod walk;
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl}; use crate::ast_node::{make_ast_enum_member, make_ast_node_impl};
use crate::build_fn::make_build_fn; use crate::build_fn::make_build_fn;
@ -14,6 +15,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use spec::BuildSpec; use spec::BuildSpec;
use syn::File; use syn::File;
use crate::walk::make_walk_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 ***");
@ -184,6 +186,14 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
} }
} }
fn generate_walk_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
let stream = make_walk_fn(build_specs);
AstGeneratedFile {
name: String::from("walk.rs"),
contents: token_stream_to_string(stream),
}
}
pub fn get_build_specs(yaml: &str) -> Vec<BuildSpec> { pub fn get_build_specs(yaml: &str) -> Vec<BuildSpec> {
deserialize_yaml_spec(yaml) deserialize_yaml_spec(yaml)
} }
@ -194,5 +204,6 @@ pub fn generate_files(build_specs: &[BuildSpec]) -> Vec<AstGeneratedFile> {
generate_node_file(build_specs), generate_node_file(build_specs),
generate_pretty_print_file(build_specs), generate_pretty_print_file(build_specs),
generate_ast_node_file(build_specs), generate_ast_node_file(build_specs),
generate_walk_file(build_specs),
] ]
} }

60
ast-generator/src/walk.rs Normal file
View File

@ -0,0 +1,60 @@
use crate::spec::BuildSpec;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_walk_fn(specs: &[BuildSpec]) -> TokenStream {
let child_match_arms = specs
.iter()
.map(|spec| match spec {
BuildSpec::Enum(enum_spec) => Some((
format_ident!("{}", enum_spec.build()),
format_ident!("{}", enum_spec.build().to_case(Case::Snake)),
)),
BuildSpec::LeafEnum(leaf_enum) => Some((
format_ident!("{}", leaf_enum.build()),
format_ident!("{}", leaf_enum.build().to_case(Case::Snake)),
)),
BuildSpec::Struct(struct_spec) => Some((
format_ident!("{}", struct_spec.build()),
format_ident!("{}", struct_spec.build().to_case(Case::Snake)),
)),
BuildSpec::LeafStruct(leaf_struct) => Some((
format_ident!("{}", leaf_struct.build()),
format_ident!("{}", leaf_struct.build().to_case(Case::Snake)),
)),
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_type) => Some((
format_ident!("{}", polymorphic_type.name()),
format_ident!("{}", polymorphic_type.name().to_case(Case::Snake)),
)),
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some((
format_ident!("{}", polymorphic_enum_loop.name()),
format_ident!("{}", polymorphic_enum_loop.name().to_case(Case::Snake)),
)),
BuildSpec::PolymorphicPassThrough(_) => None,
})
.filter(Option::is_some)
.map(Option::unwrap)
.map(|(type_ident, inner_ident)| {
quote! {
#type_ident(#inner_ident) => walk_depth_first(#inner_ident, f)
}
})
.collect::<Vec<_>>();
quote! {
use crate::ast::node::*;
use crate::ast::ast_node::*;
pub fn walk_depth_first(node: &impl AstNode, f: &mut impl FnMut(AstNodeRef)) {
use AstNodeRef::*;
for child in node.children() {
match child {
#(#child_match_arms,)*
}
}
}
}
}

View File

@ -161,3 +161,7 @@ pub mod ast_node {
} }
} }
} }
pub mod walk {
include!(concat!(env!("OUT_DIR"), "/src/ast/walk.rs"));
}