New deserialization code.
This commit is contained in:
parent
0f64fee5ef
commit
63643d86ba
13
ast-generator/src/deserialize/leaf_enum_spec.rs
Normal file
13
ast-generator/src/deserialize/leaf_enum_spec.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use yaml_rust2::Yaml;
|
||||||
|
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
||||||
|
|
||||||
|
pub fn deserialize_leaf_enum(name: &str, props: &Yaml) -> LeafEnumBuildSpec {
|
||||||
|
let rules = props["rules"].as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|rule_yaml| {
|
||||||
|
rule_yaml.as_str().unwrap().to_string()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
LeafEnumBuildSpec::new(name, rules)
|
||||||
|
}
|
||||||
21
ast-generator/src/deserialize/leaf_struct_spec.rs
Normal file
21
ast-generator/src/deserialize/leaf_struct_spec.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::deserialize::util::unwrap_single_member_hash;
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind};
|
||||||
|
|
||||||
|
fn deserialize_member(member_name: &str) -> LeafStructMember {
|
||||||
|
LeafStructMember::new(member_name, LeafStructMemberKind::String)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_leaf_struct(name: &str, props: &Yaml) -> LeafStructBuildSpec {
|
||||||
|
let members = props["members"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|member_hash| {
|
||||||
|
let (member_name, _props) = unwrap_single_member_hash(member_hash);
|
||||||
|
deserialize_member(&member_name)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
LeafStructBuildSpec::new(name, members)
|
||||||
|
}
|
||||||
@ -1,451 +1,67 @@
|
|||||||
use crate::spec::{
|
mod leaf_enum_spec;
|
||||||
AlternativeAction, AlternativeBuild, AlternativeBuildChild, AlternativeChild, AlternativeTest,
|
mod leaf_struct_spec;
|
||||||
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind,
|
mod node_production_spec;
|
||||||
EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember,
|
mod polymorphic_enum_loop_spec;
|
||||||
LeafStructMemberKind, MemberChild, MemberChildToBuild, NameAndKind, NodeChildToBuild,
|
mod polymorphic_type_spec;
|
||||||
PolymorphicBuildAlternative, PolymorphicBuildBuildSpec, PolymorphicEnumBuildSpec,
|
mod production_spec;
|
||||||
PolymorphicEnumMember, PolymorphicEnumRule, PolymorphicTypeBuildSpec, ProductionBuildSpec,
|
mod struct_spec;
|
||||||
ProductionKind, ProductionNodeKind, ProductionStringFrom, SkipChild, StructBuildSpec,
|
mod tree_enum_spec;
|
||||||
StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild,
|
pub(crate) mod util;
|
||||||
};
|
|
||||||
use crate::util::make_build_fn_name;
|
use crate::deserialize::leaf_enum_spec::deserialize_leaf_enum;
|
||||||
use convert_case::{Case, Casing};
|
use crate::deserialize::leaf_struct_spec::deserialize_leaf_struct;
|
||||||
|
use crate::deserialize::node_production_spec::deserialize_node_production;
|
||||||
|
use crate::deserialize::polymorphic_enum_loop_spec::deserialize_polymorphic_enum_loop;
|
||||||
|
use crate::deserialize::polymorphic_type_spec::deserialize_polymorphic_type;
|
||||||
|
use crate::deserialize::production_spec::deserialize_production;
|
||||||
|
use crate::deserialize::struct_spec::deserialize_struct_spec;
|
||||||
|
use crate::deserialize::tree_enum_spec::deserialize_tree_enum;
|
||||||
|
use crate::spec::BuildSpec;
|
||||||
use yaml_rust2::{Yaml, YamlLoader};
|
use yaml_rust2::{Yaml, YamlLoader};
|
||||||
|
|
||||||
fn get_as_bool(yaml: &Yaml) -> bool {
|
|
||||||
yaml.as_bool().unwrap_or_else(|| false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
|
||||||
let as_hash = hash.as_hash().unwrap();
|
|
||||||
if as_hash.is_empty() {
|
|
||||||
panic!("empty hash");
|
|
||||||
} else if as_hash.len() > 1 {
|
|
||||||
panic!("hash contains more than one key");
|
|
||||||
}
|
|
||||||
let (member_key, member_value) = as_hash.iter().collect::<Vec<(&Yaml, &Yaml)>>()[0];
|
|
||||||
let key_as_string = member_key.as_str().unwrap().to_string();
|
|
||||||
(key_as_string, member_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_polymorphic_enum_build_spec(
|
|
||||||
name: &str,
|
|
||||||
build_spec: &Yaml,
|
|
||||||
) -> PolymorphicEnumBuildSpec {
|
|
||||||
let return_type = build_spec["return_type"].as_str().unwrap();
|
|
||||||
let rules = build_spec["rules"]
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|rule_yaml| {
|
|
||||||
let (rule_name, props) = unwrap_single_member_hash(rule_yaml);
|
|
||||||
if props["wrap"].is_hash() {
|
|
||||||
PolymorphicEnumRule::Wrap(NameAndKind::new(
|
|
||||||
&rule_name,
|
|
||||||
props["wrap"]["enum_variant"].as_str().unwrap(),
|
|
||||||
))
|
|
||||||
} else if props["return_build"].is_hash() {
|
|
||||||
PolymorphicEnumRule::ReturnBuild(NameAndKind::new(
|
|
||||||
&rule_name,
|
|
||||||
props["return_build"]["kind"].as_str().unwrap(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(Box::new)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
PolymorphicEnumBuildSpec::new(name, return_type, rules)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_polymorphic_action(action_yaml: &Yaml) -> AlternativeAction {
|
|
||||||
if action_yaml["return_build"].is_hash() {
|
|
||||||
let kind = action_yaml["return_build"]["kind"].as_str().unwrap();
|
|
||||||
AlternativeAction::ReturnBuild(kind.to_string())
|
|
||||||
} else if action_yaml["build"].is_hash() {
|
|
||||||
let build_children = action_yaml["build"]["children"]
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|child_yaml| {
|
|
||||||
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
|
|
||||||
if get_as_bool(&child_props["skip"]) {
|
|
||||||
AlternativeChild::Skip
|
|
||||||
} else {
|
|
||||||
let kind = child_props["kind"].as_str().unwrap();
|
|
||||||
let rule = child_props["rule"].as_str().unwrap();
|
|
||||||
AlternativeChild::Build(AlternativeBuildChild::new(&child_name, kind, rule))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(Box::new)
|
|
||||||
.collect();
|
|
||||||
let enum_variant = action_yaml["build"]["enum_variant"].as_str().unwrap();
|
|
||||||
let build = AlternativeBuild::new(enum_variant, build_children);
|
|
||||||
AlternativeAction::Build(build)
|
|
||||||
} else {
|
|
||||||
panic!("return_build or build is required for an alternative")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_polymorphic_build_build_spec(
|
|
||||||
name: &str,
|
|
||||||
polymorphic_build_yaml: &Yaml,
|
|
||||||
) -> PolymorphicBuildBuildSpec {
|
|
||||||
let return_type = polymorphic_build_yaml["return_type"].as_str().unwrap();
|
|
||||||
let alternatives = polymorphic_build_yaml["alternatives"]
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|alternative_yaml| {
|
|
||||||
let number_of_pairs = alternative_yaml["test"]["number_of_pairs"]
|
|
||||||
.as_i64()
|
|
||||||
.unwrap();
|
|
||||||
let action = deserialize_polymorphic_action(&alternative_yaml["action"]);
|
|
||||||
PolymorphicBuildAlternative::new(
|
|
||||||
AlternativeTest::NumberOfPairs(number_of_pairs),
|
|
||||||
action,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(Box::new)
|
|
||||||
.collect();
|
|
||||||
PolymorphicBuildBuildSpec::new(name, return_type, alternatives)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_polymorphic_enum_members(
|
|
||||||
enum_members_yaml: &Yaml,
|
|
||||||
) -> Vec<Box<PolymorphicEnumMember>> {
|
|
||||||
enum_members_yaml
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|enum_member_yaml| {
|
|
||||||
let (member_name, member_hash) = unwrap_single_member_hash(enum_member_yaml);
|
|
||||||
let inner_kind = member_hash["inner"]["kind"].as_str().unwrap();
|
|
||||||
PolymorphicEnumMember::new(&member_name, inner_kind)
|
|
||||||
})
|
|
||||||
.map(Box::new)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicTypeBuildSpec {
|
|
||||||
let enum_members = deserialize_polymorphic_enum_members(&spec_props["enum_members"]);
|
|
||||||
let build_kind = spec_props["build"]["kind"].as_str().unwrap();
|
|
||||||
PolymorphicTypeBuildSpec::new(name, enum_members, build_kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
|
||||||
let kind = if production_yaml["node"].is_hash() {
|
|
||||||
let kind = production_yaml["node"]["kind"].as_str().unwrap();
|
|
||||||
let with = production_yaml["node"]["with"].as_str().unwrap();
|
|
||||||
ProductionKind::Node(ProductionNodeKind::new(kind, with))
|
|
||||||
} else {
|
|
||||||
match production_yaml["kind"].as_str().unwrap() {
|
|
||||||
"int" => ProductionKind::Int,
|
|
||||||
"long" => ProductionKind::Long,
|
|
||||||
"double" => ProductionKind::Double,
|
|
||||||
"boolean" => ProductionKind::Boolean,
|
|
||||||
"string" => {
|
|
||||||
let from = match production_yaml["from"].as_str().unwrap() {
|
|
||||||
"string_inner" => ProductionStringFrom::StringInner,
|
|
||||||
"whole_pair" => ProductionStringFrom::WholePair,
|
|
||||||
_ => panic!(
|
|
||||||
"invalid from: {}",
|
|
||||||
production_yaml["from"].as_str().unwrap()
|
|
||||||
),
|
|
||||||
};
|
|
||||||
ProductionKind::String(from)
|
|
||||||
}
|
|
||||||
_ => panic!(
|
|
||||||
"invalid kind: {}",
|
|
||||||
production_yaml["kind"].as_str().unwrap()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ProductionBuildSpec::new(rule, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_leaf_enum_rule(rule_yaml: &Yaml) -> Box<LeafEnumRule> {
|
|
||||||
Box::new(LeafEnumRule::new(rule_yaml.as_str().unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec<Box<LeafEnumRule>> {
|
|
||||||
rules_yaml
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|rule_yaml| deserialize_leaf_enum_rule(rule_yaml))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> {
|
|
||||||
if !rule_props["child"].as_bool().unwrap_or(true) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let kind = match rule_props["kind"].as_str().unwrap() {
|
|
||||||
"int" => EnumRuleChildKind::Int,
|
|
||||||
"long" => EnumRuleChildKind::Long,
|
|
||||||
"double" => EnumRuleChildKind::Double,
|
|
||||||
"usize" => EnumRuleChildKind::USize,
|
|
||||||
"string" => EnumRuleChildKind::String,
|
|
||||||
"boolean" => EnumRuleChildKind::Boolean,
|
|
||||||
_ => panic!(
|
|
||||||
"unsupported enum rule kind: {}",
|
|
||||||
rule_props["kind"].as_str().unwrap()
|
|
||||||
),
|
|
||||||
};
|
|
||||||
Some(Box::new(EnumRuleChild::new(Box::new(kind))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_enum_rule_node_child(rule: &str) -> Box<EnumRuleChild> {
|
|
||||||
Box::new(EnumRuleChild::new(Box::new(EnumRuleChildKind::Node(
|
|
||||||
EnumRuleNodeChild::new(rule),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box<EnumRule> {
|
|
||||||
if rule_yaml.is_hash() {
|
|
||||||
let (rule, rule_props) = unwrap_single_member_hash(rule_yaml);
|
|
||||||
Box::new(EnumRule::new(
|
|
||||||
&rule,
|
|
||||||
deserialize_enum_rule_custom_child(rule_props),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
let rule_as_str = rule_yaml.as_str().unwrap();
|
|
||||||
Box::new(EnumRule::new(
|
|
||||||
rule_as_str,
|
|
||||||
Some(deserialize_enum_rule_node_child(rule_as_str)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_enum_rules(rules_yaml: &Yaml) -> Vec<Box<EnumRule>> {
|
|
||||||
rules_yaml
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|rule_yaml| deserialize_enum_rule(rule_yaml))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_leaf_struct_member(name: &str, props: &Yaml) -> Box<LeafStructMember> {
|
|
||||||
let kind = props["kind"].as_str().unwrap();
|
|
||||||
if kind == "string" {
|
|
||||||
Box::new(LeafStructMember::new(name, LeafStructMemberKind::String))
|
|
||||||
} else {
|
|
||||||
panic!("invalid member kind: {}", kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_leaf_struct_members(members_yaml: &Yaml) -> Vec<Box<LeafStructMember>> {
|
|
||||||
members_yaml
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|member| {
|
|
||||||
let (member_name, member_props) = unwrap_single_member_hash(member);
|
|
||||||
deserialize_leaf_struct_member(&member_name, member_props)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_member_node_to_build(
|
|
||||||
rule: &str,
|
|
||||||
build_props: &Yaml,
|
|
||||||
optional: bool,
|
|
||||||
) -> Box<MemberChildToBuild> {
|
|
||||||
let or_else = build_props["or_else"]
|
|
||||||
.as_str()
|
|
||||||
.or_else(|| {
|
|
||||||
if get_as_bool(&build_props["or_else_default"]) {
|
|
||||||
Some("default")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(ToString::to_string);
|
|
||||||
|
|
||||||
let kind = build_props["kind"]
|
|
||||||
.as_str()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.unwrap_or_else(|| make_build_fn_name(rule));
|
|
||||||
|
|
||||||
let with = build_props["with"]
|
|
||||||
.as_str()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.unwrap_or_else(|| make_build_fn_name(rule));
|
|
||||||
|
|
||||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
|
|
||||||
&kind, &with, or_else, optional,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_member_boolean_to_build(name: &str) -> Box<MemberChildToBuild> {
|
|
||||||
Box::new(MemberChildToBuild::Boolean(BooleanChildToBuild::new(name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_member_child_to_build(
|
|
||||||
name: &str,
|
|
||||||
rule: &str,
|
|
||||||
props: &Yaml,
|
|
||||||
optional: bool,
|
|
||||||
) -> Box<MemberChildToBuild> {
|
|
||||||
if props["build"].is_hash() {
|
|
||||||
let build_props = &props["build"];
|
|
||||||
let kind = build_props["kind"].as_str().or(Some("node")).unwrap();
|
|
||||||
if kind == "node" {
|
|
||||||
deserialize_member_node_to_build(rule, build_props, optional)
|
|
||||||
} else if kind == "boolean" {
|
|
||||||
deserialize_member_boolean_to_build(name)
|
|
||||||
} else {
|
|
||||||
panic!("unsupported kind: {}", kind)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let optional = get_as_bool(&props["optional"]);
|
|
||||||
let with = props["with"]
|
|
||||||
.as_str()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.unwrap_or_else(|| make_build_fn_name(rule));
|
|
||||||
|
|
||||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
|
|
||||||
rule, &with, None, optional,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_member_child(
|
|
||||||
name: &str,
|
|
||||||
rule: &str,
|
|
||||||
optional: bool,
|
|
||||||
props: &Yaml,
|
|
||||||
) -> Box<StructChildSpec> {
|
|
||||||
Box::new(StructChildSpec::MemberChild(MemberChild::new(
|
|
||||||
name,
|
|
||||||
rule,
|
|
||||||
deserialize_member_child_to_build(name, rule, props, optional),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_vec_node_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
|
|
||||||
let rule = props["rule"].as_str().unwrap();
|
|
||||||
Box::new(StructChildSpec::VecChild(VecChild::new(
|
|
||||||
name,
|
|
||||||
rule,
|
|
||||||
Box::new(VecChildToBuild::Node(VecNodeChildToBuild::new(rule))),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_vec_string_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
|
|
||||||
let rule = props["rule"].as_str().unwrap();
|
|
||||||
Box::new(StructChildSpec::VecChild(VecChild::new(
|
|
||||||
name,
|
|
||||||
rule,
|
|
||||||
Box::new(VecChildToBuild::String),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_vec_child(name: &str, props: &Yaml) -> Box<StructChildSpec> {
|
|
||||||
let kind = props["kind"].as_str().or_else(|| Some("node")).unwrap();
|
|
||||||
if kind == "node" {
|
|
||||||
deserialize_vec_node_child(name, props)
|
|
||||||
} else if kind == "string" {
|
|
||||||
deserialize_vec_string_child(name, props)
|
|
||||||
} else {
|
|
||||||
panic!("invalid kind: {}", kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_skip_child(name: &str, rule: &str) -> Box<StructChildSpec> {
|
|
||||||
Box::new(StructChildSpec::SkipChild(SkipChild::new(name, rule)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_struct_hash_child(child: &Yaml) -> Box<StructChildSpec> {
|
|
||||||
let (name, props) = unwrap_single_member_hash(child);
|
|
||||||
|
|
||||||
let rule = props["rule"]
|
|
||||||
.as_str()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.unwrap_or(name.to_case(Case::Pascal));
|
|
||||||
|
|
||||||
if get_as_bool(&props["skip"]) {
|
|
||||||
deserialize_skip_child(&name, &rule)
|
|
||||||
} else {
|
|
||||||
if get_as_bool(&props["vec"]) {
|
|
||||||
deserialize_vec_child(&name, props)
|
|
||||||
} else {
|
|
||||||
let optional = get_as_bool(&props["optional"]);
|
|
||||||
deserialize_member_child(&name, &rule, optional, props)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_struct_string_child(child: &Yaml) -> Box<StructChildSpec> {
|
|
||||||
let child_as_str = child.as_str().unwrap();
|
|
||||||
let child_name_pascal = child_as_str.to_case(Case::Pascal);
|
|
||||||
Box::new(StructChildSpec::MemberChild(MemberChild::new(
|
|
||||||
child_as_str,
|
|
||||||
&child_name_pascal,
|
|
||||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
|
|
||||||
&child_name_pascal,
|
|
||||||
&make_build_fn_name(&child_name_pascal),
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
))),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_struct_children(children: &Yaml) -> Vec<Box<StructChildSpec>> {
|
|
||||||
children
|
|
||||||
.as_vec()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|child_spec| {
|
|
||||||
if child_spec.is_hash() {
|
|
||||||
deserialize_struct_hash_child(child_spec)
|
|
||||||
} else {
|
|
||||||
deserialize_struct_string_child(child_spec)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
|
fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec {
|
||||||
if build_spec["children"].is_array() {
|
if build_spec["struct"].is_hash() {
|
||||||
let children = deserialize_struct_children(&build_spec["children"]);
|
BuildSpec::Struct(deserialize_struct_spec(
|
||||||
BuildSpec::Struct(StructBuildSpec::new(build_spec_name, children))
|
|
||||||
} else if build_spec["members"].is_array() {
|
|
||||||
let members = deserialize_leaf_struct_members(&build_spec["members"]);
|
|
||||||
BuildSpec::LeafStruct(LeafStructBuildSpec::new(build_spec_name, members))
|
|
||||||
} else if build_spec["rules"].is_array() {
|
|
||||||
let rules = deserialize_enum_rules(&build_spec["rules"]);
|
|
||||||
BuildSpec::Enum(EnumBuildSpec::new(build_spec_name, rules))
|
|
||||||
} else if build_spec["leaf_rules"].is_array() {
|
|
||||||
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
|
|
||||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
|
||||||
} else if build_spec["produce"].is_hash() {
|
|
||||||
BuildSpec::Production(deserialize_production_spec(
|
|
||||||
build_spec_name,
|
build_spec_name,
|
||||||
&build_spec["produce"],
|
&build_spec["struct"],
|
||||||
|
))
|
||||||
|
} else if build_spec["leaf_struct"].is_hash() {
|
||||||
|
BuildSpec::LeafStruct(deserialize_leaf_struct(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["leaf_struct"],
|
||||||
|
))
|
||||||
|
} else if build_spec["tree_enum"].is_hash() {
|
||||||
|
BuildSpec::Enum(deserialize_tree_enum(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["tree_enum"],
|
||||||
|
))
|
||||||
|
} else if build_spec["leaf_enum"].is_hash() {
|
||||||
|
BuildSpec::LeafEnum(deserialize_leaf_enum(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["leaf_enum"],
|
||||||
|
))
|
||||||
|
} else if build_spec["production"].is_hash() {
|
||||||
|
BuildSpec::Production(deserialize_production(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["production"],
|
||||||
|
))
|
||||||
|
} else if build_spec["node_production"].is_hash() {
|
||||||
|
BuildSpec::NodeProduction(deserialize_node_production(
|
||||||
|
build_spec_name,
|
||||||
|
&build_spec["node_production"],
|
||||||
))
|
))
|
||||||
} else if build_spec["polymorphic_type"].is_hash() {
|
} else if build_spec["polymorphic_type"].is_hash() {
|
||||||
BuildSpec::Polymorphic(deserialize_polymorphic_spec(
|
BuildSpec::PolymorphicType(deserialize_polymorphic_type(
|
||||||
build_spec_name,
|
build_spec_name,
|
||||||
&build_spec["polymorphic_type"],
|
&build_spec["polymorphic_type"],
|
||||||
))
|
))
|
||||||
} else if build_spec["polymorphic_build"].is_hash() {
|
} else if build_spec["polymorphic_enum_loop_build"].is_hash() {
|
||||||
BuildSpec::PolymorphicBuild(deserialize_polymorphic_build_build_spec(
|
BuildSpec::PolymorphicEnumLoop(deserialize_polymorphic_enum_loop(
|
||||||
build_spec_name,
|
build_spec_name,
|
||||||
&build_spec["polymorphic_build"],
|
&build_spec["polymorphic_enum_loop_build"],
|
||||||
))
|
|
||||||
} else if build_spec["polymorphic_enum"].is_hash() {
|
|
||||||
BuildSpec::PolymorphicEnum(deserialize_polymorphic_enum_build_spec(
|
|
||||||
build_spec_name,
|
|
||||||
&build_spec["polymorphic_enum"],
|
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!("Missing or incorrect build type for {}", build_spec_name);
|
||||||
"Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, production, polymorphic type, or polymorphic build type."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
ast-generator/src/deserialize/node_production_spec.rs
Normal file
9
ast-generator/src/deserialize/node_production_spec.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use crate::deserialize::util::make_build_fn_name;
|
||||||
|
use crate::spec::node_production_spec::NodeProductionBuildSpec;
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
pub fn deserialize_node_production(name: &str, props: &Yaml) -> NodeProductionBuildSpec {
|
||||||
|
let kind = props["kind"].as_str().unwrap();
|
||||||
|
let with = make_build_fn_name(props["with"].as_str().unwrap());
|
||||||
|
NodeProductionBuildSpec::new(name, kind, &with)
|
||||||
|
}
|
||||||
74
ast-generator/src/deserialize/polymorphic_enum_loop_spec.rs
Normal file
74
ast-generator/src/deserialize/polymorphic_enum_loop_spec.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use crate::deserialize::util::{make_build_fn_name, unwrap_single_member_hash};
|
||||||
|
use crate::spec::polymorphic_enum_loop_spec::{
|
||||||
|
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopChildUseCurrent, PolymorphicEnumLoopRule,
|
||||||
|
PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild,
|
||||||
|
PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough,
|
||||||
|
};
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
fn deserialize_build_child(child_name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuildChild {
|
||||||
|
if props["use_current"].is_hash() {
|
||||||
|
let kind = props["use_current"]["kind"].as_str().unwrap();
|
||||||
|
PolymorphicEnumLoopRuleBuildChild::UseCurrent(PolymorphicEnumLoopChildUseCurrent::new(
|
||||||
|
child_name, kind,
|
||||||
|
))
|
||||||
|
} else if props["on_each"].is_hash() {
|
||||||
|
let rule = props["on_each"]["rule"].as_str().unwrap();
|
||||||
|
PolymorphicEnumLoopRuleBuildChild::OnEach(PolymorphicEnumLoopRuleChildOnEach::new(
|
||||||
|
child_name, rule,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
panic!("Expected 'use_current' or 'on_each' hash for polymorphic enum loop build child");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_build(name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuild {
|
||||||
|
let variant = props["variant"].as_str().unwrap();
|
||||||
|
let children = props["children"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|child_yaml| {
|
||||||
|
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
|
||||||
|
deserialize_build_child(&child_name, child_props)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
PolymorphicEnumLoopRuleBuild::new(name, variant, children)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_pass_through(name: &str, props: &Yaml) -> PolymorphicEnumLoopRulePassThrough {
|
||||||
|
let kind = props["kind"].as_str().unwrap();
|
||||||
|
let with = make_build_fn_name(props["with"].as_str().unwrap());
|
||||||
|
PolymorphicEnumLoopRulePassThrough::new(name, kind, &with)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_rule(rule_name: &str, props: &Yaml) -> PolymorphicEnumLoopRule {
|
||||||
|
if props["pass_through"].is_hash() {
|
||||||
|
PolymorphicEnumLoopRule::PassThrough(deserialize_pass_through(
|
||||||
|
rule_name,
|
||||||
|
&props["pass_through"],
|
||||||
|
))
|
||||||
|
} else if props["build"].is_hash() {
|
||||||
|
PolymorphicEnumLoopRule::Build(deserialize_build(rule_name, &props["build"]))
|
||||||
|
} else {
|
||||||
|
panic!("Polymorphic enum loop rule must have 'pass_through' or 'build' hash.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_polymorphic_enum_loop(name: &str, props: &Yaml) -> PolymorphicEnumLoopBuildSpec {
|
||||||
|
let kind = props["kind"].as_str().unwrap();
|
||||||
|
let rules = props["rules"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|rule_yaml| {
|
||||||
|
let (rule_name, rule_props) = unwrap_single_member_hash(rule_yaml);
|
||||||
|
deserialize_rule(&rule_name, rule_props)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
PolymorphicEnumLoopBuildSpec::new(name, kind, rules)
|
||||||
|
}
|
||||||
23
ast-generator/src/deserialize/polymorphic_type_spec.rs
Normal file
23
ast-generator/src/deserialize/polymorphic_type_spec.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use crate::deserialize::util::unwrap_single_member_hash;
|
||||||
|
use crate::spec::polymorphic_type_spec::{PolymorphicTypeBuildSpec, PolymorphicTypeVariant};
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
fn deserialize_variant(variant_name: &str, props: &Yaml) -> PolymorphicTypeVariant {
|
||||||
|
let inner_kind = props["inner"]["kind"].as_str().unwrap();
|
||||||
|
PolymorphicTypeVariant::new(variant_name, inner_kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_polymorphic_type(name: &str, props: &Yaml) -> PolymorphicTypeBuildSpec {
|
||||||
|
let variants = props["variants"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|variant_yaml| {
|
||||||
|
let (variant_name, variant_props) = unwrap_single_member_hash(variant_yaml);
|
||||||
|
deserialize_variant(&variant_name, variant_props)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
let kind = props["build"]["kind"].as_str().unwrap();
|
||||||
|
PolymorphicTypeBuildSpec::new(name, variants, kind)
|
||||||
|
}
|
||||||
21
ast-generator/src/deserialize/production_spec.rs
Normal file
21
ast-generator/src/deserialize/production_spec.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::spec::production_spec::{ProductionBooleanFrom, ProductionBuildSpec, ProductionKind, ProductionStringFrom};
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
pub fn deserialize_production(name: &str, props: &Yaml) -> ProductionBuildSpec {
|
||||||
|
let kind = match props["kind"].as_str().unwrap() {
|
||||||
|
"int" => ProductionKind::Int,
|
||||||
|
"long" => ProductionKind::Long,
|
||||||
|
"double" => ProductionKind::Double,
|
||||||
|
"string" => {
|
||||||
|
let from = match props["from"].as_str().unwrap() {
|
||||||
|
"string_inner" => ProductionStringFrom::StringInner,
|
||||||
|
"whole_pair" => ProductionStringFrom::WholePair,
|
||||||
|
_ => panic!("Unknown string production from: {}", props["from"].as_str().unwrap())
|
||||||
|
};
|
||||||
|
ProductionKind::String(from)
|
||||||
|
},
|
||||||
|
"boolean" => ProductionKind::Boolean(ProductionBooleanFrom::ParseWholePair),
|
||||||
|
_ => panic!("Unknown production kind: {}", props["kind"].as_str().unwrap()),
|
||||||
|
};
|
||||||
|
ProductionBuildSpec::new(name, kind)
|
||||||
|
}
|
||||||
140
ast-generator/src/deserialize/struct_spec.rs
Normal file
140
ast-generator/src/deserialize/struct_spec.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
use crate::deserialize_error;
|
||||||
|
use convert_case::{Case, Casing};
|
||||||
|
|
||||||
|
use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_member_hash};
|
||||||
|
use crate::spec::struct_spec::*;
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
fn deserialize_skip_child(props: &Yaml) -> StructChild {
|
||||||
|
let rule = props["rule"].as_str().unwrap();
|
||||||
|
StructChild::SkipChild(SkipChild::new(rule))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_vec_child(child_name: &str, props: &Yaml) -> StructChild {
|
||||||
|
let rule = props["rule"].as_str().unwrap();
|
||||||
|
let kind = props["kind"].as_str()
|
||||||
|
.unwrap_or(rule);
|
||||||
|
StructChild::VecChild(VecChild::new(child_name, rule, kind))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_member_build(child_name: &str, rule: &str, props: &Yaml) -> MemberChildBuild {
|
||||||
|
if props["node"].is_hash() {
|
||||||
|
let node_props = &props["node"];
|
||||||
|
let kind = node_props["kind"].as_str().unwrap_or(rule);
|
||||||
|
let with = node_props["with"]
|
||||||
|
.as_str()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.unwrap_or_else(|| make_build_fn_name(kind));
|
||||||
|
|
||||||
|
let or_else = if get_as_bool(&node_props["or_else_default"]) {
|
||||||
|
Some(String::from("default"))
|
||||||
|
} else if let Some(or_else) = node_props["or_else"].as_str() {
|
||||||
|
Some(or_else.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
MemberChildBuild::Node(NodeMemberBuild::new(kind, &with, or_else))
|
||||||
|
} else if props["boolean"].is_hash() {
|
||||||
|
let boolean_props = &props["boolean"];
|
||||||
|
if let Some(on) = boolean_props["on"].as_str() {
|
||||||
|
if on == "rule_present" {
|
||||||
|
MemberChildBuild::Boolean(BooleanMemberBuild::new(
|
||||||
|
BooleanMemberBuildOn::RulePresent,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Expected 'on' in 'boolean' in 'build' in {} to be 'rule_present'",
|
||||||
|
child_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Expected 'on' in 'boolean' in 'build' in {}", child_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Expected either of 'node' or 'boolean' in 'build' in {}",
|
||||||
|
child_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_member_child(child_name: &str, props: &Yaml) -> StructChild {
|
||||||
|
let rule = props["rule"]
|
||||||
|
.as_str()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.unwrap_or_else(|| child_name.to_case(Case::Pascal));
|
||||||
|
let optional = get_as_bool(&props["optional"]);
|
||||||
|
if props["build"].is_hash() {
|
||||||
|
let build = deserialize_member_build(child_name, &rule, &props["build"]);
|
||||||
|
StructChild::MemberChild(MemberChild::new(
|
||||||
|
child_name,
|
||||||
|
&rule,
|
||||||
|
optional,
|
||||||
|
Box::new(build),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
StructChild::MemberChild(MemberChild::new(
|
||||||
|
child_name,
|
||||||
|
&rule,
|
||||||
|
optional,
|
||||||
|
Box::new(MemberChildBuild::Node(NodeMemberBuild::new(
|
||||||
|
&rule,
|
||||||
|
&make_build_fn_name(&rule),
|
||||||
|
None,
|
||||||
|
))),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild {
|
||||||
|
if props["skip"].is_hash() {
|
||||||
|
deserialize_skip_child(&props["skip"])
|
||||||
|
} else if props["vec"].is_hash() {
|
||||||
|
deserialize_vec_child(name, &props["vec"])
|
||||||
|
} else if props["member"].is_hash() {
|
||||||
|
deserialize_member_child(name, &props["member"])
|
||||||
|
} else {
|
||||||
|
panic!("Expected 'skip' or 'vec' in 'member' in {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_string_child(name: &str) -> StructChild {
|
||||||
|
let name_pascal = name.to_case(Case::Pascal);
|
||||||
|
StructChild::MemberChild(MemberChild::new(
|
||||||
|
name,
|
||||||
|
&name_pascal,
|
||||||
|
false,
|
||||||
|
Box::new(MemberChildBuild::Node(NodeMemberBuild::new(
|
||||||
|
&name_pascal,
|
||||||
|
&make_build_fn_name(name),
|
||||||
|
None,
|
||||||
|
))),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_children(children_yaml: &Yaml) -> Vec<Box<StructChild>> {
|
||||||
|
children_yaml
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|child_yaml| {
|
||||||
|
if let Some(name) = child_yaml.as_str() {
|
||||||
|
deserialize_string_child(name)
|
||||||
|
} else {
|
||||||
|
let (child_name, child_props) = unwrap_single_member_hash(child_yaml);
|
||||||
|
deserialize_hash_child(&child_name, child_props)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
|
||||||
|
let children = if struct_yaml["children"].is_array() {
|
||||||
|
deserialize_children(&struct_yaml["children"])
|
||||||
|
} else {
|
||||||
|
deserialize_error!("array", "children", name);
|
||||||
|
};
|
||||||
|
StructSpec::new(name, children)
|
||||||
|
}
|
||||||
50
ast-generator/src/deserialize/tree_enum_spec.rs
Normal file
50
ast-generator/src/deserialize/tree_enum_spec.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use crate::deserialize::util::{get_as_bool_or, unwrap_single_member_hash};
|
||||||
|
use crate::spec::tree_enum_spec::{
|
||||||
|
EnumRuleChild, EnumRuleChildKind, TreeEnumBuildSpec, TreeEnumRule,
|
||||||
|
};
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
fn deserialize_hash_enum_rule(rule: &str, props: &Yaml) -> TreeEnumRule {
|
||||||
|
if get_as_bool_or(&props["child"], true) {
|
||||||
|
let kind = match props["kind"].as_str().unwrap() {
|
||||||
|
"int" => EnumRuleChildKind::Int,
|
||||||
|
"long" => EnumRuleChildKind::Long,
|
||||||
|
"double" => EnumRuleChildKind::Double,
|
||||||
|
"string" => EnumRuleChildKind::String,
|
||||||
|
"boolean" => EnumRuleChildKind::Boolean,
|
||||||
|
_ => panic!("Invalid kind: {}", props["kind"].as_str().unwrap()),
|
||||||
|
};
|
||||||
|
TreeEnumRule::new(rule, Some(Box::new(EnumRuleChild::new(Box::new(kind)))))
|
||||||
|
} else {
|
||||||
|
// no child
|
||||||
|
TreeEnumRule::new(rule, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_string_enum_rule(rule: &str) -> TreeEnumRule {
|
||||||
|
TreeEnumRule::new(
|
||||||
|
rule,
|
||||||
|
Some(Box::new(EnumRuleChild::new(Box::new(
|
||||||
|
EnumRuleChildKind::Node,
|
||||||
|
)))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_tree_enum(name: &str, props: &Yaml) -> TreeEnumBuildSpec {
|
||||||
|
let rules = props["rules"]
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|rule_yaml| {
|
||||||
|
if let Some(rule) = rule_yaml.as_str() {
|
||||||
|
deserialize_string_enum_rule(rule)
|
||||||
|
} else {
|
||||||
|
let (rule, props) = unwrap_single_member_hash(rule_yaml);
|
||||||
|
deserialize_hash_enum_rule(&rule, props)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
TreeEnumBuildSpec::new(name, rules)
|
||||||
|
}
|
||||||
37
ast-generator/src/deserialize/util.rs
Normal file
37
ast-generator/src/deserialize/util.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use convert_case::{Case, Casing};
|
||||||
|
use yaml_rust2::Yaml;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! deserialize_error {
|
||||||
|
($kind:expr, $key:expr, $name:expr) => {
|
||||||
|
panic!("Expected {} '{}' in {}.", $kind, $key, $name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_build_fn_name(s: &str) -> String {
|
||||||
|
format!("build_{}", s.to_case(Case::Snake))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_build_pair(s: &str) -> String {
|
||||||
|
format!("{}_pair", s.to_case(Case::Snake))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
||||||
|
let as_hash = hash.as_hash().unwrap();
|
||||||
|
if as_hash.is_empty() {
|
||||||
|
panic!("empty hash");
|
||||||
|
} else if as_hash.len() > 1 {
|
||||||
|
panic!("hash contains more than one key");
|
||||||
|
}
|
||||||
|
let (member_key, member_value) = as_hash.iter().collect::<Vec<(&Yaml, &Yaml)>>()[0];
|
||||||
|
let key_as_string = member_key.as_str().unwrap().to_string();
|
||||||
|
(key_as_string, member_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_as_bool(yaml: &Yaml) -> bool {
|
||||||
|
yaml.as_bool().unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_as_bool_or(yaml: &Yaml, or: bool) -> bool {
|
||||||
|
yaml.as_bool().unwrap_or(or)
|
||||||
|
}
|
||||||
21
ast-generator/src/spec/leaf_enum_spec.rs
Normal file
21
ast-generator/src/spec/leaf_enum_spec.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
pub struct LeafEnumBuildSpec {
|
||||||
|
build: String,
|
||||||
|
rules: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafEnumBuildSpec {
|
||||||
|
pub fn new(build: &str, rules: Vec<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
build: build.to_string(),
|
||||||
|
rules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&self) -> &str {
|
||||||
|
&self.build
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rules(&self) -> impl Iterator<Item = &str> {
|
||||||
|
self.rules.iter().map(AsRef::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
47
ast-generator/src/spec/leaf_struct_spec.rs
Normal file
47
ast-generator/src/spec/leaf_struct_spec.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
pub struct LeafStructBuildSpec {
|
||||||
|
build: String,
|
||||||
|
members: Vec<Box<LeafStructMember>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafStructBuildSpec {
|
||||||
|
pub fn new(build: &str, members: Vec<Box<LeafStructMember>>) -> Self {
|
||||||
|
Self {
|
||||||
|
build: build.to_string(),
|
||||||
|
members,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&self) -> &str {
|
||||||
|
&self.build
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn members(&self) -> impl Iterator<Item = &LeafStructMember> {
|
||||||
|
self.members.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LeafStructMember {
|
||||||
|
name: String,
|
||||||
|
kind: LeafStructMemberKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LeafStructMember {
|
||||||
|
pub fn new(name: &str, kind: LeafStructMemberKind) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &LeafStructMemberKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LeafStructMemberKind {
|
||||||
|
String,
|
||||||
|
}
|
||||||
@ -1,700 +1,28 @@
|
|||||||
|
use crate::spec::node_production_spec::NodeProductionBuildSpec;
|
||||||
|
use leaf_enum_spec::LeafEnumBuildSpec;
|
||||||
|
use leaf_struct_spec::LeafStructBuildSpec;
|
||||||
|
use polymorphic_type_spec::PolymorphicTypeBuildSpec;
|
||||||
|
use production_spec::ProductionBuildSpec;
|
||||||
|
use struct_spec::StructSpec;
|
||||||
|
use tree_enum_spec::TreeEnumBuildSpec;
|
||||||
|
use crate::spec::polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
|
||||||
|
|
||||||
|
pub(crate) mod leaf_enum_spec;
|
||||||
|
pub(crate) mod leaf_struct_spec;
|
||||||
|
pub(crate) mod node_production_spec;
|
||||||
|
pub(crate) mod polymorphic_enum_loop_spec;
|
||||||
|
pub(crate) mod polymorphic_type_spec;
|
||||||
|
pub(crate) mod production_spec;
|
||||||
|
pub(crate) mod struct_spec;
|
||||||
|
pub(crate) mod tree_enum_spec;
|
||||||
|
|
||||||
pub enum BuildSpec {
|
pub enum BuildSpec {
|
||||||
Enum(EnumBuildSpec),
|
Enum(TreeEnumBuildSpec),
|
||||||
LeafEnum(LeafEnumBuildSpec),
|
LeafEnum(LeafEnumBuildSpec),
|
||||||
Struct(StructBuildSpec),
|
Struct(StructSpec),
|
||||||
LeafStruct(LeafStructBuildSpec),
|
LeafStruct(LeafStructBuildSpec),
|
||||||
Production(ProductionBuildSpec),
|
Production(ProductionBuildSpec),
|
||||||
Polymorphic(PolymorphicTypeBuildSpec),
|
NodeProduction(NodeProductionBuildSpec),
|
||||||
PolymorphicBuild(PolymorphicBuildBuildSpec),
|
PolymorphicType(PolymorphicTypeBuildSpec),
|
||||||
PolymorphicEnum(PolymorphicEnumBuildSpec),
|
PolymorphicEnumLoop(PolymorphicEnumLoopBuildSpec),
|
||||||
}
|
|
||||||
|
|
||||||
// Enum build spec
|
|
||||||
|
|
||||||
pub struct EnumBuildSpec {
|
|
||||||
build: String,
|
|
||||||
rules: Vec<Box<EnumRule>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EnumBuildSpec {
|
|
||||||
pub fn new(build: &str, rules: Vec<Box<EnumRule>>) -> Self {
|
|
||||||
EnumBuildSpec {
|
|
||||||
build: build.to_string(),
|
|
||||||
rules,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The enum type to be built, in Pascal case.
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The individual rule specs.
|
|
||||||
pub fn rules(&self) -> impl Iterator<Item = &EnumRule> {
|
|
||||||
self.rules.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnumRule {
|
|
||||||
rule: String,
|
|
||||||
child: Option<Box<EnumRuleChild>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EnumRule {
|
|
||||||
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
|
||||||
Self {
|
|
||||||
rule: rule.to_string(),
|
|
||||||
child,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The enum rule to match, in Pascal case.
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn child(&self) -> Option<&EnumRuleChild> {
|
|
||||||
if let Some(child) = &self.child {
|
|
||||||
Some(child.as_ref())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnumRuleChild {
|
|
||||||
kind: Box<EnumRuleChildKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EnumRuleChild {
|
|
||||||
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
|
|
||||||
Self { kind }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &EnumRuleChildKind {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum EnumRuleChildKind {
|
|
||||||
Node(EnumRuleNodeChild),
|
|
||||||
Int,
|
|
||||||
Long,
|
|
||||||
Double,
|
|
||||||
USize,
|
|
||||||
String,
|
|
||||||
Boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EnumRuleNodeChild {
|
|
||||||
build: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EnumRuleNodeChild {
|
|
||||||
pub fn new(build: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
build: build.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leaf enum build spec
|
|
||||||
|
|
||||||
pub struct LeafEnumBuildSpec {
|
|
||||||
build: String,
|
|
||||||
rules: Vec<Box<LeafEnumRule>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LeafEnumBuildSpec {
|
|
||||||
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
|
|
||||||
Self {
|
|
||||||
build: build.to_string(),
|
|
||||||
rules,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rules(&self) -> impl Iterator<Item = &LeafEnumRule> {
|
|
||||||
self.rules.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LeafEnumRule {
|
|
||||||
rule: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LeafEnumRule {
|
|
||||||
pub fn new(rule: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
rule: rule.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Struct build spec
|
|
||||||
|
|
||||||
pub struct StructBuildSpec {
|
|
||||||
build: String,
|
|
||||||
children: Vec<Box<StructChildSpec>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StructBuildSpec {
|
|
||||||
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
|
|
||||||
Self {
|
|
||||||
build: build.to_string(),
|
|
||||||
children,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type to be built, in Pascal case.
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The children for this build spec.
|
|
||||||
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
|
|
||||||
self.children.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum StructChildSpec {
|
|
||||||
SkipChild(SkipChild),
|
|
||||||
VecChild(VecChild),
|
|
||||||
MemberChild(MemberChild),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SkipChild {
|
|
||||||
name: String,
|
|
||||||
rule: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SkipChild {
|
|
||||||
pub fn new(name: &str, rule: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
rule: rule.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name of this child spec.
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The grammar rule to match.
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VecChild {
|
|
||||||
name: String,
|
|
||||||
rule: String,
|
|
||||||
build: Box<VecChildToBuild>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VecChild {
|
|
||||||
pub fn new(name: &str, rule: &str, build: Box<VecChildToBuild>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
rule: rule.to_string(),
|
|
||||||
build,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name of this child.
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The rule to match to build this child.
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The build info for this child.
|
|
||||||
pub fn build(&self) -> &VecChildToBuild {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum VecChildToBuild {
|
|
||||||
Node(VecNodeChildToBuild),
|
|
||||||
String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct VecNodeChildToBuild {
|
|
||||||
build: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VecNodeChildToBuild {
|
|
||||||
pub fn new(build: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
build: build.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type to build, in Pascal case.
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MemberChild {
|
|
||||||
name: String,
|
|
||||||
rule: String,
|
|
||||||
build: Box<MemberChildToBuild>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemberChild {
|
|
||||||
pub fn new(name: &str, rule: &str, build: Box<MemberChildToBuild>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
rule: rule.to_string(),
|
|
||||||
build,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name of this child in the yaml file, in snake case.
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The grammar rule to match to build this child.
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The specification for what to actually build.
|
|
||||||
pub fn build(&self) -> &MemberChildToBuild {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MemberChildToBuild {
|
|
||||||
Node(NodeChildToBuild),
|
|
||||||
Boolean(BooleanChildToBuild),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NodeChildToBuild {
|
|
||||||
kind: String,
|
|
||||||
with: String,
|
|
||||||
or_else: Option<String>,
|
|
||||||
optional: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeChildToBuild {
|
|
||||||
pub fn new(kind: &str, with: &str, or_else: Option<String>, optional: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
kind: kind.to_string(),
|
|
||||||
with: with.to_string(),
|
|
||||||
or_else,
|
|
||||||
optional,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type to build, in Pascal case.
|
|
||||||
pub fn kind(&self) -> &str {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with(&self) -> &str {
|
|
||||||
&self.with
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The default fn to call when unwrapping the child (before passing as arg to new).
|
|
||||||
pub fn or_else(&self) -> Option<&str> {
|
|
||||||
self.or_else.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the type should be wrapped in an Option.
|
|
||||||
pub fn optional(&self) -> bool {
|
|
||||||
self.optional
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BooleanChildToBuild {
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BooleanChildToBuild {
|
|
||||||
pub fn new(name: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leaf Struct build spec
|
|
||||||
|
|
||||||
pub struct LeafStructBuildSpec {
|
|
||||||
build: String,
|
|
||||||
members: Vec<Box<LeafStructMember>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LeafStructBuildSpec {
|
|
||||||
pub fn new(build: &str, members: Vec<Box<LeafStructMember>>) -> Self {
|
|
||||||
Self {
|
|
||||||
build: build.to_string(),
|
|
||||||
members,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self) -> &str {
|
|
||||||
&self.build
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn members(&self) -> impl Iterator<Item = &LeafStructMember> {
|
|
||||||
self.members.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LeafStructMember {
|
|
||||||
name: String,
|
|
||||||
kind: LeafStructMemberKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LeafStructMember {
|
|
||||||
pub fn new(name: &str, kind: LeafStructMemberKind) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &LeafStructMemberKind {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LeafStructMemberKind {
|
|
||||||
String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ProductionBuildSpec {
|
|
||||||
rule: String,
|
|
||||||
kind: ProductionKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProductionBuildSpec {
|
|
||||||
pub fn new(rule: &str, kind: ProductionKind) -> Self {
|
|
||||||
Self {
|
|
||||||
rule: rule.to_string(),
|
|
||||||
kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &ProductionKind {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ProductionKind {
|
|
||||||
Int,
|
|
||||||
Long,
|
|
||||||
Double,
|
|
||||||
String(ProductionStringFrom),
|
|
||||||
Boolean,
|
|
||||||
Node(ProductionNodeKind),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ProductionNodeKind {
|
|
||||||
kind: String,
|
|
||||||
with: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProductionNodeKind {
|
|
||||||
pub fn new(kind: &str, with: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
kind: kind.to_string(),
|
|
||||||
with: with.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &str {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with(&self) -> &str {
|
|
||||||
&self.with
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ProductionStringFrom {
|
|
||||||
StringInner,
|
|
||||||
WholePair,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Polymorphic build spec
|
|
||||||
|
|
||||||
pub struct PolymorphicTypeBuildSpec {
|
|
||||||
name: String,
|
|
||||||
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
|
||||||
build_kind: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolymorphicTypeBuildSpec {
|
|
||||||
pub fn new(
|
|
||||||
name: &str,
|
|
||||||
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
|
||||||
build_kind: &str,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
enum_members,
|
|
||||||
build_kind: build_kind.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
|
|
||||||
self.enum_members.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_kind(&self) -> &str {
|
|
||||||
self.build_kind.as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PolymorphicEnumMember {
|
|
||||||
name: String,
|
|
||||||
inner_kind: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolymorphicEnumMember {
|
|
||||||
pub fn new(name: &str, inner_kind: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
inner_kind: inner_kind.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner_kind(&self) -> &str {
|
|
||||||
&self.inner_kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PolymorphicBuildBuildSpec {
|
|
||||||
name: String,
|
|
||||||
return_type: String,
|
|
||||||
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolymorphicBuildBuildSpec {
|
|
||||||
pub fn new(
|
|
||||||
name: &str,
|
|
||||||
return_type: &str,
|
|
||||||
alternatives: Vec<Box<PolymorphicBuildAlternative>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
return_type: return_type.to_string(),
|
|
||||||
alternatives,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn return_type(&self) -> &str {
|
|
||||||
&self.return_type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alternatives(&self) -> impl Iterator<Item = &PolymorphicBuildAlternative> {
|
|
||||||
self.alternatives.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn primary_alternative(&self) -> (&AlternativeTest, &AlternativeBuild) {
|
|
||||||
let primary_build_alternative = self
|
|
||||||
.alternatives
|
|
||||||
.iter()
|
|
||||||
.find(|alternative| match alternative.action {
|
|
||||||
AlternativeAction::Build(_) => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
.map(Box::as_ref)
|
|
||||||
.unwrap();
|
|
||||||
let alternative_build =
|
|
||||||
if let AlternativeAction::Build(build) = &primary_build_alternative.action {
|
|
||||||
build
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
(primary_build_alternative.test(), alternative_build)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PolymorphicBuildAlternative {
|
|
||||||
test: AlternativeTest,
|
|
||||||
action: AlternativeAction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolymorphicBuildAlternative {
|
|
||||||
pub fn new(test: AlternativeTest, action: AlternativeAction) -> Self {
|
|
||||||
Self { test, action }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test(&self) -> &AlternativeTest {
|
|
||||||
&self.test
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn action(&self) -> &AlternativeAction {
|
|
||||||
&self.action
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum AlternativeTest {
|
|
||||||
NumberOfPairs(i64),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum AlternativeAction {
|
|
||||||
ReturnBuild(String),
|
|
||||||
Build(AlternativeBuild),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AlternativeBuild {
|
|
||||||
enum_variant: String,
|
|
||||||
children: Vec<Box<AlternativeChild>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AlternativeBuild {
|
|
||||||
pub fn new(enum_variant: &str, children: Vec<Box<AlternativeChild>>) -> Self {
|
|
||||||
Self {
|
|
||||||
enum_variant: enum_variant.to_string(),
|
|
||||||
children,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enum_variant(&self) -> &str {
|
|
||||||
&self.enum_variant
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> impl Iterator<Item = &AlternativeChild> {
|
|
||||||
self.children.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum AlternativeChild {
|
|
||||||
Skip,
|
|
||||||
Build(AlternativeBuildChild),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AlternativeBuildChild {
|
|
||||||
name: String,
|
|
||||||
kind: String,
|
|
||||||
rule: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AlternativeBuildChild {
|
|
||||||
pub fn new(name: &str, kind: &str, rule: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
kind: kind.to_string(),
|
|
||||||
rule: rule.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &str {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rule(&self) -> &str {
|
|
||||||
&self.rule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PolymorphicEnumBuildSpec {
|
|
||||||
name: String,
|
|
||||||
return_type: String,
|
|
||||||
rules: Vec<Box<PolymorphicEnumRule>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolymorphicEnumBuildSpec {
|
|
||||||
pub fn new(name: &str, return_type: &str, rules: Vec<Box<PolymorphicEnumRule>>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
return_type: return_type.to_string(),
|
|
||||||
rules,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn return_type(&self) -> &str {
|
|
||||||
&self.return_type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumRule> {
|
|
||||||
self.rules.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum PolymorphicEnumRule {
|
|
||||||
Wrap(NameAndKind),
|
|
||||||
ReturnBuild(NameAndKind),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NameAndKind {
|
|
||||||
name: String,
|
|
||||||
kind: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NameAndKind {
|
|
||||||
pub fn new(name: &str, kind: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.to_string(),
|
|
||||||
kind: kind.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &str {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
27
ast-generator/src/spec/node_production_spec.rs
Normal file
27
ast-generator/src/spec/node_production_spec.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
pub struct NodeProductionBuildSpec {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
with: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeProductionBuildSpec {
|
||||||
|
pub fn new(name: &str, kind: &str, with: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
with: with.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(&self) -> &str {
|
||||||
|
&self.with
|
||||||
|
}
|
||||||
|
}
|
||||||
133
ast-generator/src/spec/polymorphic_enum_loop_spec.rs
Normal file
133
ast-generator/src/spec/polymorphic_enum_loop_spec.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
pub struct PolymorphicEnumLoopBuildSpec {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
rules: Vec<Box<PolymorphicEnumLoopRule>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumLoopBuildSpec {
|
||||||
|
pub fn new(name: &str, kind: &str, rules: Vec<Box<PolymorphicEnumLoopRule>>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
rules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rules(&self) -> impl Iterator<Item = &PolymorphicEnumLoopRule> {
|
||||||
|
self.rules.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PolymorphicEnumLoopRule {
|
||||||
|
PassThrough(PolymorphicEnumLoopRulePassThrough),
|
||||||
|
Build(PolymorphicEnumLoopRuleBuild),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumLoopRulePassThrough {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
with: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumLoopRulePassThrough {
|
||||||
|
pub fn new(name: &str, kind: &str, with: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
with: with.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(&self) -> &str {
|
||||||
|
&self.with
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumLoopRuleBuild {
|
||||||
|
name: String,
|
||||||
|
variant: String,
|
||||||
|
children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumLoopRuleBuild {
|
||||||
|
pub fn new(name: &str, variant: &str, children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
variant: variant.to_string(),
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variant(&self) -> &str {
|
||||||
|
&self.variant
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self) -> impl Iterator<Item = &PolymorphicEnumLoopRuleBuildChild> {
|
||||||
|
self.children.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PolymorphicEnumLoopRuleBuildChild {
|
||||||
|
UseCurrent(PolymorphicEnumLoopChildUseCurrent),
|
||||||
|
OnEach(PolymorphicEnumLoopRuleChildOnEach),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumLoopChildUseCurrent {
|
||||||
|
name: String,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumLoopChildUseCurrent {
|
||||||
|
pub fn new(name: &str, kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumLoopRuleChildOnEach {
|
||||||
|
name: String,
|
||||||
|
rule: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumLoopRuleChildOnEach {
|
||||||
|
pub fn new(name: &str, rule: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
rule: rule.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
}
|
||||||
49
ast-generator/src/spec/polymorphic_type_spec.rs
Normal file
49
ast-generator/src/spec/polymorphic_type_spec.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
pub struct PolymorphicTypeBuildSpec {
|
||||||
|
name: String,
|
||||||
|
variants: Vec<Box<PolymorphicTypeVariant>>,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicTypeBuildSpec {
|
||||||
|
pub fn new(name: &str, variants: Vec<Box<PolymorphicTypeVariant>>, kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
variants,
|
||||||
|
kind: kind.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variants(&self) -> impl Iterator<Item = &PolymorphicTypeVariant> {
|
||||||
|
self.variants.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
self.kind.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicTypeVariant {
|
||||||
|
name: String,
|
||||||
|
inner_kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicTypeVariant {
|
||||||
|
pub fn new(name: &str, inner_kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
inner_kind: inner_kind.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_kind(&self) -> &str {
|
||||||
|
&self.inner_kind
|
||||||
|
}
|
||||||
|
}
|
||||||
38
ast-generator/src/spec/production_spec.rs
Normal file
38
ast-generator/src/spec/production_spec.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
pub struct ProductionBuildSpec {
|
||||||
|
name: String,
|
||||||
|
kind: ProductionKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProductionBuildSpec {
|
||||||
|
pub fn new(name: &str, kind: ProductionKind) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &ProductionKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProductionKind {
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Double,
|
||||||
|
String(ProductionStringFrom),
|
||||||
|
Boolean(ProductionBooleanFrom),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProductionStringFrom {
|
||||||
|
StringInner,
|
||||||
|
WholePair,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProductionBooleanFrom {
|
||||||
|
ParseWholePair,
|
||||||
|
}
|
||||||
171
ast-generator/src/spec/struct_spec.rs
Normal file
171
ast-generator/src/spec/struct_spec.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
pub struct StructSpec {
|
||||||
|
build: String,
|
||||||
|
children: Vec<Box<StructChild>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructSpec {
|
||||||
|
pub fn new(build: &str, children: Vec<Box<StructChild>>) -> Self {
|
||||||
|
Self {
|
||||||
|
build: build.to_string(),
|
||||||
|
children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type to be built, in Pascal case.
|
||||||
|
pub fn build(&self) -> &str {
|
||||||
|
&self.build
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The children for this build spec.
|
||||||
|
pub fn children(&self) -> impl Iterator<Item = &StructChild> {
|
||||||
|
self.children.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum StructChild {
|
||||||
|
SkipChild(SkipChild),
|
||||||
|
VecChild(VecChild),
|
||||||
|
MemberChild(MemberChild),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SkipChild {
|
||||||
|
rule: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SkipChild {
|
||||||
|
pub fn new(rule: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
rule: rule.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The grammar rule to match.
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VecChild {
|
||||||
|
name: String,
|
||||||
|
rule: String,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VecChild {
|
||||||
|
pub fn new(name: &str, rule: &str, kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
rule: rule.to_string(),
|
||||||
|
kind: kind.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of this child.
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The rule to match to build this child.
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MemberChild {
|
||||||
|
name: String,
|
||||||
|
rule: String,
|
||||||
|
optional: bool,
|
||||||
|
build: Box<MemberChildBuild>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemberChild {
|
||||||
|
pub fn new(name: &str, rule: &str, optional: bool, build: Box<MemberChildBuild>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
rule: rule.to_string(),
|
||||||
|
optional,
|
||||||
|
build,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of this child in the yaml file, in snake case.
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The grammar rule to match to build this child.
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn optional(&self) -> bool {
|
||||||
|
self.optional
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The specification for what to actually build.
|
||||||
|
pub fn build(&self) -> &MemberChildBuild {
|
||||||
|
&self.build
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MemberChildBuild {
|
||||||
|
Node(NodeMemberBuild),
|
||||||
|
Boolean(BooleanMemberBuild),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NodeMemberBuild {
|
||||||
|
kind: String,
|
||||||
|
with: String,
|
||||||
|
or_else: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeMemberBuild {
|
||||||
|
pub fn new(kind: &str, with: &str, or_else: Option<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
kind: kind.to_string(),
|
||||||
|
with: with.to_string(),
|
||||||
|
or_else,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type to build, in Pascal case.
|
||||||
|
pub fn kind(&self) -> &str {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(&self) -> &str {
|
||||||
|
&self.with
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default fn to call when unwrapping the child (before passing as arg to new).
|
||||||
|
pub fn or_else(&self) -> Option<&str> {
|
||||||
|
self.or_else.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BooleanMemberBuild {
|
||||||
|
on: BooleanMemberBuildOn,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BooleanMemberBuild {
|
||||||
|
pub fn new(on: BooleanMemberBuildOn) -> Self {
|
||||||
|
Self { on }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on(&self) -> &BooleanMemberBuildOn {
|
||||||
|
&self.on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BooleanMemberBuildOn {
|
||||||
|
RulePresent
|
||||||
|
}
|
||||||
73
ast-generator/src/spec/tree_enum_spec.rs
Normal file
73
ast-generator/src/spec/tree_enum_spec.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
pub struct TreeEnumBuildSpec {
|
||||||
|
build: String,
|
||||||
|
rules: Vec<Box<TreeEnumRule>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeEnumBuildSpec {
|
||||||
|
pub fn new(build: &str, rules: Vec<Box<TreeEnumRule>>) -> Self {
|
||||||
|
TreeEnumBuildSpec {
|
||||||
|
build: build.to_string(),
|
||||||
|
rules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The enum type to be built, in Pascal case.
|
||||||
|
pub fn build(&self) -> &str {
|
||||||
|
&self.build
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The individual rule specs.
|
||||||
|
pub fn rules(&self) -> impl Iterator<Item = &TreeEnumRule> {
|
||||||
|
self.rules.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TreeEnumRule {
|
||||||
|
rule: String,
|
||||||
|
child: Option<Box<EnumRuleChild>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeEnumRule {
|
||||||
|
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
||||||
|
Self {
|
||||||
|
rule: rule.to_string(),
|
||||||
|
child,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The enum rule to match, in Pascal case.
|
||||||
|
pub fn rule(&self) -> &str {
|
||||||
|
&self.rule
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn child(&self) -> Option<&EnumRuleChild> {
|
||||||
|
if let Some(child) = &self.child {
|
||||||
|
Some(child.as_ref())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EnumRuleChild {
|
||||||
|
kind: Box<EnumRuleChildKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnumRuleChild {
|
||||||
|
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
|
||||||
|
Self { kind }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &EnumRuleChildKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum EnumRuleChildKind {
|
||||||
|
Node,
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Double,
|
||||||
|
String,
|
||||||
|
Boolean,
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
use convert_case::{Case, Casing};
|
|
||||||
|
|
||||||
pub fn make_build_fn_name(s: &str) -> String {
|
|
||||||
format!("build_{}", s.to_case(Case::Snake))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_build_pair(s: &str) -> String {
|
|
||||||
format!("{}_pair", s.to_case(Case::Snake))
|
|
||||||
}
|
|
||||||
@ -171,7 +171,9 @@ $defs:
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
properties:
|
properties:
|
||||||
boolean:
|
boolean:
|
||||||
$ref: "#/$defs/StructChildMemberBuildBooleanProps"
|
$ref: "#/$defs/StructChildMemberBuildBooleanProps"'
|
||||||
|
required:
|
||||||
|
- boolean
|
||||||
StructChildMemberBuildBooleanProps:
|
StructChildMemberBuildBooleanProps:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
@ -181,6 +183,8 @@ $defs:
|
|||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- rule_present
|
- rule_present
|
||||||
|
required:
|
||||||
|
- on
|
||||||
|
|
||||||
# Leaf Struct Node
|
# Leaf Struct Node
|
||||||
LeafStructNodeDefinition:
|
LeafStructNodeDefinition:
|
||||||
@ -219,12 +223,8 @@ $defs:
|
|||||||
kind:
|
kind:
|
||||||
enum:
|
enum:
|
||||||
- string
|
- string
|
||||||
from:
|
|
||||||
enum:
|
|
||||||
- whole_pair
|
|
||||||
required:
|
required:
|
||||||
- kind
|
- kind
|
||||||
- from
|
|
||||||
|
|
||||||
# Enum node
|
# Enum node
|
||||||
EnumNodeDefinition:
|
EnumNodeDefinition:
|
||||||
|
|||||||
@ -33,7 +33,6 @@ Identifier:
|
|||||||
members:
|
members:
|
||||||
- name:
|
- name:
|
||||||
kind: string
|
kind: string
|
||||||
from: whole_pair
|
|
||||||
FullyQualifiedName:
|
FullyQualifiedName:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
@ -801,6 +800,7 @@ OrRhs:
|
|||||||
build:
|
build:
|
||||||
node:
|
node:
|
||||||
kind: Expression
|
kind: Expression
|
||||||
|
with: AndExpression
|
||||||
|
|
||||||
# And
|
# And
|
||||||
AndExpression:
|
AndExpression:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user