#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum GreType {
End = 0,
Alt = 1,
RuleRef = 2,
Char = 3,
CharNot = 4,
CharRngUpper = 5,
CharAlt = 6,
CharAny = 7,
Token = 8,
TokenNot = 9,
}
impl GreType {
pub fn is_char_element(self) -> bool {
matches!(
self,
GreType::Char
| GreType::CharNot
| GreType::CharAlt
| GreType::CharRngUpper
| GreType::CharAny
)
}
pub fn is_stack_terminal(self) -> bool {
matches!(
self,
GreType::Char
| GreType::CharNot
| GreType::CharAny
| GreType::Token
| GreType::TokenNot
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GrammarElement {
pub gtype: GreType,
pub value: u32,
}
impl GrammarElement {
pub const fn new(gtype: GreType, value: u32) -> Self {
Self { gtype, value }
}
pub fn is_end_of_sequence(self) -> bool {
matches!(self.gtype, GreType::End | GreType::Alt)
}
}
pub type GrammarRule = Vec<GrammarElement>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RulePos {
pub rule: u32,
pub index: u32,
}
impl RulePos {
pub const fn new(rule: u32, index: u32) -> Self {
Self { rule, index }
}
pub const fn next(self) -> Self {
Self {
rule: self.rule,
index: self.index + 1,
}
}
pub const fn advance(self, n: u32) -> Self {
Self {
rule: self.rule,
index: self.index + n,
}
}
}
pub type GrammarStack = Vec<RulePos>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn end_and_alt_terminate_a_sequence() {
assert!(GrammarElement::new(GreType::End, 0).is_end_of_sequence());
assert!(GrammarElement::new(GreType::Alt, 0).is_end_of_sequence());
assert!(!GrammarElement::new(GreType::Char, b'a' as u32).is_end_of_sequence());
assert!(!GrammarElement::new(GreType::RuleRef, 3).is_end_of_sequence());
}
#[test]
fn char_range_modifiers_are_char_elements_but_not_stack_terminals() {
assert!(GreType::CharAlt.is_char_element());
assert!(GreType::CharRngUpper.is_char_element());
assert!(!GreType::CharAlt.is_stack_terminal());
assert!(!GreType::CharRngUpper.is_stack_terminal());
assert!(GreType::CharAny.is_char_element());
assert!(GreType::CharAny.is_stack_terminal());
assert!(!GreType::Token.is_char_element());
assert!(GreType::Token.is_stack_terminal());
}
#[test]
fn discriminants_match_llama_cpp() {
assert_eq!(GreType::End as u8, 0);
assert_eq!(GreType::Alt as u8, 1);
assert_eq!(GreType::RuleRef as u8, 2);
assert_eq!(GreType::Char as u8, 3);
assert_eq!(GreType::CharNot as u8, 4);
assert_eq!(GreType::CharRngUpper as u8, 5);
assert_eq!(GreType::CharAlt as u8, 6);
assert_eq!(GreType::CharAny as u8, 7);
assert_eq!(GreType::Token as u8, 8);
assert_eq!(GreType::TokenNot as u8, 9);
}
#[test]
fn cursor_orders_by_rule_then_index() {
assert!(RulePos::new(0, 5) < RulePos::new(1, 0));
assert!(RulePos::new(1, 0) < RulePos::new(1, 1));
assert_eq!(RulePos::new(2, 3).next(), RulePos::new(2, 4));
assert_eq!(RulePos::new(2, 3).advance(2), RulePos::new(2, 5));
}
}