Big refactor of ast gen.
This commit is contained in:
parent
5d640ca585
commit
f3c3e40eb2
@ -53,7 +53,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
|
||||
}
|
||||
|
||||
fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> {
|
||||
if !rule_props["child"].as_bool().unwrap() {
|
||||
if !rule_props["child"].as_bool().unwrap_or(true) {
|
||||
None
|
||||
} else {
|
||||
let kind = match rule_props["kind"].as_str().unwrap() {
|
||||
@ -163,7 +163,8 @@ fn deserialize_member_child_to_build(
|
||||
panic!("unsupported kind: {}", kind)
|
||||
}
|
||||
} else {
|
||||
panic!("build is required for a member child")
|
||||
let optional = get_as_bool(&props["optional"]);
|
||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(rule, None, optional)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,7 +277,7 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
|
||||
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
|
||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
||||
} else if build_spec["produce"].is_hash() {
|
||||
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
|
||||
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
|
||||
} else {
|
||||
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::spec::EnumBuildSpec;
|
||||
use crate::spec::{EnumBuildSpec, EnumRuleChildKind};
|
||||
use crate::util::{make_build_fn_name, make_build_pair};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
@ -10,12 +10,28 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream {
|
||||
|
||||
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)
|
||||
if let Some(child) = enum_rule.child() {
|
||||
let inner_builder = match child.kind() {
|
||||
EnumRuleChildKind::Node(node_child) => {
|
||||
let inner_build_fn_ident =
|
||||
format_ident!("{}", make_build_fn_name(node_child.build()));
|
||||
quote! { #inner_build_fn_ident(inner_pair) }
|
||||
}
|
||||
_ => {
|
||||
let inner_build_fn_ident =
|
||||
format_ident!("{}", make_build_fn_name(enum_rule.rule()));
|
||||
quote! { #inner_build_fn_ident(inner_pair) }
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
Rule::#rule_ident => #return_type_ident::#rule_ident(#inner_builder)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
Rule::#rule_ident => #return_type_ident::#rule_ident
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@ -24,7 +40,8 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream {
|
||||
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),*
|
||||
#(#rule_branches,)*
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,18 +9,10 @@ pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> Toke
|
||||
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
|
||||
}
|
||||
quote! {
|
||||
Rule::#rule_ident => #return_type_ident::#rule_ident
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@ -30,7 +22,7 @@ pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> Toke
|
||||
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||
match inner_pair.as_rule() {
|
||||
#(#rule_branches,)*
|
||||
_ => panic!("Unexpected rule: {:?}", inner_pair.as_rule())
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,10 +10,9 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea
|
||||
|
||||
let child_builders = build_spec
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let child_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
match leaf_struct_child.r#type() {
|
||||
.map(|member| {
|
||||
let child_ident = format_ident!("{}", member.name());
|
||||
match member.kind() {
|
||||
LeafStructMemberKind::String => {
|
||||
quote! {
|
||||
let #child_ident = #pair_ident.as_str()
|
||||
@ -25,8 +24,7 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea
|
||||
|
||||
let child_args = build_spec
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
|
||||
.map(|member| format_ident!("{}", member.name()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
|
||||
@ -100,6 +100,7 @@ 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! {
|
||||
#(#types)*
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
use ast_generator::test_dump;
|
||||
|
||||
fn main() {
|
||||
let s = test_dump();
|
||||
println!("{}", s);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom};
|
||||
use crate::util::{make_build_fn_name, make_build_pair};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> TokenStream {
|
||||
let build_fn_ident = format_ident!("{}", make_build_fn_name(production_build_spec.rule()));
|
||||
@ -13,13 +13,13 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
|
||||
ProductionKind::Boolean => format_ident!("bool"),
|
||||
};
|
||||
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule()));
|
||||
|
||||
|
||||
let pair_mapper = match production_build_spec.kind() {
|
||||
ProductionKind::Int => quote! {
|
||||
let number_base_pair = #pair_ident.to_inner()
|
||||
let number_base_pair = #pair_ident.into_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_number_base_pair = number_base_pair.to_inner()
|
||||
let inner_number_base_pair = number_base_pair.into_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
match inner_number_base_pair.as_rule() {
|
||||
@ -36,10 +36,10 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
|
||||
}
|
||||
},
|
||||
ProductionKind::Long => quote! {
|
||||
let number_base_pair = #pair_ident.to_inner()
|
||||
let number_base_pair = #pair_ident.into_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_number_base_pair = number_base_pair.to_inner()
|
||||
let inner_number_base_pair = number_base_pair.into_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
match inner_number_base_pair.as_rule() {
|
||||
@ -58,33 +58,30 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
|
||||
ProductionKind::Double => quote! {
|
||||
#pair_ident.as_str().parse::<f64>().unwrap()
|
||||
},
|
||||
ProductionKind::String(from) => {
|
||||
match from {
|
||||
ProductionStringFrom::StringInner => {
|
||||
quote! {
|
||||
#pair_ident.to_inner()
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.to_string()
|
||||
}
|
||||
ProductionKind::String(from) => match from {
|
||||
ProductionStringFrom::StringInner => {
|
||||
quote! {
|
||||
#pair_ident.into_inner()
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.to_string()
|
||||
}
|
||||
ProductionStringFrom::WholePair => {
|
||||
quote! {
|
||||
#pair_ident.as_string().to_string()
|
||||
}
|
||||
}
|
||||
ProductionStringFrom::WholePair => {
|
||||
quote! {
|
||||
#pair_ident.as_str().to_string()
|
||||
}
|
||||
}
|
||||
},
|
||||
ProductionKind::Boolean => quote! {
|
||||
#pair_ident.as_str().parse::<bool>().unwrap()
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
quote! {
|
||||
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||
#pair_mapper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
use crate::util::make_build_fn_name;
|
||||
use convert_case::{Case, Casing};
|
||||
|
||||
pub enum BuildSpec {
|
||||
Enum(EnumBuildSpec),
|
||||
LeafEnum(LeafEnumBuildSpec),
|
||||
|
||||
@ -1,20 +1,32 @@
|
||||
use crate::spec::{
|
||||
BooleanChildToBuild, BuildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec,
|
||||
LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec,
|
||||
VecChild, VecChildToBuild,
|
||||
};
|
||||
use convert_case::{Case, Casing};
|
||||
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild};
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
|
||||
let children: Vec<TokenStream> = build_spec
|
||||
.rules()
|
||||
.iter()
|
||||
.map(|rule| {
|
||||
let member_name_ident = format_ident!("{}", rule.rule());
|
||||
let child_name_ident = format_ident!("{}", rule.build());
|
||||
quote! {
|
||||
#member_name_ident(#child_name_ident)
|
||||
.map(|enum_rule| {
|
||||
let member_name_ident = format_ident!("{}", enum_rule.rule());
|
||||
if let Some(enum_rule_child) = enum_rule.child() {
|
||||
let child_type_ident = match enum_rule_child.kind() {
|
||||
EnumRuleChildKind::Node(node_child) => {
|
||||
format_ident!("{}", node_child.build())
|
||||
},
|
||||
EnumRuleChildKind::Int => format_ident!("i32"),
|
||||
EnumRuleChildKind::Long => format_ident!("i64"),
|
||||
EnumRuleChildKind::Double => format_ident!("f64"),
|
||||
EnumRuleChildKind::USize => format_ident!("usize"),
|
||||
EnumRuleChildKind::String => format_ident!("String"),
|
||||
EnumRuleChildKind::Boolean => format_ident!("bool"),
|
||||
};
|
||||
quote! {
|
||||
#member_name_ident(#child_type_ident)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#member_name_ident
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -30,19 +42,10 @@ 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
|
||||
}
|
||||
quote! {
|
||||
#rule_name_ident
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@ -60,12 +63,13 @@ fn handle_vec_child(
|
||||
annotated_members: &mut Vec<TokenStream>,
|
||||
accessors: &mut Vec<TokenStream>,
|
||||
) {
|
||||
let (child_ident, child_ident_mut, child_type_ident) = match vec_child.build() {
|
||||
VecChildToBuild::Node(vec_type_child) => (
|
||||
format_ident!("{}", vec_type_child.var_name()),
|
||||
format_ident!("{}_mut", vec_type_child.var_name()),
|
||||
format_ident!("{}", vec_type_child.build()),
|
||||
),
|
||||
let (child_ident, child_ident_mut) = (
|
||||
format_ident!("{}", vec_child.name()),
|
||||
format_ident!("{}", vec_child.name()),
|
||||
);
|
||||
let child_type_ident = match vec_child.build() {
|
||||
VecChildToBuild::Node(vec_node_child) => format_ident!("{}", vec_node_child.build()),
|
||||
VecChildToBuild::String => format_ident!("{}", "String"),
|
||||
};
|
||||
|
||||
member_names.push(child_ident.clone());
|
||||
@ -83,17 +87,19 @@ fn handle_vec_child(
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_single_type_child(
|
||||
single_type_child: &NodeChildToBuild,
|
||||
fn handle_node_child(
|
||||
node_child: &NodeChildToBuild,
|
||||
member_names: &mut Vec<Ident>,
|
||||
annotated_members: &mut Vec<TokenStream>,
|
||||
accessors: &mut Vec<TokenStream>,
|
||||
) {
|
||||
let child_ident = format_ident!("{}", single_type_child.var_name());
|
||||
let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name());
|
||||
let child_type_ident = format_ident!("{}", single_type_child.build());
|
||||
let child_ident = format_ident!("{}", node_child.build().to_case(Case::Snake));
|
||||
let child_ident_mut = format_ident!("{}_mut", child_ident);
|
||||
let child_type_ident = format_ident!("{}", node_child.build());
|
||||
|
||||
member_names.push(child_ident.clone());
|
||||
if single_type_child.optional() {
|
||||
|
||||
if node_child.optional() {
|
||||
annotated_members.push(quote! {
|
||||
#child_ident: Option<Box<#child_type_ident>>
|
||||
});
|
||||
@ -102,7 +108,7 @@ fn handle_single_type_child(
|
||||
#child_ident: Box<#child_type_ident>
|
||||
})
|
||||
}
|
||||
if single_type_child.optional() {
|
||||
if node_child.optional() {
|
||||
accessors.push(quote! {
|
||||
pub fn #child_ident(&self) -> Option<&#child_type_ident> {
|
||||
if let Some(#child_ident) = &self.#child_ident {
|
||||
@ -133,7 +139,7 @@ fn handle_single_type_child(
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_single_boolean_child(
|
||||
fn handle_boolean_child(
|
||||
single_boolean_child: &BooleanChildToBuild,
|
||||
member_names: &mut Vec<Ident>,
|
||||
annotated_members: &mut Vec<TokenStream>,
|
||||
@ -156,7 +162,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
let mut annotated_members: Vec<TokenStream> = vec![];
|
||||
let mut accessors: Vec<TokenStream> = vec![];
|
||||
|
||||
for child_spec in build_spec.children().iter() {
|
||||
for child_spec in build_spec.children() {
|
||||
match child_spec {
|
||||
StructChildSpec::SkipChild(_) => {}
|
||||
StructChildSpec::VecChild(vec_child) => {
|
||||
@ -167,25 +173,24 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
&mut accessors,
|
||||
);
|
||||
}
|
||||
StructChildSpec::MemberChild(single_child) => {
|
||||
match single_child.build() {
|
||||
MemberChildToBuild::Node(single_type_child) => {
|
||||
handle_single_type_child(
|
||||
single_type_child,
|
||||
StructChildSpec::MemberChild(member_child) => {
|
||||
match member_child.build() {
|
||||
MemberChildToBuild::Node(node_child) => {
|
||||
handle_node_child(
|
||||
node_child,
|
||||
&mut member_names,
|
||||
&mut annotated_members,
|
||||
&mut accessors,
|
||||
);
|
||||
}
|
||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
||||
handle_single_boolean_child(
|
||||
single_boolean_child,
|
||||
MemberChildToBuild::Boolean(boolean_child) => {
|
||||
handle_boolean_child(
|
||||
boolean_child,
|
||||
&mut member_names,
|
||||
&mut annotated_members,
|
||||
&mut accessors,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -215,10 +220,9 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
|
||||
let annotated_members = build_spec
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let name_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
let type_ident = match leaf_struct_child.r#type() {
|
||||
.map(|member| {
|
||||
let name_ident = format_ident!("{}", member.name());
|
||||
let type_ident = match member.kind() {
|
||||
LeafStructMemberKind::String => format_ident!("{}", "String"),
|
||||
};
|
||||
quote! {
|
||||
@ -229,16 +233,14 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
|
||||
let member_names = build_spec
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let accessors = build_spec
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let name_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
match leaf_struct_child.r#type() {
|
||||
.map(|member| {
|
||||
let name_ident = format_ident!("{}", member.name());
|
||||
match member.kind() {
|
||||
LeafStructMemberKind::String => {
|
||||
quote! {
|
||||
pub fn #name_ident(&self) -> &str {
|
||||
@ -267,13 +269,14 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_type(build_spec: &BuildSpec) -> TokenStream {
|
||||
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
|
||||
match build_spec {
|
||||
BuildSpec::Enum(enum_build_spec) => make_enum_type(enum_build_spec),
|
||||
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::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)),
|
||||
BuildSpec::LeafEnum(leaf_enum_build_spec) => Some(make_leaf_enum_type(leaf_enum_build_spec)),
|
||||
BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)),
|
||||
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
|
||||
make_leaf_struct_type(leaf_struct_build_spec)
|
||||
}
|
||||
Some(make_leaf_struct_type(leaf_struct_build_spec))
|
||||
},
|
||||
BuildSpec::Production(production_build_spec) => None
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user