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 text;
|
||||
mod combinators;
|
||||
|
|
|
@ -92,7 +92,7 @@ where
|
|||
fn bind<TResult, F, P>(self, f: F) -> BindParser<Self, F, T>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(&T) -> P,
|
||||
F: Fn(T) -> P,
|
||||
P: Parser<TToken, TResult, TContext>,
|
||||
{
|
||||
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>
|
||||
where
|
||||
TToken: Debug + Clone,
|
||||
|
|
|
@ -37,7 +37,7 @@ impl<TToken, T1, T2, TContext, P, P2, F> Parser<TToken, T2, TContext> for BindPa
|
|||
where
|
||||
TToken: Debug + Clone,
|
||||
P: Parser<TToken, T1, TContext>,
|
||||
F: Fn(&T1) -> P2,
|
||||
F: Fn(T1) -> P2,
|
||||
P2: Parser<TToken, T2, TContext>,
|
||||
{
|
||||
fn parse<'a>(
|
||||
|
@ -47,7 +47,7 @@ where
|
|||
) -> ParserResult<'a, TToken, T2> {
|
||||
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