Compare commits
12 Commits
2dd3bf5a06
...
fe2fff5882
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe2fff5882 | ||
|
|
e795664a09 | ||
|
|
49a96eba85 | ||
|
|
9e3d71d73b | ||
|
|
5ff14f9dea | ||
|
|
522869371e | ||
|
|
11f97a2174 | ||
|
|
26cb28307c | ||
|
|
cce927d964 | ||
|
|
7399a8748c | ||
|
|
a7eabae3e3 | ||
|
|
c94a698a52 |
@ -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,21 +18,132 @@ 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() {
|
||||
"int" => ProductionKind::Int,
|
||||
"long" => ProductionKind::Long,
|
||||
"double" => ProductionKind::Double,
|
||||
"boolean" => ProductionKind::Boolean,
|
||||
"string" => {
|
||||
let from = match production_yaml["from"].as_str().unwrap() {
|
||||
"string_inner" => ProductionStringFrom::StringInner,
|
||||
"whole_pair" => ProductionStringFrom::WholePair,
|
||||
_ => panic!("invalid from: {}", production_yaml["from"].as_str().unwrap()),
|
||||
};
|
||||
ProductionKind::String(from)
|
||||
},
|
||||
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()),
|
||||
let kind = if production_yaml["kind"].is_hash() {
|
||||
let node = production_yaml["kind"]["node"].as_str().unwrap();
|
||||
ProductionKind::Node(node.to_string())
|
||||
} else {
|
||||
match production_yaml["kind"].as_str().unwrap() {
|
||||
"int" => ProductionKind::Int,
|
||||
"long" => ProductionKind::Long,
|
||||
"double" => ProductionKind::Double,
|
||||
"boolean" => ProductionKind::Boolean,
|
||||
"string" => {
|
||||
let from = match production_yaml["from"].as_str().unwrap() {
|
||||
"string_inner" => ProductionStringFrom::StringInner,
|
||||
"whole_pair" => ProductionStringFrom::WholePair,
|
||||
_ => panic!(
|
||||
"invalid from: {}",
|
||||
production_yaml["from"].as_str().unwrap()
|
||||
),
|
||||
};
|
||||
ProductionKind::String(from)
|
||||
}
|
||||
_ => panic!(
|
||||
"invalid kind: {}",
|
||||
production_yaml["kind"].as_str().unwrap()
|
||||
),
|
||||
}
|
||||
};
|
||||
ProductionBuildSpec::new(rule, kind)
|
||||
}
|
||||
@ -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."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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),
|
||||
]
|
||||
}
|
||||
|
||||
134
ast-generator/src/polymorphic_build_build_fn.rs
Normal file
134
ast-generator/src/polymorphic_build_build_fn.rs
Normal 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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
ast-generator/src/polymorphic_build_fn.rs
Normal file
18
ast-generator/src/polymorphic_build_fn.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
42
ast-generator/src/polymorphic_enum_build_fn.rs
Normal file
42
ast-generator/src/polymorphic_enum_build_fn.rs
Normal 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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
256
ast-generator/src/pretty_print.rs
Normal file
256
ast-generator/src/pretty_print.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
@ -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! {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
3
examples/forty_two.dm
Normal file
@ -0,0 +1,3 @@
|
||||
fn main()
|
||||
println 42
|
||||
end
|
||||
19
examples/worlds.dm
Normal file
19
examples/worlds.dm
Normal 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
|
||||
@ -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"));
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
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() {
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
@ -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:
|
||||
children:
|
||||
- or_expression
|
||||
- ternary_alternatives:
|
||||
optional: true
|
||||
TernaryAlternatives:
|
||||
children:
|
||||
- ternary_true_alternative
|
||||
- ternary_false_alternative
|
||||
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:
|
||||
- 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:
|
||||
children:
|
||||
- left:
|
||||
rule: AndExpression
|
||||
- or_sym:
|
||||
rule: Or
|
||||
skip: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
AndExpression:
|
||||
children:
|
||||
- left:
|
||||
rule: ComparisonExpression
|
||||
- and_sym:
|
||||
rule: And
|
||||
skip: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
ComparisonExpression:
|
||||
children:
|
||||
- left:
|
||||
rule: ShiftExpression
|
||||
- operator:
|
||||
rule: ComparisonOperator
|
||||
optional: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
- right:
|
||||
kind: Expression
|
||||
rule: Expression
|
||||
ComparisonOperator:
|
||||
leaf_rules:
|
||||
- Greater
|
||||
@ -620,64 +725,144 @@ ComparisonOperator:
|
||||
- EqualTo
|
||||
- NotEqualTo
|
||||
ShiftExpression:
|
||||
children:
|
||||
- left:
|
||||
rule: AdditiveExpression
|
||||
- operator:
|
||||
rule: ShiftOperator
|
||||
optional: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
- right:
|
||||
kind: Expression
|
||||
rule: Expression
|
||||
ShiftOperator:
|
||||
leaf_rules:
|
||||
- LeftShift
|
||||
- RightShift
|
||||
AdditiveExpression:
|
||||
children:
|
||||
- left:
|
||||
rule: MultiplicativeExpression
|
||||
- operator:
|
||||
rule: AdditiveOperator
|
||||
optional: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
- right:
|
||||
kind: Expression
|
||||
rule: Expression
|
||||
AdditiveOperator:
|
||||
leaf_rules:
|
||||
- Add
|
||||
- Subtract
|
||||
MultiplicativeExpression:
|
||||
children:
|
||||
- left:
|
||||
rule: PrefixExpression
|
||||
- operator:
|
||||
rule: MultiplicativeOperator
|
||||
optional: true
|
||||
- right:
|
||||
rule: Expression
|
||||
optional: true
|
||||
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
|
||||
- right:
|
||||
kind: Expression
|
||||
rule: Expression
|
||||
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:
|
||||
- left:
|
||||
rule: PrimaryExpression
|
||||
- operators:
|
||||
rule: SuffixOperator
|
||||
vec: true
|
||||
@ -697,11 +882,27 @@ ObjectIndex:
|
||||
children:
|
||||
- expression
|
||||
PrimaryExpression:
|
||||
rules:
|
||||
- Literal
|
||||
- FullyQualifiedName
|
||||
- Closure
|
||||
- ParenthesizedExpression
|
||||
polymorphic_enum:
|
||||
return_type: Expression
|
||||
rules:
|
||||
- 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
|
||||
|
||||
@ -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
|
||||
~ (
|
||||
ComparisonOperator
|
||||
~ Expression
|
||||
)?
|
||||
~ ComparisonRhs*
|
||||
}
|
||||
|
||||
ComparisonRhs = {
|
||||
ComparisonOperator
|
||||
~ Expression
|
||||
}
|
||||
|
||||
ComparisonOperator = {
|
||||
@ -643,10 +655,12 @@ ComparisonOperator = {
|
||||
|
||||
ShiftExpression = {
|
||||
AdditiveExpression
|
||||
~ (
|
||||
ShiftOperator
|
||||
~ Expression
|
||||
)?
|
||||
~ ShiftRhs*
|
||||
}
|
||||
|
||||
ShiftRhs = {
|
||||
ShiftOperator
|
||||
~ AdditiveExpression
|
||||
}
|
||||
|
||||
ShiftOperator = {
|
||||
@ -656,10 +670,12 @@ ShiftOperator = {
|
||||
|
||||
AdditiveExpression = {
|
||||
MultiplicativeExpression
|
||||
~ (
|
||||
AdditiveOperator
|
||||
~ Expression
|
||||
)?
|
||||
~ AdditiveRhs*
|
||||
}
|
||||
|
||||
AdditiveRhs = {
|
||||
AdditiveOperator
|
||||
~ MultiplicativeExpression
|
||||
}
|
||||
|
||||
AdditiveOperator = {
|
||||
@ -669,10 +685,12 @@ AdditiveOperator = {
|
||||
|
||||
MultiplicativeExpression = {
|
||||
PrefixExpression
|
||||
~ (
|
||||
MultiplicativeOperator
|
||||
~ Expression
|
||||
)?
|
||||
~ MultiplicativeRhs*
|
||||
}
|
||||
|
||||
MultiplicativeRhs = {
|
||||
MultiplicativeOperator
|
||||
~ 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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user