use std::fmt::Display;
use crate::{
context::ParserContext,
error::{MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
matcher::{DirectMatchRunner, Matcher, NoMemoizeBacktrackingRunner, runner::MatchRunner},
parser::{ParserCombinator, internal::ParserImpl},
};
#[derive(Clone)]
pub struct ToParser<Match, Output> {
matcher: Match,
output: Output,
}
impl<Match, Output> ToParser<Match, Output> {
pub fn new(matcher: Match, output: Output) -> Self {
Self { matcher, output }
}
}
impl<Match, Output> std::fmt::Debug for ToParser<Match, Output>
where
Match: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ToParser")
.field("matcher", &self.matcher)
.finish()
}
}
impl<Match, Output> ParserCombinator for ToParser<Match, Output> {}
impl<'src, Inp, Match, Output> ParserImpl<'src, Inp> for ToParser<Match, Output>
where
Inp: Input<'src>,
Match: Matcher<'src, Inp, ((), (), ())>,
Output: Clone,
{
type Output = Output;
const CAN_FAIL: bool = Match::CAN_FAIL;
#[inline]
fn parse(
&self,
context: &mut ParserContext<'src>,
error_handler: &mut impl ErrorHandler,
input: &mut InputStream<'src, Inp>,
) -> Result<Option<Self::Output>, MatcherRunError> {
if Match::CAN_MATCH_DIRECTLY && !error_handler.is_real() && !context.is_in_error_recovery {
let mut runner = DirectMatchRunner::new(context);
if runner.run_match(&self.matcher, error_handler, input)? {
Ok(Some(self.output.clone()))
} else {
Ok(None)
}
} else {
let mut runner = NoMemoizeBacktrackingRunner::new(context);
if runner.run_match(&self.matcher, error_handler, input)? {
Ok(Some(self.output.clone()))
} else {
Ok(None)
}
}
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
self.matcher.maybe_label()
}
}