use std::fmt::Display;
use crate::{
context::ParserContext,
error::{FurthestFailError, MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
matcher::{MatchRunner, Matcher, MatcherCombinator},
parser::{Parser, ParserCombinator, internal::ParserImpl},
};
#[derive(Clone, Debug)]
pub struct ErrorContextualizer<Happy, Pars> {
happy: Happy,
error_parser: Pars,
}
impl<Matcher, Pars> MatcherCombinator for ErrorContextualizer<Matcher, Pars> where
Matcher: MatcherCombinator
{
}
impl<Happy, Pars> ParserCombinator for ErrorContextualizer<Happy, Pars> where Happy: ParserCombinator
{}
impl<Matcher, Pars> ErrorContextualizer<Matcher, Pars> {
pub fn new(happy: Matcher, error_parser: Pars) -> Self {
Self {
happy,
error_parser,
}
}
}
impl<'src, Inp: Input<'src>, Happy, Pars, MRes> super::internal::MatcherImpl<'src, Inp, MRes>
for ErrorContextualizer<Happy, Pars>
where
Happy: Matcher<'src, Inp, MRes>,
Pars: Parser<'src, Inp, Output = Box<dyn Fn(&mut FurthestFailError)>>,
Inp: Input<'src>,
{
const CAN_MATCH_DIRECTLY: bool = Happy::CAN_MATCH_DIRECTLY;
const HAS_PROPERTY: bool = Happy::HAS_PROPERTY;
const CAN_FAIL: bool = Happy::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 start_pos = input.get_pos();
match runner.run_match(&self.happy, error_handler, input) {
Ok(true) => Ok(true),
Ok(false) => Ok(false),
Err(MatcherRunError::RetryRerunNeeded) => Err(MatcherRunError::RetryRerunNeeded),
Err(MatcherRunError::FurthestFail(mut e)) => {
let resume_pos = input.get_pos();
input.set_pos(start_pos.clone());
if let Ok(Some(f)) =
self.error_parser
.parse(runner.get_parser_context(), error_handler, input)
{
f(&mut e);
}
input.set_pos(resume_pos);
Err(MatcherRunError::FurthestFail(e))
}
}
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
self.happy.maybe_label()
}
}
impl<'src, Inp: Input<'src>, Happy, Pars> ParserImpl<'src, Inp> for ErrorContextualizer<Happy, Pars>
where
Happy: Parser<'src, Inp>,
Pars: Parser<'src, Inp, Output = Box<dyn Fn(&mut FurthestFailError)>>,
Inp: Input<'src>,
{
type Output = Happy::Output;
const CAN_FAIL: bool = Happy::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> {
let start_pos = input.get_pos();
match self.happy.parse(context, error_handler, input) {
Ok(Some(output)) => Ok(Some(output)),
Ok(None) => Ok(None),
Err(MatcherRunError::RetryRerunNeeded) => Err(MatcherRunError::RetryRerunNeeded),
Err(MatcherRunError::FurthestFail(mut e)) => {
let resume_pos = input.get_pos();
input.set_pos(start_pos);
if let Ok(Some(f)) = self.error_parser.parse(context, error_handler, input) {
f(&mut e);
}
input.set_pos(resume_pos);
Err(MatcherRunError::FurthestFail(e))
}
}
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
self.happy.maybe_label()
}
}