WIP refactor of deserialization and ast code generation.
This commit is contained in:
parent
2aee2cdd4e
commit
b5cdb8dd29
@ -1,11 +1,4 @@
|
||||
use crate::spec::{
|
||||
BooleanBuild, BuildSpec, ChildSpec, EnumBuildSpec, EnumRule, LeafEnumBuildSpec, LeafEnumRule,
|
||||
LeafEnumRuleBuild, LeafEnumRuleBuildChild, LeafStructBuildSpec, LeafStructChild,
|
||||
LeafStructChildType, SingleBooleanChildToBuild, SingleChild, SingleChildToBuild,
|
||||
SingleLiteralChildToBuild, SingleTypeChildToBuild, SkipChild, StructBuildSpec, VecChild,
|
||||
VecChildToBuild, VecTypeChildToBuild,
|
||||
};
|
||||
use crate::util::make_build_fn_name;
|
||||
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NodeChildToBuild, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
|
||||
use convert_case::{Case, Casing};
|
||||
use yaml_rust2::{Yaml, YamlLoader};
|
||||
|
||||
@ -13,150 +6,6 @@ fn get_as_bool(yaml: &Yaml) -> bool {
|
||||
yaml.as_bool().unwrap_or_else(|| false)
|
||||
}
|
||||
|
||||
fn get_vec_child_to_build(build: &Yaml, name: &str, rule: &str) -> VecChildToBuild {
|
||||
if build.is_hash() {
|
||||
let build_type = build["build"].as_str().unwrap();
|
||||
let var_name = build["var"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| build_type.to_case(Case::Snake));
|
||||
let with = build["with"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| make_build_fn_name(build_type));
|
||||
|
||||
VecChildToBuild::Type(VecTypeChildToBuild::new(build_type, &var_name, &with))
|
||||
} else {
|
||||
let build_as_str = build.as_str().unwrap_or(rule);
|
||||
VecChildToBuild::Type(VecTypeChildToBuild::new(
|
||||
build_as_str,
|
||||
name,
|
||||
make_build_fn_name(build_as_str).as_str(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_vec_child(name: &str, rule: &str, build: &Yaml) -> ChildSpec {
|
||||
ChildSpec::VecChild(VecChild::new(
|
||||
name,
|
||||
rule,
|
||||
get_vec_child_to_build(build, name, rule),
|
||||
))
|
||||
}
|
||||
|
||||
fn get_single_child_to_build(
|
||||
name: &str,
|
||||
rule: &str,
|
||||
optional: bool,
|
||||
build: &Yaml,
|
||||
) -> SingleChildToBuild {
|
||||
if build.is_hash() {
|
||||
match build["type"].as_str() {
|
||||
Some(r#type) => {
|
||||
let var_name = build["var"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or(name.to_string());
|
||||
match r#type {
|
||||
"boolean" => {
|
||||
if yaml_is_string(&build["on"], "rule_present") {
|
||||
SingleChildToBuild::Boolean(SingleBooleanChildToBuild::new(
|
||||
&var_name,
|
||||
BooleanBuild::RulePresent,
|
||||
))
|
||||
} else if yaml_is_string(&build["from"], "parse_whole_pair") {
|
||||
SingleChildToBuild::Boolean(SingleBooleanChildToBuild::new(
|
||||
&var_name,
|
||||
BooleanBuild::ParseWholePair,
|
||||
))
|
||||
} else {
|
||||
panic!("invalid build on/from with type boolean");
|
||||
}
|
||||
}
|
||||
"i32" => SingleChildToBuild::Int(SingleLiteralChildToBuild::new(&var_name)),
|
||||
"i64" => SingleChildToBuild::Long(SingleLiteralChildToBuild::new(&var_name)),
|
||||
"f64" => SingleChildToBuild::Double(SingleLiteralChildToBuild::new(&var_name)),
|
||||
"string" => {
|
||||
SingleChildToBuild::String(SingleLiteralChildToBuild::new(&var_name))
|
||||
}
|
||||
_ => panic!("unsupported build type: {}", r#type),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let or_else = build["or_else"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| {
|
||||
let or_else_default =
|
||||
build["or_else_default"].as_bool().unwrap_or_else(|| false);
|
||||
if or_else_default {
|
||||
Some(String::from("default"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
||||
rule, or_else, optional,
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match build.as_str() {
|
||||
Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
||||
s, None, optional,
|
||||
)),
|
||||
None => SingleChildToBuild::Type(SingleTypeChildToBuild::new(
|
||||
&rule,
|
||||
&name,
|
||||
&make_build_fn_name(&rule),
|
||||
None,
|
||||
optional,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_single_child(name: &str, rule: &str, optional: bool, build: &Yaml) -> ChildSpec {
|
||||
ChildSpec::SingleChild(SingleChild::new(
|
||||
name,
|
||||
rule,
|
||||
get_single_child_to_build(name, rule, optional, build),
|
||||
))
|
||||
}
|
||||
|
||||
fn get_child_specs(children: &Yaml) -> Vec<ChildSpec> {
|
||||
children
|
||||
.as_vec()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|child_spec| {
|
||||
if child_spec.is_hash() {
|
||||
let (name, props) = unwrap_single_member_hash(child_spec);
|
||||
|
||||
let rule = props["rule"]
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or(name.to_case(Case::Pascal));
|
||||
|
||||
if get_as_bool(&props["skip"]) {
|
||||
return ChildSpec::SkipChild(SkipChild::new(&name, &rule));
|
||||
}
|
||||
|
||||
let build = &props["build"];
|
||||
|
||||
if get_as_bool(&props["vec"]) {
|
||||
get_vec_child(&name, &rule, build)
|
||||
} else {
|
||||
let optional = get_as_bool(&props["optional"]);
|
||||
get_single_child(&name, &rule, optional, build)
|
||||
}
|
||||
} else {
|
||||
ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap()))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
||||
let as_hash = hash.as_hash().unwrap();
|
||||
if as_hash.is_empty() {
|
||||
@ -169,110 +18,267 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
||||
(key_as_string, member_value)
|
||||
}
|
||||
|
||||
fn get_leaf_enum_rules(rules: &Yaml) -> Vec<LeafEnumRule> {
|
||||
rules
|
||||
.as_vec()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|rule| {
|
||||
if rule.is_hash() {
|
||||
let (rule_as_string, rule_hash) = unwrap_single_member_hash(rule);
|
||||
if get_as_bool(&rule_hash["child"]) {
|
||||
let build = LeafEnumRuleBuild::new(
|
||||
&rule_as_string,
|
||||
Some(LeafEnumRuleBuildChild::new(
|
||||
&rule_as_string,
|
||||
&make_build_fn_name(&rule_as_string),
|
||||
)),
|
||||
);
|
||||
LeafEnumRule::new(&rule_as_string, build)
|
||||
} else {
|
||||
panic!(
|
||||
"if a leaf_enum rule is a hash, its child prop must be present and true"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let rule_as_str = rule.as_str().unwrap();
|
||||
let build = LeafEnumRuleBuild::new(rule_as_str, None);
|
||||
LeafEnumRule::new(rule_as_str, build)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_enum_rules(rule_specs: &Yaml) -> Vec<EnumRule> {
|
||||
rule_specs
|
||||
.as_vec()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|rule_spec| {
|
||||
if rule_spec.is_hash() {
|
||||
let rule = rule_spec["rule"].as_str().unwrap();
|
||||
let build = rule_spec["build"].as_str().unwrap();
|
||||
let with = if !rule_spec["with"].is_badvalue() {
|
||||
rule_spec.as_str().unwrap().to_string()
|
||||
} else {
|
||||
make_build_fn_name(build)
|
||||
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
||||
let kind = match production_yaml["kind"].as_str().unwrap() {
|
||||
"int" => ProductionKind::Int,
|
||||
"long" => ProductionKind::Long,
|
||||
"double" => ProductionKind::Double,
|
||||
"boolean" => ProductionKind::Boolean,
|
||||
"string" => {
|
||||
let from = match production_yaml["from"].as_str().unwrap() {
|
||||
"string_inner" => ProductionStringFrom::StringInner,
|
||||
"whole_pair" => ProductionStringFrom::WholePair,
|
||||
_ => panic!("invalid from: {}", production_yaml["from"].as_str().unwrap()),
|
||||
};
|
||||
ProductionKind::String(from)
|
||||
},
|
||||
_ => panic!("invalid kind: {}", production_yaml["kind"].as_str().unwrap()),
|
||||
};
|
||||
ProductionBuildSpec::new(rule, kind)
|
||||
}
|
||||
|
||||
EnumRule::new(rule, build, &with)
|
||||
} else {
|
||||
EnumRule::from_rule(rule_spec.as_str().unwrap())
|
||||
}
|
||||
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 get_leaf_struct_child_specs(children: &Yaml) -> Vec<LeafStructChild> {
|
||||
fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option<Box<EnumRuleChild>> {
|
||||
if !rule_props["child"].as_bool().unwrap() {
|
||||
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);
|
||||
|
||||
Box::new(MemberChildToBuild::Node(NodeChildToBuild::new(
|
||||
rule, 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 {
|
||||
panic!("build is required for a member child")
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
None,
|
||||
false,
|
||||
))),
|
||||
)))
|
||||
}
|
||||
|
||||
fn deserialize_struct_children(children: &Yaml) -> Vec<Box<StructChildSpec>> {
|
||||
children
|
||||
.as_vec()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|child_spec| {
|
||||
let (name, hash) = unwrap_single_member_hash(child_spec);
|
||||
LeafStructChild::new(&name, LeafStructChildType::String)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn yaml_is_string(yaml: &Yaml, test: &str) -> bool {
|
||||
match yaml.as_str() {
|
||||
Some(s) => s == test,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_build_spec(build_spec_name: &Yaml, build_spec: &Yaml) -> BuildSpec {
|
||||
let build_spec_name_pascal = build_spec_name.as_str().unwrap();
|
||||
let node_type = &build_spec["type"];
|
||||
let children = &build_spec["children"];
|
||||
let rules = &build_spec["rules"];
|
||||
|
||||
if yaml_is_string(node_type, "leaf_struct") && children.is_array() {
|
||||
let child_specs = get_leaf_struct_child_specs(children);
|
||||
BuildSpec::LeafStruct(LeafStructBuildSpec::new(
|
||||
build_spec_name_pascal,
|
||||
build_spec_name_pascal,
|
||||
child_specs,
|
||||
))
|
||||
} else if children.is_array() {
|
||||
let child_specs = get_child_specs(children);
|
||||
BuildSpec::Struct(StructBuildSpec::from_name(
|
||||
build_spec_name_pascal,
|
||||
child_specs,
|
||||
))
|
||||
} else if yaml_is_string(node_type, "leaf_enum") && rules.is_array() {
|
||||
let leaf_enum_rules = get_leaf_enum_rules(rules);
|
||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::from_name(
|
||||
build_spec_name_pascal,
|
||||
leaf_enum_rules,
|
||||
))
|
||||
} else if rules.is_array() {
|
||||
// enum node
|
||||
let enum_rules = get_enum_rules(rules);
|
||||
BuildSpec::Enum(EnumBuildSpec::from_name(build_spec_name_pascal, enum_rules))
|
||||
if child_spec.is_hash() {
|
||||
deserialize_struct_hash_child(child_spec)
|
||||
} else {
|
||||
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type.");
|
||||
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(build_spec_name, &build_spec["produce"]))
|
||||
} else {
|
||||
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,6 +289,9 @@ pub fn deserialize_yaml_spec(yaml: &str) -> Vec<BuildSpec> {
|
||||
doc.as_hash()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(build_spec_name, build_spec)| deserialize_build_spec(build_spec_name, build_spec))
|
||||
.map(|(build_spec_name, build_spec)| {
|
||||
let name_as_str = build_spec_name.as_str().unwrap();
|
||||
deserialize_build_spec(name_as_str, build_spec)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::spec::{LeafStructBuildSpec, LeafStructChildType};
|
||||
use crate::spec::{LeafStructBuildSpec, LeafStructMemberKind};
|
||||
use crate::util::{make_build_fn_name, make_build_pair};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
@ -9,12 +9,12 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea
|
||||
let return_type_ident = format_ident!("{}", build_spec.build());
|
||||
|
||||
let child_builders = build_spec
|
||||
.children()
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let child_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
match leaf_struct_child.r#type() {
|
||||
LeafStructChildType::String => {
|
||||
LeafStructMemberKind::String => {
|
||||
quote! {
|
||||
let #child_ident = #pair_ident.as_str()
|
||||
}
|
||||
@ -24,7 +24,7 @@ pub fn make_leaf_struct_build_fn(build_spec: &LeafStructBuildSpec) -> TokenStrea
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let child_args = build_spec
|
||||
.children()
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -2,6 +2,7 @@ pub mod deserialize;
|
||||
mod enum_build_fn;
|
||||
mod leaf_enum_build_fn;
|
||||
mod leaf_struct_build_fn;
|
||||
mod production_build_fn;
|
||||
mod spec;
|
||||
mod struct_build_fn;
|
||||
mod type_gen;
|
||||
@ -10,6 +11,7 @@ mod util;
|
||||
use crate::enum_build_fn::make_enum_build_fn;
|
||||
use crate::leaf_enum_build_fn::make_leaf_enum_build_fn;
|
||||
use crate::leaf_struct_build_fn::make_leaf_struct_build_fn;
|
||||
use crate::production_build_fn::make_production_build_fn;
|
||||
use crate::struct_build_fn::make_struct_build_fn;
|
||||
use crate::type_gen::make_type;
|
||||
use proc_macro2::TokenStream;
|
||||
@ -21,16 +23,22 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
||||
println!("*** BuildSpec ***");
|
||||
match build_spec {
|
||||
BuildSpec::Enum(enum_build_spec) => {
|
||||
println!("Spec name: {}", enum_build_spec.name());
|
||||
println!("Enum Spec - build: {}", enum_build_spec.build());
|
||||
}
|
||||
BuildSpec::LeafEnum(leaf_enum_build_spec) => {
|
||||
println!("Spec name: {}", leaf_enum_build_spec.name());
|
||||
println!("Leaf Enum Spec - build: {}", leaf_enum_build_spec.build());
|
||||
}
|
||||
BuildSpec::Struct(struct_build_spec) => {
|
||||
println!("Spec name: {}", struct_build_spec.name());
|
||||
println!("Struct Spec - build: {}", struct_build_spec.build());
|
||||
}
|
||||
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
|
||||
println!("Spec name: {}", leaf_struct_build_spec.name());
|
||||
println!(
|
||||
"Leaf Struct Spec - build: {}",
|
||||
leaf_struct_build_spec.build()
|
||||
);
|
||||
}
|
||||
BuildSpec::Production(production_build_spec) => {
|
||||
println!("Production Spec - rule: {}", production_build_spec.rule())
|
||||
}
|
||||
}
|
||||
println!("{:#?}", token_stream);
|
||||
@ -72,6 +80,11 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
||||
debug_built_spec(build_spec, &stream);
|
||||
stream
|
||||
}
|
||||
BuildSpec::Production(production_build_spec) => {
|
||||
let stream = make_production_build_fn(production_build_spec);
|
||||
debug_built_spec(build_spec, &stream);
|
||||
stream
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let combined = quote! {
|
||||
@ -103,33 +116,3 @@ pub fn generate_files(build_specs: &[BuildSpec]) -> Vec<AstGeneratedFile> {
|
||||
generate_node_file(build_specs),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn test_dump() -> String {
|
||||
let build_specs = deserialize::deserialize_yaml_spec(include_str!("../../src/parser/ast.yaml"));
|
||||
let mut streams: Vec<TokenStream> = vec![];
|
||||
|
||||
for build_spec in &build_specs {
|
||||
let type_stream = make_type(build_spec);
|
||||
debug_built_spec(build_spec, &type_stream);
|
||||
streams.push(type_stream);
|
||||
}
|
||||
|
||||
for build_spec in &build_specs {
|
||||
match build_spec {
|
||||
BuildSpec::Enum(_) => {}
|
||||
BuildSpec::LeafEnum(_) => {}
|
||||
BuildSpec::Struct(struct_spec) => {
|
||||
let struct_build_fn_stream = make_struct_build_fn(struct_spec);
|
||||
debug_built_spec(build_spec, &struct_build_fn_stream);
|
||||
streams.push(struct_build_fn_stream);
|
||||
}
|
||||
BuildSpec::LeafStruct(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let combined = quote! {
|
||||
#(#streams)*
|
||||
};
|
||||
let file: File = syn::parse2(combined).unwrap();
|
||||
prettyplease::unparse(&file)
|
||||
}
|
||||
|
||||
90
ast-generator/src/production_build_fn.rs
Normal file
90
ast-generator/src/production_build_fn.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use crate::spec::{ProductionBuildSpec, ProductionKind, ProductionStringFrom};
|
||||
use crate::util::{make_build_fn_name, make_build_pair};
|
||||
|
||||
pub fn make_production_build_fn(production_build_spec: &ProductionBuildSpec) -> TokenStream {
|
||||
let build_fn_ident = format_ident!("{}", make_build_fn_name(production_build_spec.rule()));
|
||||
let return_type_ident = match production_build_spec.kind() {
|
||||
ProductionKind::Int => format_ident!("i32"),
|
||||
ProductionKind::Long => format_ident!("i64"),
|
||||
ProductionKind::Double => format_ident!("f64"),
|
||||
ProductionKind::String(_) => format_ident!("String"),
|
||||
ProductionKind::Boolean => format_ident!("bool"),
|
||||
};
|
||||
let pair_ident = format_ident!("{}", make_build_pair(production_build_spec.rule()));
|
||||
|
||||
let pair_mapper = match production_build_spec.kind() {
|
||||
ProductionKind::Int => quote! {
|
||||
let number_base_pair = #pair_ident.to_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_number_base_pair = number_base_pair.to_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
match inner_number_base_pair.as_rule() {
|
||||
Rule::BinaryBase => {
|
||||
todo!()
|
||||
}
|
||||
Rule::HexadecimalBase => {
|
||||
todo!()
|
||||
}
|
||||
Rule::DecimalBase => {
|
||||
inner_number_base_pair.as_str().parse::<i32>().unwrap()
|
||||
}
|
||||
_ => panic!()
|
||||
}
|
||||
},
|
||||
ProductionKind::Long => quote! {
|
||||
let number_base_pair = #pair_ident.to_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_number_base_pair = number_base_pair.to_inner()
|
||||
.next()
|
||||
.unwrap();
|
||||
match inner_number_base_pair.as_rule() {
|
||||
Rule::BinaryBase => {
|
||||
todo!()
|
||||
}
|
||||
Rule::HexadecimalBase => {
|
||||
todo!()
|
||||
}
|
||||
Rule::DecimalBase => {
|
||||
inner_number_base_pair.as_str().parse::<i64>().unwrap()
|
||||
}
|
||||
_ => panic!()
|
||||
}
|
||||
},
|
||||
ProductionKind::Double => quote! {
|
||||
#pair_ident.as_str().parse::<f64>().unwrap()
|
||||
},
|
||||
ProductionKind::String(from) => {
|
||||
match from {
|
||||
ProductionStringFrom::StringInner => {
|
||||
quote! {
|
||||
#pair_ident.to_inner()
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
ProductionStringFrom::WholePair => {
|
||||
quote! {
|
||||
#pair_ident.as_string().to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ProductionKind::Boolean => quote! {
|
||||
#pair_ident.as_str().parse::<bool>().unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||
#pair_mapper
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,59 +6,45 @@ pub enum BuildSpec {
|
||||
LeafEnum(LeafEnumBuildSpec),
|
||||
Struct(StructBuildSpec),
|
||||
LeafStruct(LeafStructBuildSpec),
|
||||
Production(ProductionBuildSpec),
|
||||
}
|
||||
|
||||
// Enum build spec
|
||||
|
||||
pub struct EnumBuildSpec {
|
||||
name: String,
|
||||
build: String,
|
||||
rules: Vec<EnumRule>,
|
||||
rules: Vec<Box<EnumRule>>,
|
||||
}
|
||||
|
||||
impl EnumBuildSpec {
|
||||
pub fn from_name(name: &str, rules: Vec<EnumRule>) -> Self {
|
||||
pub fn new(build: &str, rules: Vec<Box<EnumRule>>) -> Self {
|
||||
EnumBuildSpec {
|
||||
name: name.to_string(),
|
||||
build: name.to_string(),
|
||||
build: build.to_string(),
|
||||
rules,
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level key for the build spec in the yaml file.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The enum type to be built, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
/// The individual rule specs.
|
||||
pub fn rules(&self) -> &[EnumRule] {
|
||||
&self.rules
|
||||
pub fn rules(&self) -> impl Iterator<Item = &EnumRule> {
|
||||
self.rules.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EnumRule {
|
||||
rule: String,
|
||||
build: String,
|
||||
with: String,
|
||||
child: Option<Box<EnumRuleChild>>
|
||||
}
|
||||
|
||||
impl EnumRule {
|
||||
pub fn from_rule(rule: &str) -> Self {
|
||||
pub fn new(rule: &str, child: Option<Box<EnumRuleChild>>) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
build: rule.to_string(),
|
||||
with: make_build_fn_name(rule),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(rule: &str, build: &str, with: &str) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
build: build.to_string(),
|
||||
with: with.to_string(),
|
||||
child
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,160 +53,125 @@ impl EnumRule {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
/// The type to build, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
pub fn child(&self) -> Option<&EnumRuleChild> {
|
||||
if let Some(child) = &self.child {
|
||||
Some(child.as_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
/// The build-fn name, in snake case.
|
||||
pub fn with(&self) -> &str {
|
||||
&self.with
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
name: String,
|
||||
build: String,
|
||||
rules: Vec<LeafEnumRule>,
|
||||
rules: Vec<Box<LeafEnumRule>>,
|
||||
}
|
||||
|
||||
impl LeafEnumBuildSpec {
|
||||
pub fn from_name(name: &str, rules: Vec<LeafEnumRule>) -> Self {
|
||||
pub fn new(build: &str, rules: Vec<Box<LeafEnumRule>>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
build: name.to_string(),
|
||||
rules,
|
||||
build: build.to_string(),
|
||||
rules
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
pub fn rules(&self) -> &[LeafEnumRule] {
|
||||
&self.rules
|
||||
pub fn rules(&self) -> impl Iterator<Item = &LeafEnumRule> {
|
||||
self.rules.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafEnumRule {
|
||||
rule: String,
|
||||
build: LeafEnumRuleBuild,
|
||||
}
|
||||
|
||||
impl LeafEnumRule {
|
||||
pub fn new(rule: &str, build: LeafEnumRuleBuild) -> Self {
|
||||
pub fn new(rule: &str) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
build,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &LeafEnumRuleBuild {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafEnumRuleBuild {
|
||||
rule: String,
|
||||
child: Option<LeafEnumRuleBuildChild>,
|
||||
}
|
||||
|
||||
impl LeafEnumRuleBuild {
|
||||
pub fn new(rule: &str, child: Option<LeafEnumRuleBuildChild>) -> Self {
|
||||
Self {
|
||||
rule: rule.to_string(),
|
||||
child,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rule(&self) -> &str {
|
||||
&self.rule
|
||||
}
|
||||
|
||||
pub fn child(&self) -> Option<&LeafEnumRuleBuildChild> {
|
||||
self.child.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafEnumRuleBuildChild {
|
||||
build: String,
|
||||
with: String,
|
||||
}
|
||||
|
||||
impl LeafEnumRuleBuildChild {
|
||||
pub fn new(build: &str, with: &str) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
with: with.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
pub fn with(&self) -> &str {
|
||||
&self.with
|
||||
}
|
||||
}
|
||||
// Struct build spec
|
||||
|
||||
pub struct StructBuildSpec {
|
||||
name: String,
|
||||
build: String,
|
||||
var_name: String,
|
||||
with: String,
|
||||
children: Vec<ChildSpec>,
|
||||
children: Vec<Box<StructChildSpec>>,
|
||||
}
|
||||
|
||||
impl StructBuildSpec {
|
||||
pub fn from_name(name: &str, child_specs: Vec<ChildSpec>) -> Self {
|
||||
pub fn new(build: &str, children: Vec<Box<StructChildSpec>>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
build: name.to_string(),
|
||||
var_name: name.to_case(Case::Snake),
|
||||
with: make_build_fn_name(name),
|
||||
children: child_specs,
|
||||
build: build.to_string(),
|
||||
children
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level name of this build spec.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The type to be built, in Pascal case.
|
||||
pub fn build(&self) -> &str {
|
||||
&self.build
|
||||
}
|
||||
|
||||
/// The name of the variable to be built, in snake case.
|
||||
pub fn var_name(&self) -> &str {
|
||||
&self.var_name
|
||||
}
|
||||
|
||||
/// The build-fn name, in snake case.
|
||||
pub fn with(&self) -> &str {
|
||||
&self.with
|
||||
}
|
||||
|
||||
/// The children for this build spec.
|
||||
pub fn children(&self) -> &[ChildSpec] {
|
||||
&self.children
|
||||
pub fn children(&self) -> impl Iterator<Item = &StructChildSpec> {
|
||||
self.children.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ChildSpec {
|
||||
pub enum StructChildSpec {
|
||||
SkipChild(SkipChild),
|
||||
VecChild(VecChild),
|
||||
SingleChild(SingleChild),
|
||||
MemberChild(MemberChild),
|
||||
}
|
||||
|
||||
pub struct SkipChild {
|
||||
@ -250,11 +201,11 @@ impl SkipChild {
|
||||
pub struct VecChild {
|
||||
name: String,
|
||||
rule: String,
|
||||
build: VecChildToBuild,
|
||||
build: Box<VecChildToBuild>,
|
||||
}
|
||||
|
||||
impl VecChild {
|
||||
pub fn new(name: &str, rule: &str, build: VecChildToBuild) -> Self {
|
||||
pub fn new(name: &str, rule: &str, build: Box<VecChildToBuild>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: rule.to_string(),
|
||||
@ -280,62 +231,35 @@ impl VecChild {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VecChildToBuild {
|
||||
Type(VecTypeChildToBuild),
|
||||
Node(VecNodeChildToBuild),
|
||||
String
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VecTypeChildToBuild {
|
||||
pub struct VecNodeChildToBuild {
|
||||
build: String,
|
||||
var_name: String,
|
||||
with: String,
|
||||
}
|
||||
|
||||
impl VecTypeChildToBuild {
|
||||
pub fn new(build: &str, var_name: &str, with: &str) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
var_name: var_name.to_string(),
|
||||
with: with.to_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
|
||||
}
|
||||
|
||||
/// The name of the variable to build, in snake case.
|
||||
pub fn var_name(&self) -> &str {
|
||||
&self.var_name
|
||||
}
|
||||
|
||||
/// The build-fn name.
|
||||
pub fn with(&self) -> &str {
|
||||
&self.with
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleChild {
|
||||
pub struct MemberChild {
|
||||
name: String,
|
||||
rule: String,
|
||||
build: SingleChildToBuild,
|
||||
build: Box<MemberChildToBuild>,
|
||||
}
|
||||
|
||||
impl SingleChild {
|
||||
pub fn from_name_snake(name: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: name.to_case(Case::Pascal),
|
||||
build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
|
||||
&name.to_case(Case::Pascal),
|
||||
None,
|
||||
false,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(name: &str, rule: &str, build: SingleChildToBuild) -> Self {
|
||||
impl MemberChild {
|
||||
pub fn new(name: &str, rule: &str, build: Box<MemberChildToBuild>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
rule: rule.to_string(),
|
||||
@ -354,56 +278,32 @@ impl SingleChild {
|
||||
}
|
||||
|
||||
/// The specification for what to actually build.
|
||||
pub fn build(&self) -> &SingleChildToBuild {
|
||||
pub fn build(&self) -> &MemberChildToBuild {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SingleChildToBuild {
|
||||
Type(SingleTypeChildToBuild),
|
||||
Boolean(SingleBooleanChildToBuild),
|
||||
Int(SingleLiteralChildToBuild),
|
||||
Long(SingleLiteralChildToBuild),
|
||||
Double(SingleLiteralChildToBuild),
|
||||
String(SingleLiteralChildToBuild),
|
||||
pub enum MemberChildToBuild {
|
||||
Node(NodeChildToBuild),
|
||||
Boolean(BooleanChildToBuild),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleTypeChildToBuild {
|
||||
pub struct NodeChildToBuild {
|
||||
build: String,
|
||||
var_name: String,
|
||||
with: String,
|
||||
or_else: Option<String>,
|
||||
optional: bool,
|
||||
}
|
||||
|
||||
impl SingleTypeChildToBuild {
|
||||
pub fn from_build_or_rule(
|
||||
build_or_rule: &str,
|
||||
or_else: Option<String>,
|
||||
optional: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
build: build_or_rule.to_string(),
|
||||
var_name: build_or_rule.to_case(Case::Snake),
|
||||
with: make_build_fn_name(build_or_rule),
|
||||
or_else,
|
||||
optional,
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeChildToBuild {
|
||||
pub fn new(
|
||||
build: &str,
|
||||
var_name: &str,
|
||||
with: &str,
|
||||
or_else: Option<String>,
|
||||
optional: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
build: build.to_string(),
|
||||
var_name: var_name.to_string(),
|
||||
with: with.to_string(),
|
||||
or_else,
|
||||
optional,
|
||||
}
|
||||
@ -414,16 +314,6 @@ impl SingleTypeChildToBuild {
|
||||
&self.build
|
||||
}
|
||||
|
||||
/// The variable name to build, in snake case.
|
||||
pub fn var_name(&self) -> &str {
|
||||
&self.var_name
|
||||
}
|
||||
|
||||
/// The build-fn name.
|
||||
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()
|
||||
@ -436,89 +326,56 @@ impl SingleTypeChildToBuild {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleBooleanChildToBuild {
|
||||
var_name: String,
|
||||
build: BooleanBuild,
|
||||
pub struct BooleanChildToBuild {
|
||||
name: String
|
||||
}
|
||||
|
||||
impl SingleBooleanChildToBuild {
|
||||
pub fn new(var_name: &str, build: BooleanBuild) -> Self {
|
||||
impl BooleanChildToBuild {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
var_name: var_name.to_string(),
|
||||
build,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_name(&self) -> &str {
|
||||
&self.var_name
|
||||
}
|
||||
|
||||
pub fn build(&self) -> &BooleanBuild {
|
||||
&self.build
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BooleanBuild {
|
||||
RulePresent,
|
||||
ParseWholePair,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleLiteralChildToBuild {
|
||||
var_name: String,
|
||||
}
|
||||
|
||||
impl SingleLiteralChildToBuild {
|
||||
pub fn new(var_name: &str) -> Self {
|
||||
Self {
|
||||
var_name: var_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_name(&self) -> &str {
|
||||
&self.var_name
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafStructBuildSpec {
|
||||
name: String,
|
||||
build: String,
|
||||
children: Vec<LeafStructChild>,
|
||||
}
|
||||
|
||||
impl LeafStructBuildSpec {
|
||||
pub fn new(name: &str, build: &str, children: Vec<LeafStructChild>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
build: build.to_string(),
|
||||
children,
|
||||
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 children(&self) -> &[LeafStructChild] {
|
||||
&self.children
|
||||
pub fn members(&self) -> impl Iterator<Item = &LeafStructMember> {
|
||||
self.members.iter().map(Box::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LeafStructChild {
|
||||
pub struct LeafStructMember {
|
||||
name: String,
|
||||
r#type: LeafStructChildType,
|
||||
kind: LeafStructMemberKind,
|
||||
}
|
||||
|
||||
impl LeafStructChild {
|
||||
pub fn new(name: &str, r#type: LeafStructChildType) -> Self {
|
||||
impl LeafStructMember {
|
||||
pub fn new(name: &str, kind: LeafStructMemberKind) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
r#type,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,11 +383,46 @@ impl LeafStructChild {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn r#type(&self) -> &LeafStructChildType {
|
||||
&self.r#type
|
||||
pub fn kind(&self) -> &LeafStructMemberKind {
|
||||
&self.kind
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LeafStructChildType {
|
||||
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
|
||||
}
|
||||
|
||||
pub enum ProductionStringFrom {
|
||||
StringInner,
|
||||
WholePair
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::spec::{
|
||||
BooleanBuild, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild,
|
||||
SingleLiteralChildToBuild, SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild,
|
||||
BooleanChildToBuild, MemberChildToBuild, NodeChildToBuild,
|
||||
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
||||
};
|
||||
use crate::util::make_build_pair;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
@ -8,7 +8,7 @@ use quote::{format_ident, quote};
|
||||
|
||||
fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
|
||||
let (child_ident, child_type_ident) = match vec_child.build() {
|
||||
VecChildToBuild::Type(vec_type_child) => (
|
||||
VecChildToBuild::Node(vec_type_child) => (
|
||||
format_ident!("{}", vec_type_child.var_name()),
|
||||
format_ident!("{}", vec_type_child.build()),
|
||||
),
|
||||
@ -18,7 +18,7 @@ fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_single_type_child_holder(single_type_child: &SingleTypeChildToBuild) -> TokenStream {
|
||||
fn make_single_type_child_holder(single_type_child: &NodeChildToBuild) -> TokenStream {
|
||||
let child_ident = format_ident!("{}", single_type_child.var_name());
|
||||
let child_type_ident = format_ident!("{}", single_type_child.build());
|
||||
quote! {
|
||||
@ -26,10 +26,8 @@ fn make_single_type_child_holder(single_type_child: &SingleTypeChildToBuild) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn make_single_boolean_child_holder(
|
||||
single_boolean_child: &SingleBooleanChildToBuild,
|
||||
) -> TokenStream {
|
||||
let child_ident = format_ident!("{}", single_boolean_child.var_name());
|
||||
fn make_single_boolean_child_holder(single_boolean_child: &BooleanChildToBuild) -> TokenStream {
|
||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
||||
quote! {
|
||||
let mut #child_ident: bool = false
|
||||
}
|
||||
@ -45,30 +43,30 @@ fn make_literal_child_holder(
|
||||
}
|
||||
}
|
||||
|
||||
fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> {
|
||||
fn make_child_holder(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
||||
match child_spec {
|
||||
ChildSpec::SkipChild(_) => None,
|
||||
ChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
|
||||
ChildSpec::SingleChild(single_child) => match single_child.build() {
|
||||
SingleChildToBuild::Type(single_type_child) => {
|
||||
StructChildSpec::SkipChild(_) => None,
|
||||
StructChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
|
||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
||||
MemberChildToBuild::Node(single_type_child) => {
|
||||
Some(make_single_type_child_holder(single_type_child))
|
||||
}
|
||||
SingleChildToBuild::Boolean(boolean_child) => {
|
||||
MemberChildToBuild::Boolean(boolean_child) => {
|
||||
Some(make_single_boolean_child_holder(boolean_child))
|
||||
}
|
||||
SingleChildToBuild::Int(literal_child) => Some(make_literal_child_holder(
|
||||
MemberChildToBuild::Int(literal_child) => Some(make_literal_child_holder(
|
||||
literal_child,
|
||||
format_ident!("i32"),
|
||||
)),
|
||||
SingleChildToBuild::Long(literal_child) => Some(make_literal_child_holder(
|
||||
MemberChildToBuild::Long(literal_child) => Some(make_literal_child_holder(
|
||||
literal_child,
|
||||
format_ident!("i64"),
|
||||
)),
|
||||
SingleChildToBuild::Double(literal_child) => Some(make_literal_child_holder(
|
||||
MemberChildToBuild::Double(literal_child) => Some(make_literal_child_holder(
|
||||
literal_child,
|
||||
format_ident!("f64"),
|
||||
)),
|
||||
SingleChildToBuild::String(literal_child) => Some(make_literal_child_holder(
|
||||
MemberChildToBuild::String(literal_child) => Some(make_literal_child_holder(
|
||||
literal_child,
|
||||
format_ident!("String"),
|
||||
)),
|
||||
@ -80,12 +78,12 @@ fn get_literal_child_ident(literal_child: &SingleLiteralChildToBuild) -> Ident {
|
||||
format_ident!("{}", literal_child.var_name())
|
||||
}
|
||||
|
||||
fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
|
||||
fn make_match_action(child_spec: &StructChildSpec) -> TokenStream {
|
||||
match child_spec {
|
||||
ChildSpec::SkipChild(_) => quote! {},
|
||||
ChildSpec::VecChild(vec_child) => {
|
||||
StructChildSpec::SkipChild(_) => quote! {},
|
||||
StructChildSpec::VecChild(vec_child) => {
|
||||
let (child_name_ident, build_fn_ident) = match vec_child.build() {
|
||||
VecChildToBuild::Type(vec_type_child) => (
|
||||
VecChildToBuild::Node(vec_type_child) => (
|
||||
format_ident!("{}", vec_type_child.var_name()),
|
||||
format_ident!("{}", vec_type_child.with()),
|
||||
),
|
||||
@ -94,16 +92,16 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
|
||||
#child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
|
||||
}
|
||||
}
|
||||
ChildSpec::SingleChild(single_child) => match single_child.build() {
|
||||
SingleChildToBuild::Type(single_type_child) => {
|
||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
||||
MemberChildToBuild::Node(single_type_child) => {
|
||||
let child_name_ident = format_ident!("{}", single_type_child.var_name());
|
||||
let build_fn_ident = format_ident!("{}", single_type_child.with());
|
||||
quote! {
|
||||
#child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::Boolean(single_boolean_child) => {
|
||||
let child_name_ident = format_ident!("{}", single_boolean_child.var_name());
|
||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
||||
let child_name_ident = format_ident!("{}", single_boolean_child.name());
|
||||
match single_boolean_child.build() {
|
||||
BooleanBuild::RulePresent => quote! {
|
||||
#child_name_ident = true
|
||||
@ -113,13 +111,13 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
|
||||
},
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::Int(literal_child) => {
|
||||
MemberChildToBuild::Int(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
quote! {
|
||||
#child_ident = Some(inner_pair.as_str().parse().unwrap())
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::Long(literal_child) => {
|
||||
MemberChildToBuild::Long(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
quote! {
|
||||
let as_string = inner_pair.as_str();
|
||||
@ -127,13 +125,13 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
|
||||
#child_ident = Some(without_el.parse().unwrap())
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::Double(literal_child) => {
|
||||
MemberChildToBuild::Double(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
quote! {
|
||||
#child_ident = Some(inner_pair.as_str().parse().unwrap())
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::String(literal_child) => {
|
||||
MemberChildToBuild::String(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
quote! {
|
||||
#child_ident = Some(inner_pair.as_str().to_string())
|
||||
@ -143,11 +141,11 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_rule_matcher(child_spec: &ChildSpec) -> TokenStream {
|
||||
fn make_rule_matcher(child_spec: &StructChildSpec) -> TokenStream {
|
||||
let rule_ident = match child_spec {
|
||||
ChildSpec::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
|
||||
ChildSpec::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
|
||||
ChildSpec::SingleChild(single_child) => format_ident!("{}", single_child.rule()),
|
||||
StructChildSpec::SkipChild(skip_child) => format_ident!("{}", skip_child.rule()),
|
||||
StructChildSpec::VecChild(vec_child) => format_ident!("{}", vec_child.rule()),
|
||||
StructChildSpec::MemberChild(single_child) => format_ident!("{}", single_child.rule()),
|
||||
};
|
||||
let action = make_match_action(child_spec);
|
||||
|
||||
@ -158,19 +156,19 @@ fn make_rule_matcher(child_spec: &ChildSpec) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_child_arg(child_spec: &ChildSpec) -> Option<TokenStream> {
|
||||
fn make_child_arg(child_spec: &StructChildSpec) -> Option<TokenStream> {
|
||||
match child_spec {
|
||||
ChildSpec::SkipChild(_) => None,
|
||||
ChildSpec::VecChild(vec_child) => {
|
||||
StructChildSpec::SkipChild(_) => None,
|
||||
StructChildSpec::VecChild(vec_child) => {
|
||||
let child_ident = match vec_child.build() {
|
||||
VecChildToBuild::Type(vec_type_child) => {
|
||||
VecChildToBuild::Node(vec_type_child) => {
|
||||
format_ident!("{}", vec_type_child.var_name())
|
||||
}
|
||||
};
|
||||
Some(quote! { #child_ident })
|
||||
}
|
||||
ChildSpec::SingleChild(single_child) => match single_child.build() {
|
||||
SingleChildToBuild::Type(single_type_child) => {
|
||||
StructChildSpec::MemberChild(single_child) => match single_child.build() {
|
||||
MemberChildToBuild::Node(single_type_child) => {
|
||||
let child_ident = format_ident!("{}", single_type_child.var_name());
|
||||
if single_type_child.optional() {
|
||||
Some(quote! { #child_ident })
|
||||
@ -184,23 +182,23 @@ fn make_child_arg(child_spec: &ChildSpec) -> Option<TokenStream> {
|
||||
Some(quote! { #child_ident.unwrap() })
|
||||
}
|
||||
}
|
||||
SingleChildToBuild::Boolean(single_boolean_child) => {
|
||||
let child_ident = format_ident!("{}", single_boolean_child.var_name());
|
||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
||||
Some(quote! { #child_ident })
|
||||
}
|
||||
SingleChildToBuild::Int(literal_child) => {
|
||||
MemberChildToBuild::Int(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
Some(quote! { #child_ident.unwrap() })
|
||||
}
|
||||
SingleChildToBuild::Long(literal_child) => {
|
||||
MemberChildToBuild::Long(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
Some(quote! { #child_ident.unwrap() })
|
||||
}
|
||||
SingleChildToBuild::Double(literal_child) => {
|
||||
MemberChildToBuild::Double(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
Some(quote! { #child_ident.unwrap() })
|
||||
}
|
||||
SingleChildToBuild::String(literal_child) => {
|
||||
MemberChildToBuild::String(literal_child) => {
|
||||
let child_ident = get_literal_child_ident(literal_child);
|
||||
Some(quote! { #child_ident.unwrap() })
|
||||
}
|
||||
@ -269,14 +267,14 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::spec::VecTypeChildToBuild;
|
||||
use crate::spec::VecNodeChildToBuild;
|
||||
|
||||
#[test]
|
||||
fn vec_child_holder() {
|
||||
let vec_child = VecChild::new(
|
||||
"test_child",
|
||||
"Test",
|
||||
VecChildToBuild::Type(VecTypeChildToBuild::new(
|
||||
VecChildToBuild::Node(VecNodeChildToBuild::new(
|
||||
"TestType",
|
||||
"test_child",
|
||||
"build_test_child",
|
||||
@ -293,7 +291,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn single_type_child_holder() {
|
||||
let single_type_child = SingleTypeChildToBuild::from_build_or_rule("TestType", None, false);
|
||||
let single_type_child = NodeChildToBuild::from_build_or_rule("TestType", None, false);
|
||||
assert_eq!(
|
||||
make_single_type_child_holder(&single_type_child).to_string(),
|
||||
quote! {
|
||||
@ -306,7 +304,7 @@ mod tests {
|
||||
#[test]
|
||||
fn single_boolean_child_holder() {
|
||||
let single_boolean_child =
|
||||
SingleBooleanChildToBuild::new("test_child", BooleanBuild::RulePresent);
|
||||
BooleanChildToBuild::new("test_child", BooleanBuild::RulePresent);
|
||||
assert_eq!(
|
||||
make_single_boolean_child_holder(&single_boolean_child).to_string(),
|
||||
quote! {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::spec::{
|
||||
BuildSpec, ChildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec,
|
||||
LeafStructChildType, SingleBooleanChildToBuild, SingleChildToBuild, SingleTypeChildToBuild,
|
||||
StructBuildSpec, VecChild, VecChildToBuild,
|
||||
BooleanChildToBuild, BuildSpec, EnumBuildSpec, LeafEnumBuildSpec, LeafStructBuildSpec,
|
||||
LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild, StructBuildSpec, StructChildSpec,
|
||||
VecChild, VecChildToBuild,
|
||||
};
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@ -61,7 +61,7 @@ fn handle_vec_child(
|
||||
accessors: &mut Vec<TokenStream>,
|
||||
) {
|
||||
let (child_ident, child_ident_mut, child_type_ident) = match vec_child.build() {
|
||||
VecChildToBuild::Type(vec_type_child) => (
|
||||
VecChildToBuild::Node(vec_type_child) => (
|
||||
format_ident!("{}", vec_type_child.var_name()),
|
||||
format_ident!("{}_mut", vec_type_child.var_name()),
|
||||
format_ident!("{}", vec_type_child.build()),
|
||||
@ -84,7 +84,7 @@ fn handle_vec_child(
|
||||
}
|
||||
|
||||
fn handle_single_type_child(
|
||||
single_type_child: &SingleTypeChildToBuild,
|
||||
single_type_child: &NodeChildToBuild,
|
||||
member_names: &mut Vec<Ident>,
|
||||
annotated_members: &mut Vec<TokenStream>,
|
||||
accessors: &mut Vec<TokenStream>,
|
||||
@ -134,12 +134,12 @@ fn handle_single_type_child(
|
||||
}
|
||||
|
||||
fn handle_single_boolean_child(
|
||||
single_boolean_child: &SingleBooleanChildToBuild,
|
||||
single_boolean_child: &BooleanChildToBuild,
|
||||
member_names: &mut Vec<Ident>,
|
||||
annotated_members: &mut Vec<TokenStream>,
|
||||
accessors: &mut Vec<TokenStream>,
|
||||
) {
|
||||
let child_ident = format_ident!("{}", single_boolean_child.var_name());
|
||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
||||
member_names.push(child_ident.clone());
|
||||
annotated_members.push(quote! {
|
||||
#child_ident: bool
|
||||
@ -158,8 +158,8 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
|
||||
for child_spec in build_spec.children().iter() {
|
||||
match child_spec {
|
||||
ChildSpec::SkipChild(_) => {}
|
||||
ChildSpec::VecChild(vec_child) => {
|
||||
StructChildSpec::SkipChild(_) => {}
|
||||
StructChildSpec::VecChild(vec_child) => {
|
||||
handle_vec_child(
|
||||
vec_child,
|
||||
&mut member_names,
|
||||
@ -167,9 +167,9 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
&mut accessors,
|
||||
);
|
||||
}
|
||||
ChildSpec::SingleChild(single_child) => {
|
||||
StructChildSpec::MemberChild(single_child) => {
|
||||
match single_child.build() {
|
||||
SingleChildToBuild::Type(single_type_child) => {
|
||||
MemberChildToBuild::Node(single_type_child) => {
|
||||
handle_single_type_child(
|
||||
single_type_child,
|
||||
&mut member_names,
|
||||
@ -177,7 +177,7 @@ fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
||||
&mut accessors,
|
||||
);
|
||||
}
|
||||
SingleChildToBuild::Boolean(single_boolean_child) => {
|
||||
MemberChildToBuild::Boolean(single_boolean_child) => {
|
||||
handle_single_boolean_child(
|
||||
single_boolean_child,
|
||||
&mut member_names,
|
||||
@ -214,12 +214,12 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", build_spec.build());
|
||||
|
||||
let annotated_members = build_spec
|
||||
.children()
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let name_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
let type_ident = match leaf_struct_child.r#type() {
|
||||
LeafStructChildType::String => format_ident!("{}", "String"),
|
||||
LeafStructMemberKind::String => format_ident!("{}", "String"),
|
||||
};
|
||||
quote! {
|
||||
#name_ident: #type_ident
|
||||
@ -228,18 +228,18 @@ fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let member_names = build_spec
|
||||
.children()
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let accessors = build_spec
|
||||
.children()
|
||||
.members()
|
||||
.iter()
|
||||
.map(|leaf_struct_child| {
|
||||
let name_ident = format_ident!("{}", leaf_struct_child.name());
|
||||
match leaf_struct_child.r#type() {
|
||||
LeafStructChildType::String => {
|
||||
LeafStructMemberKind::String => {
|
||||
quote! {
|
||||
pub fn #name_ident(&self) -> &str {
|
||||
&self.#name_ident
|
||||
|
||||
@ -132,6 +132,7 @@ $defs:
|
||||
kind:
|
||||
type: string
|
||||
enum:
|
||||
- node # default
|
||||
- string
|
||||
vec:
|
||||
type: boolean
|
||||
@ -142,9 +143,6 @@ $defs:
|
||||
StructChildMemberDefinition:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
A definition for a child rule that builds one member. If a bare string, it is assumed to be the name/build-type
|
||||
for a node. An object allows different types (i.e., things additional to nodes) to be built.
|
||||
properties:
|
||||
rule:
|
||||
type: string
|
||||
@ -195,15 +193,15 @@ $defs:
|
||||
oneOf:
|
||||
- type: string
|
||||
description: Shorthand where child name, var, build, and with are inferred from the given Pascal-case rule name.
|
||||
- $ref: "#/$defs/LongEnumChildDefinition"
|
||||
LongEnumChildDefinition:
|
||||
- $ref: "#/$defs/LongEnumChildWrapper"
|
||||
LongEnumChildWrapper:
|
||||
type: object
|
||||
minProperties: 1
|
||||
maxProperties: 1
|
||||
additionalProperties: false
|
||||
description: A format for an advanced enum child.
|
||||
properties:
|
||||
child:
|
||||
type: boolean
|
||||
kind:
|
||||
patternProperties:
|
||||
"^([A-Z][a-z]*)*$":
|
||||
type: string
|
||||
enum:
|
||||
- int
|
||||
- long
|
||||
@ -211,12 +209,6 @@ $defs:
|
||||
- usize
|
||||
- string
|
||||
- boolean
|
||||
from:
|
||||
enum:
|
||||
- translate
|
||||
required:
|
||||
- kind
|
||||
- from
|
||||
|
||||
# Production definition
|
||||
ProductionDefinition:
|
||||
@ -234,7 +226,6 @@ $defs:
|
||||
- boolean
|
||||
from:
|
||||
enum:
|
||||
- translate_and_parse
|
||||
- string_inner
|
||||
- whole_pair
|
||||
- parse_whole_pair
|
||||
|
||||
@ -753,35 +753,27 @@ Literal:
|
||||
rules:
|
||||
- IntLiteral:
|
||||
kind: int
|
||||
from: translate
|
||||
- LongLiteral:
|
||||
kind: long
|
||||
from: translate
|
||||
- DoubleLiteral:
|
||||
kind: double
|
||||
from: translate
|
||||
- SingleQuoteString:
|
||||
kind: string
|
||||
from: translate
|
||||
- DString
|
||||
- BacktickString
|
||||
- BooleanLiteral:
|
||||
kind: boolean
|
||||
from: translate
|
||||
|
||||
# Numbers
|
||||
IntLiteral:
|
||||
produce:
|
||||
kind: int
|
||||
from: translate_and_parse
|
||||
LongLiteral:
|
||||
produce:
|
||||
kind: long
|
||||
from: translate_and_parse
|
||||
DoubleLiteral:
|
||||
produce:
|
||||
kind: double
|
||||
from: translate_and_parse
|
||||
|
||||
# Strings
|
||||
SingleQuoteString:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user