use std::marker::PhantomData;
use crate::*;
pub trait ParseMapper<P> {
type Result;
fn map(self, result: Result<P, ParseError>) -> Self::Result;
}
pub trait ResultMapperExt<P> {
type Result<Mapper: ParseMapper<P>>;
fn apply<M: ParseMapper<P>>(self, mapper: M) -> Self::Result<M>;
}
impl<P> ResultMapperExt<P> for Result<P, ParseError> {
type Result<Mapper: ParseMapper<P>> = Mapper::Result;
fn apply<M: ParseMapper<P>>(self, mapper: M) -> Self::Result<M> {
mapper.map(self)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MustMatch;
impl<P> ParseMapper<P> for MustMatch {
type Result = Result<P, ParseError>;
fn map(self, result: Result<P, ParseError>) -> Result<P, ParseError> {
result.map_err(|e| {
if e.kind() == ParseErrorKind::Unmatch {
ParseError {
error: e.error(),
kind: ParseErrorKind::Semantic,
}
} else {
e
}
})
}
}
#[derive(Debug, Clone)]
pub struct Equal<P, E> {
eq: P,
or: E,
}
impl<P, E> ParseMapper<P> for Equal<P, E>
where
P: PartialEq + WithSpan,
E: FnOnce(Span) -> Result<P, ParseError>,
{
type Result = Result<P, ParseError>;
fn map(self, result: Result<P, ParseError>) -> Result<P, ParseError> {
let result = result?;
if result == self.eq {
Ok(result)
} else {
(self.or)(result.get_span())
}
}
}
impl<P, E> Equal<P, E>
where
P: PartialEq + WithSpan,
E: FnOnce(Span) -> Result<P, ParseError>,
{
pub fn new(eq: P, or: E) -> Self {
Self { eq, or }
}
}
pub struct Satisfy<P, C, E>
where
C: FnOnce(&P) -> bool,
E: FnOnce(Span) -> Result<P, ParseError>,
{
cond: C,
or: E,
_p: PhantomData<P>,
}
impl<P, C, E> ParseMapper<P> for Satisfy<P, C, E>
where
P: WithSpan,
C: FnOnce(&P) -> bool,
E: FnOnce(Span) -> Result<P, ParseError>,
{
type Result = Result<P, ParseError>;
fn map(self, result: Result<P, ParseError>) -> Result<P, ParseError> {
let result = result?;
if (self.cond)(&result) {
Ok(result)
} else {
(self.or)(result.get_span())
}
}
}
impl<P, C, E> Satisfy<P, C, E>
where
C: FnOnce(&P) -> bool,
E: FnOnce(Span) -> Result<P, ParseError>,
{
pub fn new(cond: C, or: E) -> Self {
Self {
cond,
or,
_p: PhantomData,
}
}
}
pub struct Try;
impl<P> ParseMapper<P> for Try {
type Result = Result<Option<P>, ParseError>;
#[inline]
fn map(self, result: Result<P, ParseError>) -> Result<Option<P>, ParseError> {
match result {
Ok(p) => Ok(Some(p)),
Err(e) if e.kind() == ParseErrorKind::Unmatch => Ok(None),
Err(e) => Err(e),
}
}
}