marser 0.1.0

Parser combinator toolkit with matcher-level backtracking and rich error reporting.
//! Treat a [`crate::parser::Parser`] as a [`crate::matcher::Matcher`]: succeed only when parse output equals `expected_output`.

use crate::{
    error::{MatcherRunError, error_handler::ErrorHandler},
    input::{Input, InputStream},
    matcher::MatchRunner,
    parser::{Parser, ParserCombinator},
};

/// Runs `parser` and compares the result to `expected_output` with [`PartialEq`].
#[derive(Clone, Debug)]
pub struct ParserMatcher<Pars, ParserOutput> {
    parser: Pars,
    expected_output: ParserOutput,
}

impl<Pars, ParserOutput> ParserMatcher<Pars, ParserOutput> {
    /// Matcher succeeds when `parser` returns `Some(expected_output)`.
    pub fn new(parser: Pars, expected_output: ParserOutput) -> Self {
        Self {
            parser,
            expected_output,
        }
    }
}

/// Convenience constructor for [`ParserMatcher`].
pub fn match_parsed<Pars, ParserOutput>(
    parser: Pars,
    expected_output: ParserOutput,
) -> ParserMatcher<Pars, ParserOutput> {
    ParserMatcher::new(parser, expected_output)
}

impl<Pars, ParserOutput> super::MatcherCombinator for ParserMatcher<Pars, ParserOutput> where
    Pars: ParserCombinator
{
}

impl<'src, Inp: Input<'src>, MRes, Pars, ParserOutput> super::internal::MatcherImpl<'src, Inp, MRes>
    for ParserMatcher<Pars, ParserOutput>
where
    Pars: Parser<'src, Inp, Output = ParserOutput>,
    Inp: Input<'src>,
    ParserOutput: PartialEq + Clone + std::fmt::Debug,
{
    const CAN_MATCH_DIRECTLY: bool = true;
    const HAS_PROPERTY: bool = false;
    const CAN_FAIL: bool = Pars::CAN_FAIL;

    #[inline]
    fn match_with_runner<'a, Runner>(
        &'a self,
        runner: &mut Runner,
        error_handler: &mut impl ErrorHandler,
        input: &mut InputStream<'src, Inp>,
    ) -> Result<bool, MatcherRunError>
    where
        Runner: MatchRunner<'a, 'src, Inp, MRes = MRes>,
        'src: 'a,
    {
        let parsed = self
            .parser
            .parse(runner.get_parser_context(), error_handler, input)?;
        if let Some(output) = parsed
            && output == self.expected_output
        {
            return Ok(true);
        }
        Ok(false)
    }
}