deimos-lang/ast-generator/src/spec.rs

537 lines
11 KiB
Rust

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<EnumRule>,
}
impl EnumBuildSpec {
pub fn from_name(name: &str, rules: Vec<EnumRule>) -> 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<LeafEnumRule>,
}
impl LeafEnumBuildSpec {
pub fn from_name(name: &str, rules: Vec<LeafEnumRule>) -> 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<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
}
}
pub struct StructBuildSpec {
name: String,
build: String,
var_name: String,
with: String,
children: Vec<ChildSpec>,
}
impl StructBuildSpec {
pub fn from_name(name: &str, child_specs: Vec<ChildSpec>) -> 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<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,
}
}
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,
}
}
/// 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<LeafStructChild>,
}
impl LeafStructBuildSpec {
pub fn new(name: &str, build: &str, children: Vec<LeafStructChild>) -> 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,
}