use nom::Parser;
use crate::{
error::{ParseError, ParseErrorKind},
span::Span,
};
use super::input::Input;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum Token {
BStart,
BEnd,
BWord,
Star,
Plus,
QuestionMark,
Pipe,
Colon,
OpenParen,
CloseParen,
OpenBrace,
CloseBrace,
Comma,
Not,
OpenBracket,
Dash,
CloseBracket,
Dot,
LookAhead,
LookBehind,
Backref,
Semicolon,
Equals,
String,
CodePoint,
Number,
Identifier,
ErrorMsg(ParseErrorMsg),
Error,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum ParseErrorMsg {
#[error("`^` is not a valid token")]
Caret,
#[error("`$` is not a valid token")]
Dollar,
#[error("This syntax is not supported")]
SpecialGroup,
#[error("Backslash escapes are not supported")]
Backslash,
#[error("Backslash escapes are not supported")]
BackslashU4,
#[error("Backslash escapes are not supported")]
BackslashX2,
#[error("Backslash escapes are not supported")]
BackslashUnicode,
#[error("Backslash escapes are not supported")]
BackslashK,
#[error("This string literal doesn't have a closing quote")]
UnclosedString,
}
impl core::fmt::Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Token::BStart => "`<%`",
Token::BEnd => "`%>`",
Token::BWord => "`%`",
Token::Star => "`*`",
Token::Plus => "`+`",
Token::QuestionMark => "`?`",
Token::Pipe => "`|`",
Token::Colon => "`:`",
Token::OpenParen => "`(`",
Token::CloseParen => "`)`",
Token::OpenBrace => "`{`",
Token::CloseBrace => "`}`",
Token::Comma => "`,`",
Token::LookAhead => "`>>`",
Token::LookBehind => "`<<`",
Token::Backref => "`::`",
Token::Not => "`!`",
Token::OpenBracket => "`[`",
Token::Dash => "`-`",
Token::CloseBracket => "`]`",
Token::Dot => "`.`",
Token::Semicolon => "`;`",
Token::Equals => "`=`",
Token::String => "string",
Token::CodePoint => "code point",
Token::Number => "number",
Token::Identifier => "identifier",
Token::ErrorMsg(_) | Token::Error => "error",
})
}
}
impl<'i, 'b> Parser<Input<'i, 'b>, (&'i str, Span), ParseError> for Token {
fn parse(
&mut self,
mut input: Input<'i, 'b>,
) -> nom::IResult<Input<'i, 'b>, (&'i str, Span), ParseError> {
match input.peek() {
Some((t, s)) if t == *self => {
let span = input.span();
let _ = input.next();
Ok((input, (s, span)))
}
_ => Err(nom::Err::Error(ParseErrorKind::ExpectedToken(*self).at(input.span()))),
}
}
}
impl<'i, 'b> Parser<Input<'i, 'b>, (Token, Span), ParseError> for &'i str {
fn parse(
&mut self,
mut input: Input<'i, 'b>,
) -> nom::IResult<Input<'i, 'b>, (Token, Span), ParseError> {
match input.peek() {
Some((t, s)) if s == *self => {
let span = input.span();
let _ = input.next();
Ok((input, (t, span)))
}
_ => Err(nom::Err::Error(ParseErrorKind::Expected("word").at(input.span()))),
}
}
}