From e2c4388a0c9a39c14d578b36ad256558927da9ea Mon Sep 17 00:00:00 2001 From: jackfiled Date: Tue, 19 Nov 2024 21:34:32 +0800 Subject: [PATCH] refact: make FialedParserResult to implement std::Error:Error. --- src/combinators.rs | 4 ++-- src/combinators/many_parsers.rs | 8 +++---- src/parser.rs | 38 ++++++++++++++++++++++-------- src/parser/modified_parsers.rs | 22 +++++++---------- src/parser/primitive_parsers.rs | 27 ++++++++++----------- tests/file_lexical_parser_tests.rs | 2 +- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/combinators.rs b/src/combinators.rs index 079ad9e..30a145d 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -219,7 +219,7 @@ where PSeparator: Parser<'a, TToken, TSeparator, TContext>, { separate_by1(parser, separator).next(|r| match r { - Err((input, _)) => Ok((input, vec![])), + Err(r) => Ok((r.input(), vec![])), r => r, }) } @@ -274,7 +274,7 @@ where PSeparator: Parser<'a, TToken, TSeparator, TContext>, { separate_or_end_by1(parser, separator).next(|r| match r { - Err((i, _)) => Ok((i, vec![])), + Err(r) => Ok((r.input(), vec![])), r => r, }) } diff --git a/src/combinators/many_parsers.rs b/src/combinators/many_parsers.rs index d100e68..6b3e35d 100644 --- a/src/combinators/many_parsers.rs +++ b/src/combinators/many_parsers.rs @@ -136,9 +136,9 @@ where input = i; result.push(r); } else { - return Err(( + return Err(FailedParserResult::new_with_str( input, - FailedParserResult::new("End with other elements.".to_owned()), + "End with other elements.", )); } } @@ -174,9 +174,9 @@ where result.push(r); input = i; } else { - return Err(( + return Err(FailedParserResult::new_with_str( input, - FailedParserResult::new("End with other elements.".to_owned()), + "End with other elements.", )); } } diff --git a/src/parser.rs b/src/parser.rs index f1825a1..d9bd2dc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -10,33 +10,51 @@ use crate::parser::primitive_parsers::{ TakeParser, }; use std::cell::RefCell; +use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; use std::rc::Rc; #[derive(Debug)] -pub struct FailedParserResult { +pub struct FailedParserResult<'a, TToken: Debug> { + input: &'a [TToken], message: String, } -impl FailedParserResult { - pub fn new(message: String) -> Self { - Self { message } +impl<'a, TToken: Debug> FailedParserResult<'a, TToken> { + pub fn new(input: &'a [TToken], message: String) -> Self { + Self { input, message } + } + + pub fn new_with_str(input: &'a [TToken], message: &'static str) -> Self { + Self { + input, + message: message.to_owned(), + } } pub fn message(&self) -> &str { self.message.as_str() } -} -impl Display for FailedParserResult { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Parse failed: {}.", self.message) + pub fn input(&self) -> &'a [TToken] { + self.input } } -pub type ParserResult<'a, TToken, T> = - Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>; +impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {} + +impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Parse failed: {}, the input is '{:?}'.", + self.message, self.input + ) + } +} + +pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>; pub struct ParserContext where diff --git a/src/parser/modified_parsers.rs b/src/parser/modified_parsers.rs index 1d6c861..2c4405e 100644 --- a/src/parser/modified_parsers.rs +++ b/src/parser/modified_parsers.rs @@ -121,11 +121,9 @@ where let (input, _) = self.parser.parse(context, input)?; if origin_input.is_empty() { - return Err(( + return Err(FailedParserResult::new_with_str( input, - FailedParserResult::new( - "Empty input, the 'literal' parser cann't get length of elememt.".to_owned(), - ), + "Empty input, the 'literal' parser cann't get length of elememt.", )); } @@ -156,11 +154,9 @@ where let (input, _) = self.parser.parse(context, input)?; if origin_input.is_empty() { - return Err(( + return Err(FailedParserResult::new_with_str( input, - FailedParserResult::new( - "Empty input, the 'literal' parser cann't get length of elememt.".to_owned(), - ), + "Empty input, the 'literal' parser cann't get length of elememt.", )); } @@ -212,11 +208,11 @@ where input: &'a [TToken], ) -> ParserResult<'a, TToken, TResult> { match self.parser.parse(context, input) { - Ok((input, _)) => Err(( + Ok(_) => Err(FailedParserResult::new_with_str( input, - FailedParserResult::new("Reverse failed succeeded.".to_owned()), + "Reverse successful parser.", )), - Err((input, _)) => Ok((input, self.result.clone())), + Err(_) => Ok((input, self.result.clone())), } } } @@ -269,7 +265,7 @@ mod test { let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?; match result.to_digit(10) { - None => Err((input, FailedParserResult::new("What?".to_string()))), + None => Err(FailedParserResult::new_with_str(input, "What?")), Some(r) => Ok((input, Number(r as i32))), } } @@ -300,7 +296,7 @@ mod test { 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()))), + None => Err(FailedParserResult::new_with_str(input, "What?")), Some(r) => Ok((input, Number(r as i32))), }, Err(r) => Err(r), diff --git a/src/parser/primitive_parsers.rs b/src/parser/primitive_parsers.rs index da5b9cf..e7dcb1e 100644 --- a/src/parser/primitive_parsers.rs +++ b/src/parser/primitive_parsers.rs @@ -35,9 +35,9 @@ where _: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T> { - Err(( + Err(FailedParserResult::new_with_str( input, - FailedParserResult::new("Default failed parser.".to_owned()), + "Default failed parser.", )) } } @@ -56,7 +56,7 @@ where _: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T> { - Err((input, FailedParserResult::new(self.message.clone()))) + Err(FailedParserResult::new(input, self.message.clone())) } } @@ -75,16 +75,13 @@ where input: &'a [TToken], ) -> ParserResult<'a, TToken, TToken> { if input.is_empty() { - return Err((input, FailedParserResult::new("Input is empty.".to_owned()))); + return Err(FailedParserResult::new_with_str(input, "Input is empty")); } if (self.predicate)(&input[0]) { Ok((&input[1..], input[0].clone())) } else { - Err(( - input, - FailedParserResult::new("Predicate failed.".to_owned()), - )) + Err(FailedParserResult::new_with_str(input, "Predicate failed.")) } } } @@ -101,7 +98,7 @@ where input: &'a [TToken], ) -> ParserResult<'a, TToken, TToken> { if input.is_empty() { - Err((input, FailedParserResult::new("Input is empty.".to_owned()))) + Err(FailedParserResult::new_with_str(input, "Input is empty")) } else { Ok((&input[1..], input[0].clone())) } @@ -122,12 +119,12 @@ where input: &'a [TToken], ) -> ParserResult<'a, TToken, Vec> { if input.len() < self.count { - Err(( + Err(FailedParserResult::new( input, - FailedParserResult::new(format!( + format!( "The input doesn't contain enough {} elemements.", self.count - )), + ), )) } else { Ok(( @@ -152,12 +149,12 @@ where input: &'a [TToken], ) -> ParserResult<'a, TToken, ()> { if input.len() < self.count { - Err(( + Err(FailedParserResult::new( input, - FailedParserResult::new(format!( + format!( "The input doesn't contain enough {} elemements.", self.count - )), + ), )) } else { Ok((&input[self.count..], ())) diff --git a/tests/file_lexical_parser_tests.rs b/tests/file_lexical_parser_tests.rs index 9129aca..67eff2c 100644 --- a/tests/file_lexical_parser_tests.rs +++ b/tests/file_lexical_parser_tests.rs @@ -78,7 +78,7 @@ fn file_lexical_parser_test() -> anyhow::Result<()> { let context = ParserContext::new_with_str(source_file.content.as_str(), ()); let borrowed_context = context.borrow(); let (_, zero_tokens) = zero_lexical_parser(context.clone(), borrowed_context.input_slice()) - .or_else(|e| Err(anyhow!("{}", e.1)))?; + .or_else(|e| Err(anyhow!("{}", e)))?; assert_eq!(nom_tokens.len(), zero_tokens.len());