use crate::{
context::ParserContext,
error::{MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
parser::ParserCombinator,
};
#[derive(Clone)]
pub struct TokenParser<CheckF, ParseF> {
check_fn: CheckF,
parse_fn: ParseF,
}
impl<CheckF, ParseF> ParserCombinator for TokenParser<CheckF, ParseF>
where
CheckF: Clone,
ParseF: Clone,
{
}
impl<CheckF, ParseF> std::fmt::Debug for TokenParser<CheckF, ParseF> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TokenParser").finish()
}
}
impl<CheckF, ParseF> TokenParser<CheckF, ParseF> {
pub fn new<Token, Out>(check_fn: CheckF, parse_fn: ParseF) -> Self
where
CheckF: Fn(&Token) -> bool,
ParseF: Fn(&Token) -> Out,
{
Self { check_fn, parse_fn }
}
}
pub fn token_parser<CheckF, ParseF, Token, Out>(
check_fn: CheckF,
parse_fn: ParseF,
) -> TokenParser<CheckF, ParseF>
where
CheckF: Fn(&Token) -> bool,
ParseF: Fn(&Token) -> Out,
{
TokenParser::new(check_fn, parse_fn)
}
impl<'src, Inp: Input<'src>, Out, CheckF, ParseF> super::internal::ParserImpl<'src, Inp>
for TokenParser<CheckF, ParseF>
where
CheckF: Fn(&<Inp as Input<'src>>::Token) -> bool + Clone,
ParseF: Fn(&<Inp as Input<'src>>::Token) -> Out + Clone,
{
type Output = Out;
const CAN_FAIL: bool = true;
#[inline]
fn parse(
&self,
_context: &mut ParserContext<'src>,
_error_handler: &mut impl ErrorHandler,
input: &mut InputStream<'src, Inp>,
) -> Result<Option<Self::Output>, MatcherRunError> {
let start = input.get_pos();
let Some(token) = input.next() else {
return Ok(None);
};
if (self.check_fn)(&token) {
return Ok(Some((self.parse_fn)(&token)));
}
input.set_pos(start);
Ok(None)
}
}