From f69406bc027a4d023761db39cb6ae02cbe1a5341 Mon Sep 17 00:00:00 2001 From: jackfiled Date: Fri, 22 Nov 2024 14:33:14 +0800 Subject: [PATCH] fix: rewrite quote and make quote to read the right quote. --- src/combinators.rs | 12 ++++- src/combinators/many_parsers.rs | 12 +++++ src/combinators/separated_parsers.rs | 66 +++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/combinators.rs b/src/combinators.rs index 30a145d..1b6aaf3 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -9,7 +9,9 @@ use crate::combinators::left_right_parsers::{LeftParser, RightParser}; use crate::combinators::many_parsers::{ Many1Parser, Many1TillParser, ManyParser, ManyTillParser, Skip1Parser, SkipParser, }; -use crate::combinators::separated_parsers::{SeparateBy1Parser, SeparateOrEndBy1Parser}; +use crate::combinators::separated_parsers::{ + QuoteParser, SeparateBy1Parser, SeparateOrEndBy1Parser, +}; use crate::combinators::tuple_parser::{ParserTuple, TupleParser}; use crate::parser::{any, Parser}; use std::fmt::Debug; @@ -190,7 +192,13 @@ where PLeft: Parser<'a, TToken, TLeft, TContext>, PRight: Parser<'a, TToken, TRight, TContext>, { - left.right(parser.many_till(right)) + QuoteParser { + left, + parser, + right, + left_data: PhantomData, + right_data: PhantomData, + } } pub fn separate_by1<'a, TToken, T: 'a, TSeparator: 'a, TContext, P, PSeparator>( diff --git a/src/combinators/many_parsers.rs b/src/combinators/many_parsers.rs index 6b3e35d..0b5bd65 100644 --- a/src/combinators/many_parsers.rs +++ b/src/combinators/many_parsers.rs @@ -270,6 +270,18 @@ mod test { char_parser('a').many_till(char_parser('b')).parse(c, i) }); + parser_test_helper( + ParserContext::new_with_str("aaabc", ()), + &vec!['a', 'a', 'a'], + |c, i| { + char_parser('a') + .many_till(char_parser('b')) + .left(char_parser('b')) + .left(char_parser('c')) + .parse(c, i) + }, + ); + failed_parser_test_helper(ParserContext::new_with_str("aaacb", ()), |c, i| { char_parser('a').many_till(char_parser('b')).parse(c, i) }); diff --git a/src/combinators/separated_parsers.rs b/src/combinators/separated_parsers.rs index 2722cf5..e6b66d9 100644 --- a/src/combinators/separated_parsers.rs +++ b/src/combinators/separated_parsers.rs @@ -1,9 +1,60 @@ -use crate::parser::{Parser, ParserContext, ParserResult}; +use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult}; use std::cell::RefCell; use std::fmt::Debug; use std::marker::PhantomData; use std::rc::Rc; +pub struct QuoteParser { + pub(crate) parser: P, + pub(crate) left: PLeft, + pub(crate) right: PRight, + pub(crate) left_data: PhantomData, + pub(crate) right_data: PhantomData, +} + +impl<'a, TToken, T: 'a, TLeft: 'a, TRight: 'a, TContext, P, PLeft, PRight> + Parser<'a, TToken, Vec, TContext> for QuoteParser +where + TToken: Debug + Clone, + P: Parser<'a, TToken, T, TContext>, + PLeft: Parser<'a, TToken, TLeft, TContext>, + PRight: Parser<'a, TToken, TRight, TContext>, +{ + fn parse( + &self, + context: Rc>>, + input: &'a [TToken], + ) -> ParserResult<'a, TToken, Vec> { + let (mut input, _) = match self.left.parse(context.clone(), input) { + Err(r) => Err(FailedParserResult::new( + r.input(), + format!("Failed to parse left quote: {}", r.message()), + )), + r => r, + }?; + + let mut result = vec![]; + + loop { + if let Ok((i, _)) = self.right.parse(context.clone(), input) { + input = i; + break; + } + + if let Ok((i, r)) = self.parser.parse(context.clone(), input) { + input = i; + result.push(r); + } else { + return Err(FailedParserResult::new_with_str( + input, + "Quote without the right quote.", + )); + } + } + Ok((input, result)) + } +} + pub struct SeparateBy1Parser { pub(crate) parser: P, pub(crate) separator: PSeparator, @@ -82,6 +133,7 @@ mod test { use super::*; use crate::combinators::{ end_by, end_by1, quote, separate_by, separate_by1, separate_or_end_by, separate_or_end_by1, + ParserExt, }; use crate::parser::{failed_parser_test_helper, parser_test_helper, satisfy}; use crate::text::char_parser; @@ -106,7 +158,17 @@ mod test { parser, ); parser_test_helper(ParserContext::new_with_str("''", ()), &vec![], parser); - failed_parser_test_helper(ParserContext::new_with_str("asd", ()), parser) + failed_parser_test_helper(ParserContext::new_with_str("asd", ()), parser); + + parser_test_helper( + ParserContext::new_with_str("'a'b", ()), + &vec!['a'], + |c, i| { + quote(char_parser('\''), char_parser('a'), char_parser('\'')) + .left(char_parser('b')) + .parse(c, i) + }, + ) } #[test]