#[derive(Clone, Debug, Default)]
pub struct Grammar {
pub name: String,
pub tokens: Vec<TokenDef>,
pub rules: Vec<RuleDef>,
}
impl Grammar {
pub fn token(&self, name: &str) -> Option<&TokenDef> {
self.tokens.iter().find(|t| t.name == name)
}
pub fn rule(&self, name: &str) -> Option<&RuleDef> {
self.rules.iter().find(|r| r.name == name)
}
pub fn rule_index(&self, name: &str) -> Option<usize> {
self.rules.iter().position(|r| r.name == name)
}
pub fn token_index(&self, name: &str) -> Option<usize> {
self.tokens.iter().position(|t| t.name == name)
}
pub fn default_start(&self) -> Option<&RuleDef> {
self.rules.first()
}
}
#[derive(Clone, Debug)]
pub struct TokenDef {
pub name: String,
pub pattern: TokenPattern,
pub skip: bool,
pub is_fragment: bool,
pub span: crate::span::Span,
}
#[derive(Clone, Debug)]
pub enum TokenPattern {
Empty,
Literal(String),
Class(CharClass),
Ref(String),
Seq(Vec<TokenPattern>),
Alt(Vec<TokenPattern>),
Opt(Box<TokenPattern>),
Star(Box<TokenPattern>),
Plus(Box<TokenPattern>),
}
impl TokenPattern {
pub fn is_literal(&self) -> bool {
matches!(self, TokenPattern::Literal(_))
}
pub fn seq(xs: Vec<TokenPattern>) -> TokenPattern {
match xs.len() {
0 => TokenPattern::Empty,
1 => xs.into_iter().next().unwrap(),
_ => TokenPattern::Seq(xs),
}
}
pub fn alt(xs: Vec<TokenPattern>) -> TokenPattern {
match xs.len() {
0 => TokenPattern::Empty,
1 => xs.into_iter().next().unwrap(),
_ => TokenPattern::Alt(xs),
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CharClass {
pub negated: bool,
pub items: Vec<ClassItem>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ClassItem {
Char(u32),
Range(u32, u32),
}
impl CharClass {
pub fn contains(&self, cp: u32) -> bool {
let hit = self.items.iter().any(|it| match it {
ClassItem::Char(c) => *c == cp,
ClassItem::Range(lo, hi) => *lo <= cp && cp <= *hi,
});
if self.negated {
!hit
} else {
hit
}
}
}
#[derive(Clone, Debug)]
pub struct RuleDef {
pub name: String,
pub body: Expr,
pub is_fragment: bool,
pub span: crate::span::Span,
}
#[derive(Clone, Debug)]
pub enum Expr {
Empty,
Token(String),
Rule(String),
Seq(Vec<Expr>),
Alt(Vec<Expr>),
Opt(Box<Expr>),
Star(Box<Expr>),
Plus(Box<Expr>),
}
impl Expr {
pub fn seq(items: Vec<Expr>) -> Expr {
match items.len() {
0 => Expr::Empty,
1 => items.into_iter().next().unwrap(),
_ => Expr::Seq(items),
}
}
pub fn alt(items: Vec<Expr>) -> Expr {
match items.len() {
0 => Expr::Empty,
1 => items.into_iter().next().unwrap(),
_ => Expr::Alt(items),
}
}
}