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 yaml_rust2::{Yaml, YamlLoader};
@ -18,8 +18,112 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
(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 = match production_yaml["kind"].as_str().unwrap() {
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,
@ -28,11 +132,18 @@ fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> Production
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()),
_ => panic!(
"invalid from: {}",
production_yaml["from"].as_str().unwrap()
),
};
ProductionKind::String(from)
},
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()),
}
_ => panic!(
"invalid kind: {}",
production_yaml["kind"].as_str().unwrap()
),
}
};
ProductionBuildSpec::new(rule, kind)
}
@ -46,9 +157,7 @@ fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
.as_vec()
.unwrap()
.iter()
.map(|rule_yaml| {
deserialize_leaf_enum_rule(rule_yaml)
})
.map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
.collect()
}
@ -63,16 +172,19 @@ fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleC
"usize" => EnumRuleChildKind::USize,
"string" => EnumRuleChildKind::String,
"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))))
}
}
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
Box::new(EnumRuleChild::new(Box::new(
EnumRuleChildKind::Node(EnumRuleNodeChild::new(rule)),
)))
Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
EnumRuleNodeChild::new(rule),
))))
}
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);
Box::new(EnumRule::new(
&rule,
deserialize_enum_rule_custom_child(rule_props)
deserialize_enum_rule_custom_child(rule_props),
))
} else {
let rule_as_str = rule_yaml.as_str().unwrap();
@ -164,7 +276,9 @@ fn deserialize_member_child_to_build(
}
} else {
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"]);
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
} else if build_spec["produce"].is_hash() {
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
BuildSpec::Production(deserialize_production_spec(
build_spec_name,
&build_spec["produce"],
))
} else 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, 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 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 production_build_fn;
mod spec;
mod struct_build_fn;
@ -11,6 +15,10 @@ mod util;
use crate::enum_build_fn::make_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::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;
@ -38,7 +46,25 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
);
}
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);
@ -85,9 +111,31 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
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<_>>();
let combined = quote! {
//noinspection RsUnusedImport
use crate::parser::Rule;
//noinspection RsUnusedImport
use pest::iterators::Pair;
//noinspection RsUnusedImport
use crate::ast::node::*;
#(#build_fns)*
};
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> {
vec![
generate_build_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::String(_) => format_ident!("String"),
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()));
@ -77,6 +78,13 @@ pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) ->
ProductionKind::Boolean => quote! {
#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! {

View File

@ -4,6 +4,9 @@ pub enum BuildSpec {
Struct(StructBuildSpec),
LeafStruct(LeafStructBuildSpec),
Production(ProductionBuildSpec),
Polymorphic(PolymorphicTypeBuildSpec),
PolymorphicBuild(PolymorphicBuildBuildSpec),
PolymorphicEnum(PolymorphicEnumBuildSpec),
}
// Enum build spec
@ -34,14 +37,14 @@ impl EnumBuildSpec {
pub struct EnumRule {
rule: String,
child: Option<Box<EnumRuleChild>>
child: Option<Box<EnumRuleChild>>,
}
impl EnumRule {
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
Self {
rule: rule.to_string(),
child
child,
}
}
@ -60,7 +63,7 @@ impl EnumRule {
}
pub struct EnumRuleChild {
kind: Box<EnumRuleChildKind>
kind: Box<EnumRuleChildKind>,
}
impl EnumRuleChild {
@ -80,11 +83,11 @@ pub enum EnumRuleChildKind {
Double,
USize,
String,
Boolean
Boolean,
}
pub struct EnumRuleNodeChild {
build: String
build: String,
}
impl EnumRuleNodeChild {
@ -110,7 +113,7 @@ impl LeafEnumBuildSpec {
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
Self {
build: build.to_string(),
rules
rules,
}
}
@ -150,7 +153,7 @@ impl StructBuildSpec {
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
Self {
build: build.to_string(),
children
children,
}
}
@ -229,7 +232,7 @@ impl VecChild {
#[derive(Debug)]
pub enum VecChildToBuild {
Node(VecNodeChildToBuild),
String
String,
}
#[derive(Debug)]
@ -239,7 +242,9 @@ pub struct VecNodeChildToBuild {
impl VecNodeChildToBuild {
pub fn new(build: &str) -> Self {
Self { build: build.to_string() }
Self {
build: build.to_string(),
}
}
/// The type to build, in Pascal case.
@ -294,11 +299,7 @@ pub struct NodeChildToBuild {
}
impl NodeChildToBuild {
pub fn new(
build: &str,
or_else: Option<String>,
optional: bool,
) -> Self {
pub fn new(build: &str, or_else: Option<String>, optional: bool) -> Self {
Self {
build: build.to_string(),
or_else,
@ -324,13 +325,13 @@ impl NodeChildToBuild {
#[derive(Debug)]
pub struct BooleanChildToBuild {
name: String
name: String,
}
impl BooleanChildToBuild {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string()
name: name.to_string(),
}
}
@ -416,10 +417,256 @@ pub enum ProductionKind {
Long,
Double,
String(ProductionStringFrom),
Boolean
Boolean,
Node(String),
}
pub enum ProductionStringFrom {
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::{
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
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()
@ -348,5 +453,12 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
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,
}
}

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,15 +45,15 @@ pub mod node {
}
pub mod build {
//noinspection RsUnusedImport
use crate::parser::Rule;
//noinspection RsUnusedImport
use pest::iterators::Pair;
//noinspection RsUnusedImport
use crate::ast::node::*;
use pest::iterators::Pairs;
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)]
mod build_tests {
use super::*;
@ -102,5 +102,42 @@ pub mod build {
assert_eq!(backtick_string.inners().count(), 2);
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 p3;
mod p3;
// mod unparse;
//
// use std::path::PathBuf;
//
use std::path::PathBuf;
// use crate::name_analysis::name_analysis;
// use crate::p3::pretty_print_parse;
use crate::p3::pretty_print_parse;
// use crate::unparse::unparse;
// use clap::{Parser, Subcommand};
//
// #[derive(Debug, Parser)]
// #[command(name = "dmc")]
// #[command(about = "Deimos Compiler", long_about = None)]
// struct Cli {
// #[command(subcommand)]
// command: Commands,
// }
//
// #[derive(Debug, Subcommand)]
// enum Commands {
// #[command(arg_required_else_help = true)]
// Unparse {
// paths: Vec<PathBuf>,
// },
// P3 {
// paths: Vec<PathBuf>,
// },
// NameAnalysis {
// paths: Vec<PathBuf>,
// },
// }
//
// fn main() {
// let args = Cli::parse();
// match args.command {
use clap::{Parser, Subcommand};
#[derive(Debug, Parser)]
#[command(name = "dmc")]
#[command(about = "Deimos Compiler", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
#[command(arg_required_else_help = true)]
Unparse {
paths: Vec<PathBuf>,
},
P3 {
paths: Vec<PathBuf>,
},
NameAnalysis {
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::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() {
panic!("TODO")
_ => todo!()
}
}

View File

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

View File

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

View File

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