use std::fmt::Display;
use std::marker::PhantomData;
use crate::{
context::ParserContext,
error::{MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
matcher::{DirectMatchRunner, Matcher, NoMemoizeBacktrackingRunner, runner::MatchRunner},
parser::{ParserCombinator, internal::ParserImpl},
};
use super::match_result::{MatchResultMultiple, MatchResultOptional, MatchResultSingle};
pub struct Capture<MRes, Match, F> {
pub(super) matcher: Match,
pub(super) constructor: F,
pub(super) _phantom: PhantomData<MRes>,
}
impl<MRes, Match, F> Clone for Capture<MRes, Match, F>
where
Match: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
matcher: self.matcher.clone(),
constructor: self.constructor.clone(),
_phantom: PhantomData,
}
}
}
impl<MRes, Match, F> std::fmt::Debug for Capture<MRes, Match, F>
where
Match: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Capture")
.field("matcher", &self.matcher)
.finish()
}
}
impl<MResSingle, MResMultiple, MResOptional, Match, F> ParserCombinator
for Capture<(MResSingle, MResMultiple, MResOptional), Match, F>
where
Match: crate::matcher::MatcherCombinator,
{
}
impl<Out, MResSingle, MResMultiple, MResOptional, Match, F>
Capture<(MResSingle, MResMultiple, MResOptional), Match, F>
where
MResSingle: MatchResultSingle,
MResMultiple: MatchResultMultiple,
MResOptional: MatchResultOptional,
F: Fn(MResSingle::Output, MResMultiple, MResOptional) -> Out,
{
pub fn new<
'a,
'ctx: 'a,
GF: FnOnce(MResSingle::Properties, MResMultiple::Properties, MResOptional::Properties) -> Match,
>(
grammar_factory: GF,
constructor: F,
) -> Self {
let properties_single = MResSingle::new_properties();
let properties_multiple = MResMultiple::new_properties();
let properties_optional = MResOptional::new_properties();
Self {
matcher: grammar_factory(properties_single, properties_multiple, properties_optional),
constructor,
_phantom: PhantomData,
}
}
}
impl<'src, Inp: Input<'src>, Out, MResSingle, MResMultiple, MResOptional, Match, F>
ParserImpl<'src, Inp> for Capture<(MResSingle, MResMultiple, MResOptional), Match, F>
where
MResSingle: MatchResultSingle,
MResMultiple: MatchResultMultiple,
MResOptional: MatchResultOptional,
Match: Matcher<'src, Inp, (MResSingle, MResMultiple, MResOptional)>,
Inp: Input<'src>,
F: Fn(MResSingle::Output, MResMultiple, MResOptional) -> Out + Clone,
{
type Output = Out;
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);
match runner.run_match(&self.matcher, error_handler, input) {
Ok(true) => {
let (res_single, res_multiple, res_optional) = runner.get_match_result();
let result =
(self.constructor)(res_single.to_output(), res_multiple, res_optional);
Ok(Some(result))
}
Ok(false) => Ok(None),
Err(e) => Err(e),
}
} else {
let mut runner = NoMemoizeBacktrackingRunner::new(context);
match runner.run_match(&self.matcher, error_handler, input) {
Ok(true) => {
let (res_single, res_multiple, res_optional) = runner.get_match_result();
let result =
(self.constructor)(res_single.to_output(), res_multiple, res_optional);
Ok(Some(result))
}
Ok(false) => Ok(None),
Err(e) => Err(e),
}
}
}
#[inline]
fn maybe_label(&self) -> Option<Box<dyn Display>> {
self.matcher.maybe_label()
}
}