add: parser combinators.
This commit is contained in:
parent
0e9684c32e
commit
8a9c58966b
281
src/combinators.rs
Normal file
281
src/combinators.rs
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
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;
|
||||||
|
use crate::parser::{any, Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub trait ParserExt<TToken, T, TContext>: Parser<TToken, T, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
{
|
||||||
|
fn left<TRight, PRight>(self, right_parser: PRight) -> LeftParser<Self, PRight, TRight>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
PRight: Parser<TToken, TRight, TContext>,
|
||||||
|
{
|
||||||
|
LeftParser {
|
||||||
|
left_parser: self,
|
||||||
|
right_parser,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right<TRight, PRight>(self, right_parser: PRight) -> RightParser<Self, PRight, T>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
PRight: Parser<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<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, PTerminator>(
|
||||||
|
self,
|
||||||
|
terminator: PTerminator,
|
||||||
|
) -> ManyTillParser<Self, PTerminator, TTerminator>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
ManyTillParser {
|
||||||
|
parser: self,
|
||||||
|
terminator,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn many1_till<TTerminator, PTerminator>(
|
||||||
|
self,
|
||||||
|
terminator: PTerminator,
|
||||||
|
) -> Many1TillParser<Self, PTerminator, TTerminator>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
Many1TillParser {
|
||||||
|
parser: self,
|
||||||
|
terminator,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P> ParserExt<TToken, T, TContext> for P
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alternate_helper<TToken, T, TContext, P1, P2>(first: P1, second: P2) -> AlternateParser<P1, P2>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T, TContext>,
|
||||||
|
P2: Parser<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<TToken, T, TContext, TList>(
|
||||||
|
list: TList,
|
||||||
|
) -> impl Fn(Rc<RefCell<ParserContext<TToken, TContext>>>, &[TToken]) -> ParserResult<TToken, T>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
TList: ParserTuple<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
move |context, input| list.parse(context, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_till<TToken, TTerminator, TContext, PTerminator>(
|
||||||
|
termiantor: PTerminator,
|
||||||
|
) -> impl Parser<TToken, Vec<TToken>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
any().many_till(termiantor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take1_till<TToken, TTerminator, TContext, PTerminator>(
|
||||||
|
terminator: PTerminator,
|
||||||
|
) -> impl Parser<TToken, Vec<TToken>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
any().many1_till(terminator)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quote<TToken, T, TLeft, TRight, TContext, PLeft, P, PRight>(
|
||||||
|
left: PLeft,
|
||||||
|
parser: P,
|
||||||
|
right: PRight,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PLeft: Parser<TToken, TLeft, TContext>,
|
||||||
|
PRight: Parser<TToken, TRight, TContext>,
|
||||||
|
{
|
||||||
|
left.right(parser.many_till(right))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn separate_by1<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
SeparateBy1Parser {
|
||||||
|
parser,
|
||||||
|
separator,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn separate_by<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
separate_by1(parser, separator).next(|r| match r {
|
||||||
|
Err((input, _)) => Ok((input, vec![])),
|
||||||
|
r => r,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_by1<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
parser.many1_till(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_by<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
parser.many_till(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn separate_or_end_by1<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
SeparateOrEndBy1Parser {
|
||||||
|
parser,
|
||||||
|
separator,
|
||||||
|
phantom_data: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn separate_or_end_by<TToken, T, TSeparator, TContext, P, PSeparator>(
|
||||||
|
parser: P,
|
||||||
|
separator: PSeparator,
|
||||||
|
) -> impl Parser<TToken, Vec<T>, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
separate_or_end_by1(parser, separator).next(|r| match r {
|
||||||
|
Err((i, _)) => Ok((i, vec![])),
|
||||||
|
r => r,
|
||||||
|
})
|
||||||
|
}
|
67
src/combinators/alternate_parser.rs
Normal file
67
src/combinators/alternate_parser.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct AlternateParser<P1, P2> {
|
||||||
|
pub(crate) first: P1,
|
||||||
|
pub(crate) second: P2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P1, P2> Parser<TToken, T, TContext> for AlternateParser<P1, P2>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T, TContext>,
|
||||||
|
P2: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, T> {
|
||||||
|
match self.first.parse(context.clone(), input) {
|
||||||
|
Err((input, _)) => self.second.parse(context, input),
|
||||||
|
r => r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::alternate;
|
||||||
|
use crate::combinators::ParserExt;
|
||||||
|
use crate::parser::parser_test_helper;
|
||||||
|
use crate::text::char_parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alternate_test() {
|
||||||
|
fn parser(
|
||||||
|
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||||
|
input: &[char],
|
||||||
|
) -> ParserResult<char, char> {
|
||||||
|
char_parser('a')
|
||||||
|
.alternate(char_parser('b'))
|
||||||
|
.alternate(char_parser('c'))
|
||||||
|
.parse(context, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', parser);
|
||||||
|
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser);
|
||||||
|
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alternate_macro_test() {
|
||||||
|
fn parser(
|
||||||
|
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||||
|
input: &[char],
|
||||||
|
) -> ParserResult<char, char> {
|
||||||
|
alternate!(char_parser('a'), char_parser('b'), char_parser('c')).parse(context, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', parser);
|
||||||
|
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser);
|
||||||
|
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser);
|
||||||
|
}
|
||||||
|
}
|
82
src/combinators/left_right_parsers.rs
Normal file
82
src/combinators/left_right_parsers.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
use crate::combinators::ParserExt;
|
||||||
|
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct LeftParser<PLeft, PRight, TRight> {
|
||||||
|
pub(crate) left_parser: PLeft,
|
||||||
|
pub(crate) right_parser: PRight,
|
||||||
|
pub(crate) phantom_data: PhantomData<TRight>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, TRight, PLeft, PRight> Parser<TToken, T, TContext>
|
||||||
|
for LeftParser<PLeft, PRight, TRight>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
PLeft: Parser<TToken, T, TContext>,
|
||||||
|
PRight: Parser<TToken, TRight, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, T> {
|
||||||
|
let (input, r) = self.left_parser.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
match self.right_parser.parse(context, input) {
|
||||||
|
Ok((input, _)) => Ok((input, r)),
|
||||||
|
Err(r) => Err(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RightParser<PLeft, PRight, T> {
|
||||||
|
pub(crate) left_parser: PLeft,
|
||||||
|
pub(crate) right_parser: PRight,
|
||||||
|
pub(crate) phantom_data: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, TRight, PLeft, PRight> Parser<TToken, TRight, TContext>
|
||||||
|
for RightParser<PLeft, PRight, T>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
PLeft: Parser<TToken, T, TContext>,
|
||||||
|
PRight: Parser<TToken, TRight, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, TRight> {
|
||||||
|
let (input, _) = self.left_parser.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
self.right_parser.parse(context, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::parser::{parser_test_helper, ParserContext};
|
||||||
|
use crate::text::char_parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn left_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
&'a',
|
||||||
|
char_parser('a').left(char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn right_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
&'b',
|
||||||
|
char_parser('a').right(char_parser('b')),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
338
src/combinators/many_parsers.rs
Normal file
338
src/combinators/many_parsers.rs
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct ManyParser<P> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P> Parser<TToken, Vec<T>, TContext> for ManyParser<P>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let mut result = vec![];
|
||||||
|
let mut input = input;
|
||||||
|
|
||||||
|
while let Ok((i, r)) = self.parser.parse(context.clone(), input) {
|
||||||
|
result.push(r);
|
||||||
|
input = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Many1Parser<P> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P> Parser<TToken, Vec<T>, TContext> for Many1Parser<P>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let (mut input, first_result) = self.parser.parse(context.clone(), input)?;
|
||||||
|
let mut result = vec![first_result];
|
||||||
|
|
||||||
|
while let Ok((i, r)) = self.parser.parse(context.clone(), input) {
|
||||||
|
result.push(r);
|
||||||
|
input = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SkipParser<P, T> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) phantom_data: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P> Parser<TToken, (), TContext> for SkipParser<P, T>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, ()> {
|
||||||
|
let mut input = input;
|
||||||
|
|
||||||
|
while let Ok((i, _)) = self.parser.parse(context.clone(), input) {
|
||||||
|
input = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Skip1Parser<P, T> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) phantom_data: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext, P> Parser<TToken, (), TContext> for Skip1Parser<P, T>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, ()> {
|
||||||
|
let (mut input, _) = self.parser.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
while let Ok((i, _)) = self.parser.parse(context.clone(), input) {
|
||||||
|
input = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ManyTillParser<P, PTerminator, TTerminator> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) terminator: PTerminator,
|
||||||
|
pub(crate) phantom_data: PhantomData<TTerminator>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TTerminator, TContext, P, PTerminator> Parser<TToken, Vec<T>, TContext>
|
||||||
|
for ManyTillParser<P, PTerminator, TTerminator>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let mut input = input;
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if self.terminator.parse(context.clone(), input).is_ok() {
|
||||||
|
return Ok((input, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok((i, r)) = self.parser.parse(context.clone(), input) {
|
||||||
|
input = i;
|
||||||
|
result.push(r);
|
||||||
|
} else {
|
||||||
|
return Err((
|
||||||
|
input,
|
||||||
|
FailedParserResult::new("End with other elements.".to_owned()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct Many1TillParser<P, PTerminator, TTerminator> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) terminator: PTerminator,
|
||||||
|
pub(crate) phantom_data: PhantomData<TTerminator>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TTerminator, TContext, P, PTerminator> Parser<TToken, Vec<T>, TContext>
|
||||||
|
for Many1TillParser<P, PTerminator, TTerminator>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PTerminator: Parser<TToken, TTerminator, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let (mut input, r) = self.parser.parse(context.clone(), input)?;
|
||||||
|
let mut result = vec![r];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if self.terminator.parse(context.clone(), input).is_ok() {
|
||||||
|
return Ok((input, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok((i, r)) = self.parser.parse(context.clone(), input) {
|
||||||
|
result.push(r);
|
||||||
|
input = i;
|
||||||
|
} else {
|
||||||
|
return Ok((input, result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::combinators::{take1_till, take_till, tuple, ParserExt};
|
||||||
|
use crate::parser::{failed_parser_test_helper, parser_test_helper};
|
||||||
|
use crate::text::char_parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaa", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many(),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaabbaa", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many(),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("bbaa", ()),
|
||||||
|
&vec![],
|
||||||
|
char_parser('a').many(),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("", ()),
|
||||||
|
&vec![],
|
||||||
|
char_parser('a').many(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many1_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaa", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many1(),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaabbaa", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many1(),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("bbaa", ()),
|
||||||
|
char_parser('a').many1(),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("", ()),
|
||||||
|
char_parser('a').many1(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skip_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&'b',
|
||||||
|
char_parser('a').skip().right(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
&'b',
|
||||||
|
char_parser('a').skip().right(char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skip1_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&'b',
|
||||||
|
char_parser('a').skip1().right(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
char_parser('a').skip1().right(char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many_till_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
&vec![],
|
||||||
|
char_parser('a').many_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaacb", ()),
|
||||||
|
char_parser('a').many_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many1_till_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&vec!['a', 'a', 'a'],
|
||||||
|
char_parser('a').many_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
char_parser('a').many1_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaacb", ()),
|
||||||
|
char_parser('a').many_till(char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn take_till_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&(vec!['a', 'a', 'a'], 'b'),
|
||||||
|
tuple((take_till(char_parser('b')), char_parser('b'))),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
&(vec![], 'b'),
|
||||||
|
tuple((take_till(char_parser('b')), char_parser('b'))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn take1_till_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aaab", ()),
|
||||||
|
&(vec!['a', 'a', 'a'], 'b'),
|
||||||
|
tuple((take1_till(char_parser('b')), char_parser('b'))),
|
||||||
|
);
|
||||||
|
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
tuple((take1_till(char_parser('b')), char_parser('b'))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
256
src/combinators/separated_parsers.rs
Normal file
256
src/combinators/separated_parsers.rs
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct SeparateBy1Parser<P, PSeparator, TSeparator> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) separator: PSeparator,
|
||||||
|
pub(crate) phantom_data: PhantomData<TSeparator>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TSeparator, TContext, P, PSeparator> Parser<TToken, Vec<T>, TContext>
|
||||||
|
for SeparateBy1Parser<P, PSeparator, TSeparator>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let (mut input, first) = self.parser.parse(context.clone(), input)?;
|
||||||
|
let mut result = vec![first];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok((i, _)) = self.separator.parse(context.clone(), input) {
|
||||||
|
let (i, r) = self.parser.parse(context.clone(), i)?;
|
||||||
|
input = i;
|
||||||
|
result.push(r);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SeparateOrEndBy1Parser<P, PSeparator, TSeparator> {
|
||||||
|
pub(crate) parser: P,
|
||||||
|
pub(crate) separator: PSeparator,
|
||||||
|
pub(crate) phantom_data: PhantomData<TSeparator>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TSeparator, TContext, P, PSeparator> Parser<TToken, Vec<T>, TContext>
|
||||||
|
for SeparateOrEndBy1Parser<P, PSeparator, TSeparator>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P: Parser<TToken, T, TContext>,
|
||||||
|
PSeparator: Parser<TToken, TSeparator, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, Vec<T>> {
|
||||||
|
let (mut input, first) = self.parser.parse(context.clone(), input)?;
|
||||||
|
let mut result = vec![first];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok((i, _)) = self.separator.parse(context.clone(), input) {
|
||||||
|
if let Ok((i, r)) = self.parser.parse(context.clone(), i) {
|
||||||
|
result.push(r);
|
||||||
|
input = i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::combinators::{
|
||||||
|
end_by, end_by1, quote, separate_by, separate_by1, separate_or_end_by, separate_or_end_by1,
|
||||||
|
};
|
||||||
|
use crate::parser::{failed_parser_test_helper, parser_test_helper, satisfy};
|
||||||
|
use crate::text::char_parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quote_test() {
|
||||||
|
fn parser(
|
||||||
|
context: Rc<RefCell<ParserContext<char, ()>>>,
|
||||||
|
input: &[char],
|
||||||
|
) -> ParserResult<char, Vec<char>> {
|
||||||
|
quote(
|
||||||
|
char_parser('\''),
|
||||||
|
satisfy(|c: &char| c.is_ascii()),
|
||||||
|
char_parser('\''),
|
||||||
|
)
|
||||||
|
.parse(context, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("'abc'", ()),
|
||||||
|
&vec!['a', 'b', 'c'],
|
||||||
|
parser,
|
||||||
|
);
|
||||||
|
parser_test_helper(ParserContext::new_with_str("''", ()), &vec![], parser);
|
||||||
|
failed_parser_test_helper(ParserContext::new_with_str("asd", ()), parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn separate_by1_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("a,b,c", ()),
|
||||||
|
&vec!['a', 'b', 'c'],
|
||||||
|
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("a", ()),
|
||||||
|
&vec!['a'],
|
||||||
|
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("bbc", ()),
|
||||||
|
&vec!['b'],
|
||||||
|
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn separate_by_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,2,3", ()),
|
||||||
|
&vec!['1', '2', '3'],
|
||||||
|
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1", ()),
|
||||||
|
&vec!['1'],
|
||||||
|
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("", ()),
|
||||||
|
&vec![],
|
||||||
|
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
&vec!['a'],
|
||||||
|
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn end_by1_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aab", ()),
|
||||||
|
&vec!['a', 'a'],
|
||||||
|
end_by1(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("ab", ()),
|
||||||
|
&vec!['a'],
|
||||||
|
end_by1(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
end_by1(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("cd", ()),
|
||||||
|
end_by1(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn end_by_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("aab", ()),
|
||||||
|
&vec!['a', 'a'],
|
||||||
|
end_by(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("ab", ()),
|
||||||
|
&vec!['a'],
|
||||||
|
end_by(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("b", ()),
|
||||||
|
&vec![],
|
||||||
|
end_by(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("cd", ()),
|
||||||
|
end_by(char_parser('a'), char_parser('b')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn separate_or_end_by1_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,2,3,", ()),
|
||||||
|
&vec!['1', '2', '3'],
|
||||||
|
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,", ()),
|
||||||
|
&vec!['1'],
|
||||||
|
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,2,3", ()),
|
||||||
|
&vec!['1', '2', '3'],
|
||||||
|
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1", ()),
|
||||||
|
&vec!['1'],
|
||||||
|
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
failed_parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn separate_or_end_by_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,2,3,", ()),
|
||||||
|
&vec!['1', '2', '3'],
|
||||||
|
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,", ()),
|
||||||
|
&vec!['1'],
|
||||||
|
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1,2,3", ()),
|
||||||
|
&vec!['1', '2', '3'],
|
||||||
|
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("1", ()),
|
||||||
|
&vec!['1'],
|
||||||
|
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
&vec![],
|
||||||
|
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
136
src/combinators/tuple_parser.rs
Normal file
136
src/combinators/tuple_parser.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
use crate::parser::{Parser, ParserContext, ParserResult};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub trait ParserTuple<TToken, T, TContext>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T1, T2, TContext, P1, P2> ParserTuple<TToken, (T1, T2), TContext> for (P1, P2)
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T1, TContext>,
|
||||||
|
P2: Parser<TToken, T2, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, (T1, T2)> {
|
||||||
|
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||||
|
let (input, r2) = self.1.parse(context, input)?;
|
||||||
|
|
||||||
|
Ok((input, (r1, r2)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T1, T2, T3, TContext, P1, P2, P3> ParserTuple<TToken, (T1, T2, T3), TContext>
|
||||||
|
for (P1, P2, P3)
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T1, TContext>,
|
||||||
|
P2: Parser<TToken, T2, TContext>,
|
||||||
|
P3: Parser<TToken, T3, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, (T1, T2, T3)> {
|
||||||
|
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||||
|
let (input, r2) = self.1.parse(context.clone(), input)?;
|
||||||
|
let (input, r3) = self.2.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
Ok((input, (r1, r2, r3)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T1, T2, T3, T4, TContext, P1, P2, P3, P4>
|
||||||
|
ParserTuple<TToken, (T1, T2, T3, T4), TContext> for (P1, P2, P3, P4)
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T1, TContext>,
|
||||||
|
P2: Parser<TToken, T2, TContext>,
|
||||||
|
P3: Parser<TToken, T3, TContext>,
|
||||||
|
P4: Parser<TToken, T4, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, (T1, T2, T3, T4)> {
|
||||||
|
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||||
|
let (input, r2) = self.1.parse(context.clone(), input)?;
|
||||||
|
let (input, r3) = self.2.parse(context.clone(), input)?;
|
||||||
|
let (input, r4) = self.3.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
Ok((input, (r1, r2, r3, r4)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TToken, T1, T2, T3, T4, T5, TContext, P1, P2, P3, P4, P5>
|
||||||
|
ParserTuple<TToken, (T1, T2, T3, T4, T5), TContext> for (P1, P2, P3, P4, P5)
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
P1: Parser<TToken, T1, TContext>,
|
||||||
|
P2: Parser<TToken, T2, TContext>,
|
||||||
|
P3: Parser<TToken, T3, TContext>,
|
||||||
|
P4: Parser<TToken, T4, TContext>,
|
||||||
|
P5: Parser<TToken, T5, TContext>,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, (T1, T2, T3, T4, T5)> {
|
||||||
|
let (input, r1) = self.0.parse(context.clone(), input)?;
|
||||||
|
let (input, r2) = self.1.parse(context.clone(), input)?;
|
||||||
|
let (input, r3) = self.2.parse(context.clone(), input)?;
|
||||||
|
let (input, r4) = self.3.parse(context.clone(), input)?;
|
||||||
|
let (input, r5) = self.4.parse(context.clone(), input)?;
|
||||||
|
|
||||||
|
Ok((input, (r1, r2, r3, r4, r5)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::combinators::tuple;
|
||||||
|
use crate::parser::parser_test_helper;
|
||||||
|
use crate::text::char_parser;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_test() {
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("ab", ()),
|
||||||
|
&('a', 'b'),
|
||||||
|
tuple((char_parser('a'), char_parser('b'))),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abc", ()),
|
||||||
|
&('a', 'b', 'c'),
|
||||||
|
tuple((char_parser('a'), char_parser('b'), char_parser('c'))),
|
||||||
|
);
|
||||||
|
|
||||||
|
parser_test_helper(
|
||||||
|
ParserContext::new_with_str("abcd", ()),
|
||||||
|
&('a', 'b', 'c', 'd'),
|
||||||
|
tuple((
|
||||||
|
char_parser('a'),
|
||||||
|
char_parser('b'),
|
||||||
|
char_parser('c'),
|
||||||
|
char_parser('d'),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
mod parser;
|
mod parser;
|
||||||
mod text;
|
mod text;
|
||||||
|
mod combinators;
|
||||||
|
|
|
@ -92,7 +92,7 @@ where
|
||||||
fn bind<TResult, F, P>(self, f: F) -> BindParser<Self, F, T>
|
fn bind<TResult, F, P>(self, f: F) -> BindParser<Self, F, T>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
F: Fn(&T) -> P,
|
F: Fn(T) -> P,
|
||||||
P: Parser<TToken, TResult, TContext>,
|
P: Parser<TToken, TResult, TContext>,
|
||||||
{
|
{
|
||||||
BindParser {
|
BindParser {
|
||||||
|
@ -175,6 +175,19 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TToken, T, TContext> Parser<TToken, T, TContext> for Box<dyn Parser<TToken, T, TContext>>
|
||||||
|
where
|
||||||
|
TToken: Debug + Clone,
|
||||||
|
{
|
||||||
|
fn parse<'a>(
|
||||||
|
&self,
|
||||||
|
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
|
input: &'a [TToken],
|
||||||
|
) -> ParserResult<'a, TToken, T> {
|
||||||
|
(**self).parse(context, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn succeed<TToken, T, TContext>(value: T) -> impl Parser<TToken, T, TContext>
|
pub fn succeed<TToken, T, TContext>(value: T) -> impl Parser<TToken, T, TContext>
|
||||||
where
|
where
|
||||||
TToken: Debug + Clone,
|
TToken: Debug + Clone,
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl<TToken, T1, T2, TContext, P, P2, F> Parser<TToken, T2, TContext> for BindPa
|
||||||
where
|
where
|
||||||
TToken: Debug + Clone,
|
TToken: Debug + Clone,
|
||||||
P: Parser<TToken, T1, TContext>,
|
P: Parser<TToken, T1, TContext>,
|
||||||
F: Fn(&T1) -> P2,
|
F: Fn(T1) -> P2,
|
||||||
P2: Parser<TToken, T2, TContext>,
|
P2: Parser<TToken, T2, TContext>,
|
||||||
{
|
{
|
||||||
fn parse<'a>(
|
fn parse<'a>(
|
||||||
|
@ -47,7 +47,7 @@ where
|
||||||
) -> ParserResult<'a, TToken, T2> {
|
) -> ParserResult<'a, TToken, T2> {
|
||||||
let (input, middle) = self.parser.parse(context.clone(), input)?;
|
let (input, middle) = self.parser.parse(context.clone(), input)?;
|
||||||
|
|
||||||
(self.binder)(&middle).parse(context, input)
|
(self.binder)(middle).parse(context, input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user