zero-parser/src/combinators.rs

281 lines
7.1 KiB
Rust

mod alternate_parser;
mod left_right_parsers;
mod many_parsers;
mod separated_parsers;
mod tuple_parser;
use crate::combinators::alternate_parser::AlternateParser;
use crate::combinators::left_right_parsers::{LeftParser, RightParser};
use crate::combinators::many_parsers::{
Many1Parser, Many1TillParser, ManyParser, ManyTillParser, Skip1Parser, SkipParser,
};
use crate::combinators::separated_parsers::{SeparateBy1Parser, SeparateOrEndBy1Parser};
use crate::combinators::tuple_parser::{ParserTuple, TupleParser};
use crate::parser::{any, Parser};
use std::fmt::Debug;
use std::marker::PhantomData;
pub trait ParserExt<'a, TToken, T: 'a, TContext>: Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
fn left<TRight: 'a, PRight>(self, right_parser: PRight) -> LeftParser<Self, PRight, TRight>
where
Self: Sized,
PRight: Parser<'a, TToken, TRight, TContext>,
{
LeftParser {
left_parser: self,
right_parser,
phantom_data: PhantomData,
}
}
fn right<TRight: 'a, PRight>(self, right_parser: PRight) -> RightParser<Self, PRight, T>
where
Self: Sized,
PRight: Parser<'a, TToken, TRight, TContext>,
{
RightParser {
left_parser: self,
right_parser,
phantom_data: PhantomData,
}
}
fn alternate<P>(self, second_parser: P) -> AlternateParser<Self, P>
where
Self: Sized,
P: Parser<'a, TToken, T, TContext>,
{
AlternateParser {
first: self,
second: second_parser,
}
}
fn many(self) -> ManyParser<Self>
where
Self: Sized,
{
ManyParser { parser: self }
}
fn many1(self) -> Many1Parser<Self>
where
Self: Sized,
{
Many1Parser { parser: self }
}
fn skip(self) -> SkipParser<Self, T>
where
Self: Sized,
{
SkipParser {
parser: self,
phantom_data: PhantomData,
}
}
fn skip1(self) -> Skip1Parser<Self, T>
where
Self: Sized,
{
Skip1Parser {
parser: self,
phantom_data: PhantomData,
}
}
fn many_till<TTerminator: 'a, PTerminator>(
self,
terminator: PTerminator,
) -> ManyTillParser<Self, PTerminator, TTerminator>
where
Self: Sized,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
ManyTillParser {
parser: self,
terminator,
phantom_data: PhantomData,
}
}
fn many1_till<TTerminator: 'a, PTerminator>(
self,
terminator: PTerminator,
) -> Many1TillParser<Self, PTerminator, TTerminator>
where
Self: Sized,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
Many1TillParser {
parser: self,
terminator,
phantom_data: PhantomData,
}
}
}
impl<'a, TToken, T: 'a, TContext, P> ParserExt<'a, TToken, T, TContext> for P
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
}
pub fn alternate_helper<'a, TToken, T: 'a, TContext, P1, P2>(
first: P1,
second: P2,
) -> AlternateParser<P1, P2>
where
TToken: Debug + Clone,
P1: Parser<'a, TToken, T, TContext>,
P2: Parser<'a, TToken, T, TContext>,
{
AlternateParser { first, second }
}
#[macro_export]
macro_rules! alternate {
($first:expr, $( $second:expr ),*) => {
{
let parser = $first;
$(
let parser = $crate::combinators::alternate_helper(parser, $second);
)*
parser
}
};
}
pub fn tuple<'a, TToken, T: 'a, TContext, TList>(list: TList) -> TupleParser<TList>
where
TToken: Debug + Clone + 'a,
TList: ParserTuple<'a, TToken, T, TContext>,
{
TupleParser { parser: list }
}
pub fn take_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>(
termiantor: PTerminator,
) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone + 'a,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
any().many_till(termiantor)
}
pub fn take1_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>(
terminator: PTerminator,
) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone + 'a,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
any().many1_till(terminator)
}
pub fn quote<'a, TToken, T: 'a, TLeft: 'a, TRight: 'a, TContext, PLeft, P, PRight>(
left: PLeft,
parser: P,
right: PRight,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PLeft: Parser<'a, TToken, TLeft, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
left.right(parser.many_till(right))
}
pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
SeparateBy1Parser {
parser,
separator,
phantom_data: PhantomData,
}
}
pub fn separate_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
separate_by1(parser, separator).next(|r| match r {
Err((input, _)) => Ok((input, vec![])),
r => r,
})
}
pub fn end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
parser.many1_till(separator)
}
pub fn end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
parser.many_till(separator)
}
pub fn separate_or_end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
SeparateOrEndBy1Parser {
parser,
separator,
phantom_data: PhantomData,
}
}
pub fn separate_or_end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
separate_or_end_by1(parser, separator).next(|r| match r {
Err((i, _)) => Ok((i, vec![])),
r => r,
})
}