diff --git a/Cargo.lock b/Cargo.lock index 28954a6..634c401 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", +] diff --git a/Cargo.toml b/Cargo.toml index 2c6120c..b6833b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +anyhow = { version = "1" } + +[dev-dependencies] +nom = { version = "7" } \ No newline at end of file diff --git a/src/combinators.rs b/src/combinators.rs index e2b5a9a..079ad9e 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -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: Parser +pub trait ParserExt<'a, TToken, T: 'a, TContext>: Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, { - fn left(self, right_parser: PRight) -> LeftParser + fn left(self, right_parser: PRight) -> LeftParser where Self: Sized, - PRight: Parser, + PRight: Parser<'a, TToken, TRight, TContext>, { LeftParser { left_parser: self, @@ -33,10 +31,10 @@ where } } - fn right(self, right_parser: PRight) -> RightParser + fn right(self, right_parser: PRight) -> RightParser where Self: Sized, - PRight: Parser, + PRight: Parser<'a, TToken, TRight, TContext>, { RightParser { left_parser: self, @@ -48,7 +46,7 @@ where fn alternate

(self, second_parser: P) -> AlternateParser where Self: Sized, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { AlternateParser { first: self, @@ -90,13 +88,13 @@ where } } - fn many_till( + fn many_till( self, terminator: PTerminator, ) -> ManyTillParser where Self: Sized, - PTerminator: Parser, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { ManyTillParser { parser: self, @@ -105,13 +103,13 @@ where } } - fn many1_till( + fn many1_till( self, terminator: PTerminator, ) -> Many1TillParser where Self: Sized, - PTerminator: Parser, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { Many1TillParser { parser: self, @@ -121,18 +119,21 @@ where } } -impl ParserExt for P +impl<'a, TToken, T: 'a, TContext, P> ParserExt<'a, TToken, T, TContext> for P where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { } -fn alternate_helper(first: P1, second: P2) -> AlternateParser +pub fn alternate_helper<'a, TToken, T: 'a, TContext, P1, P2>( + first: P1, + second: P2, +) -> AlternateParser where TToken: Debug + Clone, - P1: Parser, - P2: Parser, + 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( - list: TList, -) -> impl Fn(Rc>>, &[TToken]) -> ParserResult +pub fn tuple<'a, TToken, T: 'a, TContext, TList>(list: TList) -> TupleParser where - TToken: Debug + Clone, - TList: ParserTuple, + TToken: Debug + Clone + 'a, + TList: ParserTuple<'a, TToken, T, TContext>, { - move |context, input| list.parse(context, input) + TupleParser { parser: list } } -pub fn take_till( +pub fn take_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>( termiantor: PTerminator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - PTerminator: Parser, + TToken: Debug + Clone + 'a, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { any().many_till(termiantor) } -pub fn take1_till( +pub fn take1_till<'a, TToken, TTerminator: 'a, TContext, PTerminator>( terminator: PTerminator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - PTerminator: Parser, + TToken: Debug + Clone + 'a, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { any().many1_till(terminator) } -pub fn quote( +pub fn quote<'a, TToken, T: 'a, TLeft: 'a, TRight: 'a, TContext, PLeft, P, PRight>( left: PLeft, parser: P, right: PRight, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PLeft: Parser, - PRight: Parser, + 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( +pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + 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( +pub fn separate_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + 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( +pub fn end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + TToken: Debug + Clone + 'a, + P: Parser<'a, TToken, T, TContext>, + PSeparator: Parser<'a, TToken, TSeparator, TContext>, { parser.many1_till(separator) } -pub fn end_by( +pub fn end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + 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( +pub fn separate_or_end_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + 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( +pub fn separate_or_end_by<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( parser: P, separator: PSeparator, -) -> impl Parser, TContext> +) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + 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![])), diff --git a/src/combinators/alternate_parser.rs b/src/combinators/alternate_parser.rs index eb8ccf7..305fe7f 100644 --- a/src/combinators/alternate_parser.rs +++ b/src/combinators/alternate_parser.rs @@ -8,19 +8,20 @@ pub struct AlternateParser { pub(crate) second: P2, } -impl Parser for AlternateParser +impl<'a, TToken, T: 'a, TContext, P1, P2> Parser<'a, TToken, T, TContext> + for AlternateParser where TToken: Debug + Clone, - P1: Parser, - P2: Parser, + P1: Parser<'a, TToken, T, TContext>, + P2: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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>>, + input: &[char], + ) -> ParserResult { + 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>>, + input: &[char], + ) -> ParserResult { + alternate!(char_parser('a').literal(), char_parser('b').literal()).parse(context, input) + } + + fn parser2( + context: Rc>>, + input: &[char], + ) -> ParserResult { + 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) + }, + ); + } } diff --git a/src/combinators/left_right_parsers.rs b/src/combinators/left_right_parsers.rs index a553cad..45e0f29 100644 --- a/src/combinators/left_right_parsers.rs +++ b/src/combinators/left_right_parsers.rs @@ -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 { pub(crate) phantom_data: PhantomData, } -impl Parser +impl<'a, TToken, T: 'a, TContext, TRight: 'a, PLeft, PRight> Parser<'a, TToken, T, TContext> for LeftParser where TToken: Debug + Clone, - PLeft: Parser, - PRight: Parser, + PLeft: Parser<'a, TToken, T, TContext>, + PRight: Parser<'a, TToken, TRight, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -38,14 +37,14 @@ pub struct RightParser { pub(crate) phantom_data: PhantomData, } -impl Parser +impl<'a, TToken, T: 'a, TContext, TRight: 'a, PLeft, PRight> Parser<'a, TToken, TRight, TContext> for RightParser where TToken: Debug + Clone, - PLeft: Parser, - PRight: Parser, + PLeft: Parser<'a, TToken, T, TContext>, + PRight: Parser<'a, TToken, TRight, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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) + }) } } diff --git a/src/combinators/many_parsers.rs b/src/combinators/many_parsers.rs index 6483af1..d100e68 100644 --- a/src/combinators/many_parsers.rs +++ b/src/combinators/many_parsers.rs @@ -8,12 +8,12 @@ pub struct ManyParser

{ pub(crate) parser: P, } -impl Parser, TContext> for ManyParser

+impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec, TContext> for ManyParser

where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -34,12 +34,12 @@ pub struct Many1Parser

{ pub(crate) parser: P, } -impl Parser, TContext> for Many1Parser

+impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Vec, TContext> for Many1Parser

where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -61,12 +61,12 @@ pub struct SkipParser { pub(crate) phantom_data: PhantomData, } -impl Parser for SkipParser +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for SkipParser where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -86,12 +86,12 @@ pub struct Skip1Parser { pub(crate) phantom_data: PhantomData, } -impl Parser for Skip1Parser +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, (), TContext> for Skip1Parser where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -112,14 +112,14 @@ pub struct ManyTillParser { pub(crate) phantom_data: PhantomData, } -impl Parser, TContext> - for ManyTillParser +impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator> + Parser<'a, TToken, Vec, TContext> for ManyTillParser where TToken: Debug + Clone, - P: Parser, - PTerminator: Parser, + P: Parser<'a, TToken, T, TContext>, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -150,14 +150,14 @@ pub struct Many1TillParser { pub(crate) phantom_data: PhantomData, } -impl Parser, TContext> - for Many1TillParser +impl<'a, TToken, T: 'a, TTerminator: 'a, TContext, P, PTerminator> + Parser<'a, TToken, Vec, TContext> for Many1TillParser where TToken: Debug + Clone, - P: Parser, - PTerminator: Parser, + P: Parser<'a, TToken, T, TContext>, + PTerminator: Parser<'a, TToken, TTerminator, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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) + }); } } diff --git a/src/combinators/separated_parsers.rs b/src/combinators/separated_parsers.rs index fca1fe4..2722cf5 100644 --- a/src/combinators/separated_parsers.rs +++ b/src/combinators/separated_parsers.rs @@ -10,14 +10,14 @@ pub struct SeparateBy1Parser { pub(crate) phantom_data: PhantomData, } -impl Parser, TContext> - for SeparateBy1Parser +impl<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator> + Parser<'a, TToken, Vec, TContext> for SeparateBy1Parser where TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + P: Parser<'a, TToken, T, TContext>, + PSeparator: Parser<'a, TToken, TSeparator, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -45,14 +45,14 @@ pub struct SeparateOrEndBy1Parser { pub(crate) phantom_data: PhantomData, } -impl Parser, TContext> - for SeparateOrEndBy1Parser +impl<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator> + Parser<'a, TToken, Vec, TContext> for SeparateOrEndBy1Parser where TToken: Debug + Clone, - P: Parser, - PSeparator: Parser, + P: Parser<'a, TToken, T, TContext>, + PSeparator: Parser<'a, TToken, TSeparator, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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) + }); } } diff --git a/src/combinators/tuple_parser.rs b/src/combinators/tuple_parser.rs index 85ac91b..a2cb6f3 100644 --- a/src/combinators/tuple_parser.rs +++ b/src/combinators/tuple_parser.rs @@ -3,24 +3,43 @@ use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; -pub trait ParserTuple +pub trait ParserTuple<'a, TToken, T: 'a, TContext> where TToken: Debug + Clone, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T>; } -impl ParserTuple for (P1, P2) +pub struct TupleParser

{ + pub(crate) parser: P, +} + +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, T, TContext> for TupleParser

where TToken: Debug + Clone, - P1: Parser, - P2: Parser, + P: ParserTuple<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( + &self, + context: Rc>>, + 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>>, input: &'a [TToken], @@ -32,15 +51,15 @@ where } } -impl ParserTuple - 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, - P2: Parser, - P3: Parser, + 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>>, input: &'a [TToken], @@ -53,16 +72,16 @@ where } } -impl - ParserTuple 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, - P2: Parser, - P3: Parser, - P4: Parser, + 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>>, input: &'a [TToken], @@ -76,17 +95,17 @@ where } } -impl - ParserTuple 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, - P2: Parser, - P3: Parser, - P4: Parser, - P5: Parser, + 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>>, 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'), - tuple(( - char_parser('a'), - char_parser('b'), - char_parser('c'), - char_parser('d'), - )), + |c, i| { + tuple(( + char_parser('a'), + char_parser('b'), + char_parser('c'), + char_parser('d'), + )) + .parse(c, i) + }, ); } } diff --git a/src/lib.rs b/src/lib.rs index ef8357e..c865415 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,3 @@ -mod parser; -mod text; -mod combinators; +pub mod combinators; +pub mod parser; +pub mod text; diff --git a/src/parser.rs b/src/parser.rs index 5726da5..f1825a1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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 ParserContext { } } -pub trait Parser +pub trait Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, + T: 'a, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -80,7 +85,7 @@ where fn map(self, f: F) -> MapParser where Self: Sized, - F: Fn(&T) -> TResult, + F: Fn(T) -> TResult, { MapParser { parser: self, @@ -89,11 +94,11 @@ where } } - fn bind(self, f: F) -> BindParser + fn bind(self, f: F) -> BindParser where Self: Sized, F: Fn(T) -> P, - P: Parser, + P: Parser<'a, TToken, TResult, TContext>, { BindParser { parser: self, @@ -125,6 +130,16 @@ where } } + fn literal_count(self) -> LitervalCountParser + where + Self: Sized, + { + LitervalCountParser { + parser: self, + phantom_data: PhantomData, + } + } + fn literal(self) -> LitervalParser where Self: Sized, @@ -158,15 +173,15 @@ where } } -impl Parser 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>>, - &'f [TToken], - ) -> ParserResult<'f, TToken, T>, + &'a [TToken], + ) -> ParserResult<'a, TToken, T>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -175,11 +190,12 @@ where } } -impl Parser for Box> +impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> + for Box> where TToken: Debug + Clone, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -188,15 +204,15 @@ where } } -pub fn succeed(value: T) -> impl Parser +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() -> impl Parser +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(message: &str) -> impl Parser +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(predicate: TP) -> impl Parser +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() -> impl Parser +pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext> where - TToken: Debug + Clone, + TToken: Debug + Clone + 'a, { AnyParser {} } -pub fn take(count: usize) -> impl Parser, TContext> +pub fn take<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, Vec, TContext> where - TToken: Debug + Clone, + TToken: Debug + Clone + 'a, { TakeParser { count } } -pub fn skip(count: usize) -> impl Parser +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( test_parser: P, ) where T: PartialEq + Debug, - P: Parser, + P: for<'a> Fn(Rc>>, &'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( test_parser: P, ) where T: Debug, - P: Parser, + P: for<'a> Fn(Rc>>, &'a [char]) -> ParserResult<'a, char, T>, { let borrowed_context = context.borrow(); let input = borrowed_context.input_slice(); diff --git a/src/parser/modified_parsers.rs b/src/parser/modified_parsers.rs index 59fdc52..1d6c861 100644 --- a/src/parser/modified_parsers.rs +++ b/src/parser/modified_parsers.rs @@ -10,20 +10,21 @@ pub struct MapParser { pub(crate) phantom: PhantomData, } -impl Parser for MapParser +impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, F> Parser<'a, TToken, T2, TContext> + for MapParser where TToken: Debug + Clone, - P: Parser, - F: Fn(&T1) -> T2, + P: Parser<'a, TToken, T1, TContext>, + F: Fn(T1) -> T2, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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 { pub(crate) phantom_data: PhantomData, } -impl Parser for BindParser +impl<'a, TToken, T1: 'a, T2: 'a, TContext, P, P2, F> Parser<'a, TToken, T2, TContext> + for BindParser where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T1, TContext>, F: Fn(T1) -> P2, - P2: Parser, + P2: Parser<'a, TToken, T2, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -57,13 +59,14 @@ pub struct ConvertParser { pub(crate) phantom_data2: PhantomData, } -impl Parser for ConvertParser +impl<'a, TToken, T1: 'a, T2: 'a, TContext, P> Parser<'a, TToken, T2, TContext> + for ConvertParser where TToken: Debug + Clone, T2: From, - P: Parser, + P: Parser<'a, TToken, T1, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -80,13 +83,14 @@ pub struct NextParser { pub(crate) phantom_data: PhantomData, } -impl Parser for NextParser +impl<'a, TToken, T: 'a, TResult: 'a, TContext, P, H> Parser<'a, TToken, TResult, TContext> + for NextParser where TToken: Debug + Clone, - P: Parser, + 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>>, input: &'a [TToken], @@ -102,16 +106,17 @@ pub struct LitervalParser { pub(crate) phantom_data: PhantomData, } -impl Parser, TContext> for LitervalParser +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, &'a [TToken], TContext> + for LitervalParser where - TToken: Debug + Clone, - P: Parser, + TToken: Debug + Clone + 'a, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], - ) -> ParserResult<'a, TToken, Vec> { + ) -> 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(( - input, - (&origin_input[..index]) - .into_iter() - .map(|x| x.clone()) - .collect(), - )) + Ok((input, &origin_input[..index])) + } +} + +pub struct LitervalCountParser { + pub(crate) parser: P, + pub(crate) phantom_data: PhantomData, +} + +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, usize, TContext> + for LitervalCountParser +where + TToken: Debug + Clone, + P: Parser<'a, TToken, T, TContext>, +{ + fn parse( + &self, + context: Rc>>, + 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, + 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 { pub(crate) phantom_data: PhantomData, } -impl Parser for LookAheadParser +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, T, TContext> for LookAheadParser where TToken: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, input: &'a [TToken], @@ -165,14 +199,14 @@ pub struct ReverseParser { pub(crate) phantom_data: PhantomData, } -impl Parser +impl<'a, TToken, T: 'a, TResult: 'a, TContext, P> Parser<'a, TToken, TResult, TContext> for ReverseParser where TToken: Debug + Clone, TResult: Debug + Clone, - P: Parser, + P: Parser<'a, TToken, T, TContext>, { - fn parse<'a>( + fn parse( &self, context: Rc>>, 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::(), - ); + failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { + single_numer_parser.convert::().parse(c, i) + }); } #[test] fn next_test() { - let parser = || { - 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), - }) - }; + fn parser( + context: Rc>>, + input: &[char], + ) -> ParserResult { + 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::(), - ); + failed_parser_test_helper(ParserContext::new_with_str("abc", ()), |c, i| { + parser.convert::().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'], - char_parser('a') - .bind(|_| char_parser('b')) - .bind(|_| char_parser('c')) - .literal(), + |c, i| { + char_parser('a') + .bind(|_| char_parser('b')) + .bind(|_| char_parser('c')) + .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) + }); } } diff --git a/src/parser/primitive_parsers.rs b/src/parser/primitive_parsers.rs index 82e1442..da5b9cf 100644 --- a/src/parser/primitive_parsers.rs +++ b/src/parser/primitive_parsers.rs @@ -8,12 +8,12 @@ pub struct SucceedParser { pub(crate) value: T, } -impl Parser for SucceedParser +impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for SucceedParser where TToken: Debug + Clone, T: Debug + Clone, { - fn parse<'a>( + fn parse( &self, _: Rc>>, input: &'a [TToken], @@ -26,11 +26,11 @@ pub struct FailParser { pub(crate) phantom_data: PhantomData, } -impl Parser for FailParser +impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for FailParser where TToken: Debug + Clone, { - fn parse<'a>( + fn parse( &self, _: Rc>>, input: &'a [TToken], @@ -47,11 +47,11 @@ pub struct FailWithMessageParser { pub(crate) phantom_data: PhantomData, } -impl Parser for FailWithMessageParser +impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for FailWithMessageParser where TToken: Debug + Clone, { - fn parse<'a>( + fn parse( &self, _: Rc>>, input: &'a [TToken], @@ -64,12 +64,12 @@ pub struct SatisfyParser { pub(crate) predicate: F, } -impl Parser for SatisfyParser +impl<'a, TToken, TContext, F> Parser<'a, TToken, TToken, TContext> for SatisfyParser where - TToken: Debug + Clone, + TToken: Debug + Clone + 'a, F: Fn(&TToken) -> bool, { - fn parse<'a>( + fn parse( &self, _: Rc>>, input: &'a [TToken], @@ -91,11 +91,11 @@ where pub struct AnyParser {} -impl Parser 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>>, input: &'a [TToken], @@ -112,11 +112,11 @@ pub struct TakeParser { pub(crate) count: usize, } -impl Parser, TContext> for TakeParser +impl<'a, TToken, TContext> Parser<'a, TToken, Vec, TContext> for TakeParser where - TToken: Debug + Clone, + TToken: Debug + Clone + 'a, { - fn parse<'a>( + fn parse( &self, _: Rc>>, input: &'a [TToken], @@ -142,11 +142,11 @@ pub struct SkipParser { pub(crate) count: usize, } -impl Parser for SkipParser +impl<'a, TToken, TContext> Parser<'a, TToken, (), TContext> for SkipParser where TToken: Debug + Clone, { - fn parse<'a>( + fn parse( &self, _: Rc>>, 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::().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::("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) + }); } } diff --git a/src/text.rs b/src/text.rs index d186316..fab818c 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,14 +1,13 @@ use crate::parser::{satisfy, take, FailedParserResult, Parser}; -pub fn char_parser(c: char) -> impl Parser { +pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> { satisfy(move |x| *x == c) } -pub fn string_parser(str: String) -> impl Parser { - take::(str.len()).next(move |result| { +pub fn string_parser<'a, TContext>(str: &'static str) -> impl Parser<'a, char, String, TContext> { + take::(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(str: String) -> impl Parser(str: &'static str) -> impl Parser<'a, char, char, TContext> { + let str: Vec = 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>>, input: &[char], ) -> ParserResult { - 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), ) } }