use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum TerminalSymbol<Term> {
Term(Term), Error, Eof, }
impl<Term> TerminalSymbol<Term> {
pub fn is_error(&self) -> bool {
matches!(self, TerminalSymbol::Error)
}
pub fn is_term(&self) -> bool {
matches!(self, TerminalSymbol::Term(_))
}
pub fn is_eof(&self) -> bool {
matches!(self, TerminalSymbol::Eof)
}
pub fn to_term(&self) -> Option<&Term> {
match self {
TerminalSymbol::Term(term) => Some(term),
TerminalSymbol::Error => None,
TerminalSymbol::Eof => None,
}
}
pub fn into_term(self) -> Option<Term> {
match self {
TerminalSymbol::Term(term) => Some(term),
TerminalSymbol::Error => None,
TerminalSymbol::Eof => None,
}
}
}
impl<Term: Display> std::fmt::Display for TerminalSymbol<Term> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TerminalSymbol::Term(term) => write!(f, "{}", term),
TerminalSymbol::Error => write!(f, "error"),
TerminalSymbol::Eof => write!(f, "eof"),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Token<Term, NonTerm> {
Term(Term),
NonTerm(NonTerm),
}
impl<Term: Display, NonTerm: Display> Display for Token<Term, NonTerm> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::Term(term) => write!(f, "{}", term),
Token::NonTerm(nonterm) => write!(f, "{}", nonterm),
}
}
}
impl<Term: Debug, NonTerm: Debug> Debug for Token<Term, NonTerm> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::Term(term) => write!(f, "{:?}", term),
Token::NonTerm(nonterm) => write!(f, "{:?}", nonterm),
}
}
}
impl<Term, NonTerm> Token<Term, NonTerm> {
pub fn map<NewTerm, NewNonTerm>(
self,
term_map: impl Fn(Term) -> NewTerm,
nonterm_map: impl Fn(NonTerm) -> NewNonTerm,
) -> Token<NewTerm, NewNonTerm> {
match self {
Token::Term(term) => Token::Term(term_map(term)),
Token::NonTerm(nonterm) => Token::NonTerm(nonterm_map(nonterm)),
}
}
}