use crate::util::make_build_fn_name; use convert_case::{Case, Casing}; pub enum BuildSpec { Enum(EnumBuildSpec), LeafEnum(LeafEnumBuildSpec), Struct(StructBuildSpec), LeafStruct(LeafStructBuildSpec), } pub struct EnumBuildSpec { name: String, build: String, rules: Vec, } impl EnumBuildSpec { pub fn from_name(name: &str, rules: Vec) -> Self { EnumBuildSpec { name: name.to_string(), build: name.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 struct EnumRule { rule: String, build: String, with: String, } impl EnumRule { pub fn from_rule(rule: &str) -> 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(), } } /// The enum rule to match, in Pascal case. 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 struct LeafEnumBuildSpec { name: String, build: String, rules: Vec, } impl LeafEnumBuildSpec { pub fn from_name(name: &str, rules: Vec) -> Self { Self { name: name.to_string(), build: name.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 struct LeafEnumRule { rule: String, build: LeafEnumRuleBuild, } impl LeafEnumRule { pub fn new(rule: &str, build: LeafEnumRuleBuild) -> 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 } } pub struct StructBuildSpec { name: String, build: String, var_name: String, with: String, children: Vec, } impl StructBuildSpec { pub fn from_name(name: &str, child_specs: 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, } } /// 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 enum ChildSpec { SkipChild(SkipChild), VecChild(VecChild), SingleChild(SingleChild), } pub struct SkipChild { name: String, rule: String, } impl SkipChild { pub fn new(name: &str, rule: &str) -> Self { Self { name: name.to_string(), rule: rule.to_string(), } } /// The name of this child spec. pub fn name(&self) -> &str { &self.name } /// The grammar rule to match. pub fn rule(&self) -> &str { &self.rule } } pub struct VecChild { name: String, rule: String, build: VecChildToBuild, } impl VecChild { pub fn new(name: &str, rule: &str, build: VecChildToBuild) -> Self { Self { name: name.to_string(), rule: rule.to_string(), build, } } /// The name of this child. pub fn name(&self) -> &str { &self.name } /// The rule to match to build this child. pub fn rule(&self) -> &str { &self.rule } /// The build info for this child. pub fn build(&self) -> &VecChildToBuild { &self.build } } #[derive(Debug)] pub enum VecChildToBuild { Type(VecTypeChildToBuild), } #[derive(Debug)] pub struct VecTypeChildToBuild { 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(), } } /// 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 { name: String, rule: String, build: SingleChildToBuild, } 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 { Self { name: name.to_string(), rule: rule.to_string(), build, } } /// The name of this child in the yaml file, in snake case. pub fn name(&self) -> &str { &self.name } /// The grammar rule to match to build this child. pub fn rule(&self) -> &str { &self.rule } /// The specification for what to actually build. pub fn build(&self) -> &SingleChildToBuild { &self.build } } #[derive(Debug)] pub enum SingleChildToBuild { Type(SingleTypeChildToBuild), Boolean(SingleBooleanChildToBuild), Int(SingleLiteralChildToBuild), Long(SingleLiteralChildToBuild), Double(SingleLiteralChildToBuild), String(SingleLiteralChildToBuild), } #[derive(Debug)] pub struct SingleTypeChildToBuild { 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, } } 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, } } /// The type to build, in Pascal case. pub fn build(&self) -> &str { &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() } /// If the type should be wrapped in an Option. pub fn optional(&self) -> bool { self.optional } } #[derive(Debug)] pub struct SingleBooleanChildToBuild { var_name: String, build: BooleanBuild, } impl SingleBooleanChildToBuild { pub fn new(var_name: &str, build: BooleanBuild) -> 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, } } pub fn name(&self) -> &str { &self.name } pub fn build(&self) -> &str { &self.build } pub fn children(&self) -> &[LeafStructChild] { &self.children } } pub struct LeafStructChild { name: String, r#type: LeafStructChildType, } impl LeafStructChild { pub fn new(name: &str, r#type: LeafStructChildType) -> Self { Self { name: name.to_string(), r#type, } } pub fn name(&self) -> &str { &self.name } pub fn r#type(&self) -> &LeafStructChildType { &self.r#type } } pub enum LeafStructChildType { String, }