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::{
|
||||
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, ProductionNodeKind, ProductionStringFrom, SkipChild, StructBuildSpec,
|
||||
StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild,
|
||||
};
|
||||
use crate::util::make_build_fn_name;
|
||||
use convert_case::{Case, Casing};
|
||||
mod leaf_enum_spec;
|
||||
mod leaf_struct_spec;
|
||||
mod node_production_spec;
|
||||
mod polymorphic_enum_loop_spec;
|
||||
mod polymorphic_type_spec;
|
||||
mod production_spec;
|
||||
mod struct_spec;
|
||||
mod tree_enum_spec;
|
||||
pub(crate) mod util;
|
||||
|
||||
use crate::deserialize::leaf_enum_spec::deserialize_leaf_enum;
|
||||
use crate::deserialize::leaf_struct_spec::deserialize_leaf_struct;
|
||||
use crate::deserialize::node_production_spec::deserialize_node_production;
|
||||
use crate::deserialize::polymorphic_enum_loop_spec::deserialize_polymorphic_enum_loop;
|
||||
use crate::deserialize::polymorphic_type_spec::deserialize_polymorphic_type;
|
||||
use crate::deserialize::production_spec::deserialize_production;
|
||||
use crate::deserialize::struct_spec::deserialize_struct_spec;
|
||||
use crate::deserialize::tree_enum_spec::deserialize_tree_enum;
|
||||
use crate::spec::BuildSpec;
|
||||
use yaml_rust2::{Yaml, YamlLoader};
|
||||
|
||||
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 {
|
||||
if build_spec["children"].is_array() {
|
||||
let children = deserialize_struct_children(&build_spec["children"]);
|
||||
BuildSpec::Struct(StructBuildSpec::new(build_spec_name, children))
|
||||
} else if build_spec["members"].is_array() {
|
||||
let members = deserialize_leaf_struct_members(&build_spec["members"]);
|
||||
BuildSpec::LeafStruct(LeafStructBuildSpec::new(build_spec_name, members))
|
||||
} else if build_spec["rules"].is_array() {
|
||||
let rules = deserialize_enum_rules(&build_spec["rules"]);
|
||||
BuildSpec::Enum(EnumBuildSpec::new(build_spec_name, rules))
|
||||
} else if build_spec["leaf_rules"].is_array() {
|
||||
let leaf_rules = deserialize_leaf_enum_rules(&build_spec["leaf_rules"]);
|
||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
||||
} else if build_spec["produce"].is_hash() {
|
||||
BuildSpec::Production(deserialize_production_spec(
|
||||
if build_spec["struct"].is_hash() {
|
||||
BuildSpec::Struct(deserialize_struct_spec(
|
||||
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() {
|
||||
BuildSpec::Polymorphic(deserialize_polymorphic_spec(
|
||||
BuildSpec::PolymorphicType(deserialize_polymorphic_type(
|
||||
build_spec_name,
|
||||
&build_spec["polymorphic_type"],
|
||||
))
|
||||
} else if build_spec["polymorphic_build"].is_hash() {
|
||||
BuildSpec::PolymorphicBuild(deserialize_polymorphic_build_build_spec(
|
||||
} else if build_spec["polymorphic_enum_loop_build"].is_hash() {
|
||||
BuildSpec::PolymorphicEnumLoop(deserialize_polymorphic_enum_loop(
|
||||
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"],
|
||||
&build_spec["polymorphic_enum_loop_build"],
|
||||
))
|
||||
} else {
|
||||
panic!(
|
||||
"Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, production, polymorphic type, or polymorphic build type."
|
||||
);
|
||||
panic!("Missing or incorrect build type for {}", build_spec_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
Enum(EnumBuildSpec),
|
||||
Enum(TreeEnumBuildSpec),
|
||||
LeafEnum(LeafEnumBuildSpec),
|
||||
Struct(StructBuildSpec),
|
||||
Struct(StructSpec),
|
||||
LeafStruct(LeafStructBuildSpec),
|
||||
Production(ProductionBuildSpec),
|
||||
Polymorphic(PolymorphicTypeBuildSpec),
|
||||
PolymorphicBuild(PolymorphicBuildBuildSpec),
|
||||
PolymorphicEnum(PolymorphicEnumBuildSpec),
|
||||
}
|
||||
|
||||
// Enum build spec
|
||||
|
||||
pub struct EnumBuildSpec {
|
||||
build: String,
|
||||
rules: Vec<Box<EnumRule>>,
|
||||
}
|
||||
|
||||
impl EnumBuildSpec {
|
||||
pub fn new(build: &str, rules: Vec<Box<EnumRule>>) -> Self {
|
||||
EnumBuildSpec {
|
||||
build: build.to_string(),
|
||||
rules,
|
||||
}
|
||||
}
|
||||
|
||||
/// The enum type to be built, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
/// The individual rule specs.
|
||||
pub fn rules(&self) -> impl Iterator<Item = &EnumRule> {
|
||||
self.rules.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EnumRule {
|
||||
rule: String,
|
||||
child: Option<Box<EnumRuleChild>>,
|
||||
}
|
||||
|
||||
impl EnumRule {
|
||||
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
child,
|
||||
}
|
||||
}
|
||||
|
||||
/// The enum rule to match, in Pascal case.
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
pub fn child(&self) -> Option<&EnumRuleChild> {
|
||||
if let Some(child) = &self.child {
|
||||
Some(child.as_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EnumRuleChild {
|
||||
kind: Box<EnumRuleChildKind>,
|
||||
}
|
||||
|
||||
impl EnumRuleChild {
|
||||
pub fn new(kind: Box<EnumRuleChildKind>) -> Self {
|
||||
Self { kind }
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> &EnumRuleChildKind {
|
||||
&self.kind
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EnumRuleChildKind {
|
||||
Node(EnumRuleNodeChild),
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
USize,
|
||||
String,
|
||||
Boolean,
|
||||
}
|
||||
|
||||
pub struct EnumRuleNodeChild {
|
||||
build: String,
|
||||
}
|
||||
|
||||
impl EnumRuleNodeChild {
|
||||
pub fn new(build: &str) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
// Leaf enum build spec
|
||||
|
||||
pub struct LeafEnumBuildSpec {
|
||||
build: String,
|
||||
rules: Vec<Box<LeafEnumRule>>,
|
||||
}
|
||||
|
||||
impl LeafEnumBuildSpec {
|
||||
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
rules,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
pub fn rules(&self) -> impl Iterator<Item = &LeafEnumRule> {
|
||||
self.rules.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafEnumRule {
|
||||
rule: String,
|
||||
}
|
||||
|
||||
impl LeafEnumRule {
|
||||
pub fn new(rule: &str) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
}
|
||||
|
||||
// Struct build spec
|
||||
|
||||
pub struct StructBuildSpec {
|
||||
build: String,
|
||||
children: Vec<Box<StructChildSpec>>,
|
||||
}
|
||||
|
||||
impl StructBuildSpec {
|
||||
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
/// The type to be built, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
/// The children for this build spec.
|
||||
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
|
||||
self.children.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum StructChildSpec {
|
||||
SkipChild(SkipChild),
|
||||
VecChild(VecChild),
|
||||
MemberChild(MemberChild),
|
||||
}
|
||||
|
||||
pub struct SkipChild {
|
||||
name: String,
|
||||
rule: String,
|
||||
}
|
||||
|
||||
impl SkipChild {
|
||||
pub fn new(name: &str, rule: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: rule.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of this child spec.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The grammar rule to match.
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VecChild {
|
||||
name: String,
|
||||
rule: String,
|
||||
build: Box<VecChildToBuild>,
|
||||
}
|
||||
|
||||
impl VecChild {
|
||||
pub fn new(name: &str, rule: &str, build: Box<VecChildToBuild>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: rule.to_string(),
|
||||
build,
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of this child.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The rule to match to build this child.
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
/// The build info for this child.
|
||||
pub fn build(&self) -> &VecChildToBuild {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VecChildToBuild {
|
||||
Node(VecNodeChildToBuild),
|
||||
String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VecNodeChildToBuild {
|
||||
build: String,
|
||||
}
|
||||
|
||||
impl VecNodeChildToBuild {
|
||||
pub fn new(build: &str) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The type to build, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MemberChild {
|
||||
name: String,
|
||||
rule: String,
|
||||
build: Box<MemberChildToBuild>,
|
||||
}
|
||||
|
||||
impl MemberChild {
|
||||
pub fn new(name: &str, rule: &str, build: Box<MemberChildToBuild>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: rule.to_string(),
|
||||
build,
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of this child in the yaml file, in snake case.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The grammar rule to match to build this child.
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
/// The specification for what to actually build.
|
||||
pub fn build(&self) -> &MemberChildToBuild {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemberChildToBuild {
|
||||
Node(NodeChildToBuild),
|
||||
Boolean(BooleanChildToBuild),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NodeChildToBuild {
|
||||
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
|
||||
}
|
||||
NodeProduction(NodeProductionBuildSpec),
|
||||
PolymorphicType(PolymorphicTypeBuildSpec),
|
||||
PolymorphicEnumLoop(PolymorphicEnumLoopBuildSpec),
|
||||
}
|
||||
|
||||
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
|
||||
properties:
|
||||
boolean:
|
||||
$ref: "#/$defs/StructChildMemberBuildBooleanProps"
|
||||
$ref: "#/$defs/StructChildMemberBuildBooleanProps"'
|
||||
required:
|
||||
- boolean
|
||||
StructChildMemberBuildBooleanProps:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@ -181,6 +183,8 @@ $defs:
|
||||
type: string
|
||||
enum:
|
||||
- rule_present
|
||||
required:
|
||||
- on
|
||||
|
||||
# Leaf Struct Node
|
||||
LeafStructNodeDefinition:
|
||||
@ -219,12 +223,8 @@ $defs:
|
||||
kind:
|
||||
enum:
|
||||
- string
|
||||
from:
|
||||
enum:
|
||||
- whole_pair
|
||||
required:
|
||||
- kind
|
||||
- from
|
||||
|
||||
# Enum node
|
||||
EnumNodeDefinition:
|
||||
|
||||
@ -33,7 +33,6 @@ Identifier:
|
||||
members:
|
||||
- name:
|
||||
kind: string
|
||||
from: whole_pair
|
||||
FullyQualifiedName:
|
||||
struct:
|
||||
children:
|
||||
@ -801,6 +800,7 @@ OrRhs:
|
||||
build:
|
||||
node:
|
||||
kind: Expression
|
||||
with: AndExpression
|
||||
|
||||
# And
|
||||
AndExpression:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user