280 lines
8.2 KiB
Rust
280 lines
8.2 KiB
Rust
mod ast_node;
|
|
mod build_fn;
|
|
mod deserialize;
|
|
mod pretty_print;
|
|
mod spec;
|
|
mod type_gen;
|
|
mod walk;
|
|
|
|
use crate::ast_node::{
|
|
make_ast_enum_member, make_ast_enum_mut_member, make_ast_node_impl,
|
|
make_ast_node_ref_mut_unwrapper, make_ast_node_ref_unwrapper,
|
|
};
|
|
use crate::build_fn::make_build_fn;
|
|
use crate::deserialize::deserialize_yaml_spec;
|
|
use crate::pretty_print::make_pretty_print_impl;
|
|
use crate::type_gen::make_type;
|
|
use crate::walk::make_walk_fn;
|
|
use proc_macro2::TokenStream;
|
|
use quote::quote;
|
|
use spec::BuildSpec;
|
|
use syn::File;
|
|
|
|
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
|
println!("*** BuildSpec ***");
|
|
match build_spec {
|
|
BuildSpec::Enum(enum_build_spec) => {
|
|
println!("Enum Spec - build: {}", enum_build_spec.build());
|
|
}
|
|
BuildSpec::LeafEnum(leaf_enum_build_spec) => {
|
|
println!("Leaf Enum Spec - build: {}", leaf_enum_build_spec.build());
|
|
}
|
|
BuildSpec::Struct(struct_build_spec) => {
|
|
println!("Struct Spec - build: {}", struct_build_spec.build());
|
|
}
|
|
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
|
|
println!(
|
|
"Leaf Struct Spec - build: {}",
|
|
leaf_struct_build_spec.build()
|
|
);
|
|
}
|
|
BuildSpec::Production(production_build_spec) => {
|
|
println!("Production Spec - name: {}", production_build_spec.name());
|
|
}
|
|
BuildSpec::NodeProduction(node_production_build_spec) => {
|
|
println!(
|
|
"Node Production Spec - name: {}",
|
|
node_production_build_spec.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicType(polymorphic_build_spec) => {
|
|
println!(
|
|
"Polymorphic Type Spec - name: {}",
|
|
polymorphic_build_spec.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_build_spec) => {
|
|
println!(
|
|
"Polymorphic Enum Loop Spec - name: {}",
|
|
polymorphic_enum_loop_build_spec.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicPassThrough(pass_through_build_spec) => {
|
|
println!(
|
|
"Polymorphic Pass Through Spec - name: {}",
|
|
pass_through_build_spec.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build_spec) => {
|
|
println!(
|
|
"Polymorphic Enum Inner Build Spec - name: {}",
|
|
polymorphic_enum_inner_build_spec.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicLeafEnum(polymorphic_leaf_enum) => {
|
|
println!(
|
|
"Polymorphic Leaf Enum Build Spec - name: {}",
|
|
polymorphic_leaf_enum.name()
|
|
);
|
|
}
|
|
BuildSpec::PolymorphicTreeEnum(polymorphic_tree_enum) => {
|
|
println!(
|
|
"Polymorphic Tree Enum Build Spec - name: {}",
|
|
polymorphic_tree_enum.name()
|
|
);
|
|
}
|
|
}
|
|
println!("{:#?}", token_stream);
|
|
let parsed: File = syn::parse2(token_stream.clone()).unwrap();
|
|
println!("{}", prettyplease::unparse(&parsed));
|
|
}
|
|
|
|
pub struct AstGeneratedFile {
|
|
pub name: String,
|
|
pub contents: String,
|
|
}
|
|
|
|
fn token_stream_to_string(token_stream: TokenStream) -> String {
|
|
let file: File = syn::parse2(token_stream).unwrap();
|
|
prettyplease::unparse(&file)
|
|
}
|
|
|
|
fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|
let build_fns = build_specs
|
|
.iter()
|
|
.map(|build_spec| {
|
|
let build_fn = make_build_fn(build_spec);
|
|
debug_built_spec(build_spec, &build_fn);
|
|
build_fn
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let combined = quote! {
|
|
use crate::parser::Rule;
|
|
use pest::iterators::Pair;
|
|
use crate::ast::node::*;
|
|
use std::range::Range;
|
|
|
|
#(#build_fns)*
|
|
};
|
|
|
|
AstGeneratedFile {
|
|
name: String::from("build.rs"),
|
|
contents: token_stream_to_string(combined),
|
|
}
|
|
}
|
|
|
|
fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|
let types = build_specs
|
|
.iter()
|
|
.map(|build_spec| make_type(build_spec))
|
|
.filter(Option::is_some)
|
|
.collect::<Vec<_>>();
|
|
let combined = quote! {
|
|
use std::range::Range;
|
|
use std::rc::Rc;
|
|
use std::cell::RefCell;
|
|
use crate::name_analysis::symbol::*;
|
|
use crate::type_analysis::kinds::*;
|
|
|
|
#(#types)*
|
|
};
|
|
AstGeneratedFile {
|
|
name: String::from("node.rs"),
|
|
contents: token_stream_to_string(combined),
|
|
}
|
|
}
|
|
|
|
fn generate_pretty_print_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|
let impls = build_specs
|
|
.iter()
|
|
.map(|build_spec| {
|
|
let maybe_stream = make_pretty_print_impl(build_spec);
|
|
if let Some(stream) = &maybe_stream {
|
|
debug_built_spec(build_spec, &stream);
|
|
}
|
|
maybe_stream
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let combined = quote! {
|
|
use crate::ast::node::*;
|
|
#(#impls)*
|
|
};
|
|
AstGeneratedFile {
|
|
name: String::from("pretty_print.rs"),
|
|
contents: token_stream_to_string(combined),
|
|
}
|
|
}
|
|
|
|
fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|
let impls = build_specs
|
|
.iter()
|
|
.map(|build_spec| {
|
|
let maybe_stream = make_ast_node_impl(build_spec);
|
|
if let Some(stream) = &maybe_stream {
|
|
debug_built_spec(build_spec, &stream);
|
|
}
|
|
maybe_stream
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let ast_enum_members = build_specs
|
|
.iter()
|
|
.map(|build_spec| make_ast_enum_member(build_spec))
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let ast_enum_mut_members = build_specs
|
|
.iter()
|
|
.map(|build_spec| make_ast_enum_mut_member(build_spec))
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let inner_unwrappers = build_specs
|
|
.iter()
|
|
.map(|build_spec| make_ast_node_ref_unwrapper(build_spec))
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let inner_mut_unwrappers = build_specs
|
|
.iter()
|
|
.map(|build_spec| make_ast_node_ref_mut_unwrapper(build_spec))
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let combined = quote! {
|
|
use crate::ast::node::*;
|
|
|
|
pub enum AstNodeRef<'a> {
|
|
#(#ast_enum_members,)*
|
|
}
|
|
|
|
impl<'a> AstNodeRef<'a> {
|
|
pub fn inner(&self) -> &dyn AstNode<'a> {
|
|
match self {
|
|
#(#inner_unwrappers,)*
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum AstNodeRefMut<'a> {
|
|
#(#ast_enum_mut_members,)*
|
|
}
|
|
|
|
impl<'a> AstNodeRefMut<'a> {
|
|
pub fn inner(&mut self) -> &mut dyn AstNode<'a> {
|
|
match self {
|
|
#(#inner_mut_unwrappers,)*
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait AstNode<'a> {
|
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>;
|
|
|
|
fn for_each_child_mut(&'a mut self, f: &mut dyn FnMut(&'a mut dyn AstNode<'a>));
|
|
|
|
fn as_node_ref(&'a self) -> AstNodeRef<'a>;
|
|
|
|
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a>;
|
|
}
|
|
|
|
#(#impls)*
|
|
};
|
|
AstGeneratedFile {
|
|
name: String::from("ast_node.rs"),
|
|
contents: token_stream_to_string(combined),
|
|
}
|
|
}
|
|
|
|
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> {
|
|
deserialize_yaml_spec(yaml)
|
|
}
|
|
|
|
pub fn generate_files(build_specs: &[BuildSpec]) -> Vec<AstGeneratedFile> {
|
|
vec![
|
|
generate_build_file(build_specs),
|
|
generate_node_file(build_specs),
|
|
generate_pretty_print_file(build_specs),
|
|
generate_ast_node_file(build_specs),
|
|
generate_walk_file(build_specs),
|
|
]
|
|
}
|