diff --git a/ast-generator/src/deserialize.rs b/ast-generator/src/deserialize.rs index ba0699c..cc1a504 100644 --- a/ast-generator/src/deserialize.rs +++ b/ast-generator/src/deserialize.rs @@ -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 { - 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 { - rules +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) +} + +fn deserialize_leaf_enum_rule(rule_yaml: &Yaml) -> Box { + Box::new(LeafEnumRule::new(rule_yaml.as_str().unwrap())) +} + +fn deserialize_leaf_enum_rules(rules_yaml: &Yaml) -> Vec> { + rules_yaml .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) - } + .map(|rule_yaml| { + deserialize_leaf_enum_rule(rule_yaml) }) .collect() } -fn get_enum_rules(rule_specs: &Yaml) -> Vec { - rule_specs +fn deserialize_enum_rule_custom_child(rule_props: &Yaml) -> Option> { + 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 { + Box::new(EnumRuleChild::new(Box::new( + EnumRuleChildKind::Node(EnumRuleNodeChild::new(rule)), + ))) +} + +fn deserialize_enum_rule(rule_yaml: &Yaml) -> Box { + 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> { + rules_yaml .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) - }; + .map(|rule_yaml| deserialize_enum_rule(rule_yaml)) + .collect() +} - EnumRule::new(rule, build, &with) - } else { - EnumRule::from_rule(rule_spec.as_str().unwrap()) - } +fn deserialize_leaf_struct_member(name: &str, props: &Yaml) -> Box { + 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> { + 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 get_leaf_struct_child_specs(children: &Yaml) -> Vec { +fn deserialize_member_node_to_build( + rule: &str, + build_props: &Yaml, + optional: bool, +) -> Box { + 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 { + Box::new(MemberChildToBuild::Boolean(BooleanChildToBuild::new(name))) +} + +fn deserialize_member_child_to_build( + name: &str, + rule: &str, + props: &Yaml, + optional: bool, +) -> Box { + 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 { + 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 { + 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 { + 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 { + 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 { + Box::new(StructChildSpec::SkipChild(SkipChild::new(name, rule))) +} + +fn deserialize_struct_hash_child(child: &Yaml) -> Box { + 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 { + 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> { children .as_vec() .unwrap() .iter() .map(|child_spec| { - let (name, hash) = unwrap_single_member_hash(child_spec); - LeafStructChild::new(&name, LeafStructChildType::String) + if child_spec.is_hash() { + deserialize_struct_hash_child(child_spec) + } else { + deserialize_struct_string_child(child_spec) + } }) - .collect::>() + .collect() } -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)) +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."); + 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 { 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() } diff --git a/ast-generator/src/leaf_struct_build_fn.rs b/ast-generator/src/leaf_struct_build_fn.rs index d23aa17..71f1f2d 100644 --- a/ast-generator/src/leaf_struct_build_fn.rs +++ b/ast-generator/src/leaf_struct_build_fn.rs @@ -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::>(); let child_args = build_spec - .children() + .members() .iter() .map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name())) .collect::>(); diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index 97d5eab..0a4269d 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -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::>(); let combined = quote! { @@ -103,33 +116,3 @@ pub fn generate_files(build_specs: &[BuildSpec]) -> Vec { 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 = 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) -} diff --git a/ast-generator/src/production_build_fn.rs b/ast-generator/src/production_build_fn.rs new file mode 100644 index 0000000..cba13eb --- /dev/null +++ b/ast-generator/src/production_build_fn.rs @@ -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::().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::().unwrap() + } + _ => panic!() + } + }, + ProductionKind::Double => quote! { + #pair_ident.as_str().parse::().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::().unwrap() + } + }; + + quote! { + fn #build_fn_ident(#pair_ident: Pair) -> #return_type_ident { + #pair_mapper + } + } +} \ No newline at end of file diff --git a/ast-generator/src/spec.rs b/ast-generator/src/spec.rs index 15a6d8e..9fb47e0 100644 --- a/ast-generator/src/spec.rs +++ b/ast-generator/src/spec.rs @@ -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, + rules: Vec>, } impl EnumBuildSpec { - pub fn from_name(name: &str, rules: Vec) -> Self { + pub fn new(build: &str, rules: Vec>) -> 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 { + self.rules.iter().map(Box::as_ref) } } pub struct EnumRule { rule: String, - build: String, - with: String, + child: Option> } impl EnumRule { - pub fn from_rule(rule: &str) -> Self { + pub fn new(rule: &str, child: Option>) -> 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 } } @@ -66,161 +52,126 @@ impl EnumRule { pub fn rule(&self) -> &str { &self.rule } - - /// The type to build, in Pascal case. - pub fn build(&self) -> &str { - &self.build - } - - /// The build-fn name, in snake case. - pub fn with(&self) -> &str { - &self.with + + pub fn child(&self) -> Option<&EnumRuleChild> { + if let Some(child) = &self.child { + Some(child.as_ref()) + } else { + None + } } } +pub struct EnumRuleChild { + kind: Box +} + +impl EnumRuleChild { + pub fn new(kind: Box) -> 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, + rules: Vec>, } impl LeafEnumBuildSpec { - pub fn from_name(name: &str, rules: Vec) -> Self { + pub fn new(build: &str, rules: Vec>) -> 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 { + 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, -} - -impl LeafEnumRuleBuild { - pub fn new(rule: &str, child: Option) -> 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, + children: Vec>, } impl StructBuildSpec { - pub fn from_name(name: &str, child_specs: Vec) -> Self { + pub fn new(build: &str, children: Vec>) -> 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 { + 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, } impl VecChild { - pub fn new(name: &str, rule: &str, build: VecChildToBuild) -> Self { + pub fn new(name: &str, rule: &str, build: Box) -> 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, } -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) -> 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, optional: bool, } -impl SingleTypeChildToBuild { - pub fn from_build_or_rule( - build_or_rule: &str, - or_else: Option, - 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, 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, -} - -impl LeafStructBuildSpec { - pub fn new(name: &str, build: &str, children: Vec) -> 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>, +} + +impl LeafStructBuildSpec { + pub fn new(build: &str, members: Vec>) -> 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 { + 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 +} diff --git a/ast-generator/src/struct_build_fn.rs b/ast-generator/src/struct_build_fn.rs index 10d3523..fad891b 100644 --- a/ast-generator/src/struct_build_fn.rs +++ b/ast-generator/src/struct_build_fn.rs @@ -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 { +fn make_child_holder(child_spec: &StructChildSpec) -> Option { 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 { +fn make_child_arg(child_spec: &StructChildSpec) -> Option { 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 { 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! { diff --git a/ast-generator/src/type_gen.rs b/ast-generator/src/type_gen.rs index 2bed52c..9d9b28f 100644 --- a/ast-generator/src/type_gen.rs +++ b/ast-generator/src/type_gen.rs @@ -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, ) { 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, annotated_members: &mut Vec, accessors: &mut Vec, @@ -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, annotated_members: &mut Vec, accessors: &mut Vec, ) { - 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::>(); let member_names = build_spec - .children() + .members() .iter() .map(|leaf_struct_child| format_ident!("{}", leaf_struct_child.name())) .collect::>(); 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 diff --git a/src/parser/ast.schema.yaml b/src/parser/ast.schema.yaml index 11311fc..36cdc36 100644 --- a/src/parser/ast.schema.yaml +++ b/src/parser/ast.schema.yaml @@ -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 diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 7707261..9893252 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -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: