refact: lifetime support in trait level.

This commit is contained in:
jackfiled 2024-11-19 19:07:22 +08:00
parent 8a9c58966b
commit a282ad8f24
13 changed files with 621 additions and 480 deletions

32
Cargo.lock generated
View File

@ -2,6 +2,38 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "zero-parser"
version = "0.1.0"
dependencies = [
"anyhow",
"nom",
]

View File

@ -4,3 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = { version = "1" }
[dev-dependencies]
nom = { version = "7" }

View File

@ -10,21 +10,19 @@ 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 crate::combinators::tuple_parser::{ParserTuple, TupleParser};
use crate::parser::{any, Parser};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::rc::Rc;
pub trait ParserExt<TToken, T, TContext>: Parser<TToken, T, TContext>
pub trait ParserExt<'a, TToken, T: 'a, TContext>: Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
fn left<TRight, PRight>(self, right_parser: PRight) -> LeftParser<Self, PRight, TRight>
fn left<TRight: 'a, PRight>(self, right_parser: PRight) -> LeftParser<Self, PRight, TRight>
where
Self: Sized,
PRight: Parser<TToken, TRight, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
LeftParser {
left_parser: self,
@ -33,10 +31,10 @@ where
}
}
fn right<TRight, PRight>(self, right_parser: PRight) -> RightParser<Self, PRight, T>
fn right<TRight: 'a, PRight>(self, right_parser: PRight) -> RightParser<Self, PRight, T>
where
Self: Sized,
PRight: Parser<TToken, TRight, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
RightParser {
left_parser: self,
@ -48,7 +46,7 @@ where
fn alternate<P>(self, second_parser: P) -> AlternateParser<Self, P>
where
Self: Sized,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
AlternateParser {
first: self,
@ -90,13 +88,13 @@ where
}
}
fn many_till<TTerminator, PTerminator>(
fn many_till<TTerminator: 'a, PTerminator>(
self,
terminator: PTerminator,
) -> ManyTillParser<Self, PTerminator, TTerminator>
where
Self: Sized,
PTerminator: Parser<TToken, TTerminator, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
ManyTillParser {
parser: self,
@ -105,13 +103,13 @@ where
}
}
fn many1_till<TTerminator, PTerminator>(
fn many1_till<TTerminator: 'a, PTerminator>(
self,
terminator: PTerminator,
) -> Many1TillParser<Self, PTerminator, TTerminator>
where
Self: Sized,
PTerminator: Parser<TToken, TTerminator, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
Many1TillParser {
parser: self,
@ -121,18 +119,21 @@ where
}
}
impl<TToken, T, TContext, P> ParserExt<TToken, T, TContext> for P
impl<'a, TToken, T: 'a, TContext, P> ParserExt<'a, TToken, T, TContext> for P
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
}
fn alternate_helper<TToken, T, TContext, P1, P2>(first: P1, second: P2) -> AlternateParser<P1, P2>
pub fn alternate_helper<'a, TToken, T: 'a, TContext, P1, P2>(
first: P1,
second: P2,
) -> AlternateParser<P1, P2>
where
TToken: Debug + Clone,
P1: Parser<TToken, T, TContext>,
P2: Parser<TToken, T, TContext>,
P1: Parser<'a, TToken, T, TContext>,
P2: Parser<'a, TToken, T, TContext>,
{
AlternateParser { first, second }
}
@ -143,65 +144,63 @@ macro_rules! alternate {
{
let parser = $first;
$(
let parser = crate::combinators::alternate_helper(parser, $second);
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>
pub fn tuple<'a, TToken, T: 'a, TContext, TList>(list: TList) -> TupleParser<TList>
where
TToken: Debug + Clone,
TList: ParserTuple<TToken, T, TContext>,
TToken: Debug + Clone + 'a,
TList: ParserTuple<'a, TToken, T, TContext>,
{
move |context, input| list.parse(context, input)
TupleParser { parser: list }
}
pub fn take_till<TToken, TTerminator, TContext, PTerminator>(
pub fn take_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>(
termiantor: PTerminator,
) -> impl Parser<TToken, Vec<TToken>, TContext>
) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone,
PTerminator: Parser<TToken, TTerminator, TContext>,
TToken: Debug + Clone + 'a,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
any().many_till(termiantor)
}
pub fn take1_till<TToken, TTerminator, TContext, PTerminator>(
pub fn take1_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>(
terminator: PTerminator,
) -> impl Parser<TToken, Vec<TToken>, TContext>
) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone,
PTerminator: Parser<TToken, TTerminator, TContext>,
TToken: Debug + Clone + 'a,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
any().many1_till(terminator)
}
pub fn quote<TToken, T, TLeft, TRight, TContext, PLeft, P, PRight>(
pub fn quote<'a, TToken, T: 'a, TLeft: 'a, TRight: 'a, TContext, PLeft, P, PRight>(
left: PLeft,
parser: P,
right: PRight,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PLeft: Parser<TToken, TLeft, TContext>,
PRight: Parser<TToken, TRight, TContext>,
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<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
SeparateBy1Parser {
parser,
@ -210,14 +209,14 @@ where
}
}
pub fn separate_by<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn separate_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
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![])),
@ -225,38 +224,38 @@ where
})
}
pub fn end_by1<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
parser.many1_till(separator)
}
pub fn end_by<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
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<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn separate_or_end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
SeparateOrEndBy1Parser {
parser,
@ -265,14 +264,14 @@ where
}
}
pub fn separate_or_end_by<TToken, T, TSeparator, TContext, P, PSeparator>(
pub fn separate_or_end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>(
parser: P,
separator: PSeparator,
) -> impl Parser<TToken, Vec<T>, TContext>
) -> impl Parser<'a, TToken, Vec<T>, TContext>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
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![])),

View File

@ -8,19 +8,20 @@ pub struct AlternateParser<P1, P2> {
pub(crate) second: P2,
}
impl<TToken, T, TContext, P1, P2> Parser<TToken, T, TContext> for AlternateParser<P1, P2>
impl<'a, TToken, T: 'a, TContext, P1, P2> Parser<'a, TToken, T, TContext>
for AlternateParser<P1, P2>
where
TToken: Debug + Clone,
P1: Parser<TToken, T, TContext>,
P2: Parser<TToken, T, TContext>,
P1: Parser<'a, TToken, T, TContext>,
P2: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&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),
Err(_) => self.second.parse(context, input),
r => r,
}
}
@ -64,4 +65,47 @@ mod test {
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', parser);
parser_test_helper(ParserContext::new_with_str("c", ()), &'c', parser);
}
#[test]
fn alternate_function_test() {
fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, char> {
alternate!(char_parser('a'), char_parser('b')).parse(context, input)
}
parser_test_helper(ParserContext::new_with_str("a", ()), &'a', |c, i| {
let parser = alternate!(parser, char_parser('c'));
let parser = alternate!(parser, char_parser('d'));
parser.parse(c, i)
});
}
#[test]
fn alternate_pure_function_test() {
fn parser1(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, &[char]> {
alternate!(char_parser('a').literal(), char_parser('b').literal()).parse(context, input)
}
fn parser2(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, &[char]> {
alternate!(char_parser('c').literal(), char_parser('d').literal()).parse(context, input)
}
parser_test_helper(
ParserContext::new_with_str("a", ()),
&"a".to_owned(),
|c, i| {
alternate!(parser1, parser2)
.map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i)
},
);
}
}

View File

@ -1,4 +1,3 @@
use crate::combinators::ParserExt;
use crate::parser::{Parser, ParserContext, ParserResult};
use std::cell::RefCell;
use std::fmt::Debug;
@ -11,14 +10,14 @@ pub struct LeftParser<PLeft, PRight, TRight> {
pub(crate) phantom_data: PhantomData<TRight>,
}
impl<TToken, T, TContext, TRight, PLeft, PRight> Parser<TToken, T, TContext>
impl<'a, TToken, T: 'a, TContext, TRight: 'a, PLeft, PRight> Parser<'a, TToken, T, TContext>
for LeftParser<PLeft, PRight, TRight>
where
TToken: Debug + Clone,
PLeft: Parser<TToken, T, TContext>,
PRight: Parser<TToken, TRight, TContext>,
PLeft: Parser<'a, TToken, T, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -38,14 +37,14 @@ pub struct RightParser<PLeft, PRight, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, TRight, PLeft, PRight> Parser<TToken, TRight, TContext>
impl<'a, TToken, T: 'a, TContext, TRight: 'a, PLeft, PRight> Parser<'a, TToken, TRight, TContext>
for RightParser<PLeft, PRight, T>
where
TToken: Debug + Clone,
PLeft: Parser<TToken, T, TContext>,
PRight: Parser<TToken, TRight, TContext>,
PLeft: Parser<'a, TToken, T, TContext>,
PRight: Parser<'a, TToken, TRight, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -58,25 +57,21 @@ where
#[cfg(test)]
mod test {
use super::*;
use crate::parser::{parser_test_helper, ParserContext};
use crate::combinators::ParserExt;
use crate::parser::{parser_test_helper, Parser, 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')),
);
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
char_parser('a').left(char_parser('b')).parse(c, i)
});
}
#[test]
fn right_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'b',
char_parser('a').right(char_parser('b')),
)
parser_test_helper(ParserContext::new_with_str("abc", ()), &'b', |c, i| {
char_parser('a').right(char_parser('b')).parse(c, i)
})
}
}

View File

@ -8,12 +8,12 @@ pub struct ManyParser<P> {
pub(crate) parser: P,
}
impl<TToken, T, TContext, P> Parser<TToken, Vec<T>, TContext> for ManyParser<P>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec<T>, TContext> for ManyParser<P>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -34,12 +34,12 @@ pub struct Many1Parser<P> {
pub(crate) parser: P,
}
impl<TToken, T, TContext, P> Parser<TToken, Vec<T>, TContext> for Many1Parser<P>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec<T>, TContext> for Many1Parser<P>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -61,12 +61,12 @@ pub struct SkipParser<P, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, (), TContext> for SkipParser<P, T>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for SkipParser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -86,12 +86,12 @@ pub struct Skip1Parser<P, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, (), TContext> for Skip1Parser<P, T>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for Skip1Parser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -112,14 +112,14 @@ pub struct ManyTillParser<P, PTerminator, TTerminator> {
pub(crate) phantom_data: PhantomData<TTerminator>,
}
impl<TToken, T, TTerminator, TContext, P, PTerminator> Parser<TToken, Vec<T>, TContext>
for ManyTillParser<P, PTerminator, TTerminator>
impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator>
Parser<'a, TToken, Vec<T>, TContext> for ManyTillParser<P, PTerminator, TTerminator>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PTerminator: Parser<TToken, TTerminator, TContext>,
P: Parser<'a, TToken, T, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -150,14 +150,14 @@ pub struct Many1TillParser<P, PTerminator, TTerminator> {
pub(crate) phantom_data: PhantomData<TTerminator>,
}
impl<TToken, T, TTerminator, TContext, P, PTerminator> Parser<TToken, Vec<T>, TContext>
for Many1TillParser<P, PTerminator, TTerminator>
impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator>
Parser<'a, TToken, Vec<T>, TContext> for Many1TillParser<P, PTerminator, TTerminator>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PTerminator: Parser<TToken, TTerminator, TContext>,
P: Parser<'a, TToken, T, TContext>,
PTerminator: Parser<'a, TToken, TTerminator, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -174,7 +174,10 @@ where
result.push(r);
input = i;
} else {
return Ok((input, result));
return Err((
input,
FailedParserResult::new("End with other elements.".to_owned()),
));
}
}
}
@ -192,26 +195,22 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many(),
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many(),
|c, i| char_parser('a').many().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("bbaa", ()),
&vec![],
char_parser('a').many(),
);
parser_test_helper(ParserContext::new_with_str("bbaa", ()), &vec![], |c, i| {
char_parser('a').many().parse(c, i)
});
parser_test_helper(
ParserContext::new_with_str("", ()),
&vec![],
char_parser('a').many(),
);
parser_test_helper(ParserContext::new_with_str("", ()), &vec![], |c, i| {
char_parser('a').many().parse(c, i)
});
}
#[test]
@ -219,53 +218,44 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaa", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many1(),
|c, i| char_parser('a').many1().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("aaabbaa", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many1(),
|c, i| char_parser('a').many1().parse(c, i),
);
failed_parser_test_helper(
ParserContext::new_with_str("bbaa", ()),
char_parser('a').many1(),
);
failed_parser_test_helper(ParserContext::new_with_str("bbaa", ()), |c, i| {
char_parser('a').many1().parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("", ()),
char_parser('a').many1(),
);
failed_parser_test_helper(ParserContext::new_with_str("", ()), |c, i| {
char_parser('a').many1().parse(c, i)
});
}
#[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("aaab", ()), &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i)
});
parser_test_helper(
ParserContext::new_with_str("b", ()),
&'b',
char_parser('a').skip().right(char_parser('b')),
);
parser_test_helper(ParserContext::new_with_str("b", ()), &'b', |c, i| {
char_parser('a').skip().right(char_parser('b')).parse(c, i)
});
}
#[test]
fn skip1_test() {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&'b',
char_parser('a').skip1().right(char_parser('b')),
);
parser_test_helper(ParserContext::new_with_str("aaab", ()), &'b', |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("b", ()),
char_parser('a').skip1().right(char_parser('b')),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
char_parser('a').skip1().right(char_parser('b')).parse(c, i)
});
}
#[test]
@ -273,19 +263,16 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many_till(char_parser('b')),
|c, i| char_parser('a').many_till(char_parser('b')).parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("b", ()),
&vec![],
char_parser('a').many_till(char_parser('b')),
);
parser_test_helper(ParserContext::new_with_str("b", ()), &vec![], |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("aaacb", ()),
char_parser('a').many_till(char_parser('b')),
);
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| {
char_parser('a').many_till(char_parser('b')).parse(c, i)
});
}
#[test]
@ -293,18 +280,16 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&vec!['a', 'a', 'a'],
char_parser('a').many_till(char_parser('b')),
|c, i| char_parser('a').many1_till(char_parser('b')).parse(c, i),
);
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("b", ()), |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("aaacb", ()),
char_parser('a').many_till(char_parser('b')),
);
failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| {
char_parser('a').many1_till(char_parser('b')).parse(c, i)
});
}
#[test]
@ -312,13 +297,13 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&(vec!['a', 'a', 'a'], 'b'),
tuple((take_till(char_parser('b')), char_parser('b'))),
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("b", ()),
&(vec![], 'b'),
tuple((take_till(char_parser('b')), char_parser('b'))),
|c, i| tuple((take_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
}
@ -327,12 +312,11 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("aaab", ()),
&(vec!['a', 'a', 'a'], 'b'),
tuple((take1_till(char_parser('b')), char_parser('b'))),
|c, i| tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i),
);
failed_parser_test_helper(
ParserContext::new_with_str("b", ()),
tuple((take1_till(char_parser('b')), char_parser('b'))),
);
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
tuple((take1_till(char_parser('b')), char_parser('b'))).parse(c, i)
});
}
}

View File

@ -10,14 +10,14 @@ pub struct SeparateBy1Parser<P, PSeparator, TSeparator> {
pub(crate) phantom_data: PhantomData<TSeparator>,
}
impl<TToken, T, TSeparator, TContext, P, PSeparator> Parser<TToken, Vec<T>, TContext>
for SeparateBy1Parser<P, PSeparator, TSeparator>
impl<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>
Parser<'a, TToken, Vec<T>, TContext> for SeparateBy1Parser<P, PSeparator, TSeparator>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -45,14 +45,14 @@ pub struct SeparateOrEndBy1Parser<P, PSeparator, TSeparator> {
pub(crate) phantom_data: PhantomData<TSeparator>,
}
impl<TToken, T, TSeparator, TContext, P, PSeparator> Parser<TToken, Vec<T>, TContext>
for SeparateOrEndBy1Parser<P, PSeparator, TSeparator>
impl<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>
Parser<'a, TToken, Vec<T>, TContext> for SeparateOrEndBy1Parser<P, PSeparator, TSeparator>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
PSeparator: Parser<TToken, TSeparator, TContext>,
P: Parser<'a, TToken, T, TContext>,
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -114,17 +114,15 @@ mod 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(',')),
|c, i| separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("a", ()), &vec!['a'], |c, i| {
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
});
parser_test_helper(
ParserContext::new_with_str("bbc", ()),
&vec!['b'],
separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|c, i| separate_by1(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
}
@ -133,22 +131,18 @@ mod 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(',')),
|c, i| separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("", ()), &vec![], |c, i| {
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i)
});
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a'],
separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')),
|c, i| separate_by(satisfy(|c: &char| c.is_ascii()), char_parser(',')).parse(c, i),
);
}
@ -157,21 +151,17 @@ mod 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')),
|c, i| end_by1(char_parser('a'), char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("ab", ()), &vec!['a'], |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("b", ()), |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("cd", ()), |c, i| {
end_by1(char_parser('a'), char_parser('b')).parse(c, i)
});
}
#[test]
@ -179,22 +169,17 @@ mod 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')),
|c, i| end_by(char_parser('a'), char_parser('b')).parse(c, i),
);
parser_test_helper(ParserContext::new_with_str("ab", ()), &vec!['a'], |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("b", ()), &vec![], |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("cd", ()), |c, i| {
end_by(char_parser('a'), char_parser('b')).parse(c, i)
});
}
#[test]
@ -202,27 +187,28 @@ mod 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(',')),
|c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(','))
.parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1,", ()), &vec!['1'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
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(',')),
|c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(','))
.parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
separate_or_end_by1(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
}
#[test]
@ -230,27 +216,25 @@ mod 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(',')),
|c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1,", ()), &vec!['1'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
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(',')),
|c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
},
);
parser_test_helper(ParserContext::new_with_str("1", ()), &vec!['1'], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("abc", ()), &vec![], |c, i| {
separate_or_end_by(satisfy(|c: &char| c.is_numeric()), char_parser(',')).parse(c, i)
});
}
}

View File

@ -3,24 +3,43 @@ use std::cell::RefCell;
use std::fmt::Debug;
use std::rc::Rc;
pub trait ParserTuple<TToken, T, TContext>
pub trait ParserTuple<'a, TToken, T: 'a, TContext>
where
TToken: Debug + Clone,
{
fn parse<'a>(
fn parse(
&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)
pub struct TupleParser<P> {
pub(crate) parser: P,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, T, TContext> for TupleParser<P>
where
TToken: Debug + Clone,
P1: Parser<TToken, T1, TContext>,
P2: Parser<TToken, T2, TContext>,
P: ParserTuple<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
self.parser.parse(context, input)
}
}
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P1, P2> ParserTuple<'a, TToken, (T1, T2), TContext>
for (P1, P2)
where
TToken: Debug + Clone,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -32,15 +51,15 @@ where
}
}
impl<TToken, T1, T2, T3, TContext, P1, P2, P3> ParserTuple<TToken, (T1, T2, T3), TContext>
for (P1, P2, P3)
impl<'a, TToken, T1: 'a, T2: 'a, T3: 'a, TContext, P1, P2, P3>
ParserTuple<'a, 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>,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -53,16 +72,16 @@ where
}
}
impl<TToken, T1, T2, T3, T4, TContext, P1, P2, P3, P4>
ParserTuple<TToken, (T1, T2, T3, T4), TContext> for (P1, P2, P3, P4)
impl<'a, TToken, T1: 'a, T2: 'a, T3: 'a, T4: 'a, TContext, P1, P2, P3, P4>
ParserTuple<'a, 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>,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
P4: Parser<'a, TToken, T4, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -76,17 +95,17 @@ where
}
}
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)
impl<'a, TToken, T1: 'a, T2: 'a, T3: 'a, T4: 'a, T5: 'a, TContext, P1, P2, P3, P4, P5>
ParserTuple<'a, 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>,
P1: Parser<'a, TToken, T1, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
P3: Parser<'a, TToken, T3, TContext>,
P4: Parser<'a, TToken, T4, TContext>,
P5: Parser<'a, TToken, T5, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -113,24 +132,27 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("ab", ()),
&('a', 'b'),
tuple((char_parser('a'), char_parser('b'))),
|c, i| tuple((char_parser('a'), char_parser('b'))).parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&('a', 'b', 'c'),
tuple((char_parser('a'), char_parser('b'), char_parser('c'))),
|c, i| tuple((char_parser('a'), char_parser('b'), char_parser('c'))).parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("abcd", ()),
&('a', 'b', 'c', 'd'),
|c, i| {
tuple((
char_parser('a'),
char_parser('b'),
char_parser('c'),
char_parser('d'),
)),
))
.parse(c, i)
},
);
}
}

View File

@ -1,3 +1,3 @@
mod parser;
mod text;
mod combinators;
pub mod combinators;
pub mod parser;
pub mod text;

View File

@ -2,8 +2,8 @@ mod modified_parsers;
mod primitive_parsers;
use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalParser, LookAheadParser, MapParser, NextParser,
ReverseParser,
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
NextParser, ReverseParser,
};
use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
@ -23,6 +23,10 @@ impl FailedParserResult {
pub fn new(message: String) -> Self {
Self { message }
}
pub fn message(&self) -> &str {
self.message.as_str()
}
}
impl Display for FailedParserResult {
@ -67,11 +71,12 @@ impl<TContext> ParserContext<char, TContext> {
}
}
pub trait Parser<TToken, T, TContext>
pub trait Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
T: 'a,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -80,7 +85,7 @@ where
fn map<TResult, F>(self, f: F) -> MapParser<Self, F, T>
where
Self: Sized,
F: Fn(&T) -> TResult,
F: Fn(T) -> TResult,
{
MapParser {
parser: self,
@ -89,11 +94,11 @@ where
}
}
fn bind<TResult, F, P>(self, f: F) -> BindParser<Self, F, T>
fn bind<TResult: 'a, F, P>(self, f: F) -> BindParser<Self, F, T>
where
Self: Sized,
F: Fn(T) -> P,
P: Parser<TToken, TResult, TContext>,
P: Parser<'a, TToken, TResult, TContext>,
{
BindParser {
parser: self,
@ -125,6 +130,16 @@ where
}
}
fn literal_count(self) -> LitervalCountParser<Self, T>
where
Self: Sized,
{
LitervalCountParser {
parser: self,
phantom_data: PhantomData,
}
}
fn literal(self) -> LitervalParser<Self, T>
where
Self: Sized,
@ -158,15 +173,15 @@ where
}
}
impl<TToken, T, TContext, F> Parser<TToken, T, TContext> for F
impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F
where
TToken: Debug + Clone,
F: for<'f> Fn(
TToken: Debug + Clone + 'a,
F: Fn(
Rc<RefCell<ParserContext<TToken, TContext>>>,
&'f [TToken],
) -> ParserResult<'f, TToken, T>,
&'a [TToken],
) -> ParserResult<'a, TToken, T>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -175,11 +190,12 @@ where
}
}
impl<TToken, T, TContext> Parser<TToken, T, TContext> for Box<dyn Parser<TToken, T, TContext>>
impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext>
for Box<dyn Parser<'a, TToken, T, TContext>>
where
TToken: Debug + Clone,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -188,15 +204,15 @@ where
}
}
pub fn succeed<TToken, T, TContext>(value: T) -> impl Parser<TToken, T, TContext>
pub fn succeed<'a, TToken, T, TContext>(value: T) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
T: Debug + Clone,
T: Debug + Clone + 'a,
{
SucceedParser { value }
}
pub fn fail<TToken, T, TContext>() -> impl Parser<TToken, T, TContext>
pub fn fail<'a, TToken, T: 'a, TContext>() -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
@ -205,7 +221,9 @@ where
}
}
pub fn fail_with_message<TToken, T, TContext>(message: &str) -> impl Parser<TToken, T, TContext>
pub fn fail_with_message<'a, TToken, T: 'a, TContext>(
message: &str,
) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
{
@ -215,29 +233,29 @@ where
}
}
pub fn satisfy<TToken, TContext, TP>(predicate: TP) -> impl Parser<TToken, TToken, TContext>
pub fn satisfy<'a, TToken, TContext, TP>(predicate: TP) -> impl Parser<'a, TToken, TToken, TContext>
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
TP: Fn(&TToken) -> bool,
{
SatisfyParser { predicate }
}
pub fn any<TToken, TContext>() -> impl Parser<TToken, TToken, TContext>
pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext>
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
{
AnyParser {}
}
pub fn take<TToken, TContext>(count: usize) -> impl Parser<TToken, Vec<TToken>, TContext>
pub fn take<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, Vec<TToken>, TContext>
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
{
TakeParser { count }
}
pub fn skip<TToken, TContext>(count: usize) -> impl Parser<TToken, (), TContext>
pub fn skip<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, (), TContext>
where
TToken: Debug + Clone,
{
@ -251,7 +269,7 @@ pub fn parser_test_helper<T, P>(
test_parser: P,
) where
T: PartialEq + Debug,
P: Parser<char, T, ()>,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let borrowed_context = context.borrow();
let input = borrowed_context.input_slice();
@ -266,7 +284,7 @@ pub fn failed_parser_test_helper<T, P>(
test_parser: P,
) where
T: Debug,
P: Parser<char, T, ()>,
P: for<'a> Fn(Rc<RefCell<ParserContext<char, ()>>>, &'a [char]) -> ParserResult<'a, char, T>,
{
let borrowed_context = context.borrow();
let input = borrowed_context.input_slice();

View File

@ -10,20 +10,21 @@ pub struct MapParser<P, F, T1> {
pub(crate) phantom: PhantomData<T1>,
}
impl<TToken, T1, T2, TContext, P, F> Parser<TToken, T2, TContext> for MapParser<P, F, T1>
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, F> Parser<'a, TToken, T2, TContext>
for MapParser<P, F, T1>
where
TToken: Debug + Clone,
P: Parser<TToken, T1, TContext>,
F: Fn(&T1) -> T2,
P: Parser<'a, TToken, T1, TContext>,
F: Fn(T1) -> T2,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T2> {
self.parser
.parse(context, input)
.map(|(remainder, result)| (remainder, (self.mapper)(&result)))
.map(|(remainder, result)| (remainder, (self.mapper)(result)))
}
}
@ -33,14 +34,15 @@ pub struct BindParser<P, F, T1> {
pub(crate) phantom_data: PhantomData<T1>,
}
impl<TToken, T1, T2, TContext, P, P2, F> Parser<TToken, T2, TContext> for BindParser<P, F, T1>
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, P2, F> Parser<'a, TToken, T2, TContext>
for BindParser<P, F, T1>
where
TToken: Debug + Clone,
P: Parser<TToken, T1, TContext>,
P: Parser<'a, TToken, T1, TContext>,
F: Fn(T1) -> P2,
P2: Parser<TToken, T2, TContext>,
P2: Parser<'a, TToken, T2, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -57,13 +59,14 @@ pub struct ConvertParser<P, T1, T2> {
pub(crate) phantom_data2: PhantomData<T2>,
}
impl<TToken, T1, T2, TContext, P> Parser<TToken, T2, TContext> for ConvertParser<P, T1, T2>
impl<'a, TToken, T1: 'a, T2: 'a, TContext, P> Parser<'a, TToken, T2, TContext>
for ConvertParser<P, T1, T2>
where
TToken: Debug + Clone,
T2: From<T1>,
P: Parser<TToken, T1, TContext>,
P: Parser<'a, TToken, T1, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -80,13 +83,14 @@ pub struct NextParser<P, H, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TResult, TContext, P, H> Parser<TToken, TResult, TContext> for NextParser<P, H, T>
impl<'a, TToken, T: 'a, TResult: 'a, TContext, P, H> Parser<'a, TToken, TResult, TContext>
for NextParser<P, H, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
H: for<'f> Fn(ParserResult<'f, TToken, T>) -> ParserResult<'f, TToken, TResult>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -102,16 +106,17 @@ pub struct LitervalParser<P, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, Vec<TToken>, TContext> for LitervalParser<P, T>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, &'a [TToken], TContext>
for LitervalParser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
TToken: Debug + Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, Vec<TToken>> {
) -> ParserResult<'a, TToken, &'a [TToken]> {
let origin_input = input;
let (input, _) = self.parser.parse(context, input)?;
@ -119,7 +124,7 @@ where
return Err((
input,
FailedParserResult::new(
"Empty input, the 'literal' parser cann't get length of elememtn.".to_owned(),
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
));
}
@ -127,13 +132,42 @@ where
let length = (&origin_input[1..]).as_ptr() as usize - origin_input.as_ptr() as usize;
let index = (input.as_ptr() as usize - origin_input.as_ptr() as usize) / length;
Ok((
Ok((input, &origin_input[..index]))
}
}
pub struct LitervalCountParser<P, T> {
pub(crate) parser: P,
pub(crate) phantom_data: PhantomData<T>,
}
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, usize, TContext>
for LitervalCountParser<P, T>
where
TToken: Debug + Clone,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, usize> {
let origin_input = input;
let (input, _) = self.parser.parse(context, input)?;
if origin_input.is_empty() {
return Err((
input,
(&origin_input[..index])
.into_iter()
.map(|x| x.clone())
.collect(),
))
FailedParserResult::new(
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
));
}
let length = (&origin_input[1..]).as_ptr() as usize - origin_input.as_ptr() as usize;
let index = (input.as_ptr() as usize - origin_input.as_ptr() as usize) / length;
Ok((input, index))
}
}
@ -142,12 +176,12 @@ pub struct LookAheadParser<P, T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext, P> Parser<TToken, T, TContext> for LookAheadParser<P, T>
impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, T, TContext> for LookAheadParser<P, T>
where
TToken: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -165,14 +199,14 @@ pub struct ReverseParser<P, T, TResult> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TResult, TContext, P> Parser<TToken, TResult, TContext>
impl<'a, TToken, T: 'a, TResult: 'a, TContext, P> Parser<'a, TToken, TResult, TContext>
for ReverseParser<P, T, TResult>
where
TToken: Debug + Clone,
TResult: Debug + Clone,
P: Parser<TToken, T, TContext>,
P: Parser<'a, TToken, T, TContext>,
{
fn parse<'a>(
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -200,25 +234,22 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("hello, world!", ()),
&(),
take(5).map(|_| ()),
|c, i| take(5).map(|_| ()).parse(c, i),
)
}
#[test]
fn bind_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'b',
char_parser('a').bind(|_| char_parser('b')),
);
parser_test_helper(ParserContext::new_with_str("abc", ()), &'b', |c, i| {
char_parser('a').bind(|_| char_parser('b')).parse(c, i)
});
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'c',
parser_test_helper(ParserContext::new_with_str("abc", ()), &'c', |c, i| {
char_parser('a')
.bind(|_| char_parser('b'))
.bind(|_| char_parser('c')),
);
.bind(|_| char_parser('c'))
.parse(c, i)
});
}
struct Number(i32);
@ -246,49 +277,52 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("9", ()),
&"9".to_owned(),
single_numer_parser.convert(),
|c, i| single_numer_parser.convert().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("1", ()),
&"1".to_owned(),
single_numer_parser.convert(),
|c, i| single_numer_parser.convert().parse(c, i),
);
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
single_numer_parser.convert::<String>(),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
single_numer_parser.convert::<String>().parse(c, i)
});
}
#[test]
fn next_test() {
let parser = || {
satisfy(|c: &char| c.is_numeric()).next(|r| match r {
fn parser(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, Number> {
satisfy(|c: &char| c.is_numeric())
.next(|r| match r {
Ok((input, result)) => match result.to_digit(10) {
None => Err((input, FailedParserResult::new("What?".to_string()))),
Some(r) => Ok((input, Number(r as i32))),
},
Err(r) => Err(r),
})
};
.parse(context, input)
}
parser_test_helper(
ParserContext::new_with_str("9", ()),
&"9".to_owned(),
parser().convert(),
|c, i| parser.convert().parse(c, i),
);
parser_test_helper(
ParserContext::new_with_str("1", ()),
&"1".to_owned(),
parser().convert(),
|c, i| parser.convert().parse(c, i),
);
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
parser().convert::<String>(),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
parser.convert::<String>().parse(c, i)
});
}
#[test]
@ -296,45 +330,58 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a'],
char_parser('a').literal(),
|c, i| {
char_parser('a')
.literal()
.map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i)
},
);
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b'],
char_parser('a').bind(|_| char_parser('b')).literal(),
|c, i| {
char_parser('a')
.bind(|_| char_parser('b'))
.literal()
.map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i)
},
);
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&vec!['a', 'b', 'c'],
|c, i| {
char_parser('a')
.bind(|_| char_parser('b'))
.bind(|_| char_parser('c'))
.literal(),
.literal()
.map(|x| x.iter().map(|x| x.clone()).collect())
.parse(c, i)
},
);
}
#[test]
fn look_ahead_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'a',
char_parser('a').look_ahead().bind(|_| char_parser('a')),
);
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
char_parser('a')
.look_ahead()
.bind(|_| char_parser('a'))
.parse(c, i)
});
}
#[test]
fn reverse_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&(),
char_parser('b').reverse(()),
);
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| {
char_parser('b').reverse(()).parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
char_parser('a').reverse(()),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
char_parser('a').reverse(()).parse(c, i)
});
}
}

View File

@ -8,12 +8,12 @@ pub struct SucceedParser<T> {
pub(crate) value: T,
}
impl<TToken, T, TContext> Parser<TToken, T, TContext> for SucceedParser<T>
impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for SucceedParser<T>
where
TToken: Debug + Clone,
T: Debug + Clone,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -26,11 +26,11 @@ pub struct FailParser<T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext> Parser<TToken, T, TContext> for FailParser<T>
impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for FailParser<T>
where
TToken: Debug + Clone,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -47,11 +47,11 @@ pub struct FailWithMessageParser<T> {
pub(crate) phantom_data: PhantomData<T>,
}
impl<TToken, T, TContext> Parser<TToken, T, TContext> for FailWithMessageParser<T>
impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for FailWithMessageParser<T>
where
TToken: Debug + Clone,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -64,12 +64,12 @@ pub struct SatisfyParser<F> {
pub(crate) predicate: F,
}
impl<TToken, TContext, F> Parser<TToken, TToken, TContext> for SatisfyParser<F>
impl<'a, TToken, TContext, F> Parser<'a, TToken, TToken, TContext> for SatisfyParser<F>
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
F: Fn(&TToken) -> bool,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -91,11 +91,11 @@ where
pub struct AnyParser {}
impl<TToken, TContext> Parser<TToken, TToken, TContext> for AnyParser
impl<'a, TToken, TContext> Parser<'a, TToken, TToken, TContext> for AnyParser
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -112,11 +112,11 @@ pub struct TakeParser {
pub(crate) count: usize,
}
impl<TToken, TContext> Parser<TToken, Vec<TToken>, TContext> for TakeParser
impl<'a, TToken, TContext> Parser<'a, TToken, Vec<TToken>, TContext> for TakeParser
where
TToken: Debug + Clone,
TToken: Debug + Clone + 'a,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -142,11 +142,11 @@ pub struct SkipParser {
pub(crate) count: usize,
}
impl<TToken, TContext> Parser<TToken, (), TContext> for SkipParser
impl<'a, TToken, TContext> Parser<'a, TToken, (), TContext> for SkipParser
where
TToken: Debug + Clone,
{
fn parse<'a>(
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
@ -175,41 +175,45 @@ mod test {
#[test]
fn succeed_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), succeed(()));
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| {
succeed(()).parse(c, i)
});
}
#[test]
fn fail_test() {
failed_parser_test_helper::<(), _>(ParserContext::new_with_str("abc", ()), fail());
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
fail::<char, (), ()>().parse(c, i)
});
}
#[test]
fn fail_with_message_test() {
failed_parser_test_helper::<(), _>(
ParserContext::new_with_str("abc", ()),
fail_with_message("Failed!"),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
fail_with_message::<char, (), ()>("Failed!").parse(c, i)
});
}
#[test]
fn satisfy_test() {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'a',
satisfy(|x| x == &'a'),
);
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
satisfy(|x| x == &'a').parse(c, i)
});
failed_parser_test_helper(
ParserContext::new_with_str("abc", ()),
satisfy(|x| x == &'b'),
);
failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| {
satisfy(|x| x == &'b').parse(c, i)
});
}
#[test]
fn any_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', any());
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
any().parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("cde", ()), &'c', any());
parser_test_helper(ParserContext::new_with_str("cde", ()), &'c', |c, i| {
any().parse(c, i)
});
}
#[test]
@ -217,10 +221,12 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("hello, world!", ()),
&("hello".chars().collect()),
take(5),
|c, i| take(5).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), take(5));
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), |c, i| {
take(5).parse(c, i)
});
}
#[test]
@ -228,9 +234,11 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("hello, world!", ()),
&(),
skip(5),
|c, i| skip(5).parse(c, i),
);
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), skip(5));
failed_parser_test_helper(ParserContext::new_with_str("abcd", ()), |c, i| {
skip(5).parse(c, i)
});
}
}

View File

@ -1,14 +1,13 @@
use crate::parser::{satisfy, take, FailedParserResult, Parser};
pub fn char_parser<TContext>(c: char) -> impl Parser<char, char, TContext> {
pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> {
satisfy(move |x| *x == c)
}
pub fn string_parser<TContext>(str: String) -> impl Parser<char, String, TContext> {
take::<char, TContext>(str.len()).next(move |result| {
pub fn string_parser<'a, TContext>(str: &'static str) -> impl Parser<'a, char, String, TContext> {
take::<char, TContext>(str.chars().count()).next(move |result| {
result.and_then(|(input, chars)| {
let chars: String = chars.into_iter().collect();
let chars: String = chars.iter().collect();
if chars == str {
Ok((input, chars))
} else {
@ -21,6 +20,11 @@ pub fn string_parser<TContext>(str: String) -> impl Parser<char, String, TContex
})
}
pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TContext> {
let str: Vec<char> = str.chars().collect();
satisfy(move |c: &char| str.contains(c))
}
#[cfg(test)]
mod test {
use super::*;
@ -35,10 +39,12 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("abc", ()),
&'a',
char_parser('a'),
|context, input| char_parser('a').parse(context, input),
);
failed_parser_test_helper(ParserContext::new_with_str("bc", ()), char_parser('a'));
failed_parser_test_helper(ParserContext::new_with_str("bc", ()), |context, input| {
char_parser('a').parse(context, input)
});
}
#[test]
@ -46,17 +52,15 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("Hello, world!", ()),
&"Hello".to_owned(),
string_parser("Hello".to_owned()),
|context, input| string_parser("Hello").parse(context, input),
);
fn test_parser(
context: Rc<RefCell<ParserContext<char, ()>>>,
input: &[char],
) -> ParserResult<char, String> {
let (input, first) =
string_parser("hello, ".to_string()).parse(context.clone(), input)?;
let (input, second) =
string_parser("world!".to_owned()).parse(context.clone(), input)?;
let (input, first) = string_parser("hello, ").parse(context.clone(), input)?;
let (input, second) = string_parser("world!").parse(context.clone(), input)?;
Ok((input, first + second.as_str()))
}
@ -69,7 +73,7 @@ mod test {
parser_test_helper(
ParserContext::new_with_str("hello, world!", ()),
&(),
test_parser.map(|_| ()),
|context, input| test_parser.map(|_| ()).parse(context, input),
)
}
}