Compare commits

...

12 Commits

Author SHA1 Message Date
Jesse Brault
fe2fff5882 Update grammar to reflect correct operator precedence. 2025-09-19 21:30:43 -05:00
Jesse Brault
e795664a09 Add list expressions to grammar/ast. 2025-09-19 12:57:53 -05:00
Jesse Brault
49a96eba85 Update worlds example. 2025-09-19 12:44:57 -05:00
Jesse Brault
9e3d71d73b Update d_string example. 2025-09-18 17:14:49 -05:00
Jesse Brault
5ff14f9dea Add d_string example. 2025-09-18 17:00:20 -05:00
Jesse Brault
522869371e Or else default generics. 2025-09-18 17:00:12 -05:00
Jesse Brault
11f97a2174 Auto gen pretty_print impls. 2025-09-18 08:38:30 -05:00
Jesse Brault
26cb28307c Move imports to generated build code. 2025-09-17 19:47:53 -05:00
Jesse Brault
cce927d964 Add a couple build tests. 2025-09-17 17:28:57 -05:00
Jesse Brault
7399a8748c Add polymorphic build types gen. 2025-09-17 17:21:37 -05:00
Jesse Brault
a7eabae3e3 WIP polymorphic building. 2025-09-16 10:59:38 -05:00
Jesse Brault
c94a698a52 D string expression test. 2025-09-16 10:31:38 -05:00
16 changed files with 1522 additions and 213 deletions

View File

@ -1,4 +1,4 @@
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NodeChildToBuild, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild}; 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 convert_case::{Case, Casing};
use yaml_rust2::{Yaml, YamlLoader}; use yaml_rust2::{Yaml, YamlLoader};
@ -18,21 +18,132 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
(key_as_string, member_value) (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 { fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
let kind = match production_yaml["kind"].as_str().unwrap() { let kind = if production_yaml["kind"].is_hash() {
"int" => ProductionKind::Int, let node = production_yaml["kind"]["node"].as_str().unwrap();
"long" => ProductionKind::Long, ProductionKind::Node(node.to_string())
"double" => ProductionKind::Double, } else {
"boolean" => ProductionKind::Boolean, match production_yaml["kind"].as_str().unwrap() {
"string" => { "int" => ProductionKind::Int,
let from = match production_yaml["from"].as_str().unwrap() { "long" => ProductionKind::Long,
"string_inner" => ProductionStringFrom::StringInner, "double" => ProductionKind::Double,
"whole_pair" => ProductionStringFrom::WholePair, "boolean" => ProductionKind::Boolean,
_ => panic!("invalid from: {}", production_yaml["from"].as_str().unwrap()), "string" => {
}; let from = match production_yaml["from"].as_str().unwrap() {
ProductionKind::String(from) "string_inner" => ProductionStringFrom::StringInner,
}, "whole_pair" => ProductionStringFrom::WholePair,
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()), _ => 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) ProductionBuildSpec::new(rule, kind)
} }
@ -46,9 +157,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
.as_vec() .as_vec()
.unwrap() .unwrap()
.iter() .iter()
.map(|rule_yaml| { .map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
deserialize_leaf_enum_rule(rule_yaml)
})
.collect() .collect()
} }
@ -63,16 +172,19 @@ fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleC
"usize" => EnumRuleChildKind::USize, "usize" => EnumRuleChildKind::USize,
"string" => EnumRuleChildKind::String, "string" => EnumRuleChildKind::String,
"boolean" => EnumRuleChildKind::Boolean, "boolean" => EnumRuleChildKind::Boolean,
_ => panic!("unsupported enum rule kind: {}", rule_props["kind"].as_str().unwrap()), _ => panic!(
"unsupported enum rule kind: {}",
rule_props["kind"].as_str().unwrap()
),
}; };
Some(Box::new(EnumRuleChild::new(Box::new(kind)))) Some(Box::new(EnumRuleChild::new(Box::new(kind))))
} }
} }
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> { fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
Box::new(EnumRuleChild::new(Box::new( Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
EnumRuleChildKind::Node(EnumRuleNodeChild::new(rule)), EnumRuleNodeChild::new(rule),
))) ))))
} }
fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> { fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
@ -80,7 +192,7 @@ fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
let (rule, rule_props) = unwrap_single_member_hash(rule_yaml); let (rule, rule_props) = unwrap_single_member_hash(rule_yaml);
Box::new(EnumRule::new( Box::new(EnumRule::new(
&rule, &rule,
deserialize_enum_rule_custom_child(rule_props) deserialize_enum_rule_custom_child(rule_props),
)) ))
} else { } else {
let rule_as_str = rule_yaml.as_str().unwrap(); let rule_as_str = rule_yaml.as_str().unwrap();
@ -164,7 +276,9 @@ fn deserialize_member_child_to_build(
} }
} else { } else {
let optional = get_as_bool(&props["optional"]); let optional = get_as_bool(&props["optional"]);
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(rule, None, optional))) Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
rule, None, optional,
)))
} }
} }
@ -277,9 +391,29 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]); let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules)) BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
} else if build_spec["produce"].is_hash() { } else if build_spec["produce"].is_hash() {
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"])) BuildSpec::Production(deserialize_production_spec(
build_spec_name,
&build_spec["produce"],
))
} else 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 { } else {
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type."); panic!(
"Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, production, polymorphic type, or polymorphic build type."
);
} }
} }

View File

@ -2,6 +2,10 @@ pub mod deserialize;
mod enum_build_fn; mod enum_build_fn;
mod leaf_enum_build_fn; mod leaf_enum_build_fn;
mod leaf_struct_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 production_build_fn; mod production_build_fn;
mod spec; mod spec;
mod struct_build_fn; mod struct_build_fn;
@ -11,6 +15,10 @@ mod util;
use crate::enum_build_fn::make_enum_build_fn; use crate::enum_build_fn::make_enum_build_fn;
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn; use crate::leaf_enum_build_fn::make_leaf_enum_build_fn;
use crate::leaf_struct_build_fn::make_leaf_struct_build_fn; use crate::leaf_struct_build_fn::make_leaf_struct_build_fn;
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::production_build_fn::make_production_build_fn;
use crate::struct_build_fn::make_struct_build_fn; use crate::struct_build_fn::make_struct_build_fn;
use crate::type_gen::make_type; use crate::type_gen::make_type;
@ -38,7 +46,25 @@ 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 - rule: {}", production_build_spec.rule());
}
BuildSpec::Polymorphic(polymorphic_build_spec) => {
println!(
"Polymorphic Type Spec - name: {}",
polymorphic_build_spec.name()
);
}
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
println!(
"Polymorphic Build Spec - name: {}",
polymorphic_build_build_spec.name()
);
}
BuildSpec::PolymorphicEnum(polymorphic_enum_build_spec) => {
println!(
"Polymorphic Enum Spec - name: {}",
polymorphic_enum_build_spec.name()
);
} }
} }
println!("{:#?}", token_stream); println!("{:#?}", token_stream);
@ -85,9 +111,31 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
debug_built_spec(build_spec, &stream); debug_built_spec(build_spec, &stream);
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
use crate::parser::Rule;
//noinspection RsUnusedImport
use pest::iterators::Pair;
//noinspection RsUnusedImport
use crate::ast::node::*;
#(#build_fns)* #(#build_fns)*
}; };
AstGeneratedFile { AstGeneratedFile {
@ -111,9 +159,30 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
} }
} }
fn generate_pretty_print_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
let impls = build_specs
.iter()
.map(|build_spec| {
let stream = make_pretty_print_impl(build_spec);
debug_built_spec(build_spec, &stream);
stream
})
.collect::<Vec<_>>();
let combined = quote! {
use crate::ast::node::*;
#(#impls)*
};
AstGeneratedFile {
name: String::from("pretty_print.rs"),
contents: token_stream_to_string(combined),
}
}
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),
] ]
} }

View File

@ -0,0 +1,134 @@
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

@ -0,0 +1,18 @@
use crate::spec::PolymorphicTypeBuildSpec;
use crate::util::{make_build_fn_name, make_build_pair};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_build_fn(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
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 return_type_ident = format_ident!("{}", build_spec.name());
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind()));
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,42 @@
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

@ -0,0 +1,256 @@
use crate::spec::{
AlternativeChild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, PolymorphicBuildBuildSpec,
PolymorphicEnumBuildSpec, PolymorphicTypeBuildSpec, ProductionBuildSpec, StructBuildSpec,
StructChildSpec, VecChildToBuild,
};
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
fn make_production_p2_impl(_spec: &ProductionBuildSpec) -> TokenStream {
quote! {}
}
fn make_polymorphic_enum_p2_impl(_spec: &PolymorphicEnumBuildSpec) -> TokenStream {
quote! {}
}
fn make_polymorphic_build_p2_impl(spec: &PolymorphicBuildBuildSpec) -> TokenStream {
let (_, build) = spec.primary_alternative();
let type_ident = format_ident!("{}", spec.name());
let name_str = spec.name();
let child_statements = build
.children()
.map(|child| match child {
AlternativeChild::Skip => None,
AlternativeChild::Build(build) => {
let child_ident = format_ident!("{}", build.name());
Some(quote! {
self.#child_ident().pretty_print(writer)?
})
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<TokenStream>>();
quote! {
impl PrettyPrint for #type_ident {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
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| {
let enum_member_ident = format_ident!("{}", member.name());
let inner_name = format_ident!("{}", member.inner_kind().to_case(Case::Snake));
quote! {
#type_ident::#enum_member_ident(#inner_name) => #inner_name.pretty_print(writer)
}
})
.collect::<Vec<_>>();
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| {
let enum_variant_ident = format_ident!("{}", rule.rule());
let name_str = rule.rule();
quote! {
#type_ident::#enum_variant_ident => writer.writeln_indented(#name_str)
}
})
.collect::<Vec<_>>();
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
.rules()
.map(|rule| {
let enum_variant_ident = format_ident!("{}", rule.rule());
if let Some(child) = rule.child() {
match child.kind() {
EnumRuleChildKind::Node(node_child) => {
let child_name_ident =
format_ident!("{}", node_child.build().to_case(Case::Snake));
Some(quote! {
#type_ident::#enum_variant_ident(#child_name_ident) => {
#child_name_ident.pretty_print(writer)?;
}
})
}
_ => None,
}
} else {
let variant_str = rule.rule();
Some(quote! {
#type_ident::#enum_variant_ident => writer.writeln_indented(#variant_str)?
})
}
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
quote! {
impl PrettyPrint for #type_ident {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented(#type_str)?;
writer.increase_indent();
match self {
#(#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() {
LeafStructMemberKind::String => Some("{}"),
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>()
.join(", ");
let format_string = format!("{}({})", leaf_struct_build_spec.build(), member_formatters);
let members = leaf_struct_build_spec
.members()
.map(|member| {
let member_ident = format_ident!("{}", member.name());
quote! {
self.#member_ident()
}
})
.collect::<Vec<_>>();
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,
StructChildSpec::VecChild(vec_child) => match vec_child.build() {
VecChildToBuild::Node(_) => {
let child_ident = format_ident!("{}", vec_child.name());
Some(quote! {
for child in self.#child_ident() {
child.pretty_print(writer)?;
}
})
}
VecChildToBuild::String => None,
},
StructChildSpec::MemberChild(member_child) => match member_child.build() {
MemberChildToBuild::Node(node_member_child) => {
let child_ident = format_ident!("{}", member_child.name());
if node_member_child.optional() {
Some(quote! {
if let Some(child) = self.#child_ident() {
child.pretty_print(writer)?;
}
})
} else {
Some(quote! {
self.#child_ident().pretty_print(writer)?;
})
}
}
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());
let type_string = struct_build_spec.build();
quote! {
impl PrettyPrint for #type_ident {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
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),
BuildSpec::LeafEnum(leaf_enum) => make_leaf_enum_p2_impl(leaf_enum),
BuildSpec::Polymorphic(polymorphic) => make_polymorphic_type_p2_impl(polymorphic),
BuildSpec::PolymorphicBuild(polymorphic_build) => {
make_polymorphic_build_p2_impl(polymorphic_build)
}
BuildSpec::PolymorphicEnum(polymorphic_enum) => {
make_polymorphic_enum_p2_impl(polymorphic_enum)
}
BuildSpec::Production(production) => make_production_p2_impl(production),
}
}

View File

@ -11,6 +11,7 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
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.rule()));
@ -77,6 +78,13 @@ 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

@ -4,6 +4,9 @@ pub enum BuildSpec {
Struct(StructBuildSpec), Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec), LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec), Production(ProductionBuildSpec),
Polymorphic(PolymorphicTypeBuildSpec),
PolymorphicBuild(PolymorphicBuildBuildSpec),
PolymorphicEnum(PolymorphicEnumBuildSpec),
} }
// Enum build spec // Enum build spec
@ -34,14 +37,14 @@ impl EnumBuildSpec {
pub struct EnumRule { pub struct EnumRule {
rule: String, rule: String,
child: Option<Box<EnumRuleChild>> child: Option<Box<EnumRuleChild>>,
} }
impl EnumRule { impl EnumRule {
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self { pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
Self { Self {
rule: rule.to_string(), rule: rule.to_string(),
child child,
} }
} }
@ -49,7 +52,7 @@ impl EnumRule {
pub fn rule(&self) -> &str { pub fn rule(&self) -> &str {
&self.rule &self.rule
} }
pub fn child(&self) -> Option<&EnumRuleChild> { pub fn child(&self) -> Option<&EnumRuleChild> {
if let Some(child) = &self.child { if let Some(child) = &self.child {
Some(child.as_ref()) Some(child.as_ref())
@ -60,14 +63,14 @@ impl EnumRule {
} }
pub struct EnumRuleChild { pub struct EnumRuleChild {
kind: Box<EnumRuleChildKind> kind: Box<EnumRuleChildKind>,
} }
impl EnumRuleChild { impl EnumRuleChild {
pub fn new(kind: Box<EnumRuleChildKind>) -> Self { pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
Self { kind } Self { kind }
} }
pub fn kind(&self) -> &EnumRuleChildKind { pub fn kind(&self) -> &EnumRuleChildKind {
&self.kind &self.kind
} }
@ -80,11 +83,11 @@ pub enum EnumRuleChildKind {
Double, Double,
USize, USize,
String, String,
Boolean Boolean,
} }
pub struct EnumRuleNodeChild { pub struct EnumRuleNodeChild {
build: String build: String,
} }
impl EnumRuleNodeChild { impl EnumRuleNodeChild {
@ -93,7 +96,7 @@ impl EnumRuleNodeChild {
build: build.to_string(), build: build.to_string(),
} }
} }
pub fn build(&self) -> &str { pub fn build(&self) -> &str {
&self.build &self.build
} }
@ -110,7 +113,7 @@ impl LeafEnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self { pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
rules rules,
} }
} }
@ -150,7 +153,7 @@ impl StructBuildSpec {
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self { pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
children children,
} }
} }
@ -158,7 +161,7 @@ impl StructBuildSpec {
pub fn build(&self) -> &str { pub fn build(&self) -> &str {
&self.build &self.build
} }
/// The children for this build spec. /// The children for this build spec.
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> { pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
self.children.iter().map(Box::as_ref) self.children.iter().map(Box::as_ref)
@ -229,7 +232,7 @@ impl VecChild {
#[derive(Debug)] #[derive(Debug)]
pub enum VecChildToBuild { pub enum VecChildToBuild {
Node(VecNodeChildToBuild), Node(VecNodeChildToBuild),
String String,
} }
#[derive(Debug)] #[derive(Debug)]
@ -239,7 +242,9 @@ pub struct VecNodeChildToBuild {
impl VecNodeChildToBuild { impl VecNodeChildToBuild {
pub fn new(build: &str) -> Self { pub fn new(build: &str) -> Self {
Self { build: build.to_string() } Self {
build: build.to_string(),
}
} }
/// The type to build, in Pascal case. /// The type to build, in Pascal case.
@ -294,11 +299,7 @@ pub struct NodeChildToBuild {
} }
impl NodeChildToBuild { impl NodeChildToBuild {
pub fn new( pub fn new(build: &str, or_else: Option<String>, optional: bool) -> Self {
build: &str,
or_else: Option<String>,
optional: bool,
) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
or_else, or_else,
@ -324,13 +325,13 @@ impl NodeChildToBuild {
#[derive(Debug)] #[derive(Debug)]
pub struct BooleanChildToBuild { pub struct BooleanChildToBuild {
name: String name: String,
} }
impl BooleanChildToBuild { impl BooleanChildToBuild {
pub fn new(name: &str) -> Self { pub fn new(name: &str) -> Self {
Self { Self {
name: name.to_string() name: name.to_string(),
} }
} }
@ -401,11 +402,11 @@ impl ProductionBuildSpec {
kind, kind,
} }
} }
pub fn rule(&self) -> &str { pub fn rule(&self) -> &str {
&self.rule &self.rule
} }
pub fn kind(&self) -> &ProductionKind { pub fn kind(&self) -> &ProductionKind {
&self.kind &self.kind
} }
@ -416,10 +417,256 @@ pub enum ProductionKind {
Long, Long,
Double, Double,
String(ProductionStringFrom), String(ProductionStringFrom),
Boolean Boolean,
Node(String),
} }
pub enum ProductionStringFrom { pub enum ProductionStringFrom {
StringInner, StringInner,
WholePair 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

@ -1,11 +1,116 @@
use crate::spec::{ use crate::spec::{
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec, AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec,
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind,
MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec,
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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 { fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
let children: Vec<TokenStream> = build_spec let children: Vec<TokenStream> = build_spec
.rules() .rules()
@ -348,5 +453,12 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
Some(make_leaf_struct_type(leaf_struct_build_spec)) Some(make_leaf_struct_type(leaf_struct_build_spec))
} }
BuildSpec::Production(_) => None, 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,
} }
} }

3
examples/forty_two.dm Normal file
View File

@ -0,0 +1,3 @@
fn main()
println 42
end

19
examples/worlds.dm Normal file
View File

@ -0,0 +1,19 @@
class World(pub name: String, pub color: String) end
fn getWorlds() -> List<World> = [
World('Mercury', 'Red'),
World('Earth', 'Blue'),
World('Jupiter', 'Orange')
]
fn findWorldByColor(worlds: List<World>, color: String) -> String
worlds.find { it.color == color }
.map { it.name }
.expect "No world has the given color ${color}"
end
fn main()
let worlds = getWorlds()
let blueWorld = findWorldByColor(worlds, 'Blue')
println "Hello, ${blueWorld}!"
end

View File

@ -45,14 +45,14 @@ pub mod node {
} }
pub mod build { pub mod build {
//noinspection RsUnusedImport use pest::iterators::Pairs;
use crate::parser::Rule;
//noinspection RsUnusedImport
use pest::iterators::Pair;
//noinspection RsUnusedImport
use crate::ast::node::*;
include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs")); include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs"));
pub fn build_ast(parsed_pairs: &mut Pairs<Rule>) -> Box<CompilationUnit> {
let compilation_unit_pair = parsed_pairs.next().unwrap();
Box::new(build_compilation_unit(compilation_unit_pair))
}
#[cfg(test)] #[cfg(test)]
mod build_tests { mod build_tests {
@ -102,5 +102,42 @@ pub mod build {
assert_eq!(backtick_string.inners().count(), 2); assert_eq!(backtick_string.inners().count(), 2);
assert_eq!(backtick_string.expressions().count(), 1); assert_eq!(backtick_string.expressions().count(), 1);
} }
#[test]
fn d_string_expression_simple() {
let pair = parse(Rule::DStringExpression, "${thing}");
let d_string_expression = build_d_string_expression(pair);
}
#[test]
fn d_string_inner() {
let pair = parse(Rule::DStringInner, "Hello!");
let d_string_inner = build_d_string_inner(pair);
assert_eq!("Hello!", d_string_inner);
}
#[test]
fn d_string_mixed() {
let pair = parse(Rule::DString, "\"Hello, ${world}!\"");
let d_string = build_d_string(pair);
assert_eq!(d_string.inners().count(), 2);
assert_eq!(d_string.expressions().count(), 1);
}
#[test]
fn expression_simple_call() {
let pair = parse(Rule::Expression, "hello(42)");
let expression = build_expression(pair);
}
} }
} }
pub mod pretty_print {
use crate::util::indent_writer::IndentWriter;
pub trait PrettyPrint {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()>;
}
include!(concat!(env!("OUT_DIR"), "/src/ast/pretty_print.rs"));
}

View File

@ -1,58 +1,55 @@
// mod name_analysis; // mod name_analysis;
// mod p3; mod p3;
// mod unparse; // mod unparse;
//
// use std::path::PathBuf; use std::path::PathBuf;
//
// use crate::name_analysis::name_analysis; // use crate::name_analysis::name_analysis;
// use crate::p3::pretty_print_parse; use crate::p3::pretty_print_parse;
// use crate::unparse::unparse; // use crate::unparse::unparse;
// use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
//
// #[derive(Debug, Parser)] #[derive(Debug, Parser)]
// #[command(name = "dmc")] #[command(name = "dmc")]
// #[command(about = "Deimos Compiler", long_about = None)] #[command(about = "Deimos Compiler", long_about = None)]
// struct Cli { struct Cli {
// #[command(subcommand)] #[command(subcommand)]
// command: Commands, command: Commands,
// } }
//
// #[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
// enum Commands { enum Commands {
// #[command(arg_required_else_help = true)] #[command(arg_required_else_help = true)]
// Unparse { Unparse {
// paths: Vec<PathBuf>, paths: Vec<PathBuf>,
// }, },
// P3 { P3 {
// paths: Vec<PathBuf>, paths: Vec<PathBuf>,
// }, },
// NameAnalysis { NameAnalysis {
// paths: Vec<PathBuf>, paths: Vec<PathBuf>,
// }, },
// } }
//
// fn main() {
// let args = Cli::parse();
// match args.command {
// Commands::Unparse { paths } => {
// for path in paths {
// unparse(&path);
// }
// }
// Commands::P3 { paths } => {
// for path in paths {
// pretty_print_parse(&path)
// }
// }
// Commands::NameAnalysis { paths } => {
// let result = name_analysis(&paths);
// if let Err(e) = result {
// eprintln!("{}", e)
// }
// }
// }
// }
fn main() { fn main() {
panic!("TODO") let args = Cli::parse();
match args.command {
// Commands::Unparse { paths } => {
// for path in paths {
// unparse(&path);
// }
// }
Commands::P3 { paths } => {
for path in paths {
pretty_print_parse(&path)
}
}
// Commands::NameAnalysis { paths } => {
// let result = name_analysis(&paths);
// if let Err(e) = result {
// eprintln!("{}", e)
// }
// }
_ => todo!()
}
} }

View File

@ -10,8 +10,7 @@ pub fn pretty_print_parse(path: &PathBuf) {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src); let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src);
match parse_result { match parse_result {
Ok(mut pairs) => { Ok(mut pairs) => {
let compilation_unit_pair = pairs.next().unwrap(); let compilation_unit = build_ast(&mut pairs);
let compilation_unit = build_ast(&path.display().to_string(), 0, compilation_unit_pair);
let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout())); let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
compilation_unit compilation_unit
.pretty_print(&mut indent_writer) .pretty_print(&mut indent_writer)

View File

@ -291,6 +291,9 @@ Class:
- class_level_declarations: - class_level_declarations:
rule: ClassLevelDeclaration rule: ClassLevelDeclaration
vec: true vec: true
- end_kw:
rule: End
skip: true
# Function constructs # Function constructs
Function: Function:
@ -305,6 +308,8 @@ Function:
skip: true skip: true
- generics: - generics:
rule: GenericParameters rule: GenericParameters
build:
or_else_default: true
- identifier - identifier
- parameters - parameters
- return_type: - return_type:
@ -564,53 +569,153 @@ ForStatement:
# Expressions # Expressions
Expression: Expression:
children: polymorphic_type:
- ternary_expression enum_members:
- Ternary:
inner:
kind: TernaryExpression
- Or:
inner:
kind: OrExpression
- And:
inner:
kind: AndExpression
- Comparison:
inner:
kind: ComparisonExpression
- Shift:
inner:
kind: ShiftExpression
- Additive:
inner:
kind: AdditiveExpression
- Multiplicative:
inner:
kind: MultiplicativeExpression
- Prefix:
inner:
kind: PrefixExpression
- Suffix:
inner:
kind: SuffixExpression
- Literal:
inner:
kind: Literal
- Fqn:
inner:
kind: FullyQualifiedName
- Closure:
inner:
kind: Closure
- List:
inner:
kind: ListExpression
build:
kind: TernaryExpression
TernaryExpression: TernaryExpression:
children: polymorphic_build:
- or_expression return_type: Expression
- ternary_alternatives: alternatives:
optional: true - test:
TernaryAlternatives: number_of_pairs: 1
children: action:
- ternary_true_alternative return_build:
- ternary_false_alternative kind: OrExpression
- test:
number_of_pairs: 3
action:
build:
enum_variant: Ternary
children:
- test:
kind: Expression
rule: OrExpression
- on_true:
kind: Expression
rule: TernaryTrueAlternative
- on_false:
kind: Expression
rule: TernaryFalseAlternative
TernaryTrueAlternative: TernaryTrueAlternative:
children: produce:
- expression kind:
node: Expression
TernaryFalseAlternative: TernaryFalseAlternative:
children: produce:
- expression kind:
node: Expression
OrExpression: OrExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: AndExpression alternatives:
- or_sym: - test:
rule: Or number_of_pairs: 1
skip: true action:
- right: return_build:
rule: Expression kind: AndExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: Or
children:
- left:
kind: Expression
rule: AndExpression
- or_sym:
rule: Or
skip: true
- right:
kind: Expression
rule: Expression
AndExpression: AndExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: ComparisonExpression alternatives:
- and_sym: - test:
rule: And number_of_pairs: 1
skip: true action:
- right: return_build:
rule: Expression kind: ComparisonExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: And
children:
- left:
kind: Expression
rule: ComparisonExpression
- and_sym:
rule: And
skip: true
- right:
kind: Expression
rule: Expression
ComparisonExpression: ComparisonExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: ShiftExpression alternatives:
- operator: - test:
rule: ComparisonOperator number_of_pairs: 1
optional: true action:
- right: return_build:
rule: Expression kind: ShiftExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: Comparison
children:
- left:
kind: Expression
rule: ShiftExpression
- operator:
kind: ComparisonOperator
rule: ComparisonOperator
- right:
kind: Expression
rule: Expression
ComparisonOperator: ComparisonOperator:
leaf_rules: leaf_rules:
- Greater - Greater
@ -620,64 +725,144 @@ ComparisonOperator:
- EqualTo - EqualTo
- NotEqualTo - NotEqualTo
ShiftExpression: ShiftExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: AdditiveExpression alternatives:
- operator: - test:
rule: ShiftOperator number_of_pairs: 1
optional: true action:
- right: return_build:
rule: Expression kind: AdditiveExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: Shift
children:
- left:
kind: Expression
rule: AdditiveExpression
- operator:
kind: ShiftOperator
rule: ShiftOperator
- right:
kind: Expression
rule: Expression
ShiftOperator: ShiftOperator:
leaf_rules: leaf_rules:
- LeftShift - LeftShift
- RightShift - RightShift
AdditiveExpression: AdditiveExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: MultiplicativeExpression alternatives:
- operator: - test:
rule: AdditiveOperator number_of_pairs: 1
optional: true action:
- right: return_build:
rule: Expression kind: MultiplicativeExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: Additive
children:
- left:
kind: Expression
rule: MultiplicativeExpression
- operator:
kind: AdditiveOperator
rule: AdditiveOperator
- right:
kind: Expression
rule: Expression
AdditiveOperator: AdditiveOperator:
leaf_rules: leaf_rules:
- Add - Add
- Subtract - Subtract
MultiplicativeExpression: MultiplicativeExpression:
children: polymorphic_build:
- left: return_type: Expression
rule: PrefixExpression alternatives:
- operator: - test:
rule: MultiplicativeOperator number_of_pairs: 1
optional: true action:
- right: return_build:
rule: Expression kind: PrefixExpression
optional: true - test:
number_of_pairs: 3
action:
build:
enum_variant: Multiplicative
children:
- left:
kind: Expression
rule: PrefixExpression
- operator:
kind: MultiplicativeOperator
rule: MultiplicativeOperator
- right:
kind: Expression
rule: Expression
MultiplicativeOperator: MultiplicativeOperator:
leaf_rules: leaf_rules:
- Multiply - Multiply
- Divide - Divide
- Modulo - Modulo
PrefixExpression: PrefixExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: SuffixExpression
- test:
number_of_pairs: 2
action:
build:
enum_variant: Prefix
children:
- prefix_operators:
kind: PrefixOperators
rule: PrefixOperators
- right:
kind: Expression
rule: SuffixExpression
PrefixOperators:
children: children:
- operators: - operators:
rule: PrefixOperator rule: PrefixOperator
vec: true vec: true
- right:
rule: SuffixExpression
PrefixOperator: PrefixOperator:
leaf_rules: leaf_rules:
- Spread - Spread
- Not - Not
- Negative - Negative
SuffixExpression: SuffixExpression:
polymorphic_build:
return_type: Expression
alternatives:
- test:
number_of_pairs: 1
action:
return_build:
kind: PrimaryExpression
- test:
number_of_pairs: 2
action:
build:
enum_variant: Suffix
children:
- left:
kind: Expression
rule: PrimaryExpression
- suffix_operators:
kind: SuffixOperators
rule: SuffixOperators
SuffixOperators:
children: children:
- left:
rule: PrimaryExpression
- operators: - operators:
rule: SuffixOperator rule: SuffixOperator
vec: true vec: true
@ -697,11 +882,27 @@ ObjectIndex:
children: children:
- expression - expression
PrimaryExpression: PrimaryExpression:
rules: polymorphic_enum:
- Literal return_type: Expression
- FullyQualifiedName rules:
- Closure - Literal:
- ParenthesizedExpression wrap:
enum_variant: Literal
- FullyQualifiedName:
wrap:
enum_variant: Fqn
- Closure:
wrap:
enum_variant: Closure
- ListExpression:
wrap:
enum_variant: List
- ParenthesizedExpression:
return_build:
kind: Expression
ListExpression:
children:
- expression_list
ParenthesizedExpression: ParenthesizedExpression:
children: children:
- expression - expression

View File

@ -596,40 +596,52 @@ Expression = {
TernaryExpression = { TernaryExpression = {
OrExpression OrExpression
~ ( TernaryAlternatives )? ~ TernaryRhs*
} }
TernaryAlternatives = { TernaryRhs = {
TernaryTrueAlternative TernaryTrueAlternative
~ TernaryFalseAlternative ~ TernaryFalseAlternative
} }
TernaryTrueAlternative = { TernaryTrueAlternative = {
"?" "?"
~ Expression ~ OrExpression
} }
TernaryFalseAlternative = { TernaryFalseAlternative = {
":" ":"
~ Expression ~ OrExpression
} }
OrExpression = { OrExpression = {
AndExpression AndExpression
~ ( Or ~ Expression )? ~ OrRhs*
}
OrRhs = {
Or
~ AndExpression
} }
AndExpression = { AndExpression = {
ComparisonExpression ComparisonExpression
~ ( And ~ Expression )? ~ AndRhs*
}
AndRhs = {
And
~ ComparisonExpression
} }
ComparisonExpression = { ComparisonExpression = {
ShiftExpression ShiftExpression
~ ( ~ ComparisonRhs*
ComparisonOperator }
~ Expression
)? ComparisonRhs = {
ComparisonOperator
~ Expression
} }
ComparisonOperator = { ComparisonOperator = {
@ -643,10 +655,12 @@ ComparisonOperator = {
ShiftExpression = { ShiftExpression = {
AdditiveExpression AdditiveExpression
~ ( ~ ShiftRhs*
ShiftOperator }
~ Expression
)? ShiftRhs = {
ShiftOperator
~ AdditiveExpression
} }
ShiftOperator = { ShiftOperator = {
@ -656,10 +670,12 @@ ShiftOperator = {
AdditiveExpression = { AdditiveExpression = {
MultiplicativeExpression MultiplicativeExpression
~ ( ~ AdditiveRhs*
AdditiveOperator }
~ Expression
)? AdditiveRhs = {
AdditiveOperator
~ MultiplicativeExpression
} }
AdditiveOperator = { AdditiveOperator = {
@ -669,10 +685,12 @@ AdditiveOperator = {
MultiplicativeExpression = { MultiplicativeExpression = {
PrefixExpression PrefixExpression
~ ( ~ MultiplicativeRhs*
MultiplicativeOperator }
~ Expression
)? MultiplicativeRhs = {
MultiplicativeOperator
~ PrefixExpression
} }
MultiplicativeOperator = { MultiplicativeOperator = {
@ -682,10 +700,14 @@ MultiplicativeOperator = {
} }
PrefixExpression = { PrefixExpression = {
PrefixOperator* PrefixOperators?
~ SuffixExpression ~ SuffixExpression
} }
PrefixOperators = {
PrefixOperator+
}
PrefixOperator = { PrefixOperator = {
Spread Spread
| Not | Not
@ -694,7 +716,11 @@ PrefixOperator = {
SuffixExpression = { SuffixExpression = {
PrimaryExpression PrimaryExpression
~ SuffixOperator* ~ SuffixOperators?
}
SuffixOperators = {
SuffixOperator+
} }
SuffixOperator = { SuffixOperator = {
@ -720,9 +746,16 @@ PrimaryExpression = {
Literal Literal
| FullyQualifiedName | FullyQualifiedName
| Closure | Closure
| ListExpression
| ParenthesizedExpression | ParenthesizedExpression
} }
ListExpression = {
"["
~ ExpressionList?
~ "]"
}
ParenthesizedExpression = { ParenthesizedExpression = {
"(" "("
~ Expression ~ Expression