use std::ops::RangeInclusive;
use crate::util::{ResetIterator};
pub trait Matcher : Sized {
type Item;
fn matches<I:ResetIterator<Item=Self::Item>>(&self, input: &mut I) -> bool;
fn zero_or_more(self) -> ZeroOrMore<Self> { ZeroOrMore(self) }
fn one_or_more(self) -> OneOrMore<Self> { OneOrMore(self) }
fn or<Rhs:Matcher<Item=Self::Item>>(self, other: Rhs) -> Or<Self,Rhs> {
Or(self,other)
}
fn then<Rhs:Matcher<Item=Self::Item>>(self, other: Rhs) -> Then<Self,Rhs> {
Then(self,other)
}
}
impl Matcher for char {
type Item = char;
fn matches<I:ResetIterator<Item=char>>(&self, input: &mut I) -> bool {
match input.next() {
Some(t) if self == &t => true,
Some(_) => {
input.backup(1);
false
}
_ => false
}
}
}
impl<T:PartialEq+Copy,const N: usize> Matcher for [T;N] {
type Item = T;
fn matches<I:ResetIterator<Item=T>>(&self, input: &mut I) -> bool {
for (i,c) in self.iter().enumerate() {
match input.next() {
Some(t) if t != *c => {
input.backup(i+1);
return false;
}
None => {
input.backup(i);
return false;
}
Some(_) => { }
}
}
true
}
}
#[derive(Clone,Copy,Debug)]
pub struct Any<T:PartialEq,const N:usize>(pub [T;N]);
impl<T:PartialEq+Copy,const N:usize> Matcher for Any<T,N> {
type Item = T;
fn matches<I:ResetIterator<Item=T>>(&self, input: &mut I) -> bool {
match input.next() {
Some(t) if self.0.contains(&t) => true,
Some(_) => {
input.backup(1);
false
}
_ => false
}
}
}
#[derive(Clone,Debug)]
pub struct Within<T:PartialOrd>(pub RangeInclusive<T>);
impl<T:PartialOrd+Copy> Matcher for Within<T> {
type Item = T;
fn matches<I:ResetIterator<Item=T>>(&self, input: &mut I) -> bool {
match input.next() {
Some(t) if self.0.contains(&t) => true,
Some(_) => {
input.backup(1);
false
}
_ => false
}
}
}
#[derive(Clone,Copy,Debug)]
pub struct Many<M:Matcher>(M);
impl<M:Matcher> Matcher for Many<M> {
type Item = M::Item;
fn matches<I:ResetIterator<Item=M::Item>>(&self, input: &mut I) -> bool {
let first = self.0.matches(input);
while self.0.matches(input) {}
first
}
}
#[derive(Clone,Copy,Debug)]
pub struct OneOrMore<M:Matcher>(M);
impl<M:Matcher> Matcher for OneOrMore<M> {
type Item = M::Item;
fn matches<I:ResetIterator<Item=M::Item>>(&self, input: &mut I) -> bool {
let first = self.0.matches(input);
while self.0.matches(input) {}
first
}
}
#[derive(Clone,Copy,Debug)]
pub struct ZeroOrMore<M:Matcher>(M);
impl<M:Matcher> Matcher for ZeroOrMore<M> {
type Item = M::Item;
fn matches<I:ResetIterator<Item=M::Item>>(&self, input: &mut I) -> bool {
while self.0.matches(input) {}
true
}
}
#[derive(Clone,Copy,Debug)]
pub struct Or<Lhs:Matcher,Rhs:Matcher<Item=Lhs::Item>>(Lhs,Rhs);
impl<Lhs:Matcher,Rhs:Matcher<Item=Lhs::Item>> Matcher for Or<Lhs,Rhs> {
type Item = Lhs::Item;
fn matches<I:ResetIterator<Item=Lhs::Item>>(&self, input: &mut I) -> bool {
self.0.matches(input) || self.1.matches(input)
}
}
#[derive(Clone,Copy,Debug)]
pub struct Then<Lhs:Matcher,Rhs:Matcher<Item=Lhs::Item>>(Lhs,Rhs);
impl<Lhs:Matcher,Rhs:Matcher<Item=Lhs::Item>> Matcher for Then<Lhs,Rhs> {
type Item = Lhs::Item;
fn matches<I:ResetIterator<Item=Lhs::Item>>(&self, input: &mut I) -> bool {
let offset = input.offset();
if self.0.matches(input) {
let n = input.offset() - offset;
if self.1.matches(input) {
return true;
} else {
input.backup(n);
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::{Matcher};
use crate::util::ResetChars;
#[test]
fn test_01() {
let mut input = ResetChars::new("(".chars());
let matcher = '(';
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),None);
}
#[test]
fn test_02() {
let mut input = ResetChars::new("(abc".chars());
let matcher = '(';
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),Some('a'));
}
#[test]
fn test_03() {
let mut input = ResetChars::new("(".chars());
let matcher = '('.or(')');
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),None);
}
#[test]
fn test_04() {
let mut input = ResetChars::new(")".chars());
let matcher = '('.or(')');
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),None);
}
#[test]
fn test_05() {
let mut input = ResetChars::new("((((".chars());
let matcher = '('.one_or_more();
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),None);
}
#[test]
fn test_06() {
let mut input = ResetChars::new(")".chars());
let matcher = '('.or(')').one_or_more();
assert!(matcher.matches(&mut input));
assert_eq!(input.next(),None);
}
}