use alloc::{boxed::Box, string::String, vec::Vec};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CodePointRange {
pub lo: u32,
pub hi: u32,
}
impl CodePointRange {
#[must_use]
pub fn contains(&self, c: u32) -> bool {
c >= self.lo && c <= self.hi
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Term {
Literal(String),
NonTerminal(String),
CharClass(Vec<CodePointRange>),
Sequence(Vec<Term>),
Alternation(Vec<Term>),
Optional(Box<Term>),
ZeroOrMore(Box<Term>),
OneOrMore(Box<Term>),
Subtraction(Box<Term>, Box<Term>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Production {
pub name: String,
pub number: String,
pub rhs: Term,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Grammar {
productions: Vec<Production>,
}
impl Grammar {
#[must_use]
pub fn new() -> Self {
Self {
productions: Vec::new(),
}
}
pub fn add(&mut self, production: Production) {
self.productions.push(production);
}
#[must_use]
pub fn lookup(&self, name: &str) -> Option<&Production> {
self.productions.iter().find(|p| p.name == name)
}
#[must_use]
pub fn len(&self) -> usize {
self.productions.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.productions.is_empty()
}
pub fn productions(&self) -> impl Iterator<Item = &Production> {
self.productions.iter()
}
}