use crate::errors::{ParseError, ParseResult};
use crate::matcher::Match;
use crate::scanner::Scanner;
use crate::visitor::Visitor;
pub trait Recognizable<'a, T, V>: Match<T> {
fn recognize(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<V>>;
fn recognize_slice(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<&'a [T]>>;
}
pub fn recognize<'a, T, V, R: Recognizable<'a, T, V>>(
recognizable: R,
scanner: &mut Scanner<'a, T>,
) -> ParseResult<V> {
recognizable
.recognize(scanner)?
.ok_or(ParseError::UnexpectedToken)
}
pub fn recognize_slice<'a, T, V, R>(
recognizable: R,
scanner: &mut Scanner<'a, T>,
) -> ParseResult<&'a [T]>
where
R: Recognizable<'a, T, V>,
{
recognizable
.recognize_slice(scanner)?
.ok_or(ParseError::UnexpectedToken)
}
impl<'a, T, M: Match<T>> Recognizable<'a, T, M> for M {
fn recognize(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<M>> {
if self.size() > scanner.remaining().len() {
return Err(ParseError::UnexpectedEndOfInput);
}
let data = scanner.remaining();
let (result, size) = self.is_matching(data);
if !result {
return Ok(None);
}
if !scanner.is_empty() {
scanner.bump_by(size);
}
Ok(Some(self))
}
fn recognize_slice(self, scanner: &mut Scanner<'a, T>) -> ParseResult<Option<&'a [T]>> {
if scanner.is_empty() {
return Err(ParseError::UnexpectedEndOfInput);
}
let data = scanner.remaining();
let (result, size) = self.is_matching(data);
if !result {
return Ok(None);
}
if !scanner.is_empty() {
scanner.bump_by(size);
}
Ok(Some(&data[..size]))
}
}
pub struct Recognizer<'a, 'b, T, R> {
data: Option<R>,
scanner: &'b mut Scanner<'a, T>,
}
impl<'a, 'b, T, R: Recognizable<'a, T, R>> Recognizer<'a, 'b, T, R> {
pub fn new(scanner: &'b mut Scanner<'a, T>) -> Self {
Recognizer {
data: None,
scanner,
}
}
pub fn try_or(mut self, element: R) -> ParseResult<Self> {
if self.data.is_some() {
return Ok(self);
}
if self.scanner.is_empty() {
return Err(ParseError::UnexpectedEndOfInput);
}
if element.size() > self.scanner.remaining().len() {
return Ok(self);
}
if let Some(found) = element.recognize(self.scanner)? {
self.data = Some(found);
}
Ok(self)
}
pub fn finish(self) -> Option<R> {
self.data
}
}
impl<'a, T, R: Recognizable<'a, T, R> + Default> Visitor<'a, T> for R {
fn accept(scanner: &mut Scanner<'a, T>) -> ParseResult<Self> {
recognize(R::default(), scanner)?;
Ok(R::default())
}
}
#[cfg(test)]
mod tests {
use crate::bytes::token::Token;
use crate::errors::ParseResult;
use crate::recognizer::{Recognizable, Recognizer};
#[test]
fn test_recognizer() {
let data = b">";
let mut scanner = crate::scanner::Scanner::new(data);
let result = Token::GreaterThan
.recognize(&mut scanner)
.expect("failed to parse");
assert_eq!(result, Some(Token::GreaterThan));
}
#[test]
fn test_recognizer_multiple() -> ParseResult<()> {
let data = b">>";
let mut scanner = crate::scanner::Scanner::new(data);
let result = Recognizer::new(&mut scanner)
.try_or(Token::LessThan)?
.try_or(Token::GreaterThan)?
.finish()
.expect("failed to parse");
assert_eq!(result, Token::GreaterThan);
Ok(())
}
}