use crate::{
context::ParserContext,
error::{MatcherRunError, error_handler::ErrorHandler},
input::{Input, InputStream},
matcher::{MatchRunner, Matcher, MatcherCombinator},
parser::{Parser, ParserCombinator},
};
#[derive(Clone, Debug)]
pub struct OneOf<Tuple> {
options: Tuple,
}
impl<Tuple> OneOf<Tuple> {
pub fn new(options: Tuple) -> Self {
Self { options }
}
}
pub fn one_of<Options>(options: Options) -> OneOf<Options> {
OneOf::new(options)
}
macro_rules! impl_one_of_tuples {
() => {};
($head:ident $(,$tail:ident)*) => {
impl<$head, $($tail),*> MatcherCombinator for OneOf<($head, $($tail,)*)> where
$head: MatcherCombinator,
$($tail: MatcherCombinator,)*
{}
impl<$head, $($tail),*> ParserCombinator for OneOf<($head, $($tail,)*)> where
$head: ParserCombinator,
$($tail: ParserCombinator,)*
{}
impl<'src, Inp: Input<'src>, MRes, $head, $($tail),*> crate::matcher::internal::MatcherImpl<'src, Inp, MRes> for OneOf<($head, $($tail,)*)>
where
$head: Matcher<'src, Inp, MRes>,
$($tail: Matcher<'src, Inp, MRes>,)*
Inp: Input<'src>,
{
const CAN_MATCH_DIRECTLY: bool = $head::CAN_MATCH_DIRECTLY $(&& $tail::CAN_MATCH_DIRECTLY)*;
const HAS_PROPERTY: bool = $head::HAS_PROPERTY $(|| $tail::HAS_PROPERTY)*;
const CAN_FAIL: bool = $head::CAN_FAIL $(&& $tail::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,
{
#[allow(non_snake_case)]
let ($head, $($tail,)*) = &self.options;
if runner.run_match($head, error_handler, input)? {
return Ok(true);
}
$(
if runner.run_match($tail, error_handler, input)? {
return Ok(true);
}
)*
Ok(false)
}
}
impl<'src, Inp: Input<'src>, Output, $head, $($tail),*> crate::parser::internal::ParserImpl<'src, Inp> for OneOf<($head, $($tail,)*)>
where
$head: Parser<'src, Inp, Output = Output>,
$($tail: Parser<'src, Inp, Output = Output>,)*
Inp: Input<'src>,
{
type Output = Output;
const CAN_FAIL: bool = $head::CAN_FAIL $(&& $tail::CAN_FAIL)*;
#[inline]
fn parse(&self, context: &mut ParserContext<'src>, error_handler: &mut impl ErrorHandler, input: &mut InputStream<'src, Inp>) -> Result<Option<Output>, MatcherRunError> {
#[allow(non_snake_case)]
let ($head, $($tail,)*) = &self.options;
if let Some(output) = $head.parse(context, error_handler, input)? {
return Ok(Some(output));
}
$(
if let Some(output) = $tail.parse(context, error_handler, input)? {
return Ok(Some(output));
}
)*
Ok(None)
}
}
impl_one_of_tuples!($($tail),*);
};
}
impl_one_of_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);