use std::fmt::Display;
use crate::{
context::ParserContext,
error::{MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
matcher::{MatchRunner, Matcher, MatcherCombinator, internal::MatcherImpl},
parser::{Parser, ParserCombinator, internal::ParserImpl},
};
#[derive(Clone, Debug)]
pub struct Labeled<L, I> {
label: L,
inner: I,
}
impl<L, I> ParserCombinator for Labeled<L, I> where I: ParserCombinator {}
impl<L, I> MatcherCombinator for Labeled<L, I> where I: MatcherCombinator {}
impl<L, I> Labeled<L, I> {
pub fn new(label: L, inner: I) -> Self {
Self { label, inner }
}
}
impl<'src, Inp: Input<'src>, MRes, L, I> MatcherImpl<'src, Inp, MRes> for Labeled<L, I>
where
I: Matcher<'src, Inp, MRes>,
Inp: Input<'src>,
L: Display + Clone + 'static + std::fmt::Debug,
{
const CAN_MATCH_DIRECTLY: bool = I::CAN_MATCH_DIRECTLY;
const HAS_PROPERTY: bool = I::HAS_PROPERTY;
const CAN_FAIL: bool = I::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,
{
runner.run_match(&self.inner, error_handler, input)
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
Some(Box::new(self.label.clone()))
}
}
impl<'src, Inp: Input<'src>, L, I> ParserImpl<'src, Inp> for Labeled<L, I>
where
I: Parser<'src, Inp>,
Inp: Input<'src>,
L: Display + Clone + 'static + std::fmt::Debug,
{
type Output = I::Output;
const CAN_FAIL: bool = I::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 !error_handler.is_real() {
return self.inner.parse(context, error_handler, input);
}
let idx = error_handler.register_start(input.get_pos().into());
match self.inner.parse(context, error_handler, input)? {
Some(output) => {
error_handler.register_success(idx);
Ok(Some(output))
}
None => {
error_handler.register_failure(Some(self.label.clone()), idx);
Ok(None)
}
}
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
Some(Box::new(self.label.clone()))
}
}
pub trait WithLabel
where
Self: Sized,
{
fn with_label<L>(self, label: L) -> Labeled<L, Self>;
}
impl<I> WithLabel for I
where
I: Sized,
{
#[inline]
fn with_label<L>(self, label: L) -> Labeled<L, Self> {
Labeled::new(label, self)
}
}