use crate::data::*;
use std::collections::HashSet;
use std::fmt::{self, Display, Formatter};
#[derive(Debug, Clone)]
pub struct File {
pub start: String,
pub terminal_enum: TerminalEnum,
pub nonterminals: Vec<Nonterminal>,
}
impl File {
pub fn get_rules(&self) -> impl Iterator<Item = Rule> {
self.nonterminals
.iter()
.flat_map(|nonterminal| match nonterminal {
Nonterminal::Struct(s) => {
vec![Rule {
constructor_name: ConstructorName::Struct(&s.name.name),
fieldset: &s.fieldset,
}]
}
Nonterminal::Enum(e) => e
.variants
.iter()
.map(|v| {
let enum_name = &e.name.name;
let variant_name = &v.name.name;
Rule {
constructor_name: ConstructorName::EnumVariant {
enum_name,
variant_name,
},
fieldset: &v.fieldset,
}
})
.collect(),
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct Rule<'a> {
pub constructor_name: ConstructorName<'a>,
pub fieldset: &'a Fieldset,
}
#[derive(Debug, Clone, Copy)]
pub enum ConstructorName<'a> {
Struct(&'a str),
EnumVariant {
enum_name: &'a str,
variant_name: &'a str,
},
}
impl Display for ConstructorName<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ConstructorName::Struct(name) => write!(f, "{}", name),
ConstructorName::EnumVariant {
enum_name,
variant_name,
} => write!(f, "{}::{}", enum_name, variant_name),
}
}
}
impl ConstructorName<'_> {
pub fn type_name(&self) -> &str {
match self {
ConstructorName::Struct(name) => name,
ConstructorName::EnumVariant { enum_name, .. } => enum_name,
}
}
}
impl File {
pub fn get_defined_identifiers(&self) -> HashSet<String> {
self.get_nonterminal_names()
.chain(self.get_terminal_enum_variant_names())
.chain(std::iter::once(self.terminal_enum.name.clone()))
.collect()
}
fn get_nonterminal_names(&self) -> impl Iterator<Item = String> + '_ {
self.nonterminals
.iter()
.map(|nonterminal| match nonterminal {
Nonterminal::Struct(s) => &s.name.name,
Nonterminal::Enum(e) => &e.name.name,
})
.cloned()
}
fn get_terminal_enum_variant_names(&self) -> impl Iterator<Item = String> + '_ {
self.terminal_enum
.variants
.iter()
.map(|variant| variant.dollarless_name.to_string())
}
}
#[derive(Debug, Clone)]
pub struct TerminalEnum {
pub attributes: Vec<Attribute>,
pub name: String,
pub variants: Vec<TerminalVariant>,
}
impl TerminalEnum {
pub fn get_type(&self, variant_name: &DollarlessTerminalName) -> Option<&str> {
self.variants
.iter()
.find(|variant| variant.dollarless_name == *variant_name)
.map(|variant| -> &str { &variant.type_ })
}
}
#[derive(Debug, Clone)]
pub struct TerminalVariant {
pub dollarless_name: DollarlessTerminalName,
pub type_: String,
}
#[derive(Debug, Clone)]
pub enum Nonterminal {
Struct(Struct),
Enum(Enum),
}
impl Nonterminal {
pub fn name(&self) -> &str {
match self {
Nonterminal::Struct(s) => &s.name.name,
Nonterminal::Enum(e) => &e.name.name,
}
}
}
pub use crate::data::ast::{
Attribute, ComplexType, Enum, EnumVariant, Fieldset, NamedField, NamedFieldset, Struct,
TupleField, TupleFieldset, Type,
};
pub use crate::data::ast::{Ident, IdentOrTerminalIdent, IdentOrUnderscore, TerminalIdent, Token};