use std::marker::PhantomData;
use super::Matcher;
use crate::util::{ResetIterator};
pub trait Scanner {
type Item;
type Token;
fn scan<I:ResetIterator<Item=Self::Item>>(&mut self,input: &mut I) -> Option<Self::Token>;
fn and_match<M:Matcher,T:Copy>(self, matcher: M, token: T) -> (Self,Match<M,T>)
where Self:Sized
{
(self,Match(matcher,token))
}
fn eof<M:Matcher,T:Copy>(self, token: T) -> (Self,Eof<M,T>)
where Self:Sized
{
(self,Eof(PhantomData,Some(token)))
}
}
impl<A:Scanner,B:Scanner<Item=A::Item,Token=A::Token>> Scanner for (A,B) {
type Item = A::Item;
type Token = A::Token;
fn scan<I:ResetIterator<Item=Self::Item>>(&mut self,input: &mut I) -> Option<Self::Token> {
match self.0.scan(input) {
Some(t) => Some(t),
None => self.1.scan(input)
}
}
}
pub struct Match<M:Matcher,T>(pub M, pub T);
impl<M:Matcher,T:Copy> Scanner for Match<M,T> {
type Item = M::Item;
type Token = T;
fn scan<I:ResetIterator<Item=Self::Item>>(&mut self,input: &mut I) -> Option<Self::Token> {
match self.0.matches(input) {
false => None,
true => Some(self.1)
}
}
}
pub struct Eof<S,T>(PhantomData<S>, Option<T>);
impl<S:PartialEq+Copy,T:Copy> Scanner for Eof<S,T> {
type Item = S;
type Token = T;
fn scan<I:ResetIterator<Item=Self::Item>>(&mut self,input: &mut I) -> Option<Self::Token> {
match input.next() {
None if self.1.is_some() => { Some(self.1.take().unwrap()) }
Some(_) => { input.backup(1); None }
_ => None
}
}
}