use logos::Logos;
#[derive(Logos, Debug, PartialEq, Clone)]
pub enum Token {
#[regex(r"\\(?:[a-zA-Z]+|.)", |lex| {
let slice = lex.slice();
slice[1..].to_string()
})]
ControlSeq(String),
#[token("~")]
ActiveChar,
#[token("{")]
LBrace,
#[token("}")]
RBrace,
#[token("$")]
MathShift,
#[token("&")]
Alignment,
#[token("#")]
Parameter,
#[token("^")]
Superscript,
#[token("_")]
Subscript,
#[token("*")]
Star,
#[token("[")]
LBracket,
#[token("]")]
RBracket,
#[regex(r"['\u2019]+", callback = |lex| lex.slice().chars().count())]
Prime(usize),
#[regex(r"[ \t\n\f\u{00A0}]+")]
Whitespaces,
#[regex(r"%[^\n]*\n?", logos::skip)]
Comment,
#[regex(r"[\x20-\x7E\u{80}-\u{10FFFF}]", priority = 1, callback = |lex| {
let slice = lex.slice();
slice.chars().next().unwrap()
})]
Char(char),
}
impl std::fmt::Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::ControlSeq(name) => write!(f, "\\{name}"),
Token::ActiveChar => write!(f, "~"),
Token::LBrace => write!(f, "{{"),
Token::RBrace => write!(f, "}}"),
Token::MathShift => write!(f, "$"),
Token::Alignment => write!(f, "&"),
Token::Parameter => write!(f, "#"),
Token::Superscript => write!(f, "^"),
Token::Subscript => write!(f, "_"),
Token::Star => write!(f, "*"),
Token::LBracket => write!(f, "["),
Token::RBracket => write!(f, "]"),
Token::Prime(n) => {
for _ in 0..*n {
write!(f, "'")?;
}
Ok(())
}
Token::Whitespaces => write!(f, " "),
Token::Comment => write!(f, "%"),
Token::Char(c) => write!(f, "{c}"),
}
}
}