Compare commits

...

25 Commits

Author SHA1 Message Date
Jesse Brault
2a2936ef02 Ast gen successful, but compile errors. 2025-09-23 18:15:09 -05:00
Jesse Brault
c73bb50d6f WIP cargo build no more compile errors. 2025-09-23 18:11:53 -05:00
Jesse Brault
7a7eda97e3 Clean up other type gen. 2025-09-23 18:08:36 -05:00
Jesse Brault
2986bbe37e Refactor struct type. 2025-09-23 18:07:04 -05:00
Jesse Brault
1565abace5 Add debug for polymorphic pass through. 2025-09-23 17:35:43 -05:00
Jesse Brault
a347e69f9d Remove old enum stuff. 2025-09-23 17:34:51 -05:00
Jesse Brault
13e2ae6b0c Add polymorphic pass through. 2025-09-23 17:34:41 -05:00
Jesse Brault
4b59abc989 Update schema for ast gen. 2025-09-23 14:14:42 -05:00
Jesse Brault
e21b428e26 Various refactoring. 2025-09-23 11:03:25 -05:00
Jesse Brault
eb83d1202a Make polymorphic enum loop build fn. 2025-09-23 10:56:11 -05:00
Jesse Brault
d7b01377d7 Refactor polymorphic type build fn. 2025-09-23 10:25:52 -05:00
Jesse Brault
8aa4248e07 Make node production build fn. 2025-09-23 10:23:10 -05:00
Jesse Brault
de021789c1 Refactor production build fn. 2025-09-23 10:19:28 -05:00
Jesse Brault
f3ebcd77bd Refactor leaf enum build fn. 2025-09-23 10:17:21 -05:00
Jesse Brault
5842304f0b Refactor tree_enum deserialize and build fn. 2025-09-22 21:08:28 -05:00
Jesse Brault
2d8843b80d Move tree enum build fn. 2025-09-22 20:58:59 -05:00
Jesse Brault
1b23fbf683 Fix struct spec. 2025-09-22 20:57:45 -05:00
Jesse Brault
8143894257 Refactor build fn for leaf-struct nodes. 2025-09-22 20:57:22 -05:00
Jesse Brault
4d2e76338a Refactor build fn for struct nodes. 2025-09-22 20:56:24 -05:00
Jesse Brault
63643d86ba New deserialization code. 2025-09-22 20:19:30 -05:00
Jesse Brault
0f64fee5ef Move deserialize. 2025-09-22 08:46:52 -05:00
Jesse Brault
b5e6f1c502 Sketching rc. 2025-09-22 08:45:31 -05:00
Jesse Brault
aff2fe2a2b Moving things around and cargo fmt. 2025-09-21 11:19:27 -05:00
Jesse Brault
2176d0eb8d Add op_prec.dm. 2025-09-20 17:51:06 -05:00
Jesse Brault
dad25dcbf2 Updates to ast and schema. 2025-09-20 17:50:51 -05:00
55 changed files with 3907 additions and 3304 deletions

View File

@ -1,5 +1,5 @@
use crate::spec::LeafEnumBuildSpec; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -8,9 +8,10 @@ pub fn make_leaf_enum_build_fn(leaf_enum_build_spec: &LeafEnumBuildSpec) -> Toke
let pair_ident = format_ident!("{}", make_build_pair(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 return_type_ident = format_ident!("{}", leaf_enum_build_spec.build());
let rule_branches = leaf_enum_build_spec.rules() let rule_branches = leaf_enum_build_spec
.rules()
.map(|leaf_enum_rule| { .map(|leaf_enum_rule| {
let rule_ident = format_ident!("{}", leaf_enum_rule.rule()); let rule_ident = format_ident!("{}", leaf_enum_rule);
quote! { quote! {
Rule::#rule_ident => #return_type_ident::#rule_ident Rule::#rule_ident => #return_type_ident::#rule_ident
} }

View File

@ -1,5 +1,5 @@
use crate::spec::{LeafStructBuildSpec, LeafStructMemberKind}; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMemberKind};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};

View File

@ -0,0 +1,43 @@
use crate::build_fn::leaf_enum_build_fn::make_leaf_enum_build_fn;
use crate::build_fn::leaf_struct_build_fn::make_leaf_struct_build_fn;
use crate::build_fn::node_production_build_fn::make_node_production_build_fn;
use crate::build_fn::polymorphic_enum_loop_build_fn::make_polymorphic_enum_loop_build_fn;
use crate::build_fn::polymorphic_pass_through_build_fn::make_polymorphic_pass_through_build_fn;
use crate::build_fn::polymorphic_type_build_fn::make_polymorphic_type_build_fn;
use crate::build_fn::production_build_fn::make_production_build_fn;
use crate::build_fn::struct_build_fn::make_struct_build_fn;
use crate::build_fn::tree_enum_build_fn::make_enum_build_fn;
use crate::spec::BuildSpec;
use proc_macro2::TokenStream;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod node_production_build_fn;
mod polymorphic_enum_loop_build_fn;
mod polymorphic_pass_through_build_fn;
mod polymorphic_type_build_fn;
mod production_build_fn;
mod struct_build_fn;
mod tree_enum_build_fn;
pub fn make_build_fn(build_spec: &BuildSpec) -> TokenStream {
match build_spec {
BuildSpec::Struct(struct_spec) => make_struct_build_fn(struct_spec),
BuildSpec::LeafStruct(leaf_struct_spec) => make_leaf_struct_build_fn(leaf_struct_spec),
BuildSpec::Enum(enum_spec) => make_enum_build_fn(enum_spec),
BuildSpec::LeafEnum(leaf_enum_spec) => make_leaf_enum_build_fn(leaf_enum_spec),
BuildSpec::Production(production_spec) => make_production_build_fn(production_spec),
BuildSpec::NodeProduction(node_production_spec) => {
make_node_production_build_fn(node_production_spec)
}
BuildSpec::PolymorphicType(polymorphic_type_spec) => {
make_polymorphic_type_build_fn(polymorphic_type_spec)
}
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_spec) => {
make_polymorphic_enum_loop_build_fn(polymorphic_enum_loop_spec)
}
BuildSpec::PolymorphicPassThrough(polymorphic_pass_through_spec) => {
make_polymorphic_pass_through_build_fn(polymorphic_pass_through_spec)
}
}
}

View File

@ -0,0 +1,18 @@
use crate::deserialize::util::make_build_pair;
use crate::spec::node_production_spec::NodeProductionBuildSpec;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_node_production_build_fn(spec: &NodeProductionBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", spec.with());
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.kind());
let inner_build_fn_ident = format_ident!("{}", spec.with());
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let inner_pair = #pair_ident.into_inner().next().unwrap();
#inner_build_fn_ident(inner_pair)
}
}
}

View File

@ -0,0 +1,100 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule,
PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild,
PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_pass_through(pass_through: &PolymorphicEnumLoopRulePassThrough) -> TokenStream {
let rule_ident = format_ident!("{}", pass_through.name());
let inner_build_fn_ident = format_ident!("{}", pass_through.with());
quote! {
Rule::#rule_ident => {
result = Some(#inner_build_fn_ident(inner_pair))
}
}
}
fn make_on_each_child_build(child: &PolymorphicEnumLoopRuleChildOnEach) -> TokenStream {
let child_build_fn_ident = format_ident!("{}", make_build_fn_name(child.rule()));
quote! {
#child_build_fn_ident(inner_pair)
}
}
fn make_build(
spec: &PolymorphicEnumLoopBuildSpec,
build: &PolymorphicEnumLoopRuleBuild,
) -> TokenStream {
let rule_ident = format_ident!("{}", build.name());
let variant_type_ident = format_ident!("{}", build.name());
let return_type_ident = format_ident!("{}", spec.kind());
let variant_ident = format_ident!("{}", build.variant());
let on_each_child = build
.children()
.find(|child| match child {
PolymorphicEnumLoopRuleBuildChild::OnEach(_) => true,
_ => false,
})
.map(|child| {
match child {
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => on_each,
_ => unreachable!(),
}
})
.unwrap();
let build_on_each_child = make_on_each_child_build(on_each_child);
let child_args = build
.children()
.map(|child| match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(_) => {
quote! { result.unwrap() }
}
PolymorphicEnumLoopRuleBuildChild::OnEach(_) => quote! { on_each_child },
})
.collect::<Vec<_>>();
quote! {
Rule::#rule_ident => {
let on_each_child = #build_on_each_child;
let built = #variant_type_ident::new(#(#child_args),*);
result = Some(#return_type_ident::#variant_ident(built))
}
}
}
fn make_match_arm(spec: &PolymorphicEnumLoopBuildSpec, rule: &PolymorphicEnumLoopRule) -> TokenStream {
match rule {
PolymorphicEnumLoopRule::PassThrough(pass_through) => make_pass_through(pass_through),
PolymorphicEnumLoopRule::Build(build) => make_build(spec, build),
}
}
pub fn make_polymorphic_enum_loop_build_fn(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.kind());
let match_arms = spec
.rules()
.map(|rule| make_match_arm(spec, rule))
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let mut result: Option<#return_type_ident> = None;
for inner_pair in #pair_ident.into_inner() {
match inner_pair.as_rule() {
#(#match_arms,)*
_ => unreachable!()
}
}
result.unwrap()
}
}
}

View File

@ -0,0 +1,50 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::polymorphic_pass_through_spec::{PolymorphicPassThroughBuildSpec, PolymorphicPassThroughVariant};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_pass_through_build_fn(
spec: &PolymorphicPassThroughBuildSpec,
) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.build_kind());
let match_arms = spec.variants()
.map(|variant| {
match variant {
PolymorphicPassThroughVariant::Inner { name, kind} => {
let rule_ident = format_ident!("{}", kind);
let variant_ident = format_ident!("{}", name);
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(kind));
quote! {
Rule::#rule_ident => {
#return_type_ident::#variant_ident(
#inner_build_fn_ident(inner_pair)
)
}
}
}
PolymorphicPassThroughVariant::PassThrough { name, kind: _kind } => {
let rule_ident = format_ident!("{}", name);
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(name));
quote! {
Rule::#rule_ident => #inner_build_fn_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() {
#(#match_arms,)*
_ => unreachable!(),
}
}
}
}

View File

@ -1,13 +1,13 @@
use crate::spec::PolymorphicTypeBuildSpec; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::spec::polymorphic_type_spec::PolymorphicTypeBuildSpec;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
pub fn make_polymorphic_build_fn(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream { pub fn make_polymorphic_type_build_fn(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.name())); let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(&build_spec.name())); let pair_ident = format_ident!("{}", make_build_pair(&build_spec.name()));
let return_type_ident = format_ident!("{}", build_spec.name()); let return_type_ident = format_ident!("{}", build_spec.name());
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind())); let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.kind()));
quote! { quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident { fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {

View File

@ -1,19 +1,18 @@
use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom}; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::spec::production_spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> TokenStream { 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())); let build_fn_ident = format_ident!("{}", make_build_fn_name(production_build_spec.name()));
let return_type_ident = match production_build_spec.kind() { let return_type_ident = match production_build_spec.kind() {
ProductionKind::Int => format_ident!("i32"), ProductionKind::Int => format_ident!("i32"),
ProductionKind::Long => format_ident!("i64"), ProductionKind::Long => format_ident!("i64"),
ProductionKind::Double => format_ident!("f64"), ProductionKind::Double => format_ident!("f64"),
ProductionKind::String(_) => format_ident!("String"), ProductionKind::String(_) => format_ident!("String"),
ProductionKind::Boolean => format_ident!("bool"), ProductionKind::Boolean(_) => format_ident!("bool"),
ProductionKind::Node(node_type) => format_ident!("{}", node_type),
}; };
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule())); let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.name()));
let pair_mapper = match production_build_spec.kind() { let pair_mapper = match production_build_spec.kind() {
ProductionKind::Int => quote! { ProductionKind::Int => quote! {
@ -75,16 +74,9 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
} }
} }
}, },
ProductionKind::Boolean => quote! { ProductionKind::Boolean(_) => quote! {
#pair_ident.as_str().parse::<bool>().unwrap() #pair_ident.as_str().parse::<bool>().unwrap()
}, },
ProductionKind::Node(node_type) => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(node_type));
quote! {
let inner_pair = #pair_ident.into_inner().next().unwrap();
#build_fn_ident(inner_pair)
}
}
}; };
quote! { quote! {

View File

@ -0,0 +1,215 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::struct_spec::{
MemberChildBuild, NodeMemberBuild, StructChild, StructSpec, VecChild, VecChildBuild,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildBuild::String(_) => {
quote! {
let mut #child_ident: Vec<String> = vec![]
}
}
VecChildBuild::Node(node_build) => {
let child_type_ident = format_ident!("{}", node_build.kind());
quote! {
let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
}
}
}
}
fn make_node_child_holder(name: &str, node_child: &NodeMemberBuild) -> TokenStream {
let child_ident = format_ident!("{}", name);
let child_type_ident = format_ident!("{}", node_child.kind());
quote! {
let mut #child_ident: Option<Box<#child_type_ident>> = None
}
}
fn make_boolean_child_holder(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", name);
quote! {
let mut #child_ident: bool = false
}
}
fn make_child_holder(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_child) => {
Some(make_node_child_holder(member_child.name(), node_child))
}
MemberChildBuild::Boolean(_) => Some(make_boolean_child_holder(member_child.name())),
},
}
}
fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream {
let child_name_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildBuild::String(string_build) => {
let build_fn_ident = format_ident!("{}", string_build.with());
quote! {
#child_name_ident.push(#build_fn_ident(inner_pair))
}
}
VecChildBuild::Node(node_build) => {
let build_fn_ident = format_ident!("{}", node_build.with());
quote! {
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
}
}
}
}
fn make_node_member_child_match_action(name: &str, node_child: &NodeMemberBuild) -> TokenStream {
let child_name_ident = format_ident!("{}", name);
let build_fn_ident = format_ident!("{}", node_child.with());
quote! {
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
}
}
fn make_boolean_member_child_match_action(name: &str) -> TokenStream {
let child_name_ident = format_ident!("{}", name);
quote! {
#child_name_ident = true
}
}
fn make_match_action(child_spec: &StructChild) -> TokenStream {
match child_spec {
StructChild::SkipChild(_) => quote! {},
StructChild::VecChild(vec_child) => make_vec_child_match_action(vec_child),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_child) => {
make_node_member_child_match_action(member_child.name(), node_child)
}
MemberChildBuild::Boolean(_) => {
make_boolean_member_child_match_action(member_child.name())
}
},
}
}
fn make_rule_matcher(child_spec: &StructChild) -> TokenStream {
let rule_ident = match child_spec {
StructChild::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
StructChild::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
StructChild::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
};
let action = make_match_action(child_spec);
quote! {
Rule::#rule_ident => {
#action;
}
}
}
fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
quote! { #child_ident }
}
fn make_node_member_child_arg(
name: &str,
optional: bool,
node_child: &NodeMemberBuild,
) -> TokenStream {
let child_ident = format_ident!("{}", name);
if optional {
quote! { #child_ident }
} else if let Some(or_else) = node_child.or_else() {
let child_type_ident = format_ident!("{}", node_child.kind());
let or_else_ident = format_ident!("{}", or_else);
quote! {
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
}
} else {
quote! { #child_ident.unwrap() }
}
}
fn make_boolean_member_child_arg(name: &str) -> TokenStream {
let child_ident = format_ident!("{}", name);
quote! { #child_ident }
}
fn make_child_arg(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_member_build) => Some(make_node_member_child_arg(
member_child.name(),
member_child.optional(),
node_member_build,
)),
MemberChildBuild::Boolean(_) => {
Some(make_boolean_member_child_arg(member_child.name()))
}
},
}
}
fn make_return_value_stream(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec
.children()
.map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>();
quote! {
#type_ident::new(
#(#child_args,)*
)
}
}
pub fn make_struct_build_fn(build_spec: &StructSpec) -> 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_holders = build_spec
.children()
.map(|child_spec| make_child_holder(child_spec))
.filter(|child_holder| child_holder.is_some())
.map(|child_holder| child_holder.unwrap())
.collect::<Vec<_>>();
let rule_matchers = build_spec
.children()
.map(|child_spec| make_rule_matcher(child_spec))
.collect::<Vec<_>>();
let iter_stream = quote! {
for inner_pair in #pair_ident.into_inner() {
match inner_pair.as_rule() {
#(#rule_matchers)*
_ => panic!("Unexpected rule: {:?}", inner_pair.as_rule())
}
}
};
let new_stream = make_return_value_stream(build_spec);
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
#(#child_holders;)*
#iter_stream
#new_stream
}
}
}

View File

@ -1,9 +1,9 @@
use crate::spec::{EnumBuildSpec, EnumRuleChildKind}; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::util::{make_build_fn_name, make_build_pair}; use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; 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: &TreeEnumBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(enum_build_spec.build())); 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 pair_ident = format_ident!("{}", make_build_pair(enum_build_spec.build()));
let return_type_ident = format_ident!("{}", enum_build_spec.build()); let return_type_ident = format_ident!("{}", enum_build_spec.build());
@ -16,12 +16,27 @@ pub fn make_enum_build_fn(enum_build_spec: &EnumBuildSpec) -> TokenStream {
let inner_builder = match child.kind() { let inner_builder = match child.kind() {
EnumRuleChildKind::Node(node_child) => { EnumRuleChildKind::Node(node_child) => {
let inner_build_fn_ident = let inner_build_fn_ident =
format_ident!("{}", make_build_fn_name(node_child.build())); format_ident!("{}", node_child.with());
quote! { #inner_build_fn_ident(inner_pair) } quote! { #inner_build_fn_ident(inner_pair) }
} }
_ => { EnumRuleChildKind::Int(name_and_with) => {
let inner_build_fn_ident = let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
format_ident!("{}", make_build_fn_name(enum_rule.rule())); quote! { #inner_build_fn_ident(inner_pair) }
}
EnumRuleChildKind::Long(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(inner_pair) }
}
EnumRuleChildKind::Double(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(inner_pair) }
}
EnumRuleChildKind::String(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(inner_pair) }
}
EnumRuleChildKind::Boolean(name_and_with) => {
let inner_build_fn_ident = format_ident!("{}", name_and_with.with());
quote! { #inner_build_fn_ident(inner_pair) } quote! { #inner_build_fn_ident(inner_pair) }
} }
}; };

View File

@ -1,432 +0,0 @@
use crate::spec::{AlternativeAction, AlternativeBuild, AlternativeBuildChild, AlternativeChild, AlternativeTest, BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NameAndKind, NodeChildToBuild, PolymorphicBuildAlternative, PolymorphicBuildBuildSpec, PolymorphicEnumBuildSpec, PolymorphicEnumMember, PolymorphicEnumRule, PolymorphicTypeBuildSpec, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
use convert_case::{Case, Casing};
use yaml_rust2::{Yaml, YamlLoader};
fn get_as_bool(yaml: &Yaml) -> bool {
yaml.as_bool().unwrap_or_else(|| false)
}
fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
let as_hash = hash.as_hash().unwrap();
if as_hash.is_empty() {
panic!("empty hash");
} else if as_hash.len() > 1 {
panic!("hash contains more than one key");
}
let (member_key, member_value) = as_hash.iter().collect::<Vec<(&Yaml, &Yaml)>>()[0];
let key_as_string = member_key.as_str().unwrap().to_string();
(key_as_string, member_value)
}
fn deserialize_polymorphic_enum_build_spec(name: &str, build_spec: &Yaml) -> PolymorphicEnumBuildSpec {
let return_type = build_spec["return_type"].as_str().unwrap();
let rules = build_spec["rules"]
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
let (rule_name, props) = unwrap_single_member_hash(rule_yaml);
if props["wrap"].is_hash() {
PolymorphicEnumRule::Wrap(NameAndKind::new(
&rule_name,
props["wrap"]["enum_variant"].as_str().unwrap()
))
} else if props["return_build"].is_hash() {
PolymorphicEnumRule::ReturnBuild(NameAndKind::new(
&rule_name,
props["return_build"]["kind"].as_str().unwrap()
))
} else {
panic!()
}
})
.map(Box::new)
.collect::<Vec<_>>();
PolymorphicEnumBuildSpec::new(name, return_type, rules)
}
fn deserialize_polymorphic_action(action_yaml: &Yaml) -> AlternativeAction {
if action_yaml["return_build"].is_hash() {
let kind = action_yaml["return_build"]["kind"].as_str().unwrap();
AlternativeAction::ReturnBuild(kind.to_string())
} else if action_yaml["build"].is_hash() {
let build_children = action_yaml["build"]["children"]
.as_vec()
.unwrap()
.iter()
.map(|child_yaml| {
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
if get_as_bool(&child_props["skip"]) {
AlternativeChild::Skip
} else {
let kind = child_props["kind"].as_str().unwrap();
let rule = child_props["rule"].as_str().unwrap();
AlternativeChild::Build(AlternativeBuildChild::new(&child_name, kind, rule))
}
})
.map(Box::new)
.collect();
let enum_variant = action_yaml["build"]["enum_variant"].as_str().unwrap();
let build = AlternativeBuild::new(enum_variant, build_children);
AlternativeAction::Build(build)
} else {
panic!("return_build or build is required for an alternative")
}
}
fn deserialize_polymorphic_build_build_spec(
name: &str,
polymorphic_build_yaml: &Yaml
) -> PolymorphicBuildBuildSpec {
let return_type = polymorphic_build_yaml["return_type"].as_str().unwrap();
let alternatives = polymorphic_build_yaml["alternatives"]
.as_vec()
.unwrap()
.iter()
.map(|alternative_yaml| {
let number_of_pairs = alternative_yaml["test"]["number_of_pairs"].as_i64().unwrap();
let action = deserialize_polymorphic_action(&alternative_yaml["action"]);
PolymorphicBuildAlternative::new(
AlternativeTest::NumberOfPairs(number_of_pairs),
action
)
})
.map(Box::new)
.collect();
PolymorphicBuildBuildSpec::new(name, return_type, alternatives)
}
fn deserialize_polymorphic_enum_members(
enum_members_yaml: &Yaml,
) -> Vec<Box<PolymorphicEnumMember>> {
enum_members_yaml
.as_vec()
.unwrap()
.iter()
.map(|enum_member_yaml| {
let (member_name, member_hash) = unwrap_single_member_hash(enum_member_yaml);
let inner_kind = member_hash["inner"]["kind"].as_str().unwrap();
PolymorphicEnumMember::new(&member_name, inner_kind)
})
.map(Box::new)
.collect()
}
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicTypeBuildSpec {
let enum_members = deserialize_polymorphic_enum_members(&spec_props["enum_members"]);
let build_kind = spec_props["build"]["kind"].as_str().unwrap();
PolymorphicTypeBuildSpec::new(name, enum_members, build_kind)
}
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
let kind = if production_yaml["kind"].is_hash() {
let node = production_yaml["kind"]["node"].as_str().unwrap();
ProductionKind::Node(node.to_string())
} else {
match production_yaml["kind"].as_str().unwrap() {
"int" => ProductionKind::Int,
"long" => ProductionKind::Long,
"double" => ProductionKind::Double,
"boolean" => ProductionKind::Boolean,
"string" => {
let from = match production_yaml["from"].as_str().unwrap() {
"string_inner" => ProductionStringFrom::StringInner,
"whole_pair" => ProductionStringFrom::WholePair,
_ => panic!(
"invalid from: {}",
production_yaml["from"].as_str().unwrap()
),
};
ProductionKind::String(from)
}
_ => panic!(
"invalid kind: {}",
production_yaml["kind"].as_str().unwrap()
),
}
};
ProductionBuildSpec::new(rule, kind)
}
fn deserialize_leaf_enum_rule(rule_yaml: &Yaml) -> Box<LeafEnumRule> {
Box::new(LeafEnumRule::new(rule_yaml.as_str().unwrap()))
}
fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
rules_yaml
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
.collect()
}
fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> {
if !rule_props["child"].as_bool().unwrap_or(true) {
None
} else {
let kind = match rule_props["kind"].as_str().unwrap() {
"int" => EnumRuleChildKind::Int,
"long" => EnumRuleChildKind::Long,
"double" => EnumRuleChildKind::Double,
"usize" => EnumRuleChildKind::USize,
"string" => EnumRuleChildKind::String,
"boolean" => EnumRuleChildKind::Boolean,
_ => panic!(
"unsupported enum rule kind: {}",
rule_props["kind"].as_str().unwrap()
),
};
Some(Box::new(EnumRuleChild::new(Box::new(kind))))
}
}
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
EnumRuleNodeChild::new(rule),
))))
}
fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
if rule_yaml.is_hash() {
let (rule, rule_props) = unwrap_single_member_hash(rule_yaml);
Box::new(EnumRule::new(
&rule,
deserialize_enum_rule_custom_child(rule_props),
))
} else {
let rule_as_str = rule_yaml.as_str().unwrap();
Box::new(EnumRule::new(
rule_as_str,
Some(deserialize_enum_rule_node_child(rule_as_str)),
))
}
}
fn deserialize_enum_rules(rules_yaml: &Yaml) -> Vec<Box<EnumRule>> {
rules_yaml
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| deserialize_enum_rule(rule_yaml))
.collect()
}
fn deserialize_leaf_struct_member(name: &str, props: &Yaml) -> Box<LeafStructMember> {
let kind = props["kind"].as_str().unwrap();
if kind == "string" {
Box::new(LeafStructMember::new(name, LeafStructMemberKind::String))
} else {
panic!("invalid member kind: {}", kind);
}
}
fn deserialize_leaf_struct_members(members_yaml: &Yaml) -> Vec<Box<LeafStructMember>> {
members_yaml
.as_vec()
.unwrap()
.iter()
.map(|member| {
let (member_name, member_props) = unwrap_single_member_hash(member);
deserialize_leaf_struct_member(&member_name, member_props)
})
.collect()
}
fn deserialize_member_node_to_build(
rule: &str,
build_props: &Yaml,
optional: bool,
) -> Box<MemberChildToBuild> {
let or_else = build_props["or_else"]
.as_str()
.or_else(|| {
if get_as_bool(&build_props["or_else_default"]) {
Some("default")
} else {
None
}
})
.map(ToString::to_string);
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
rule, or_else, optional,
)))
}
fn deserialize_member_boolean_to_build(name: &str) -> Box<MemberChildToBuild> {
Box::new(MemberChildToBuild::Boolean(BooleanChildToBuild::new(name)))
}
fn deserialize_member_child_to_build(
name: &str,
rule: &str,
props: &Yaml,
optional: bool,
) -> Box<MemberChildToBuild> {
if props["build"].is_hash() {
let build_props = &props["build"];
let kind = build_props["kind"].as_str().or(Some("node")).unwrap();
if kind == "node" {
deserialize_member_node_to_build(rule, build_props, optional)
} else if kind == "boolean" {
deserialize_member_boolean_to_build(name)
} else {
panic!("unsupported kind: {}", kind)
}
} else {
let optional = get_as_bool(&props["optional"]);
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
rule, None, optional,
)))
}
}
fn deserialize_member_child(
name: &str,
rule: &str,
optional: bool,
props: &Yaml,
) -> Box<StructChildSpec> {
Box::new(StructChildSpec::MemberChild(MemberChild::new(
name,
rule,
deserialize_member_child_to_build(name, rule, props, optional),
)))
}
fn deserialize_vec_node_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
let rule = props["rule"].as_str().unwrap();
Box::new(StructChildSpec::VecChild(VecChild::new(
name,
rule,
Box::new(VecChildToBuild::Node(VecNodeChildToBuild::new(rule))),
)))
}
fn deserialize_vec_string_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
let rule = props["rule"].as_str().unwrap();
Box::new(StructChildSpec::VecChild(VecChild::new(
name,
rule,
Box::new(VecChildToBuild::String),
)))
}
fn deserialize_vec_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
let kind = props["kind"].as_str().or_else(|| Some("node")).unwrap();
if kind == "node" {
deserialize_vec_node_child(name, props)
} else if kind == "string" {
deserialize_vec_string_child(name, props)
} else {
panic!("invalid kind: {}", kind);
}
}
fn deserialize_skip_child(name: &str, rule: &str) -> Box<StructChildSpec> {
Box::new(StructChildSpec::SkipChild(SkipChild::new(name, rule)))
}
fn deserialize_struct_hash_child(child: &Yaml) -> Box<StructChildSpec> {
let (name, props) = unwrap_single_member_hash(child);
let rule = props["rule"]
.as_str()
.map(|s| s.to_string())
.unwrap_or(name.to_case(Case::Pascal));
if get_as_bool(&props["skip"]) {
deserialize_skip_child(&name, &rule)
} else {
if get_as_bool(&props["vec"]) {
deserialize_vec_child(&name, props)
} else {
let optional = get_as_bool(&props["optional"]);
deserialize_member_child(&name, &rule, optional, props)
}
}
}
fn deserialize_struct_string_child(child: &Yaml) -> Box<StructChildSpec> {
let child_as_str = child.as_str().unwrap();
let child_name_pascal = child_as_str.to_case(Case::Pascal);
Box::new(StructChildSpec::MemberChild(MemberChild::new(
child_as_str,
&child_name_pascal,
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
&child_name_pascal,
None,
false,
))),
)))
}
fn deserialize_struct_children(children: &Yaml) -> Vec<Box<StructChildSpec>> {
children
.as_vec()
.unwrap()
.iter()
.map(|child_spec| {
if child_spec.is_hash() {
deserialize_struct_hash_child(child_spec)
} else {
deserialize_struct_string_child(child_spec)
}
})
.collect()
}
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
if build_spec["children"].is_array() {
let children = deserialize_struct_children(&build_spec["children"]);
BuildSpec::Struct(StructBuildSpec::new(build_spec_name, children))
} else if build_spec["members"].is_array() {
let members = deserialize_leaf_struct_members(&build_spec["members"]);
BuildSpec::LeafStruct(LeafStructBuildSpec::new(build_spec_name, members))
} else if build_spec["rules"].is_array() {
let rules = deserialize_enum_rules(&build_spec["rules"]);
BuildSpec::Enum(EnumBuildSpec::new(build_spec_name, rules))
} else if build_spec["leaf_rules"].is_array() {
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"],
))
} else if build_spec["polymorphic_type"].is_hash() {
BuildSpec::Polymorphic(deserialize_polymorphic_spec(
build_spec_name,
&build_spec["polymorphic_type"],
))
} else if build_spec["polymorphic_build"].is_hash() {
BuildSpec::PolymorphicBuild(deserialize_polymorphic_build_build_spec(
build_spec_name,
&build_spec["polymorphic_build"],
))
} else if build_spec["polymorphic_enum"].is_hash() {
BuildSpec::PolymorphicEnum(deserialize_polymorphic_enum_build_spec(
build_spec_name,
&build_spec["polymorphic_enum"],
))
} else {
panic!(
"Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, production, polymorphic type, or polymorphic build type."
);
}
}
pub fn deserialize_yaml_spec(yaml: &str) -> Vec<BuildSpec> {
let docs = YamlLoader::load_from_str(yaml).unwrap();
let doc = &docs[0];
doc.as_hash()
.unwrap()
.iter()
.map(|(build_spec_name, build_spec)| {
let name_as_str = build_spec_name.as_str().unwrap();
deserialize_build_spec(name_as_str, build_spec)
})
.collect()
}

View File

@ -0,0 +1,13 @@
use yaml_rust2::Yaml;
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
pub fn deserialize_leaf_enum(name: &str, props: &Yaml) -> LeafEnumBuildSpec {
let rules = props["rules"].as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
rule_yaml.as_str().unwrap().to_string()
})
.collect();
LeafEnumBuildSpec::new(name, rules)
}

View File

@ -0,0 +1,21 @@
use crate::deserialize::util::unwrap_single_member_hash;
use yaml_rust2::Yaml;
use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind};
fn deserialize_member(member_name: &str) -> LeafStructMember {
LeafStructMember::new(member_name, LeafStructMemberKind::String)
}
pub fn deserialize_leaf_struct(name: &str, props: &Yaml) -> LeafStructBuildSpec {
let members = props["members"]
.as_vec()
.unwrap()
.iter()
.map(|member_hash| {
let (member_name, _props) = unwrap_single_member_hash(member_hash);
deserialize_member(&member_name)
})
.map(Box::new)
.collect();
LeafStructBuildSpec::new(name, members)
}

View File

@ -0,0 +1,87 @@
mod leaf_enum_spec;
mod leaf_struct_spec;
mod node_production_spec;
mod polymorphic_enum_loop_spec;
mod polymorphic_pass_through_spec;
mod polymorphic_type_spec;
mod production_spec;
mod struct_spec;
mod tree_enum_spec;
pub(crate) mod util;
use crate::deserialize::leaf_enum_spec::deserialize_leaf_enum;
use crate::deserialize::leaf_struct_spec::deserialize_leaf_struct;
use crate::deserialize::node_production_spec::deserialize_node_production;
use crate::deserialize::polymorphic_enum_loop_spec::deserialize_polymorphic_enum_loop;
use crate::deserialize::polymorphic_type_spec::deserialize_polymorphic_type;
use crate::deserialize::production_spec::deserialize_production;
use crate::deserialize::struct_spec::deserialize_struct_spec;
use crate::deserialize::tree_enum_spec::deserialize_tree_enum;
use crate::spec::BuildSpec;
use yaml_rust2::{Yaml, YamlLoader};
use crate::deserialize::polymorphic_pass_through_spec::deserialize_polymorphic_pass_through;
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
if build_spec["struct"].is_hash() {
BuildSpec::Struct(deserialize_struct_spec(
build_spec_name,
&build_spec["struct"],
))
} else if build_spec["leaf_struct"].is_hash() {
BuildSpec::LeafStruct(deserialize_leaf_struct(
build_spec_name,
&build_spec["leaf_struct"],
))
} else if build_spec["tree_enum"].is_hash() {
BuildSpec::Enum(deserialize_tree_enum(
build_spec_name,
&build_spec["tree_enum"],
))
} else if build_spec["leaf_enum"].is_hash() {
BuildSpec::LeafEnum(deserialize_leaf_enum(
build_spec_name,
&build_spec["leaf_enum"],
))
} else if build_spec["production"].is_hash() {
BuildSpec::Production(deserialize_production(
build_spec_name,
&build_spec["production"],
))
} else if build_spec["node_production"].is_hash() {
BuildSpec::NodeProduction(deserialize_node_production(
build_spec_name,
&build_spec["node_production"],
))
} else if build_spec["polymorphic_type"].is_hash() {
BuildSpec::PolymorphicType(deserialize_polymorphic_type(
build_spec_name,
&build_spec["polymorphic_type"],
))
} else if build_spec["polymorphic_enum_loop_build"].is_hash() {
BuildSpec::PolymorphicEnumLoop(deserialize_polymorphic_enum_loop(
build_spec_name,
&build_spec["polymorphic_enum_loop_build"],
))
} else if build_spec["polymorphic_pass_through"].is_hash() {
BuildSpec::PolymorphicPassThrough(deserialize_polymorphic_pass_through(
build_spec_name,
&build_spec["polymorphic_pass_through"],
))
} else {
panic!("Missing or incorrect build type for {}", build_spec_name);
}
}
pub fn deserialize_yaml_spec(yaml: &str) -> Vec<BuildSpec> {
let docs = YamlLoader::load_from_str(yaml).unwrap();
let doc = &docs[0];
doc.as_hash()
.unwrap()
.iter()
.map(|(build_spec_name, build_spec)| {
let name_as_str = build_spec_name.as_str().unwrap();
deserialize_build_spec(name_as_str, build_spec)
})
.collect()
}

View File

@ -0,0 +1,9 @@
use crate::deserialize::util::make_build_fn_name;
use crate::spec::node_production_spec::NodeProductionBuildSpec;
use yaml_rust2::Yaml;
pub fn deserialize_node_production(name: &str, props: &Yaml) -> NodeProductionBuildSpec {
let kind = props["kind"].as_str().unwrap();
let with = make_build_fn_name(props["with"].as_str().unwrap());
NodeProductionBuildSpec::new(name, kind, &with)
}

View File

@ -0,0 +1,77 @@
use crate::deserialize::util::{make_build_fn_name, unwrap_single_member_hash};
use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopChildUseCurrent, PolymorphicEnumLoopRule,
PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild,
PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough,
};
use yaml_rust2::Yaml;
fn deserialize_build_child(child_name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuildChild {
if props["use_current"].is_hash() {
let kind = props["use_current"]["kind"].as_str().unwrap();
PolymorphicEnumLoopRuleBuildChild::UseCurrent(PolymorphicEnumLoopChildUseCurrent::new(
child_name, kind,
))
} else if props["on_each"].is_hash() {
let rule = props["on_each"]["rule"].as_str().unwrap();
PolymorphicEnumLoopRuleBuildChild::OnEach(PolymorphicEnumLoopRuleChildOnEach::new(
child_name, rule,
))
} else {
panic!("Expected 'use_current' or 'on_each' hash for polymorphic enum loop build child");
}
}
fn deserialize_build(name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuild {
let variant = props["variant"].as_str().unwrap();
let children = props["children"]
.as_vec()
.unwrap()
.iter()
.map(|child_yaml| {
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
deserialize_build_child(&child_name, child_props)
})
.map(Box::new)
.collect();
PolymorphicEnumLoopRuleBuild::new(name, variant, children)
}
fn deserialize_pass_through(name: &str, props: &Yaml) -> PolymorphicEnumLoopRulePassThrough {
let kind = props["kind"].as_str().unwrap();
let with = make_build_fn_name(
props["with"].as_str()
.unwrap_or(kind)
);
PolymorphicEnumLoopRulePassThrough::new(name, kind, &with)
}
fn deserialize_rule(rule_name: &str, props: &Yaml) -> PolymorphicEnumLoopRule {
if props["pass_through"].is_hash() {
PolymorphicEnumLoopRule::PassThrough(deserialize_pass_through(
rule_name,
&props["pass_through"],
))
} else if props["build"].is_hash() {
PolymorphicEnumLoopRule::Build(deserialize_build(rule_name, &props["build"]))
} else {
panic!("Polymorphic enum loop rule must have 'pass_through' or 'build' hash.");
}
}
pub fn deserialize_polymorphic_enum_loop(name: &str, props: &Yaml) -> PolymorphicEnumLoopBuildSpec {
let kind = props["kind"].as_str().unwrap();
let rules = props["rules"]
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
let (rule_name, rule_props) = unwrap_single_member_hash(rule_yaml);
deserialize_rule(&rule_name, rule_props)
})
.map(Box::new)
.collect();
PolymorphicEnumLoopBuildSpec::new(name, kind, rules)
}

View File

@ -0,0 +1,30 @@
use crate::deserialize::util::unwrap_single_member_hash;
use crate::spec::polymorphic_pass_through_spec::{PolymorphicPassThroughBuildSpec, PolymorphicPassThroughVariant};
use yaml_rust2::Yaml;
pub fn deserialize_polymorphic_pass_through(name: &str, props: &Yaml) -> PolymorphicPassThroughBuildSpec {
let build_kind = props["build"]["kind"].as_str().unwrap();
let variants = props["variants"].as_vec().unwrap()
.iter()
.map(|variant_yaml| {
let (variant_name, variant_props) = unwrap_single_member_hash(variant_yaml);
if variant_props["inner"].is_hash() {
let inner_kind = variant_props["inner"]["kind"].as_str().unwrap();
PolymorphicPassThroughVariant::Inner {
name: variant_name,
kind: inner_kind.to_string(),
}
} else if variant_props["pass_through"].is_hash() {
let pass_through_kind = variant_props["pass_through"]["kind"].is_hash();
PolymorphicPassThroughVariant::PassThrough {
name: variant_name,
kind: pass_through_kind.to_string(),
}
} else {
panic!()
}
})
.map(Box::new)
.collect();
PolymorphicPassThroughBuildSpec::new(name, build_kind, variants)
}

View File

@ -0,0 +1,23 @@
use crate::deserialize::util::unwrap_single_member_hash;
use crate::spec::polymorphic_type_spec::{PolymorphicTypeBuildSpec, PolymorphicTypeVariant};
use yaml_rust2::Yaml;
fn deserialize_variant(variant_name: &str, props: &Yaml) -> PolymorphicTypeVariant {
let inner_kind = props["inner"]["kind"].as_str().unwrap();
PolymorphicTypeVariant::new(variant_name, inner_kind)
}
pub fn deserialize_polymorphic_type(name: &str, props: &Yaml) -> PolymorphicTypeBuildSpec {
let variants = props["variants"]
.as_vec()
.unwrap()
.iter()
.map(|variant_yaml| {
let (variant_name, variant_props) = unwrap_single_member_hash(variant_yaml);
deserialize_variant(&variant_name, variant_props)
})
.map(Box::new)
.collect();
let kind = props["build"]["kind"].as_str().unwrap();
PolymorphicTypeBuildSpec::new(name, variants, kind)
}

View File

@ -0,0 +1,21 @@
use crate::spec::production_spec::{ProductionBooleanFrom, ProductionBuildSpec, ProductionKind, ProductionStringFrom};
use yaml_rust2::Yaml;
pub fn deserialize_production(name: &str, props: &Yaml) -> ProductionBuildSpec {
let kind = match props["kind"].as_str().unwrap() {
"int" => ProductionKind::Int,
"long" => ProductionKind::Long,
"double" => ProductionKind::Double,
"string" => {
let from = match props["from"].as_str().unwrap() {
"string_inner" => ProductionStringFrom::StringInner,
"whole_pair" => ProductionStringFrom::WholePair,
_ => panic!("Unknown string production from: {}", props["from"].as_str().unwrap())
};
ProductionKind::String(from)
},
"boolean" => ProductionKind::Boolean(ProductionBooleanFrom::ParseWholePair),
_ => panic!("Unknown production kind: {}", props["kind"].as_str().unwrap()),
};
ProductionBuildSpec::new(name, kind)
}

View File

@ -0,0 +1,155 @@
use crate::deserialize_error;
use convert_case::{Case, Casing};
use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_member_hash};
use crate::spec::struct_spec::*;
use yaml_rust2::Yaml;
fn deserialize_skip_child(props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap();
StructChild::SkipChild(SkipChild::new(rule))
}
fn deserialize_vec_child(child_name: &str, props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap();
let kind = props["kind"].as_str()
.unwrap_or(rule);
if kind == "string" {
let build = VecChildBuild::String(VecChildStringBuild::new(
&make_build_fn_name(rule)
));
StructChild::VecChild(VecChild::new(
child_name,
rule,
Box::new(build),
))
} else {
let build = VecChildBuild::Node(VecChildNodeBuild::new(
rule,
&make_build_fn_name(rule)
));
StructChild::VecChild(VecChild::new(child_name, rule, Box::new(build)))
}
}
fn deserialize_member_build(child_name: &str, rule: &str, props: &Yaml) -> MemberChildBuild {
if props["node"].is_hash() {
let node_props = &props["node"];
let kind = node_props["kind"].as_str().unwrap_or(rule);
let with = node_props["with"]
.as_str()
.map(ToString::to_string)
.unwrap_or_else(|| make_build_fn_name(kind));
let or_else = if get_as_bool(&node_props["or_else_default"]) {
Some(String::from("default"))
} else if let Some(or_else) = node_props["or_else"].as_str() {
Some(or_else.to_string())
} else {
None
};
MemberChildBuild::Node(NodeMemberBuild::new(kind, &with, or_else))
} else if props["boolean"].is_hash() {
let boolean_props = &props["boolean"];
if let Some(on) = boolean_props["on"].as_str() {
if on == "rule_present" {
MemberChildBuild::Boolean(BooleanMemberBuild::new(
BooleanMemberBuildOn::RulePresent,
))
} else {
panic!(
"Expected 'on' in 'boolean' in 'build' in {} to be 'rule_present'",
child_name
);
}
} else {
panic!("Expected 'on' in 'boolean' in 'build' in {}", child_name);
}
} else {
panic!(
"Expected either of 'node' or 'boolean' in 'build' in {}",
child_name
);
}
}
fn deserialize_member_child(child_name: &str, props: &Yaml) -> StructChild {
let rule = props["rule"]
.as_str()
.map(ToString::to_string)
.unwrap_or_else(|| child_name.to_case(Case::Pascal));
let optional = get_as_bool(&props["optional"]);
if props["build"].is_hash() {
let build = deserialize_member_build(child_name, &rule, &props["build"]);
StructChild::MemberChild(MemberChild::new(
child_name,
&rule,
optional,
Box::new(build),
))
} else {
StructChild::MemberChild(MemberChild::new(
child_name,
&rule,
optional,
Box::new(MemberChildBuild::Node(NodeMemberBuild::new(
&rule,
&make_build_fn_name(&rule),
None,
))),
))
}
}
fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild {
if props["skip"].is_hash() {
deserialize_skip_child(&props["skip"])
} else if props["vec"].is_hash() {
deserialize_vec_child(name, &props["vec"])
} else if props["member"].is_hash() {
deserialize_member_child(name, &props["member"])
} else {
panic!("Expected 'skip' or 'vec' in 'member' in {}", name);
}
}
fn deserialize_string_child(name: &str) -> StructChild {
let name_pascal = name.to_case(Case::Pascal);
StructChild::MemberChild(MemberChild::new(
name,
&name_pascal,
false,
Box::new(MemberChildBuild::Node(NodeMemberBuild::new(
&name_pascal,
&make_build_fn_name(name),
None,
))),
))
}
fn deserialize_children(children_yaml: &Yaml) -> Vec<Box<StructChild>> {
children_yaml
.as_vec()
.unwrap()
.iter()
.map(|child_yaml| {
if let Some(name) = child_yaml.as_str() {
deserialize_string_child(name)
} else {
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
deserialize_hash_child(&child_name, child_props)
}
})
.map(Box::new)
.collect()
}
pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
let children = if struct_yaml["children"].is_array() {
deserialize_children(&struct_yaml["children"])
} else {
deserialize_error!("array", "children", name);
};
StructSpec::new(name, children)
}

View File

@ -0,0 +1,56 @@
use convert_case::{Case, Casing};
use crate::deserialize::util::{get_as_bool_or, make_build_fn_name, unwrap_single_member_hash};
use crate::spec::tree_enum_spec::{EnumRuleChild, EnumRuleChildKind, EnumRuleChildNodeKind, NameAndWith, TreeEnumBuildSpec, TreeEnumRule};
use yaml_rust2::Yaml;
fn deserialize_hash_enum_rule(rule: &str, props: &Yaml) -> TreeEnumRule {
if get_as_bool_or(&props["child"], true) {
let name_and_with = NameAndWith::new(
&rule.to_case(Case::Snake),
&make_build_fn_name(rule)
);
let kind = match props["kind"].as_str().unwrap() {
"int" => EnumRuleChildKind::Int(name_and_with),
"long" => EnumRuleChildKind::Long(name_and_with),
"double" => EnumRuleChildKind::Double(name_and_with),
"string" => EnumRuleChildKind::String(name_and_with),
"boolean" => EnumRuleChildKind::Boolean(name_and_with),
_ => panic!("Invalid kind: {}", props["kind"].as_str().unwrap()),
};
TreeEnumRule::new(rule, Some(Box::new(EnumRuleChild::new(Box::new(kind)))))
} else {
// no child
TreeEnumRule::new(rule, None)
}
}
fn deserialize_string_enum_rule(rule: &str) -> TreeEnumRule {
TreeEnumRule::new(
rule,
Some(Box::new(EnumRuleChild::new(Box::new(
EnumRuleChildKind::Node(EnumRuleChildNodeKind::new(
rule,
&make_build_fn_name(rule)
)),
)))),
)
}
pub fn deserialize_tree_enum(name: &str, props: &Yaml) -> TreeEnumBuildSpec {
let rules = props["rules"]
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
if let Some(rule) = rule_yaml.as_str() {
deserialize_string_enum_rule(rule)
} else {
let (rule, props) = unwrap_single_member_hash(rule_yaml);
deserialize_hash_enum_rule(&rule, props)
}
})
.map(Box::new)
.collect();
TreeEnumBuildSpec::new(name, rules)
}

View File

@ -0,0 +1,37 @@
use convert_case::{Case, Casing};
use yaml_rust2::Yaml;
#[macro_export]
macro_rules! deserialize_error {
($kind:expr, $key:expr, $name:expr) => {
panic!("Expected {} '{}' in {}.", $kind, $key, $name);
};
}
pub fn make_build_fn_name(s: &str) -> String {
format!("build_{}", s.to_case(Case::Snake))
}
pub fn make_build_pair(s: &str) -> String {
format!("{}_pair", s.to_case(Case::Snake))
}
pub fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
let as_hash = hash.as_hash().unwrap();
if as_hash.is_empty() {
panic!("empty hash");
} else if as_hash.len() > 1 {
panic!("hash contains more than one key");
}
let (member_key, member_value) = as_hash.iter().collect::<Vec<(&Yaml, &Yaml)>>()[0];
let key_as_string = member_key.as_str().unwrap().to_string();
(key_as_string, member_value)
}
pub fn get_as_bool(yaml: &Yaml) -> bool {
yaml.as_bool().unwrap_or(false)
}
pub fn get_as_bool_or(yaml: &Yaml, or: bool) -> bool {
yaml.as_bool().unwrap_or(or)
}

View File

@ -1,26 +1,12 @@
pub mod deserialize; mod build_fn;
mod enum_build_fn; mod deserialize;
mod leaf_enum_build_fn;
mod leaf_struct_build_fn;
mod polymorphic_build_build_fn;
mod polymorphic_build_fn;
mod polymorphic_enum_build_fn;
mod pretty_print; mod pretty_print;
mod production_build_fn;
mod spec; mod spec;
mod struct_build_fn;
mod type_gen; mod type_gen;
mod util;
use crate::enum_build_fn::make_enum_build_fn; use crate::build_fn::make_build_fn;
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn; use crate::deserialize::deserialize_yaml_spec;
use crate::leaf_struct_build_fn::make_leaf_struct_build_fn; // use crate::pretty_print::make_pretty_print_impl;
use crate::polymorphic_build_build_fn::make_polymorphic_build_build_fn;
use crate::polymorphic_build_fn::make_polymorphic_build_fn;
use crate::polymorphic_enum_build_fn::make_polymorphic_enum_build_fn;
use crate::pretty_print::make_pretty_print_impl;
use crate::production_build_fn::make_production_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;
@ -46,24 +32,30 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
); );
} }
BuildSpec::Production(production_build_spec) => { BuildSpec::Production(production_build_spec) => {
println!("Production Spec - rule: {}", production_build_spec.rule()); println!("Production Spec - name: {}", production_build_spec.name());
} }
BuildSpec::Polymorphic(polymorphic_build_spec) => { BuildSpec::NodeProduction(node_production_build_spec) => {
println!(
"Node Production Spec - name: {}",
node_production_build_spec.name()
);
}
BuildSpec::PolymorphicType(polymorphic_build_spec) => {
println!( println!(
"Polymorphic Type Spec - name: {}", "Polymorphic Type Spec - name: {}",
polymorphic_build_spec.name() polymorphic_build_spec.name()
); );
} }
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => { BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop_build_spec) => {
println!( println!(
"Polymorphic Build Spec - name: {}", "Polymorphic Enum Loop Spec - name: {}",
polymorphic_build_build_spec.name() polymorphic_enum_loop_build_spec.name()
); );
} }
BuildSpec::PolymorphicEnum(polymorphic_enum_build_spec) => { BuildSpec::PolymorphicPassThrough(pass_through_build_spec) => {
println!( println!(
"Polymorphic Enum Spec - name: {}", "Polymorphic Pass Through Spec - name: {}",
polymorphic_enum_build_spec.name() pass_through_build_spec.name()
); );
} }
} }
@ -85,49 +77,13 @@ fn token_stream_to_string(token_stream: TokenStream) -> String {
fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
let build_fns = build_specs let build_fns = build_specs
.iter() .iter()
.map(|build_spec| match build_spec { .map(|build_spec| {
BuildSpec::Enum(enum_build_spec) => { let build_fn = make_build_fn(build_spec);
let stream = make_enum_build_fn(enum_build_spec); debug_built_spec(build_spec, &build_fn);
debug_built_spec(build_spec, &stream); build_fn
stream
}
BuildSpec::LeafEnum(leaf_enum_build_spec) => {
let stream = make_leaf_enum_build_fn(leaf_enum_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
BuildSpec::Struct(struct_build_spec) => {
let stream = make_struct_build_fn(struct_build_spec);
debug_built_spec(build_spec, &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
}
BuildSpec::Production(production_build_spec) => {
let stream = make_production_build_fn(production_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
BuildSpec::Polymorphic(polymorphic_build_spec) => {
let stream = make_polymorphic_build_fn(polymorphic_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
let stream = make_polymorphic_build_build_fn(polymorphic_build_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
BuildSpec::PolymorphicEnum(polymorphic_enum_build_spec) => {
let stream = make_polymorphic_enum_build_fn(polymorphic_enum_build_spec);
debug_built_spec(build_spec, &stream);
stream
}
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let combined = quote! { let combined = quote! {
//noinspection RsUnusedImport //noinspection RsUnusedImport
use crate::parser::Rule; use crate::parser::Rule;
@ -138,6 +94,7 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
#(#build_fns)* #(#build_fns)*
}; };
AstGeneratedFile { AstGeneratedFile {
name: String::from("build.rs"), name: String::from("build.rs"),
contents: token_stream_to_string(combined), contents: token_stream_to_string(combined),
@ -160,29 +117,34 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
} }
fn generate_pretty_print_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { fn generate_pretty_print_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
let impls = build_specs // let impls = build_specs
.iter() // .iter()
.map(|build_spec| { // .map(|build_spec| {
let stream = make_pretty_print_impl(build_spec); // let stream = make_pretty_print_impl(build_spec);
debug_built_spec(build_spec, &stream); // debug_built_spec(build_spec, &stream);
stream // stream
}) // })
.collect::<Vec<_>>(); // .collect::<Vec<_>>();
//
let combined = quote! { // let combined = quote! {
use crate::ast::node::*; // use crate::ast::node::*;
#(#impls)* // #(#impls)*
}; // };
AstGeneratedFile { // AstGeneratedFile {
name: String::from("pretty_print.rs"), // name: String::from("pretty_print.rs"),
contents: token_stream_to_string(combined), // contents: token_stream_to_string(combined),
// }
todo!()
} }
pub fn get_build_specs(yaml: &str) -> Vec<BuildSpec> {
deserialize_yaml_spec(yaml)
} }
pub fn generate_files(build_specs: &[BuildSpec]) -> Vec<AstGeneratedFile> { pub fn generate_files(build_specs: &[BuildSpec]) -> Vec<AstGeneratedFile> {
vec![ vec![
generate_build_file(build_specs), generate_build_file(build_specs),
generate_node_file(build_specs), generate_node_file(build_specs),
generate_pretty_print_file(build_specs), // generate_pretty_print_file(build_specs),
] ]
} }

View File

@ -1,134 +0,0 @@
use convert_case::{Case, Casing};
use crate::spec::{AlternativeAction, AlternativeBuild, AlternativeBuildChild, AlternativeChild, AlternativeTest, PolymorphicBuildBuildSpec};
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_build_child(build_child: &AlternativeBuildChild) -> TokenStream {
let rule_ident = format_ident!("{}", build_child.rule());
let child_ident = format_ident!("{}", build_child.name());
let child_build_fn_ident = format_ident!("{}", make_build_fn_name(build_child.rule()));
quote! {
Rule::#rule_ident => {
#child_ident = Some(#child_build_fn_ident(inner_pair));
}
}
}
fn make_build_action(
spec: &PolymorphicBuildBuildSpec,
alternative_build: &AlternativeBuild,
) -> TokenStream {
let enum_type_ident = format_ident!("{}", spec.return_type());
let enum_variant_ident = format_ident!("{}", alternative_build.enum_variant());
let child_holders = alternative_build
.children()
.map(|child| {
match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build_child) => {
let child_ident = format_ident!("{}", build_child.name());
let child_type_ident = format_ident!("{}", build_child.kind());
Some(quote! {
let mut #child_ident: Option<#child_type_ident> = None
})
}
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let rule_matchers = alternative_build
.children()
.map(|child| {
match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build_child) => {
Some(make_build_child(build_child))
}
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let built_ident = format_ident!("{}", spec.name().to_case(Case::Snake));
let inner_type_ident = format_ident!("{}", spec.name());
let child_args = alternative_build.children()
.map(|child| {
match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(child_build) => {
let child_ident = format_ident!("{}", child_build.name());
Some(quote! {
Box::new(#child_ident.unwrap())
})
}
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
quote! {
#(#child_holders;)*
for inner_pair in #pair_ident.into_inner() {
match inner_pair.as_rule() {
#(#rule_matchers),*
_ => unreachable!()
}
}
let #built_ident = #inner_type_ident::new(#(#child_args),*);
#enum_type_ident::#enum_variant_ident(#built_ident)
}
}
pub fn make_polymorphic_build_build_fn(spec: &PolymorphicBuildBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.return_type());
let alternatives = spec
.alternatives()
.map(|alternative| {
let count_to_match: usize = match alternative.test() {
AlternativeTest::NumberOfPairs(count) => count.clone().try_into().unwrap(),
};
let action = match alternative.action() {
AlternativeAction::ReturnBuild(kind) => {
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(kind));
quote! {
let inner_pair = #pair_ident.into_inner().next().unwrap();
#inner_build_fn_ident(inner_pair)
}
}
AlternativeAction::Build(alternative_build) => {
make_build_action(spec, alternative_build)
}
};
quote! {
#count_to_match => {
#action
}
}
})
.collect::<Vec<_>>();
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
let count = #pair_ident.clone().into_inner().count();
match count {
#(#alternatives,)*
_ => unreachable!()
}
}
}
}

View File

@ -1,42 +0,0 @@
use crate::spec::{PolymorphicEnumBuildSpec, PolymorphicEnumRule};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::util::{make_build_fn_name, make_build_pair};
pub fn make_polymorphic_enum_build_fn(spec: &PolymorphicEnumBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.return_type());
let match_arms = spec.rules()
.map(|rule| {
match rule {
PolymorphicEnumRule::Wrap(name_and_kind) => {
let rule_ident = format_ident!("{}", name_and_kind.name());
let enum_variant_ident = format_ident!("{}", name_and_kind.kind());
let rule_build_fn = format_ident!("{}", make_build_fn_name(name_and_kind.name()));
quote! {
Rule::#rule_ident => #return_type_ident::#enum_variant_ident(#rule_build_fn(inner_pair))
}
},
PolymorphicEnumRule::ReturnBuild(name_and_kind) => {
let rule_ident = format_ident!("{}", name_and_kind.name());
let rule_build_fn = format_ident!("{}", make_build_fn_name(name_and_kind.kind()));
quote! {
Rule::#rule_ident => #rule_build_fn(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() {
#(#match_arms,)*
_ => unreachable!()
}
}
}
}

View File

@ -1,256 +1,260 @@
use crate::spec::{ // use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
AlternativeChild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec, // use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMemberKind};
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, PolymorphicBuildBuildSpec, // use crate::spec::polymorphic_type_spec::PolymorphicTypeBuildSpec;
PolymorphicEnumBuildSpec, PolymorphicTypeBuildSpec, ProductionBuildSpec, StructBuildSpec, // use crate::spec::production_spec::ProductionBuildSpec;
StructChildSpec, VecChildToBuild, // use crate::spec::struct_spec::StructSpec;
}; // use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
use convert_case::{Case, Casing}; // use crate::spec::{
use proc_macro2::TokenStream; // AlternativeChild, BuildSpec, MemberChildToBuild, PolymorphicBuildBuildSpec,
use quote::{format_ident, quote}; // PolymorphicEnumBuildSpec, StructChildSpec, VecChildToBuild,
// };
fn make_production_p2_impl(_spec: &ProductionBuildSpec) -> TokenStream { // use convert_case::{Case, Casing};
quote! {} // use proc_macro2::TokenStream;
} // use quote::{format_ident, quote};
//
fn make_polymorphic_enum_p2_impl(_spec: &PolymorphicEnumBuildSpec) -> TokenStream { // fn make_production_p2_impl(_spec: &ProductionBuildSpec) -> TokenStream {
quote! {} // quote! {}
} // }
//
fn make_polymorphic_build_p2_impl(spec: &PolymorphicBuildBuildSpec) -> TokenStream { // fn make_polymorphic_enum_p2_impl(_spec: &PolymorphicEnumBuildSpec) -> TokenStream {
let (_, build) = spec.primary_alternative(); // quote! {}
let type_ident = format_ident!("{}", spec.name()); // }
let name_str = spec.name(); //
// fn make_polymorphic_build_p2_impl(spec: &PolymorphicBuildBuildSpec) -> TokenStream {
let child_statements = build // let (_, build) = spec.primary_alternative();
.children() // let type_ident = format_ident!("{}", spec.name());
.map(|child| match child { // let name_str = spec.name();
AlternativeChild::Skip => None, //
AlternativeChild::Build(build) => { // let child_statements = build
let child_ident = format_ident!("{}", build.name()); // .children()
Some(quote! { // .map(|child| match child {
self.#child_ident().pretty_print(writer)? // AlternativeChild::Skip => None,
}) // AlternativeChild::Build(build) => {
} // let child_ident = format_ident!("{}", build.name());
}) // Some(quote! {
.filter(Option::is_some) // self.#child_ident().pretty_print(writer)?
.map(Option::unwrap) // })
.collect::<Vec<TokenStream>>(); // }
// })
quote! { // .filter(Option::is_some)
impl PrettyPrint for #type_ident { // .map(Option::unwrap)
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // .collect::<Vec<TokenStream>>();
writer.writeln_indented(#name_str); //
writer.increase_indent(); // quote! {
#(#child_statements;)* // impl PrettyPrint for #type_ident {
writer.decrease_indent(); // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
Ok(()) // writer.writeln_indented(#name_str);
} // writer.increase_indent();
} // #(#child_statements;)*
} // writer.decrease_indent();
} // Ok(())
// }
fn make_polymorphic_type_p2_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream { // }
let type_ident = format_ident!("{}", spec.name()); // }
let child_matchers = spec // }
.enum_members() //
.map(|member| { // fn make_polymorphic_type_p2_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream {
let enum_member_ident = format_ident!("{}", member.name()); // let type_ident = format_ident!("{}", spec.name());
let inner_name = format_ident!("{}", member.inner_kind().to_case(Case::Snake)); // let child_matchers = spec
quote! { // .variants()
#type_ident::#enum_member_ident(#inner_name) => #inner_name.pretty_print(writer) // .map(|member| {
} // let enum_member_ident = format_ident!("{}", member.name());
}) // let inner_name = format_ident!("{}", member.inner_kind().to_case(Case::Snake));
.collect::<Vec<_>>(); // quote! {
// #type_ident::#enum_member_ident(#inner_name) => #inner_name.pretty_print(writer)
quote! { // }
impl PrettyPrint for #type_ident { // })
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // .collect::<Vec<_>>();
match self { //
#(#child_matchers,)* // quote! {
} // impl PrettyPrint for #type_ident {
} // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
} // match self {
} // #(#child_matchers,)*
} // }
// }
fn make_leaf_enum_p2_impl(spec: &LeafEnumBuildSpec) -> TokenStream { // }
let type_ident = format_ident!("{}", spec.build()); // }
let child_matchers = spec // }
.rules() //
.map(|rule| { // fn make_leaf_enum_p2_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
let enum_variant_ident = format_ident!("{}", rule.rule()); // let type_ident = format_ident!("{}", spec.build());
let name_str = rule.rule(); // let child_matchers = spec
quote! { // .rules()
#type_ident::#enum_variant_ident => writer.writeln_indented(#name_str) // .map(|rule| {
} // let enum_variant_ident = format_ident!("{}", rule.rule());
}) // let name_str = rule.rule();
.collect::<Vec<_>>(); // quote! {
// #type_ident::#enum_variant_ident => writer.writeln_indented(#name_str)
quote! { // }
impl PrettyPrint for #type_ident { // })
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // .collect::<Vec<_>>();
match self { //
#(#child_matchers,)* // quote! {
} // impl PrettyPrint for #type_ident {
} // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
} // match self {
} // #(#child_matchers,)*
} // }
// }
fn make_enum_p2_impl(spec: &EnumBuildSpec) -> TokenStream { // }
let type_ident = format_ident!("{}", spec.build()); // }
let type_str = spec.build(); // }
//
let child_matchers = spec // fn make_enum_p2_impl(spec: &TreeEnumBuildSpec) -> TokenStream {
.rules() // let type_ident = format_ident!("{}", spec.build());
.map(|rule| { // let type_str = spec.build();
let enum_variant_ident = format_ident!("{}", rule.rule()); //
if let Some(child) = rule.child() { // let child_matchers = spec
match child.kind() { // .rules()
EnumRuleChildKind::Node(node_child) => { // .map(|rule| {
let child_name_ident = // let enum_variant_ident = format_ident!("{}", rule.rule());
format_ident!("{}", node_child.build().to_case(Case::Snake)); // if let Some(child) = rule.child() {
Some(quote! { // match child.kind() {
#type_ident::#enum_variant_ident(#child_name_ident) => { // EnumRuleChildKind::Node(node_child) => {
#child_name_ident.pretty_print(writer)?; // let child_name_ident =
} // format_ident!("{}", node_child.build().to_case(Case::Snake));
}) // Some(quote! {
} // #type_ident::#enum_variant_ident(#child_name_ident) => {
_ => None, // #child_name_ident.pretty_print(writer)?;
} // }
} else { // })
let variant_str = rule.rule(); // }
Some(quote! { // _ => None,
#type_ident::#enum_variant_ident => writer.writeln_indented(#variant_str)? // }
}) // } else {
} // let variant_str = rule.rule();
}) // Some(quote! {
.filter(Option::is_some) // #type_ident::#enum_variant_ident => writer.writeln_indented(#variant_str)?
.map(Option::unwrap) // })
.collect::<Vec<_>>(); // }
// })
quote! { // .filter(Option::is_some)
impl PrettyPrint for #type_ident { // .map(Option::unwrap)
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // .collect::<Vec<_>>();
writer.writeln_indented(#type_str)?; //
writer.increase_indent(); // quote! {
match self { // impl PrettyPrint for #type_ident {
#(#child_matchers,)* // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
_ => {} // writer.writeln_indented(#type_str)?;
} // writer.increase_indent();
writer.decrease_indent(); // match self {
Ok(()) // #(#child_matchers,)*
} // _ => {}
} // }
} // writer.decrease_indent();
} // Ok(())
// }
fn make_leaf_struct_p2_impl(leaf_struct_build_spec: &LeafStructBuildSpec) -> TokenStream { // }
let type_ident = format_ident!("{}", leaf_struct_build_spec.build()); // }
let member_formatters = leaf_struct_build_spec // }
.members() //
.map(|member| match member.kind() { // fn make_leaf_struct_p2_impl(leaf_struct_build_spec: &LeafStructBuildSpec) -> TokenStream {
LeafStructMemberKind::String => Some("{}"), // let type_ident = format_ident!("{}", leaf_struct_build_spec.build());
}) // let member_formatters = leaf_struct_build_spec
.filter(Option::is_some) // .members()
.map(Option::unwrap) // .map(|member| match member.kind() {
.collect::<Vec<_>>() // LeafStructMemberKind::String => Some("{}"),
.join(", "); // })
// .filter(Option::is_some)
let format_string = format!("{}({})", leaf_struct_build_spec.build(), member_formatters); // .map(Option::unwrap)
// .collect::<Vec<_>>()
let members = leaf_struct_build_spec // .join(", ");
.members() //
.map(|member| { // let format_string = format!("{}({})", leaf_struct_build_spec.build(), member_formatters);
let member_ident = format_ident!("{}", member.name()); //
quote! { // let members = leaf_struct_build_spec
self.#member_ident() // .members()
} // .map(|member| {
}) // let member_ident = format_ident!("{}", member.name());
.collect::<Vec<_>>(); // quote! {
// self.#member_ident()
quote! { // }
impl PrettyPrint for #type_ident { // })
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // .collect::<Vec<_>>();
writer.writeln_indented(&format!(#format_string, #(#members),*)) //
} // quote! {
} // impl PrettyPrint for #type_ident {
} // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
} // writer.writeln_indented(&format!(#format_string, #(#members),*))
// }
fn make_struct_p2_impl(struct_build_spec: &StructBuildSpec) -> TokenStream { // }
let child_print_statements = struct_build_spec // }
.children() // }
.map(|child| match child { //
StructChildSpec::SkipChild(_) => None, // fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
StructChildSpec::VecChild(vec_child) => match vec_child.build() { // let child_print_statements = struct_build_spec
VecChildToBuild::Node(_) => { // .children()
let child_ident = format_ident!("{}", vec_child.name()); // .map(|child| match child {
Some(quote! { // StructChildSpec::SkipChild(_) => None,
for child in self.#child_ident() { // StructChildSpec::VecChild(vec_child) => match vec_child.build() {
child.pretty_print(writer)?; // VecChildToBuild::Node(_) => {
} // let child_ident = format_ident!("{}", vec_child.name());
}) // Some(quote! {
} // for child in self.#child_ident() {
VecChildToBuild::String => None, // child.pretty_print(writer)?;
}, // }
StructChildSpec::MemberChild(member_child) => match member_child.build() { // })
MemberChildToBuild::Node(node_member_child) => { // }
let child_ident = format_ident!("{}", member_child.name()); // VecChildToBuild::String => None,
if node_member_child.optional() { // },
Some(quote! { // StructChildSpec::MemberChild(member_child) => match member_child.build() {
if let Some(child) = self.#child_ident() { // MemberChildToBuild::Node(node_member_child) => {
child.pretty_print(writer)?; // let child_ident = format_ident!("{}", member_child.name());
} // if node_member_child.optional() {
}) // Some(quote! {
} else { // if let Some(child) = self.#child_ident() {
Some(quote! { // child.pretty_print(writer)?;
self.#child_ident().pretty_print(writer)?; // }
}) // })
} // } else {
} // Some(quote! {
MemberChildToBuild::Boolean(boolean_member_child) => { // self.#child_ident().pretty_print(writer)?;
let format_string = format!("{}({})", boolean_member_child.name(), "{}"); // })
let child_ident = format_ident!("{}", boolean_member_child.name()); // }
Some(quote! { // }
writer.writeln_indented(&format!(#format_string, self.#child_ident()))?; // MemberChildToBuild::Boolean(boolean_member_child) => {
}) // let format_string = format!("{}({})", boolean_member_child.name(), "{}");
} // let child_ident = format_ident!("{}", boolean_member_child.name());
}, // Some(quote! {
}) // writer.writeln_indented(&format!(#format_string, self.#child_ident()))?;
.filter(Option::is_some) // })
.map(Option::unwrap) // }
.collect::<Vec<_>>(); // },
// })
let type_ident = format_ident!("{}", struct_build_spec.build()); // .filter(Option::is_some)
let type_string = struct_build_spec.build(); // .map(Option::unwrap)
// .collect::<Vec<_>>();
quote! { //
impl PrettyPrint for #type_ident { // let type_ident = format_ident!("{}", struct_build_spec.build());
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { // let type_string = struct_build_spec.build();
writer.writeln_indented(#type_string)?; //
writer.increase_indent(); // quote! {
#(#child_print_statements)* // impl PrettyPrint for #type_ident {
writer.decrease_indent(); // fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
Ok(()) // writer.writeln_indented(#type_string)?;
} // writer.increase_indent();
} // #(#child_print_statements)*
} // writer.decrease_indent();
} // Ok(())
// }
pub fn make_pretty_print_impl(build_spec: &BuildSpec) -> TokenStream { // }
match build_spec { // }
BuildSpec::Struct(struct_spec) => make_struct_p2_impl(struct_spec), // }
BuildSpec::LeafStruct(leaf_struct) => make_leaf_struct_p2_impl(leaf_struct), //
BuildSpec::Enum(enum_spec) => make_enum_p2_impl(enum_spec), // pub fn make_pretty_print_impl(build_spec: &BuildSpec) -> TokenStream {
BuildSpec::LeafEnum(leaf_enum) => make_leaf_enum_p2_impl(leaf_enum), // match build_spec {
BuildSpec::Polymorphic(polymorphic) => make_polymorphic_type_p2_impl(polymorphic), // BuildSpec::Struct(struct_spec) => make_struct_p2_impl(struct_spec),
BuildSpec::PolymorphicBuild(polymorphic_build) => { // BuildSpec::LeafStruct(leaf_struct) => make_leaf_struct_p2_impl(leaf_struct),
make_polymorphic_build_p2_impl(polymorphic_build) // BuildSpec::Enum(enum_spec) => make_enum_p2_impl(enum_spec),
} // BuildSpec::LeafEnum(leaf_enum) => make_leaf_enum_p2_impl(leaf_enum),
BuildSpec::PolymorphicEnum(polymorphic_enum) => { // BuildSpec::PolymorphicType(polymorphic) => make_polymorphic_type_p2_impl(polymorphic),
make_polymorphic_enum_p2_impl(polymorphic_enum) // BuildSpec::PolymorphicBuild(polymorphic_build) => {
} // make_polymorphic_build_p2_impl(polymorphic_build)
BuildSpec::Production(production) => make_production_p2_impl(production), // }
} // BuildSpec::PolymorphicEnum(polymorphic_enum) => {
} // make_polymorphic_enum_p2_impl(polymorphic_enum)
// }
// BuildSpec::Production(production) => make_production_p2_impl(production),
// }
// }

View File

@ -1,672 +0,0 @@
pub enum BuildSpec {
Enum(EnumBuildSpec),
LeafEnum(LeafEnumBuildSpec),
Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec),
Polymorphic(PolymorphicTypeBuildSpec),
PolymorphicBuild(PolymorphicBuildBuildSpec),
PolymorphicEnum(PolymorphicEnumBuildSpec),
}
// Enum build spec
pub struct EnumBuildSpec {
build: String,
rules: Vec<Box<EnumRule>>,
}
impl EnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<EnumRule>>) -> Self {
EnumBuildSpec {
build: build.to_string(),
rules,
}
}
/// The enum type to be built, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
/// The individual rule specs.
pub fn rules(&self) -> impl Iterator<Item = &EnumRule> {
self.rules.iter().map(Box::as_ref)
}
}
pub struct EnumRule {
rule: String,
child: Option<Box<EnumRuleChild>>,
}
impl EnumRule {
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
Self {
rule: rule.to_string(),
child,
}
}
/// The enum rule to match, in Pascal case.
pub fn rule(&self) -> &str {
&self.rule
}
pub fn child(&self) -> Option<&EnumRuleChild> {
if let Some(child) = &self.child {
Some(child.as_ref())
} else {
None
}
}
}
pub struct EnumRuleChild {
kind: Box<EnumRuleChildKind>,
}
impl EnumRuleChild {
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
Self { kind }
}
pub fn kind(&self) -> &EnumRuleChildKind {
&self.kind
}
}
pub enum EnumRuleChildKind {
Node(EnumRuleNodeChild),
Int,
Long,
Double,
USize,
String,
Boolean,
}
pub struct EnumRuleNodeChild {
build: String,
}
impl EnumRuleNodeChild {
pub fn new(build: &str) -> Self {
Self {
build: build.to_string(),
}
}
pub fn build(&self) -> &str {
&self.build
}
}
// Leaf enum build spec
pub struct LeafEnumBuildSpec {
build: String,
rules: Vec<Box<LeafEnumRule>>,
}
impl LeafEnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
Self {
build: build.to_string(),
rules,
}
}
pub fn build(&self) -> &str {
&self.build
}
pub fn rules(&self) -> impl Iterator<Item = &LeafEnumRule> {
self.rules.iter().map(Box::as_ref)
}
}
pub struct LeafEnumRule {
rule: String,
}
impl LeafEnumRule {
pub fn new(rule: &str) -> Self {
Self {
rule: rule.to_string(),
}
}
pub fn rule(&self) -> &str {
&self.rule
}
}
// Struct build spec
pub struct StructBuildSpec {
build: String,
children: Vec<Box<StructChildSpec>>,
}
impl StructBuildSpec {
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
Self {
build: build.to_string(),
children,
}
}
/// The type to be built, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
/// The children for this build spec.
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
self.children.iter().map(Box::as_ref)
}
}
pub enum StructChildSpec {
SkipChild(SkipChild),
VecChild(VecChild),
MemberChild(MemberChild),
}
pub struct SkipChild {
name: String,
rule: String,
}
impl SkipChild {
pub fn new(name: &str, rule: &str) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
}
}
/// The name of this child spec.
pub fn name(&self) -> &str {
&self.name
}
/// The grammar rule to match.
pub fn rule(&self) -> &str {
&self.rule
}
}
pub struct VecChild {
name: String,
rule: String,
build: Box<VecChildToBuild>,
}
impl VecChild {
pub fn new(name: &str, rule: &str, build: Box<VecChildToBuild>) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
build,
}
}
/// The name of this child.
pub fn name(&self) -> &str {
&self.name
}
/// The rule to match to build this child.
pub fn rule(&self) -> &str {
&self.rule
}
/// The build info for this child.
pub fn build(&self) -> &VecChildToBuild {
&self.build
}
}
#[derive(Debug)]
pub enum VecChildToBuild {
Node(VecNodeChildToBuild),
String,
}
#[derive(Debug)]
pub struct VecNodeChildToBuild {
build: String,
}
impl VecNodeChildToBuild {
pub fn new(build: &str) -> Self {
Self {
build: build.to_string(),
}
}
/// The type to build, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
}
#[derive(Debug)]
pub struct MemberChild {
name: String,
rule: String,
build: Box<MemberChildToBuild>,
}
impl MemberChild {
pub fn new(name: &str, rule: &str, build: Box<MemberChildToBuild>) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
build,
}
}
/// The name of this child in the yaml file, in snake case.
pub fn name(&self) -> &str {
&self.name
}
/// The grammar rule to match to build this child.
pub fn rule(&self) -> &str {
&self.rule
}
/// The specification for what to actually build.
pub fn build(&self) -> &MemberChildToBuild {
&self.build
}
}
#[derive(Debug)]
pub enum MemberChildToBuild {
Node(NodeChildToBuild),
Boolean(BooleanChildToBuild),
}
#[derive(Debug)]
pub struct NodeChildToBuild {
build: String,
or_else: Option<String>,
optional: bool,
}
impl NodeChildToBuild {
pub fn new(build: &str, or_else: Option<String>, optional: bool) -> Self {
Self {
build: build.to_string(),
or_else,
optional,
}
}
/// The type to build, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
/// The default fn to call when unwrapping the child (before passing as arg to new).
pub fn or_else(&self) -> Option<&str> {
self.or_else.as_deref()
}
/// If the type should be wrapped in an Option.
pub fn optional(&self) -> bool {
self.optional
}
}
#[derive(Debug)]
pub struct BooleanChildToBuild {
name: String,
}
impl BooleanChildToBuild {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
}
// Leaf Struct build spec
pub struct LeafStructBuildSpec {
build: String,
members: Vec<Box<LeafStructMember>>,
}
impl LeafStructBuildSpec {
pub fn new(build: &str, members: Vec<Box<LeafStructMember>>) -> Self {
Self {
build: build.to_string(),
members,
}
}
pub fn build(&self) -> &str {
&self.build
}
pub fn members(&self) -> impl Iterator<Item = &LeafStructMember> {
self.members.iter().map(Box::as_ref)
}
}
pub struct LeafStructMember {
name: String,
kind: LeafStructMemberKind,
}
impl LeafStructMember {
pub fn new(name: &str, kind: LeafStructMemberKind) -> Self {
Self {
name: name.to_string(),
kind,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &LeafStructMemberKind {
&self.kind
}
}
pub enum LeafStructMemberKind {
String,
}
pub struct ProductionBuildSpec {
rule: String,
kind: ProductionKind,
}
impl ProductionBuildSpec {
pub fn new(rule: &str, kind: ProductionKind) -> Self {
Self {
rule: rule.to_string(),
kind,
}
}
pub fn rule(&self) -> &str {
&self.rule
}
pub fn kind(&self) -> &ProductionKind {
&self.kind
}
}
pub enum ProductionKind {
Int,
Long,
Double,
String(ProductionStringFrom),
Boolean,
Node(String),
}
pub enum ProductionStringFrom {
StringInner,
WholePair,
}
// Polymorphic build spec
pub struct PolymorphicTypeBuildSpec {
name: String,
enum_members: Vec<Box<PolymorphicEnumMember>>,
build_kind: String,
}
impl PolymorphicTypeBuildSpec {
pub fn new(
name: &str,
enum_members: Vec<Box<PolymorphicEnumMember>>,
build_kind: &str,
) -> Self {
Self {
name: name.to_string(),
enum_members,
build_kind: build_kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
self.enum_members.iter().map(Box::as_ref)
}
pub fn build_kind(&self) -> &str {
self.build_kind.as_str()
}
}
pub struct PolymorphicEnumMember {
name: String,
inner_kind: String,
}
impl PolymorphicEnumMember {
pub fn new(name: &str, inner_kind: &str) -> Self {
Self {
name: name.to_string(),
inner_kind: inner_kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn inner_kind(&self) -> &str {
&self.inner_kind
}
}
pub struct PolymorphicBuildBuildSpec {
name: String,
return_type: String,
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
}
impl PolymorphicBuildBuildSpec {
pub fn new(
name: &str,
return_type: &str,
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
) -> Self {
Self {
name: name.to_string(),
return_type: return_type.to_string(),
alternatives,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn return_type(&self) -> &str {
&self.return_type
}
pub fn alternatives(&self) -> impl Iterator<Item = &PolymorphicBuildAlternative> {
self.alternatives.iter().map(Box::as_ref)
}
pub fn primary_alternative(&self) -> (&AlternativeTest, &AlternativeBuild) {
let primary_build_alternative = self
.alternatives
.iter()
.find(|alternative| match alternative.action {
AlternativeAction::Build(_) => true,
_ => false,
})
.map(Box::as_ref)
.unwrap();
let alternative_build =
if let AlternativeAction::Build(build) = &primary_build_alternative.action {
build
} else {
unreachable!();
};
(primary_build_alternative.test(), alternative_build)
}
}
pub struct PolymorphicBuildAlternative {
test: AlternativeTest,
action: AlternativeAction,
}
impl PolymorphicBuildAlternative {
pub fn new(test: AlternativeTest, action: AlternativeAction) -> Self {
Self { test, action }
}
pub fn test(&self) -> &AlternativeTest {
&self.test
}
pub fn action(&self) -> &AlternativeAction {
&self.action
}
}
pub enum AlternativeTest {
NumberOfPairs(i64),
}
pub enum AlternativeAction {
ReturnBuild(String),
Build(AlternativeBuild),
}
pub struct AlternativeBuild {
enum_variant: String,
children: Vec<Box<AlternativeChild>>,
}
impl AlternativeBuild {
pub fn new(enum_variant: &str, children: Vec<Box<AlternativeChild>>) -> Self {
Self {
enum_variant: enum_variant.to_string(),
children,
}
}
pub fn enum_variant(&self) -> &str {
&self.enum_variant
}
pub fn children(&self) -> impl Iterator<Item = &AlternativeChild> {
self.children.iter().map(Box::as_ref)
}
}
pub enum AlternativeChild {
Skip,
Build(AlternativeBuildChild),
}
pub struct AlternativeBuildChild {
name: String,
kind: String,
rule: String,
}
impl AlternativeBuildChild {
pub fn new(name: &str, kind: &str, rule: &str) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
rule: rule.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn rule(&self) -> &str {
&self.rule
}
}
pub struct PolymorphicEnumBuildSpec {
name: String,
return_type: String,
rules: Vec<Box<PolymorphicEnumRule>>,
}
impl PolymorphicEnumBuildSpec {
pub fn new(name: &str, return_type: &str, rules: Vec<Box<PolymorphicEnumRule>>) -> Self {
Self {
name: name.to_string(),
return_type: return_type.to_string(),
rules,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn return_type(&self) -> &str {
&self.return_type
}
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumRule> {
self.rules.iter().map(Box::as_ref)
}
}
pub enum PolymorphicEnumRule {
Wrap(NameAndKind),
ReturnBuild(NameAndKind),
}
pub struct NameAndKind {
name: String,
kind: String,
}
impl NameAndKind {
pub fn new(name: &str, kind: &str) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
}

View File

@ -0,0 +1,21 @@
pub struct LeafEnumBuildSpec {
build: String,
rules: Vec<String>,
}
impl LeafEnumBuildSpec {
pub fn new(build: &str, rules: Vec<String>) -> Self {
Self {
build: build.to_string(),
rules,
}
}
pub fn build(&self) -> &str {
&self.build
}
pub fn rules(&self) -> impl Iterator<Item = &str> {
self.rules.iter().map(AsRef::as_ref)
}
}

View File

@ -0,0 +1,47 @@
pub struct LeafStructBuildSpec {
build: String,
members: Vec<Box<LeafStructMember>>,
}
impl LeafStructBuildSpec {
pub fn new(build: &str, members: Vec<Box<LeafStructMember>>) -> Self {
Self {
build: build.to_string(),
members,
}
}
pub fn build(&self) -> &str {
&self.build
}
pub fn members(&self) -> impl Iterator<Item = &LeafStructMember> {
self.members.iter().map(Box::as_ref)
}
}
pub struct LeafStructMember {
name: String,
kind: LeafStructMemberKind,
}
impl LeafStructMember {
pub fn new(name: &str, kind: LeafStructMemberKind) -> Self {
Self {
name: name.to_string(),
kind,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &LeafStructMemberKind {
&self.kind
}
}
pub enum LeafStructMemberKind {
String,
}

View File

@ -0,0 +1,31 @@
use crate::spec::node_production_spec::NodeProductionBuildSpec;
use crate::spec::polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use leaf_enum_spec::LeafEnumBuildSpec;
use leaf_struct_spec::LeafStructBuildSpec;
use polymorphic_type_spec::PolymorphicTypeBuildSpec;
use production_spec::ProductionBuildSpec;
use struct_spec::StructSpec;
use tree_enum_spec::TreeEnumBuildSpec;
use crate::spec::polymorphic_pass_through_spec::PolymorphicPassThroughBuildSpec;
pub(crate) mod leaf_enum_spec;
pub(crate) mod leaf_struct_spec;
pub(crate) mod node_production_spec;
pub(crate) mod polymorphic_enum_loop_spec;
pub(crate) mod polymorphic_pass_through_spec;
pub(crate) mod polymorphic_type_spec;
pub(crate) mod production_spec;
pub(crate) mod struct_spec;
pub(crate) mod tree_enum_spec;
pub enum BuildSpec {
Enum(TreeEnumBuildSpec),
LeafEnum(LeafEnumBuildSpec),
Struct(StructSpec),
LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec),
NodeProduction(NodeProductionBuildSpec),
PolymorphicType(PolymorphicTypeBuildSpec),
PolymorphicEnumLoop(PolymorphicEnumLoopBuildSpec),
PolymorphicPassThrough(PolymorphicPassThroughBuildSpec)
}

View File

@ -0,0 +1,27 @@
pub struct NodeProductionBuildSpec {
name: String,
kind: String,
with: String
}
impl NodeProductionBuildSpec {
pub fn new(name: &str, kind: &str, with: &str) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
with: with.to_string()
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn with(&self) -> &str {
&self.with
}
}

View File

@ -0,0 +1,137 @@
pub struct PolymorphicEnumLoopBuildSpec {
name: String,
kind: String,
rules: Vec<Box<PolymorphicEnumLoopRule>>,
}
impl PolymorphicEnumLoopBuildSpec {
pub fn new(name: &str, kind: &str, rules: Vec<Box<PolymorphicEnumLoopRule>>) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
rules,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumLoopRule> {
self.rules.iter().map(Box::as_ref)
}
}
pub enum PolymorphicEnumLoopRule {
PassThrough(PolymorphicEnumLoopRulePassThrough),
Build(PolymorphicEnumLoopRuleBuild),
}
pub struct PolymorphicEnumLoopRulePassThrough {
name: String,
kind: String,
with: String,
}
impl PolymorphicEnumLoopRulePassThrough {
pub fn new(name: &str, kind: &str, with: &str) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
with: with.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn with(&self) -> &str {
&self.with
}
}
pub struct PolymorphicEnumLoopRuleBuild {
name: String,
variant: String,
children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>,
}
impl PolymorphicEnumLoopRuleBuild {
pub fn new(name: &str, variant: &str, children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>) -> Self {
Self {
name: name.to_string(),
variant: variant.to_string(),
children,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn variant(&self) -> &str {
&self.variant
}
pub fn children(&self) -> impl Iterator<Item = &PolymorphicEnumLoopRuleBuildChild> {
self.children.iter().map(Box::as_ref)
}
}
pub enum PolymorphicEnumLoopRuleBuildChild {
UseCurrent(PolymorphicEnumLoopChildUseCurrent),
OnEach(PolymorphicEnumLoopRuleChildOnEach),
}
pub struct PolymorphicEnumLoopChildUseCurrent {
name: String,
kind: String,
}
impl PolymorphicEnumLoopChildUseCurrent {
pub fn new(name: &str, kind: &str) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
}
pub struct PolymorphicEnumLoopRuleChildOnEach {
name: String,
rule: String,
}
impl PolymorphicEnumLoopRuleChildOnEach {
pub fn new(name: &str, rule: &str) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn rule(&self) -> &str {
&self.rule
}
}

View File

@ -0,0 +1,36 @@
pub struct PolymorphicPassThroughBuildSpec {
name: String,
build_kind: String,
variants: Vec<Box<PolymorphicPassThroughVariant>>,
}
impl PolymorphicPassThroughBuildSpec {
pub fn new(
name: &str,
build_kind: &str,
variants: Vec<Box<PolymorphicPassThroughVariant>>,
) -> Self {
Self {
name: name.to_string(),
build_kind: build_kind.to_string(),
variants,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn build_kind(&self) -> &str {
&self.build_kind
}
pub fn variants(&self) -> impl Iterator<Item = &PolymorphicPassThroughVariant> {
self.variants.iter().map(Box::as_ref)
}
}
pub enum PolymorphicPassThroughVariant {
Inner { name: String, kind: String },
PassThrough { name: String, kind: String },
}

View File

@ -0,0 +1,49 @@
pub struct PolymorphicTypeBuildSpec {
name: String,
variants: Vec<Box<PolymorphicTypeVariant>>,
kind: String,
}
impl PolymorphicTypeBuildSpec {
pub fn new(name: &str, variants: Vec<Box<PolymorphicTypeVariant>>, kind: &str) -> Self {
Self {
name: name.to_string(),
variants,
kind: kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn variants(&self) -> impl Iterator<Item = &PolymorphicTypeVariant> {
self.variants.iter().map(Box::as_ref)
}
pub fn kind(&self) -> &str {
self.kind.as_str()
}
}
pub struct PolymorphicTypeVariant {
name: String,
inner_kind: String,
}
impl PolymorphicTypeVariant {
pub fn new(name: &str, inner_kind: &str) -> Self {
Self {
name: name.to_string(),
inner_kind: inner_kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn inner_kind(&self) -> &str {
&self.inner_kind
}
}

View File

@ -0,0 +1,38 @@
pub struct ProductionBuildSpec {
name: String,
kind: ProductionKind,
}
impl ProductionBuildSpec {
pub fn new(name: &str, kind: ProductionKind) -> Self {
Self {
name: name.to_string(),
kind,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &ProductionKind {
&self.kind
}
}
pub enum ProductionKind {
Int,
Long,
Double,
String(ProductionStringFrom),
Boolean(ProductionBooleanFrom),
}
pub enum ProductionStringFrom {
StringInner,
WholePair,
}
pub enum ProductionBooleanFrom {
ParseWholePair,
}

View File

@ -0,0 +1,212 @@
pub struct StructSpec {
build: String,
children: Vec<Box<StructChild>>,
}
impl StructSpec {
pub fn new(build: &str, children: Vec<Box<StructChild>>) -> Self {
Self {
build: build.to_string(),
children,
}
}
/// The type to be built, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
/// The children for this build spec.
pub fn children(&self) -> impl Iterator<Item = &StructChild> {
self.children.iter().map(Box::as_ref)
}
}
pub enum StructChild {
SkipChild(SkipChild),
VecChild(VecChild),
MemberChild(MemberChild),
}
pub struct SkipChild {
rule: String,
}
impl SkipChild {
pub fn new(rule: &str) -> Self {
Self {
rule: rule.to_string(),
}
}
/// The grammar rule to match.
pub fn rule(&self) -> &str {
&self.rule
}
}
pub struct VecChild {
name: String,
rule: String,
build: Box<VecChildBuild>
}
impl VecChild {
pub fn new(name: &str, rule: &str, build: Box<VecChildBuild>) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
build
}
}
/// The name of this child.
pub fn name(&self) -> &str {
&self.name
}
/// The rule to match to build this child.
pub fn rule(&self) -> &str {
&self.rule
}
pub fn build(&self) -> &VecChildBuild {
&self.build
}
}
pub enum VecChildBuild {
String(VecChildStringBuild),
Node(VecChildNodeBuild)
}
pub struct VecChildStringBuild {
with: String
}
impl VecChildStringBuild {
pub fn new(with: &str) -> Self {
Self { with: with.to_string() }
}
pub fn with(&self) -> &str {
&self.with
}
}
pub struct VecChildNodeBuild {
kind: String,
with: String
}
impl VecChildNodeBuild {
pub fn new(kind: &str, with: &str) -> Self {
Self {
kind: kind.to_string(),
with: with.to_string()
}
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn with(&self) -> &str {
&self.with
}
}
#[derive(Debug)]
pub struct MemberChild {
name: String,
rule: String,
optional: bool,
build: Box<MemberChildBuild>,
}
impl MemberChild {
pub fn new(name: &str, rule: &str, optional: bool, build: Box<MemberChildBuild>) -> Self {
Self {
name: name.to_string(),
rule: rule.to_string(),
optional,
build,
}
}
/// The name of this child in the yaml file, in snake case.
pub fn name(&self) -> &str {
&self.name
}
/// The grammar rule to match to build this child.
pub fn rule(&self) -> &str {
&self.rule
}
pub fn optional(&self) -> bool {
self.optional
}
/// The specification for what to actually build.
pub fn build(&self) -> &MemberChildBuild {
&self.build
}
}
#[derive(Debug)]
pub enum MemberChildBuild {
Node(NodeMemberBuild),
Boolean(BooleanMemberBuild),
}
#[derive(Debug)]
pub struct NodeMemberBuild {
kind: String,
with: String,
or_else: Option<String>,
}
impl NodeMemberBuild {
pub fn new(kind: &str, with: &str, or_else: Option<String>) -> Self {
Self {
kind: kind.to_string(),
with: with.to_string(),
or_else,
}
}
/// The type to build, in Pascal case.
pub fn kind(&self) -> &str {
&self.kind
}
pub fn with(&self) -> &str {
&self.with
}
/// The default fn to call when unwrapping the child (before passing as arg to new).
pub fn or_else(&self) -> Option<&str> {
self.or_else.as_deref()
}
}
#[derive(Debug)]
pub struct BooleanMemberBuild {
on: BooleanMemberBuildOn,
}
impl BooleanMemberBuild {
pub fn new(on: BooleanMemberBuildOn) -> Self {
Self { on }
}
pub fn on(&self) -> &BooleanMemberBuildOn {
&self.on
}
}
#[derive(Debug)]
pub enum BooleanMemberBuildOn {
RulePresent
}

View File

@ -0,0 +1,117 @@
pub struct TreeEnumBuildSpec {
build: String,
rules: Vec<Box<TreeEnumRule>>,
}
impl TreeEnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<TreeEnumRule>>) -> Self {
TreeEnumBuildSpec {
build: build.to_string(),
rules,
}
}
/// The enum type to be built, in Pascal case.
pub fn build(&self) -> &str {
&self.build
}
/// The individual rule specs.
pub fn rules(&self) -> impl Iterator<Item = &TreeEnumRule> {
self.rules.iter().map(Box::as_ref)
}
}
pub struct TreeEnumRule {
rule: String,
child: Option<Box<EnumRuleChild>>,
}
impl TreeEnumRule {
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
Self {
rule: rule.to_string(),
child,
}
}
/// The enum rule to match, in Pascal case.
pub fn rule(&self) -> &str {
&self.rule
}
pub fn child(&self) -> Option<&EnumRuleChild> {
if let Some(child) = &self.child {
Some(child.as_ref())
} else {
None
}
}
}
pub struct EnumRuleChild {
kind: Box<EnumRuleChildKind>,
}
impl EnumRuleChild {
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
Self { kind }
}
pub fn kind(&self) -> &EnumRuleChildKind {
&self.kind
}
}
pub enum EnumRuleChildKind {
Node(EnumRuleChildNodeKind),
Int(NameAndWith),
Long(NameAndWith),
Double(NameAndWith),
String(NameAndWith),
Boolean(NameAndWith),
}
pub struct EnumRuleChildNodeKind {
node_kind: String,
with: String,
}
impl EnumRuleChildNodeKind {
pub fn new(node_kind: &str, with: &str) -> Self {
Self {
node_kind: node_kind.to_string(),
with: with.to_string(),
}
}
pub fn node_kind(&self) -> &str {
&self.node_kind
}
pub fn with(&self) -> &str {
&self.with
}
}
pub struct NameAndWith {
name: String,
with: String,
}
impl NameAndWith {
pub fn new(name: &str, with: &str) -> Self {
Self {
name: name.to_string(),
with: with.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn with(&self) -> &str {
&self.with
}
}

View File

@ -1,216 +0,0 @@
use crate::spec::{BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild};
use crate::util::{make_build_fn_name, make_build_pair};
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_var_name(s: &str) -> String {
s.to_case(Case::Snake)
}
fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildToBuild::Node(node_child) => {
let child_type_ident = format_ident!("{}", node_child.build());
quote! {
let mut #child_ident: Vec<Box<#child_type_ident >> = vec![]
}
},
VecChildToBuild::String => quote! {
let mut #child_ident: Vec<String> = vec![]
}
}
}
fn make_node_child_holder(name: &str, node_child: &NodeChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", name);
let child_type_ident = format_ident!("{}", node_child.build());
quote! {
let mut #child_ident: Option<Box<#child_type_ident>> = None
}
}
fn make_boolean_child_holder(boolean_child: &BooleanChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", boolean_child.name());
quote! {
let mut #child_ident: bool = false
}
}
fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
match child_spec {
StructChildSpec::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => {
Some(make_node_child_holder(member_child.name(), node_child))
}
MemberChildToBuild::Boolean(boolean_child) => {
Some(make_boolean_child_holder(boolean_child))
}
},
}
}
fn make_vec_child_match_action(vec_child: &VecChild) -> TokenStream {
let child_name_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildToBuild::Node(vec_node_child) => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(vec_node_child.build()));
quote! {
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
}
},
VecChildToBuild::String => {
let build_fn_ident = format_ident!("{}", make_build_fn_name(vec_child.rule()));
quote! {
#child_name_ident.push(#build_fn_ident(inner_pair))
}
}
}
}
fn make_node_member_child_match_action(name: &str, node_child: &NodeChildToBuild) -> TokenStream {
let child_name_ident = format_ident!("{}", name);
let build_fn_ident = format_ident!("{}", make_build_fn_name(node_child.build()));
quote! {
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
}
}
fn make_boolean_member_child_match_action(boolean_child: &BooleanChildToBuild) -> TokenStream {
let child_name_ident = format_ident!("{}", make_var_name(boolean_child.name()));
quote! {
#child_name_ident = true
}
}
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream {
match child_spec {
StructChildSpec::SkipChild(_) => quote! {},
StructChildSpec::VecChild(vec_child) => {
make_vec_child_match_action(vec_child)
}
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_child) => {
make_node_member_child_match_action(member_child.name(), node_child)
}
MemberChildToBuild::Boolean(boolean_child) => {
make_boolean_member_child_match_action(boolean_child)
}
},
}
}
fn make_rule_matcher(child_spec: &StructChildSpec) -> TokenStream {
let rule_ident = match child_spec {
StructChildSpec::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
StructChildSpec::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
StructChildSpec::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
};
let action = make_match_action(child_spec);
quote! {
Rule::#rule_ident => {
#action;
}
}
}
fn make_vec_child_arg(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
quote! { #child_ident }
}
fn make_node_member_child_arg(name: &str, node_child: &NodeChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", name);
if node_child.optional() {
quote! { #child_ident }
} else if let Some(or_else) = node_child.or_else() {
let child_type_ident = format_ident!("{}", node_child.build());
let or_else_ident = format_ident!("{}", or_else);
quote! {
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
}
} else {
quote! { #child_ident.unwrap() }
}
}
fn make_boolean_member_child_arg(boolean_child: &BooleanChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", boolean_child.name());
quote! { #child_ident }
}
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> {
match child_spec {
StructChildSpec::SkipChild(_) => None,
StructChildSpec::VecChild(vec_child) => {
Some(make_vec_child_arg(vec_child))
}
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(single_type_child) => {
Some(make_node_member_child_arg(member_child.name(), single_type_child))
}
MemberChildToBuild::Boolean(boolean_child) => {
Some(make_boolean_member_child_arg(boolean_child))
}
},
}
}
fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec
.children()
.map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>();
quote! {
#type_ident::new(
#(#child_args,)*
)
}
}
pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> 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_holders = build_spec
.children()
.map(|child_spec| make_child_holder(child_spec))
.filter(|child_holder| child_holder.is_some())
.map(|child_holder| child_holder.unwrap())
.collect::<Vec<_>>();
let rule_matchers = build_spec
.children()
.map(|child_spec| make_rule_matcher(child_spec))
.collect::<Vec<_>>();
let iter_stream = quote! {
for inner_pair in #pair_ident.into_inner() {
match inner_pair.as_rule() {
#(#rule_matchers)*
_ => panic!("Unexpected rule: {:?}", inner_pair.as_rule())
}
}
};
let new_stream = make_return_value_stream(build_spec);
quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
#(#child_holders;)*
#iter_stream
#new_stream
}
}
}

View File

@ -1,464 +0,0 @@
use crate::spec::{
AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec,
EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind,
MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec,
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
fn make_polymorphic_build_type(build_spec: &PolymorphicBuildBuildSpec) -> TokenStream {
let alternative_action = build_spec
.alternatives()
.find(|alternative| {
if let AlternativeAction::Build(_) = alternative.action() {
true
} else {
false
}
})
.unwrap();
let alternative_build =
if let AlternativeAction::Build(alternative_build) = alternative_action.action() {
alternative_build
} else {
unreachable!()
};
let annotated_members = alternative_build
.children()
.map(|child| match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build_child) => {
let child_name_ident = format_ident!("{}", build_child.name());
let type_ident = format_ident!("{}", build_child.kind());
Some(quote! {
#child_name_ident: Box<#type_ident>
})
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let initializers = alternative_build
.children()
.map(|child| match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build_child) => Some(format_ident!("{}", build_child.name())),
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let accessors = alternative_build
.children()
.map(|child| match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build_child) => {
let child_ident = format_ident!("{}", build_child.name());
let child_ident_mut = format_ident!("{}_mut", build_child.name());
let child_type_ident = format_ident!("{}", build_child.kind());
Some(quote! {
pub fn #child_ident(&self) -> &#child_type_ident {
&self.#child_ident
}
pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident {
&mut self.#child_ident
}
})
}
})
.collect::<Vec<_>>();
let type_ident = format_ident!("{}", build_spec.name());
quote! {
pub struct #type_ident {
#(#annotated_members),*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#initializers),*
}
}
#(#accessors)*
}
}
}
fn make_polymorphic_type_type(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
let members = build_spec
.enum_members()
.map(|enum_member| {
let member_ident = format_ident!("{}", enum_member.name());
let inner_type_ident = format_ident!("{}", enum_member.inner_kind());
quote! {
#member_ident(#inner_type_ident)
}
})
.collect::<Vec<_>>();
let type_name_ident = format_ident!("{}", build_spec.name());
quote! {
pub enum #type_name_ident {
#(#members),*
}
}
}
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
let children: Vec<TokenStream> = build_spec
.rules()
.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();
let type_name_ident = format_ident!("{}", build_spec.build());
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}
fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream {
let type_name_ident = format_ident!("{}", build_spec.build());
let children = build_spec
.rules()
.map(|leaf_enum_rule| {
let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule());
quote! {
#rule_name_ident
}
})
.collect::<Vec<_>>();
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}
fn handle_vec_child(
vec_child: &VecChild,
member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
let (child_ident, child_ident_mut) = (
format_ident!("{}", vec_child.name()),
format_ident!("{}_mut", 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());
match vec_child.build() {
VecChildToBuild::Node(_) => {
annotated_members.push(quote! {
#child_ident: Vec<Box<#child_type_ident>>
});
member_args.push(quote! {
#child_ident: Vec<Box<#child_type_ident>>
});
}
VecChildToBuild::String => {
annotated_members.push(quote! {
#child_ident: Vec<String>
});
member_args.push(quote! {
#child_ident: Vec<String>
})
}
}
match vec_child.build() {
VecChildToBuild::Node(_) => {
accessors.push(quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &#child_type_ident> {
self.#child_ident.iter().map(Box::as_ref)
}
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut #child_type_ident> {
self.#child_ident.iter_mut().map(Box::as_mut)
}
});
}
VecChildToBuild::String => accessors.push(quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &str> {
self.#child_ident.iter().map(String::as_str)
}
}),
}
}
fn handle_node_child(
name: &str,
node_child: &NodeChildToBuild,
member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
let child_ident = format_ident!("{}", name);
let child_ident_mut = format_ident!("{}_mut", name);
let child_type_ident = format_ident!("{}", node_child.build());
member_names.push(child_ident.clone());
if node_child.optional() {
annotated_members.push(quote! {
#child_ident: Option<Box<#child_type_ident>>
});
member_args.push(quote! {
#child_ident: Option<Box<#child_type_ident>>
});
} else {
annotated_members.push(quote! {
#child_ident: Box<#child_type_ident>
});
member_args.push(quote! {
#child_ident: Box<#child_type_ident>
})
}
if node_child.optional() {
accessors.push(quote! {
pub fn #child_ident(&self) -> Option<&#child_type_ident> {
if let Some(#child_ident) = &self.#child_ident {
Some(#child_ident.as_ref())
} else {
None
}
}
pub fn #child_ident_mut(&mut self) -> Option<&mut #child_type_ident> {
if let Some(#child_ident) = &mut self.#child_ident {
Some(#child_ident.as_mut())
} else {
None
}
}
});
} else {
accessors.push(quote! {
pub fn #child_ident(&self) -> &#child_type_ident {
self.#child_ident.as_ref()
}
pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident {
self.#child_ident.as_mut()
}
});
}
}
fn handle_boolean_child(
single_boolean_child: &BooleanChildToBuild,
member_names: &mut Vec<Ident>,
annotated_members: &mut Vec<TokenStream>,
member_args: &mut Vec<TokenStream>,
accessors: &mut Vec<TokenStream>,
) {
let child_ident = format_ident!("{}", single_boolean_child.name());
member_names.push(child_ident.clone());
annotated_members.push(quote! {
#child_ident: bool
});
member_args.push(quote! {
#child_ident: bool
});
accessors.push(quote! {
pub fn #child_ident(&self) -> bool {
self.#child_ident
}
});
}
fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
let mut member_names: Vec<Ident> = vec![];
let mut annotated_members: Vec<TokenStream> = vec![];
let mut member_args: Vec<TokenStream> = vec![];
let mut accessors: Vec<TokenStream> = vec![];
for child_spec in build_spec.children() {
match child_spec {
StructChildSpec::SkipChild(_) => {}
StructChildSpec::VecChild(vec_child) => {
handle_vec_child(
vec_child,
&mut member_names,
&mut annotated_members,
&mut member_args,
&mut accessors,
);
}
StructChildSpec::MemberChild(member_child) => {
match member_child.build() {
MemberChildToBuild::Node(node_child) => {
handle_node_child(
member_child.name(),
node_child,
&mut member_names,
&mut annotated_members,
&mut member_args,
&mut accessors,
);
}
MemberChildToBuild::Boolean(boolean_child) => {
handle_boolean_child(
boolean_child,
&mut member_names,
&mut annotated_members,
&mut member_args,
&mut accessors,
);
}
};
}
}
}
let type_ident = format_ident!("{}", build_spec.build());
quote! {
pub struct #type_ident {
#(#annotated_members),*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#member_names),*
}
}
#(#accessors)*
}
}
}
fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec
.members()
.map(|member| {
let name_ident = format_ident!("{}", member.name());
let type_ident = match member.kind() {
LeafStructMemberKind::String => format_ident!("{}", "String"),
};
quote! {
#name_ident: #type_ident
}
})
.collect::<Vec<_>>();
let member_args = build_spec.members().map(|member| {
let name_ident = format_ident!("{}", member.name());
let type_stream = match member.kind() {
LeafStructMemberKind::String => {
quote! { &str }
}
};
quote! {
#name_ident: #type_stream
}
});
let initializers = build_spec
.members()
.map(|leaf_struct_member| {
let member_ident = format_ident!("{}", leaf_struct_member.name());
match leaf_struct_member.kind() {
LeafStructMemberKind::String => {
quote! {
#member_ident: #member_ident.to_string()
}
}
}
})
.collect::<Vec<_>>();
let accessors = build_spec
.members()
.map(|member| {
let name_ident = format_ident!("{}", member.name());
match member.kind() {
LeafStructMemberKind::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(#(#member_args),*) -> Self {
Self {
#(#initializers),*
}
}
#(#accessors)*
}
}
}
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
match 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) => {
Some(make_leaf_struct_type(leaf_struct_build_spec))
}
BuildSpec::Production(_) => None,
BuildSpec::Polymorphic(polymorphic_build_spec) => {
Some(make_polymorphic_type_type(polymorphic_build_spec))
}
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
Some(make_polymorphic_build_type(polymorphic_build_build_spec))
}
BuildSpec::PolymorphicEnum(_) => None,
}
}

View File

@ -0,0 +1,37 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
pub fn make_enum_type(build_spec: &TreeEnumBuildSpec) -> TokenStream {
let children: Vec<TokenStream> = build_spec
.rules()
.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.node_kind())
}
EnumRuleChildKind::Int(_) => format_ident!("i32"),
EnumRuleChildKind::Long(_) => format_ident!("i64"),
EnumRuleChildKind::Double(_) => format_ident!("f64"),
EnumRuleChildKind::String(_) => format_ident!("String"),
EnumRuleChildKind::Boolean(_) => format_ident!("bool"),
};
quote! {
#member_name_ident(#child_type_ident)
}
} else {
quote! {
#member_name_ident
}
}
})
.collect();
let type_name_ident = format_ident!("{}", build_spec.build());
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}

View File

@ -0,0 +1,22 @@
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream {
let type_name_ident = format_ident!("{}", build_spec.build());
let children = build_spec
.rules()
.map(|leaf_enum_rule| {
let rule_name_ident = format_ident!("{}", leaf_enum_rule);
quote! {
#rule_name_ident
}
})
.collect::<Vec<_>>();
quote! {
pub enum #type_name_ident {
#(#children),*
}
}
}

View File

@ -0,0 +1,78 @@
use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMemberKind};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec
.members()
.map(|member| {
let name_ident = format_ident!("{}", member.name());
let type_ident = match member.kind() {
LeafStructMemberKind::String => format_ident!("{}", "String"),
};
quote! {
#name_ident: #type_ident
}
})
.collect::<Vec<_>>();
let member_args = build_spec.members().map(|member| {
let name_ident = format_ident!("{}", member.name());
let type_stream = match member.kind() {
LeafStructMemberKind::String => {
quote! { &str }
}
};
quote! {
#name_ident: #type_stream
}
});
let initializers = build_spec
.members()
.map(|leaf_struct_member| {
let member_ident = format_ident!("{}", leaf_struct_member.name());
match leaf_struct_member.kind() {
LeafStructMemberKind::String => {
quote! {
#member_ident: #member_ident.to_string()
}
}
}
})
.collect::<Vec<_>>();
let accessors = build_spec
.members()
.map(|member| {
let name_ident = format_ident!("{}", member.name());
match member.kind() {
LeafStructMemberKind::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(#(#member_args),*) -> Self {
Self {
#(#initializers),*
}
}
#(#accessors)*
}
}
}

View File

@ -0,0 +1,33 @@
mod enum_type;
mod leaf_enum_type;
mod leaf_struct_type;
mod polymorphic_type_type;
mod struct_type;
use crate::spec::BuildSpec;
use crate::type_gen::enum_type::make_enum_type;
use crate::type_gen::leaf_enum_type::make_leaf_enum_type;
use crate::type_gen::leaf_struct_type::make_leaf_struct_type;
use crate::type_gen::polymorphic_type_type::make_polymorphic_type_type;
use crate::type_gen::struct_type::make_struct_type;
use proc_macro2::TokenStream;
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
match build_spec {
BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)),
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
Some(make_leaf_struct_type(leaf_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::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_build_spec) => {
Some(make_polymorphic_type_type(polymorphic_build_spec))
}
BuildSpec::PolymorphicEnumLoop(_) => None,
BuildSpec::PolymorphicPassThrough(_) => None,
}
}

View File

@ -0,0 +1,22 @@
use crate::spec::polymorphic_type_spec::PolymorphicTypeBuildSpec;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_type_type(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
let members = build_spec
.variants()
.map(|enum_member| {
let member_ident = format_ident!("{}", enum_member.name());
let inner_type_ident = format_ident!("{}", enum_member.inner_kind());
quote! {
#member_ident(#inner_type_ident)
}
})
.collect::<Vec<_>>();
let type_name_ident = format_ident!("{}", build_spec.name());
quote! {
pub enum #type_name_ident {
#(#members),*
}
}
}

View File

@ -0,0 +1,193 @@
use crate::spec::struct_spec::{MemberChild, MemberChildBuild, StructChild, StructSpec, VecChild, VecChildBuild};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() {
VecChildBuild::String(_) => {
quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &str> {
self.#child_ident.iter().map(String::as_str)
}
}
},
VecChildBuild::Node(vec_child_node_build) => {
let child_type_ident = format_ident!("{}", vec_child_node_build.kind());
let child_ident_mut = format_ident!("{}_mut", vec_child.name());
quote! {
pub fn #child_ident(&self) -> impl Iterator<Item = &#child_type_ident> {
self.#child_ident.iter().map(Box::as_ref)
}
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut child_type_ident> {
self.#child_ident.iter().map(Box::as_mut)
}
}
}
}
}
fn make_member_child_accessors(member_child: &MemberChild) -> TokenStream {
let child_ident = format_ident!("{}", member_child.name());
match member_child.build() {
MemberChildBuild::Node(node_member_build) => {
let return_type_ident = format_ident!("{}", node_member_build.kind());
let child_ident_mut = format_ident!("{}_mut", member_child.name());
if member_child.optional() {
quote! {
pub fn #child_ident(&self) -> Option<&#return_type_ident> {
if let Some(#child_ident) = &self.#child_ident {
Some(#child_ident.as_ref())
} else {
None
}
}
pub fn #child_ident_mut(&mut self) -> Option<&mut #return_type_ident> {
if let Some(#child_ident) = &mut self.#child_ident {
Some(#child_ident.as_mut())
} else {
None
}
}
}
} else {
quote! {
pub fn #child_ident(&self) -> &#return_type_ident {
self.#child_ident.as_ref()
}
pub fn #child_ident_mut(&mut self) -> &mut #return_type_ident {
self.#child_ident.as_mut()
}
}
}
}
MemberChildBuild::Boolean(_) => {
quote! {
pub fn #child_ident(&self) -> bool {
self.#child_ident
}
}
}
}
}
fn make_accessors(child: &StructChild) -> Option<TokenStream> {
match child {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => {
Some(make_vec_child_accessors(vec_child))
}
StructChild::MemberChild(member_child) => {
Some(make_member_child_accessors(member_child))
}
}
}
fn make_member_ident(child: &StructChild) -> Option<Ident> {
match child {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => {
Some(format_ident!("{}", vec_child.name()))
},
StructChild::MemberChild(member_child) => {
Some(format_ident!("{}", member_child.name()))
}
}
}
fn make_vec_child_annotated_member(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name());
let type_stream = match vec_child.build() {
VecChildBuild::String(_) => quote! { String },
VecChildBuild::Node(vec_child_node_build) => {
let type_ident = format_ident!("{}", vec_child_node_build.kind());
quote! { Box<#type_ident> }
},
};
quote! {
#child_ident: Vec<#type_stream>
}
}
fn make_member_child_type_ident(member_child: &MemberChild) -> TokenStream {
match member_child.build() {
MemberChildBuild::Node(node_member_build) => {
let type_ident = format_ident!("{}", node_member_build.kind());
quote! { #type_ident }
},
MemberChildBuild::Boolean(_) => {
quote! { bool }
}
}
}
fn make_member_child_annotated_member(member_child: &MemberChild) -> TokenStream {
let child_name_ident = format_ident!("{}", member_child.name());
let type_ident = make_member_child_type_ident(member_child);
let type_stream = if member_child.optional() {
quote! { Option<#type_ident> }
} else {
type_ident
};
quote! {
#child_name_ident: #type_stream
}
}
fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
match child {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_annotated_member(vec_child)),
StructChild::MemberChild(member_child) => Some(make_member_child_annotated_member(member_child)),
}
}
pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec.children()
.map(|child| {
make_annotated_member(child)
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let member_names = build_spec.children()
.map(|child| {
make_member_ident(child)
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let accessors = build_spec.children()
.map(|child| {
make_accessors(child)
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
quote! {
pub struct #type_ident {
#(#annotated_members),*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#member_names),*
}
}
#(#accessors)*
}
}
}

View File

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

View File

@ -1,4 +1,4 @@
use ast_generator::{deserialize, generate_files}; use ast_generator::{get_build_specs, generate_files};
use cst_test_generator::generate_test_files; use cst_test_generator::generate_test_files;
use std::env; use std::env;
use std::fs; use std::fs;
@ -19,7 +19,7 @@ fn generate_ast_files(out_dir: &Path) -> io::Result<()> {
fs::create_dir_all(&gen_ast_dir)?; fs::create_dir_all(&gen_ast_dir)?;
let ast_yaml = include_str!("src/parser/ast.yaml"); let ast_yaml = include_str!("src/parser/ast.yaml");
let build_specs = deserialize::deserialize_yaml_spec(ast_yaml); let build_specs = get_build_specs(ast_yaml);
let generated_files = generate_files(&build_specs); let generated_files = generate_files(&build_specs);
for generated_file in &generated_files { for generated_file in &generated_files {
let path = gen_ast_dir.join(&generated_file.name); let path = gen_ast_dir.join(&generated_file.name);

3
examples/op_prec.dm Normal file
View File

@ -0,0 +1,3 @@
fn main()
1 + 2 * 3 + 4
end

View File

@ -0,0 +1,81 @@
pub class Rc<T> : Drop, Copy
class Inner<T>(t: T)
mut count = 1
end
inner: &weak Inner = Null
pub ctor(t: T)
inner = Inner(t)
end
ctor(parent: &Self)
parent.inner++
inner = &weak parent.inner
end
pub fn copy() -> Self
Self(self)
end
impl fn drop(self)
if inner.upgrade() is Some(inner) then
inner.count--
if inner.count == 0 then
drop inner
end
else
throw Exception('rc.inner could not be converted from a weak reference')
end
end
end
class Game(player: Player) end
class Player
pub mut game: &weak Game = Null
end
fn circular()
let player = Player()
let game = Game(player)
expectThrows(EmptyWeakReferenceException) {
player.game.upgrade()
}
player.game = &weak game
expectDoesNotThrow {
player.game.upgrade()
}
end
class Board
pub fn flip()
println 'Flipped!'
end
end
class ChessGame(pub board: rc Board) end
class ChessPlayer(pub board: rc Board) end
fn getGameAndPlayer() -> (ChessGame, ChessPlayer)
let board = rc Board() // Rc<Board> count is 1
let game = ChessGame(board) // Rc<Board> copied, count is 2
let player = ChessPlayer(board) // Rc<Board> copied, count is 3
(game, player) // initial Rc<Board> dropped before fn return, count now 2
end
fn playChess()
let (game, player) = getGameAndPlayer()
// Rc<Board> count is 2
let board = game.board // Copy, so count is now 3
board.flip()
drop board // count now 2
drop game // count now 1
drop player // count now 0, board memory finally dropped
end

View File

@ -50,6 +50,6 @@ fn main() {
// eprintln!("{}", e) // eprintln!("{}", e)
// } // }
// } // }
_ => todo!() _ => todo!(),
} }
} }

View File

@ -33,9 +33,21 @@ $defs:
- $ref: "#/$defs/EnumNodeDefinition" - $ref: "#/$defs/EnumNodeDefinition"
- $ref: "#/$defs/LeafEnumNodeDefinition" - $ref: "#/$defs/LeafEnumNodeDefinition"
- $ref: "#/$defs/ProductionDefinition" - $ref: "#/$defs/ProductionDefinition"
- $ref: "#/$defs/NodeProductionDefinition"
- $ref: "#/$defs/PolymorphicTypeDefinition"
- $ref: "#/$defs/PolymorphicEnumLoopBuildDefinition"
- $ref: "#/$defs/PolymorphicPassThroughDefinition"
# Four main types of nodes # Struct
StructNodeDefinition: StructNodeDefinition:
type: object
additionalProperties: false
properties:
struct:
$ref: "#/$defs/StructProps"
required:
- struct
StructProps:
type: object type: object
additionalProperties: false additionalProperties: false
description: A description of a Struct node to be built. description: A description of a Struct node to be built.
@ -44,56 +56,18 @@ $defs:
type: array type: array
description: Ordered child fields for this node. description: Ordered child fields for this node.
items: items:
$ref: "#/$defs/StructChildDefinition" $ref: "#/$defs/StructChild"
required: required:
- children - children
LeafStructNodeDefinition: StructChild:
type: object
additionalProperties: false
description: A description of a Leaf-Struct node to be built.
properties:
members:
type: array
description: Ordered members for this node.
items:
$ref: "#/$defs/LeafStructMemberDefinition"
required:
- members
EnumNodeDefinition:
type: object
additionalProperties: false
description: A description of an Enum node to be built.
properties:
rules:
type: array
description: Alternative parse rules that build this node.
items:
$ref: "#/$defs/EnumChildDefinition"
required:
- rules
LeafEnumNodeDefinition:
type: object
additionalProperties: false
description: A description of a leaf-enum node to be built.
properties:
leaf_rules:
type: array
description: Alternative parse rules that build this node.
items:
type: string
required:
- leaf_rules
# Struct node children
StructChildDefinition:
description: | description: |
A definition of a Struct node's child. Either a bare child name (string) in snake case, or an object. The former A definition of a Struct node's child. Either a bare child name (string) in snake case, or an object. The former
is a shorthand where the child name and built type are the same; casing is automatically done. The latter allows is a shorthand where the child name and built type are the same; casing is automatically done. The latter allows
further customization of the built child. further customization of the built child.
oneOf: oneOf:
- type: string - type: string
- $ref: "#/$defs/StructChildDefinitionWrapper" - $ref: "#/$defs/StructChildHash"
StructChildDefinitionWrapper: StructChildHash:
type: object type: object
description: Single-key object mapping the child-name to its advanced definition. description: Single-key object mapping the child-name to its advanced definition.
minProperties: 1 minProperties: 1
@ -101,28 +75,38 @@ $defs:
additionalProperties: false additionalProperties: false
patternProperties: patternProperties:
"^[a-z][a-z0-9_]*$": "^[a-z][a-z0-9_]*$":
$ref: "#/$defs/StructChildAdvancedDefinition" $ref: "#/$defs/StructChildProps"
StructChildAdvancedDefinition: StructChildProps:
type: object type: object
description: One of skip/vec/single child specs. description: One of skip/vec/single child specs.
oneOf: oneOf:
- $ref: "#/$defs/StructChildSkipChildDefinition" - $ref: "#/$defs/StructChildSkipHash"
- $ref: "#/$defs/StructChildVecChildDefinition" - $ref: "#/$defs/StructChildVecHash"
- $ref: "#/$defs/StructChildMemberDefinition" - $ref: "#/$defs/StructChildMemberHash"
StructChildSkipChildDefinition: StructChildSkipHash:
type: object
additionalProperties: false
properties:
skip:
$ref: "#/$defs/StructChildSkipProps"
required:
- skip
StructChildSkipProps:
type: object type: object
additionalProperties: false additionalProperties: false
description: A definition for a child rule that does nothing, i.e., is skipped. description: A definition for a child rule that does nothing, i.e., is skipped.
properties: properties:
rule: rule:
type: string type: string
skip:
type: boolean
const: true
required: required:
- rule - rule
- skip StructChildVecHash:
StructChildVecChildDefinition: type: object
additionalProperties: false
properties:
vec:
$ref: "#/$defs/StructChildVecProps"
StructChildVecProps:
type: object type: object
additionalProperties: false additionalProperties: false
description: A definition for a child rule that can be matched multiple times. description: A definition for a child rule that can be matched multiple times.
@ -131,16 +115,17 @@ $defs:
type: string type: string
kind: kind:
type: string type: string
enum:
- node # default
- string
vec:
type: boolean
const: true
required: required:
- rule - rule
- vec StructChildMemberHash:
StructChildMemberDefinition: type: object
additionalProperties: false
properties:
member:
$ref: "#/$defs/StructChildMemberProps"
required:
- member
StructChildMemberProps:
type: object type: object
additionalProperties: false additionalProperties: false
properties: properties:
@ -151,18 +136,75 @@ $defs:
type: boolean type: boolean
description: If true, this child will be stored as an Option. description: If true, this child will be stored as an Option.
build: build:
oneOf: $ref: "#/$defs/StructChildMemberBuildProps"
- type: string StructChildMemberBuildProps:
- $ref: "#/$defs/StructChildMemberBuildDefinition"
StructChildMemberBuildDefinition:
type: object type: object
additionalProperties: false additionalProperties: false
description: A definition of what exactly to build for a given child rule.
oneOf: oneOf:
- $ref: "#/$defs/BuildNode" - $ref: "#/$defs/StructChildMemberBuildNodeHash"
- $ref: "#/$defs/BuildBoolean" - $ref: "#/$defs/StructChildMemberBuildBooleanHash"
StructChildMemberBuildNodeHash:
type: object
additionalProperties: false
properties:
node:
$ref: "#/$defs/StructChildMemberBuildNodeProps"
required:
- node
StructChildMemberBuildNodeProps:
type: object
additionalProperties: false
description: A definition of a single-type child to build.
properties:
kind:
type: string
with:
type: string
or_else:
type: string
description: The method name to call upon the built-type if the rule is not found. Takes precedence over "or_else_default".
or_else_default:
type: boolean
description: Whether to call the default method on the built-type if the rule is not found.
StructChildMemberBuildBooleanHash:
type: object
additionalProperties: false
properties:
boolean:
$ref: "#/$defs/StructChildMemberBuildBooleanProps"
required:
- boolean
StructChildMemberBuildBooleanProps:
type: object
additionalProperties: false
description: A boolean member to be built.
properties:
on:
type: string
enum:
- rule_present
required:
- on
# Leaf Struct children # Leaf Struct Node
LeafStructNodeDefinition:
type: object
additionalProperties: false
description: A description of a Leaf-Struct node to be built.
properties:
leaf_struct:
type: object
additionalProperties: false
properties:
members:
type: array
description: Ordered members for this node.
items:
$ref: "#/$defs/LeafStructMemberDefinition"
required:
- members
required:
- leaf_struct
LeafStructMemberDefinition: LeafStructMemberDefinition:
type: object type: object
description: Single-key object mapping the member-name to what is to be built by parsing the Parser Pair. description: Single-key object mapping the member-name to what is to be built by parsing the Parser Pair.
@ -172,8 +214,8 @@ $defs:
patternProperties: patternProperties:
"^[a-z][a-z0-9_]*$": "^[a-z][a-z0-9_]*$":
oneOf: oneOf:
- $ref: "#/$defs/BuildMember" - $ref: "#/$defs/LeafStructBuildMember"
BuildMember: LeafStructBuildMember:
type: object type: object
description: A specification for a member to build. description: A specification for a member to build.
additionalProperties: false additionalProperties: false
@ -181,14 +223,28 @@ $defs:
kind: kind:
enum: enum:
- string - string
from:
enum:
- whole_pair
required: required:
- kind - kind
- from
# Enum children # Enum node
EnumNodeDefinition:
type: object
additionalProperties: false
description: A description of an Enum node to be built.
properties:
tree_enum:
type: object
additionalProperties: false
properties:
rules:
type: array
description: Alternative parse rules that build this node.
items:
$ref: "#/$defs/EnumChildDefinition"
required:
- rules
required:
- tree_enum
EnumChildDefinition: EnumChildDefinition:
oneOf: oneOf:
- type: string - type: string
@ -201,20 +257,263 @@ $defs:
additionalProperties: false additionalProperties: false
patternProperties: patternProperties:
"^([A-Z][a-z]*)*$": "^([A-Z][a-z]*)*$":
type: string properties:
child:
type: boolean
kind:
enum: enum:
- int - int
- long - long
- double - double
- usize
- string - string
- boolean - boolean
# Production definition # Leaf Enum
LeafEnumNodeDefinition:
type: object
additionalProperties: false
description: A description of a leaf-enum node to be built.
properties:
leaf_enum:
type: object
additionalProperties: false
properties:
rules:
type: array
description: Alternative parse rules that build this node.
items:
type: string
required:
- rules
required:
- leaf_enum
# Polymorphic Type
PolymorphicTypeDefinition:
type: object
additionalProperties: false
properties:
polymorphic_type:
type: object
additionalProperties: false
properties:
variants:
type: array
items:
$ref: "#/$defs/PolymorphicTypeVariantHash"
build:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
required:
- variants
- build
required:
- polymorphic_type
PolymorphicTypeVariantHash:
type: object
additionalProperties: false
minProperties: 1
maxProperties: 1
patternProperties:
"^([A-Z][a-z]*)*$":
properties:
inner:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
# Polymorphic Enum Loop Build
PolymorphicEnumLoopBuildDefinition:
type: object
additionalProperties: false
properties:
polymorphic_enum_loop_build:
type: object
additionalProperties: false
properties:
kind:
type: string
rules:
type: array
items:
$ref: "#/$defs/PolymorphicEnumLoopBuildRule"
required:
- kind
- rules
required:
- polymorphic_enum_loop_build
PolymorphicEnumLoopBuildRule:
type: object
additionalProperties: false
minProperties: 1
maxProperties: 1
patternProperties:
"^([A-Z][a-z]*)*$":
type: object
oneOf:
- $ref: "#/$defs/PolymorphicEnumLoopBuildPassThrough"
- $ref: "#/$defs/PolymorphicEnumLoopBuildBuild"
PolymorphicEnumLoopBuildPassThrough:
type: object
additionalProperties: false
properties:
pass_through:
type: object
additionalProperties: false
properties:
kind:
type: string
with:
type: string
required:
- kind
- with
required:
- pass_through
PolymorphicEnumLoopBuildBuild:
type: object
additionalProperties: false
properties:
build:
type: object
additionalProperties: false
properties:
variant:
type: string
children:
type: array
items:
$ref: "#/$defs/PolymorphicEnumLoopBuildBuildChild"
required:
- variant
- children
required:
- build
PolymorphicEnumLoopBuildBuildChild:
type: object
additionalProperties: false
minProperties: 1
maxProperties: 1
patternProperties:
"^[a-z][a-z_]*$":
type: object
oneOf:
- $ref: "#/$defs/PolymorphicEnumLoopBuildBuildUseCurrent"
- $ref: "#/$defs/PolymorphicEnumLoopBuildBuildOnEach"
PolymorphicEnumLoopBuildBuildUseCurrent:
type: object
additionalProperties: false
properties:
use_current:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
required:
- use_current
PolymorphicEnumLoopBuildBuildOnEach:
type: object
additionalProperties: false
properties:
on_each:
type: object
additionalProperties: false
properties:
rule:
type: string
required:
- rule
required:
- on_each
# Polymorphic Pass Through
PolymorphicPassThroughDefinition:
type: object
additionalProperties: false
properties:
polymorphic_pass_through:
$ref: "#/$defs/PolymorphicPassThroughProps"
required:
- polymorphic_pass_through
PolymorphicPassThroughProps:
type: object
additionalProperties: false
properties:
build:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
variants:
type: array
items:
$ref: "#/$defs/PolymorphicPassThroughVariantHash"
required:
- build
- variants
PolymorphicPassThroughVariantHash:
type: object
additionalProperties: false
minProperties: 1
maxProperties: 1
patternProperties:
"^([A-Z][a-z]*)*$":
$ref: "#/$defs/PolymorphicPassThroughVariantProps"
PolymorphicPassThroughVariantProps:
type: object
additionalProperties: false
oneOf:
- $ref: "#/$defs/PolymorphicPassThroughVariantInner"
- $ref: "#/$defs/PolymorphicPassThroughVariantPassThrough"
PolymorphicPassThroughVariantInner:
type: object
additionalProperties: false
properties:
inner:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
required:
- inner
PolymorphicPassThroughVariantPassThrough:
type: object
additionalProperties: false
properties:
pass_through:
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
required:
- pass_through
# Production
ProductionDefinition: ProductionDefinition:
type: object type: object
properties: properties:
produce: production:
type: object type: object
properties: properties:
kind: kind:
@ -229,28 +528,26 @@ $defs:
- string_inner - string_inner
- whole_pair - whole_pair
- parse_whole_pair - parse_whole_pair
required:
- kind
required:
- production
# Common things to build # Node Production
BuildNode: NodeProductionDefinition:
type: object type: object
additionalProperties: false additionalProperties: false
description: A definition of a single-type child to build.
properties: properties:
or_else: node_production:
type: string
description: The method name to call upon the built-type if the rule is not found. Takes precedence over "or_else_default".
or_else_default:
type: boolean
description: Whether to call the default method on the built-type if the rule is not found.
BuildBoolean:
type: object type: object
additionalProperties: false additionalProperties: false
description: A boolean member to be built.
properties: properties:
kind: kind:
type: string type: string
const: boolean with:
on:
type: string type: string
enum: required:
- rule_present - kind
- with
required:
- node_production

File diff suppressed because it is too large Load Diff

View File

@ -641,7 +641,7 @@ ComparisonExpression = {
ComparisonRhs = { ComparisonRhs = {
ComparisonOperator ComparisonOperator
~ Expression ~ ShiftExpression
} }
ComparisonOperator = { ComparisonOperator = {
@ -700,14 +700,10 @@ MultiplicativeOperator = {
} }
PrefixExpression = { PrefixExpression = {
PrefixOperators? PrefixOperator*
~ SuffixExpression ~ SuffixExpression
} }
PrefixOperators = {
PrefixOperator+
}
PrefixOperator = { PrefixOperator = {
Spread Spread
| Not | Not
@ -716,11 +712,7 @@ PrefixOperator = {
SuffixExpression = { SuffixExpression = {
PrimaryExpression PrimaryExpression
~ SuffixOperators? ~ SuffixOperator*
}
SuffixOperators = {
SuffixOperator+
} }
SuffixOperator = { SuffixOperator = {