use crate::bytes::matchers::{match_char, match_pattern};
use crate::errors::{ParseError, ParseResult};
use crate::matcher::Match;
use crate::peek::{CustomizedPeekableImplementation, PeekResult, Peekable, PeekableImplementation};
use crate::recognizer::{recognize, Recognizer};
use crate::scanner::Scanner;
use crate::visitor::Visitor;
#[derive(Copy, Clone)]
#[derive(PartialEq, Debug)]
pub enum Token {
OpenParen,
CloseParen,
Comma,
Semicolon,
Colon,
Whitespace,
GreaterThan,
LessThan,
Exclamation,
Quote,
DoubleQuote,
Equal,
Plus,
Dash,
Slash,
Star,
Percent,
Ampersand,
Pipe,
Caret,
Tilde,
Dot,
Question,
At,
Hash,
Dollar,
Backslash,
Underscore,
Sharp,
Ln,
Cr,
Tab,
CrLn,
}
impl Match<u8> for Token {
fn is_matching(&self, data: &[u8]) -> (bool, usize) {
match self {
Token::OpenParen => match_char('(', data),
Token::CloseParen => match_char(')', data),
Token::Comma => match_char(',', data),
Token::Semicolon => match_char(';', data),
Token::Colon => match_char(':', data),
Token::Whitespace => match_char(' ', data),
Token::GreaterThan => match_char('>', data),
Token::LessThan => match_char('<', data),
Token::Exclamation => match_char('!', data),
Token::Quote => match_char('\'', data),
Token::DoubleQuote => match_char('"', data),
Token::Equal => match_char('=', data),
Token::Plus => match_char('+', data),
Token::Dash => match_char('-', data),
Token::Slash => match_char('/', data),
Token::Star => match_char('*', data),
Token::Percent => match_char('%', data),
Token::Ampersand => match_char('&', data),
Token::Pipe => match_char('|', data),
Token::Caret => match_char('^', data),
Token::Tilde => match_char('~', data),
Token::Dot => match_char('.', data),
Token::Question => match_char('?', data),
Token::At => match_char('@', data),
Token::Hash => match_char('#', data),
Token::Dollar => match_char('$', data),
Token::Backslash => match_char('\\', data),
Token::Underscore => match_char('_', data),
Token::Sharp => match_char('#', data),
Token::Ln => match_char('\n', data),
Token::Cr => match_char('\r', data),
Token::Tab => match_char('\t', data),
Token::CrLn => match_pattern(b"\r\n", data),
}
}
fn size(&self) -> usize {
match self {
Token::OpenParen => 1,
Token::CloseParen => 1,
Token::Comma => 1,
Token::Semicolon => 1,
Token::Colon => 1,
Token::Whitespace => 1,
Token::GreaterThan => 1,
Token::LessThan => 1,
Token::Exclamation => 1,
Token::Quote => 1,
Token::DoubleQuote => 1,
Token::Equal => 1,
Token::Plus => 1,
Token::Dash => 1,
Token::Slash => 1,
Token::Star => 1,
Token::Percent => 1,
Token::Ampersand => 1,
Token::Pipe => 1,
Token::Caret => 1,
Token::Tilde => 1,
Token::Dot => 1,
Token::Question => 1,
Token::At => 1,
Token::Hash => 1,
Token::Dollar => 1,
Token::Backslash => 1,
Token::Underscore => 1,
Token::Sharp => 1,
Token::Ln => 1,
Token::Cr => 1,
Token::Tab => 1,
Token::CrLn => 2,
}
}
}
impl<'a> Visitor<'a, u8> for Token {
fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
Recognizer::new(scanner)
.try_or(Token::OpenParen)?
.try_or(Token::CloseParen)?
.try_or(Token::Comma)?
.try_or(Token::Semicolon)?
.try_or(Token::Colon)?
.try_or(Token::Whitespace)?
.try_or(Token::GreaterThan)?
.try_or(Token::LessThan)?
.try_or(Token::Exclamation)?
.try_or(Token::Quote)?
.try_or(Token::DoubleQuote)?
.try_or(Token::Equal)?
.try_or(Token::Plus)?
.try_or(Token::Dash)?
.try_or(Token::Slash)?
.try_or(Token::Star)?
.try_or(Token::Percent)?
.try_or(Token::Ampersand)?
.try_or(Token::Pipe)?
.try_or(Token::Caret)?
.try_or(Token::Tilde)?
.try_or(Token::Dot)?
.try_or(Token::Question)?
.try_or(Token::At)?
.try_or(Token::Hash)?
.try_or(Token::Dollar)?
.try_or(Token::Backslash)?
.try_or(Token::Underscore)?
.try_or(Token::Sharp)?
.try_or(Token::Ln)?
.try_or(Token::Cr)?
.try_or(Token::Tab)?
.try_or(Token::CrLn)?
.finish()
.ok_or(ParseError::UnexpectedToken)
}
}
impl PeekableImplementation for Token {
type Type = CustomizedPeekableImplementation;
}
impl<'a> Peekable<'a, u8> for Token {
fn peek(&self, data: &Scanner<'a, u8>) -> ParseResult<PeekResult> {
let mut scanner = Scanner::new(data.remaining());
while !scanner.is_empty() {
match recognize(*self, &mut scanner) {
Ok(element) => {
return Ok(PeekResult::Found {
end_slice: scanner.current_position(),
start_element_size: 0,
end_element_size: element.size(),
});
}
Err(ParseError::UnexpectedToken) => {
scanner.bump_by(1);
continue;
}
Err(err) => {
return Err(err);
}
}
}
Ok(PeekResult::NotFound)
}
}