diff --git a/rusty_parser/src/core/dim_name.rs b/rusty_parser/src/core/dim_name.rs index 803edc52..94e8e67b 100644 --- a/rusty_parser/src/core/dim_name.rs +++ b/rusty_parser/src/core/dim_name.rs @@ -172,13 +172,12 @@ mod type_definition { Box::new(built_in_numeric_type()), Box::new(built_in_string()), ]; - let mut expected_message = - "Expected: INTEGER or LONG or SINGLE or DOUBLE or STRING"; + let mut expected_message = "INTEGER or LONG or SINGLE or DOUBLE or STRING"; if allow_user_defined { parsers.push(Box::new(user_defined_type())); expected_message = - "Expected: INTEGER or LONG or SINGLE or DOUBLE or STRING or identifier"; + "INTEGER or LONG or SINGLE or DOUBLE or STRING or identifier"; } OrParser::new(parsers).with_expected_message(expected_message) diff --git a/rusty_parser/src/core/param_name.rs b/rusty_parser/src/core/param_name.rs index 94ef8116..f9561ea2 100644 --- a/rusty_parser/src/core/param_name.rs +++ b/rusty_parser/src/core/param_name.rs @@ -101,9 +101,7 @@ fn extended_type() -> impl Parser Self { - Self::Expected(format!("Expected: {}", expectation)) + Self::from(expectation) } } @@ -98,3 +98,17 @@ impl From for ParserError { Self::ParseNumError(e.to_string()) } } + +// Needed in order to support with_expected_message + +impl From for ParserError { + fn from(e: String) -> Self { + Self::Expected(format!("Expected: {}", e)) + } +} + +impl From<&str> for ParserError { + fn from(e: &str) -> Self { + Self::Expected(format!("Expected: {}", e)) + } +} diff --git a/rusty_parser/src/expr/binary_expression.rs b/rusty_parser/src/expr/binary_expression.rs index b657066a..4f16b3b9 100644 --- a/rusty_parser/src/expr/binary_expression.rs +++ b/rusty_parser/src/expr/binary_expression.rs @@ -5,7 +5,7 @@ use rusty_pc::*; use crate::error::ParserError; use crate::expr::{expression_pos_p, ws_expr_pos_p}; use crate::input::StringView; -use crate::pc_specific::{OrExpected, WithPos, lead_opt_ws, lead_ws}; +use crate::pc_specific::{WithPos, lead_opt_ws, lead_ws}; use crate::tokens::{TokenType, any_token}; use crate::{ExpressionPos, ExpressionPosTrait, ExpressionTrait, Keyword, Operator}; diff --git a/rusty_parser/src/expr/parenthesis.rs b/rusty_parser/src/expr/parenthesis.rs index d18dbd7c..3b29805f 100644 --- a/rusty_parser/src/expr/parenthesis.rs +++ b/rusty_parser/src/expr/parenthesis.rs @@ -2,7 +2,7 @@ use rusty_pc::*; use crate::expr::expression_pos_p; use crate::input::StringView; -use crate::pc_specific::{OrExpected, WithPos, in_parenthesis}; +use crate::pc_specific::{WithPos, in_parenthesis}; use crate::{Expression, ExpressionPos, ParserError}; pub(super) fn parser() -> impl Parser { diff --git a/rusty_parser/src/expr/parsers.rs b/rusty_parser/src/expr/parsers.rs index 6d479320..068d5697 100644 --- a/rusty_parser/src/expr/parsers.rs +++ b/rusty_parser/src/expr/parsers.rs @@ -149,6 +149,6 @@ fn opt_keyword_expr( let msg = format!("expression after {}", keyword); conditionally_opt_whitespace() .and_keep_right(keyword_ignoring(keyword).no_context()) - .and_keep_right(ws_expr_pos_p().or_expected(&msg).no_context()) + .and_keep_right(ws_expr_pos_p().or_expected(msg).no_context()) .to_option() } diff --git a/rusty_parser/src/expr/property.rs b/rusty_parser/src/expr/property.rs index 39e9c040..ecf0edc8 100644 --- a/rusty_parser/src/expr/property.rs +++ b/rusty_parser/src/expr/property.rs @@ -4,7 +4,6 @@ use rusty_pc::*; use crate::core::{name_as_tokens_p, token_to_type_qualifier}; use crate::error::ParserError; use crate::input::StringView; -use crate::pc_specific::OrExpected; use crate::tokens::dot; use crate::{BareName, Expression, ExpressionPos, ExpressionType, Name, NameAsTokens}; diff --git a/rusty_parser/src/expr/unary_expression.rs b/rusty_parser/src/expr/unary_expression.rs index 95f95574..c37b2a10 100644 --- a/rusty_parser/src/expr/unary_expression.rs +++ b/rusty_parser/src/expr/unary_expression.rs @@ -3,7 +3,7 @@ use rusty_pc::*; use crate::expr::{expression_pos_p, ws_expr_pos_p}; use crate::input::StringView; -use crate::pc_specific::{OrExpected, WithPos, keyword}; +use crate::pc_specific::{WithPos, keyword}; use crate::tokens::minus_sign; use crate::{ExpressionPos, ExpressionPosTrait, Keyword, ParserError, UnaryOperator}; diff --git a/rusty_parser/src/pc_specific/csv.rs b/rusty_parser/src/pc_specific/csv.rs index f2378291..c50a3e18 100644 --- a/rusty_parser/src/pc_specific/csv.rs +++ b/rusty_parser/src/pc_specific/csv.rs @@ -2,7 +2,6 @@ use rusty_pc::*; use crate::error::ParserError; use crate::input::StringView; -use crate::pc_specific::OrExpected; use crate::tokens::comma_ws; /// Comma separated list of items. diff --git a/rusty_parser/src/pc_specific/keyword.rs b/rusty_parser/src/pc_specific/keyword.rs index 3760468c..f89b5c94 100644 --- a/rusty_parser/src/pc_specific/keyword.rs +++ b/rusty_parser/src/pc_specific/keyword.rs @@ -4,7 +4,7 @@ use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::*; use crate::input::StringView; -use crate::pc_specific::{WithExpected, whitespace_ignoring}; +use crate::pc_specific::whitespace_ignoring; use crate::tokens::{TokenMatcher, TokenType, any_token}; use crate::{Keyword, ParserError}; @@ -42,7 +42,7 @@ pub fn keyword_ignoring(k: Keyword) -> impl Parser: Parser -where - Self: Sized, -{ - /// Demands a successful result or returns a fatal syntax error - /// with an error message like "Expected: " followed by the - /// given expectation message. - fn or_expected(self, expectation: &str) -> MapErrParser> { - self.or_fail(ParserError::expected(expectation).to_fatal()) - } -} - -impl OrExpected for P where P: Parser {} diff --git a/rusty_parser/src/pc_specific/with_expected_message.rs b/rusty_parser/src/pc_specific/with_expected_message.rs deleted file mode 100644 index 83e67b1c..00000000 --- a/rusty_parser/src/pc_specific/with_expected_message.rs +++ /dev/null @@ -1,51 +0,0 @@ -use rusty_pc::{InputTrait, Parser}; - -use crate::ParserError; - -pub trait WithExpected: Parser -where - Self: Sized, - I: InputTrait, -{ - fn with_expected_message( - self, - f: F, - ) -> impl Parser - where - F: MessageProvider, - { - self.with_soft_err(ParserError::Expected(f.to_str())) - } -} - -impl WithExpected for P -where - P: Parser, - I: InputTrait, -{ -} - -pub trait MessageProvider { - fn to_str(&self) -> String; -} - -impl MessageProvider for &str { - fn to_str(&self) -> String { - self.to_string() - } -} - -impl MessageProvider for String { - fn to_str(&self) -> String { - self.clone() - } -} - -impl MessageProvider for F -where - F: Fn() -> String, -{ - fn to_str(&self) -> String { - (self)() - } -} diff --git a/rusty_parser/src/pc_specific/with_pos.rs b/rusty_parser/src/pc_specific/with_pos.rs index 32611213..eb70e6c6 100644 --- a/rusty_parser/src/pc_specific/with_pos.rs +++ b/rusty_parser/src/pc_specific/with_pos.rs @@ -10,6 +10,7 @@ where WithPosMapper::new(self) } } + impl WithPos for P where P: Parser, diff --git a/rusty_parser/src/tokens/any_token.rs b/rusty_parser/src/tokens/any_token.rs index 9995325a..6894c1cb 100644 --- a/rusty_parser/src/tokens/any_token.rs +++ b/rusty_parser/src/tokens/any_token.rs @@ -4,7 +4,6 @@ use rusty_pc::text::{many_str, many_str_with_combiner, one_char_to_str}; use rusty_pc::*; use crate::input::StringView; -use crate::pc_specific::WithExpected; use crate::tokens::TokenType; use crate::tokens::any_symbol::any_symbol; use crate::{Keyword, ParserError}; diff --git a/rusty_pc/src/and_then.rs b/rusty_pc/src/and_then.rs index 1bd3acec..7ad6bb89 100644 --- a/rusty_pc/src/and_then.rs +++ b/rusty_pc/src/and_then.rs @@ -1,3 +1,4 @@ +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; use crate::{InputTrait, Parser}; pub struct AndThenParser { @@ -11,19 +12,25 @@ impl AndThenParser { } } -impl Parser for AndThenParser +impl MapDecorator for AndThenParser where I: InputTrait, P: Parser, F: Fn(P::Output) -> Result, { + type OriginalOutput = P::Output; type Output = U; type Error = P::Error; - fn parse(&mut self, tokenizer: &mut I) -> Result { - self.parser.parse(tokenizer).and_then(&self.mapper) + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + (self.mapper)(ok) } } + +impl MapDecoratorMarker for AndThenParser {} diff --git a/rusty_pc/src/and_then_err.rs b/rusty_pc/src/and_then_err.rs index 0a57b382..7b0a329d 100644 --- a/rusty_pc/src/and_then_err.rs +++ b/rusty_pc/src/and_then_err.rs @@ -1,4 +1,5 @@ -use crate::{InputTrait, Parser, ParserErrorTrait}; +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; +use crate::{InputTrait, Parser}; pub struct AndThenErrParser { parser: P, @@ -11,23 +12,29 @@ impl AndThenErrParser { } } -impl Parser for AndThenErrParser +impl MapDecorator for AndThenErrParser where I: InputTrait, P: Parser, F: Fn(P::Error) -> Result, { + type OriginalOutput = P::Output; type Output = P::Output; type Error = P::Error; - fn parse(&mut self, input: &mut I) -> Result { - match self.parser.parse(input) { - Ok(value) => Ok(value), - Err(err) if err.is_soft() => (self.mapper)(err), - Err(err) => Err(err), - } + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser + } + + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_soft_error(&self, err: Self::Error) -> Result { + (self.mapper)(err) } } + +impl MapDecoratorMarker for AndThenErrParser {} diff --git a/rusty_pc/src/lazy.rs b/rusty_pc/src/lazy.rs index 65c5bf6b..8fa429ff 100644 --- a/rusty_pc/src/lazy.rs +++ b/rusty_pc/src/lazy.rs @@ -1,3 +1,4 @@ +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; use crate::{InputTrait, Parser}; pub fn lazy(factory: F) -> impl Parser @@ -17,28 +18,29 @@ struct LazyParser { parser_holder: Option

, } -impl Parser for LazyParser +impl MapDecorator for LazyParser where F: Fn() -> P, I: InputTrait, P: Parser, { + type OriginalOutput = P::Output; type Output = P::Output; type Error = P::Error; - fn parse(&mut self, input: &mut I) -> Result { - match self.parser_holder.as_mut() { - Some(parser) => parser.parse(input), - None => { - let mut parser = (self.factory)(); - let result = parser.parse(input); - self.parser_holder = Some(parser); - result - } + fn decorated( + &mut self, + ) -> &mut impl Parser { + if self.parser_holder.is_none() { + let parser = (self.factory)(); + self.parser_holder = Some(parser); } + self.parser_holder.as_mut().unwrap() } - fn set_context(&mut self, _ctx: &C) { - unimplemented!() + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) } } + +impl MapDecoratorMarker for LazyParser {} diff --git a/rusty_pc/src/lib.rs b/rusty_pc/src/lib.rs index d0d0ebdf..638bd32f 100644 --- a/rusty_pc/src/lib.rs +++ b/rusty_pc/src/lib.rs @@ -15,7 +15,9 @@ pub mod many; pub mod many_ctx; pub mod map; pub mod map_ctx; -pub mod map_err; +pub mod map_decorator; +pub mod map_fatal_err; +pub mod map_soft_err; pub mod no_context; mod or; pub mod or_default; @@ -26,6 +28,7 @@ mod supplier; mod surround; pub mod text; mod then_with; +pub mod to_fatal; pub mod to_option; mod token; mod top_level; diff --git a/rusty_pc/src/map.rs b/rusty_pc/src/map.rs index 72024058..25b47c1f 100644 --- a/rusty_pc/src/map.rs +++ b/rusty_pc/src/map.rs @@ -1,3 +1,4 @@ +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; use crate::{InputTrait, Parser}; pub struct MapParser { @@ -11,23 +12,27 @@ impl MapParser { } } -impl Parser for MapParser +impl MapDecorator for MapParser where I: InputTrait, P: Parser, F: Fn(P::Output) -> U, { + type OriginalOutput = P::Output; type Output = U; type Error = P::Error; - fn parse(&mut self, tokenizer: &mut I) -> Result { - self.parser.parse(tokenizer).map(&self.mapper) + + fn decorated(&mut self) -> &mut impl Parser { + &mut self.parser } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_ok(&self, ok: P::Output) -> Result { + Ok((self.mapper)(ok)) } } +impl MapDecoratorMarker for MapParser {} + /// MapToUnitParser is the same as `.map(|_| ())`. pub struct MapToUnitParser

{ parser: P, @@ -39,22 +44,22 @@ impl

MapToUnitParser

{ } } -impl Parser for MapToUnitParser

+impl MapDecorator for MapToUnitParser

where I: InputTrait, P: Parser, { + type OriginalOutput = P::Output; type Output = (); type Error = P::Error; - fn parse(&mut self, input: &mut I) -> Result { - match self.parser.parse(input) { - Ok(_) => Ok(()), - Err(err) => Err(err), - } + fn decorated(&mut self) -> &mut impl Parser { + &mut self.parser } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_ok(&self, _ok: P::Output) -> Result { + Ok(()) } } + +impl

MapDecoratorMarker for MapToUnitParser

{} diff --git a/rusty_pc/src/map_decorator.rs b/rusty_pc/src/map_decorator.rs new file mode 100644 index 00000000..5d178c80 --- /dev/null +++ b/rusty_pc/src/map_decorator.rs @@ -0,0 +1,52 @@ +use crate::{InputTrait, Parser, ParserErrorTrait}; + +/// A parser decorator that maps the successful result +/// and optionally the soft error +/// of the decorated parser. +pub trait MapDecorator +where + I: InputTrait, +{ + type OriginalOutput; + type Output; + type Error: ParserErrorTrait; + + /// Gets the decorated parser. + fn decorated( + &mut self, + ) -> &mut impl Parser; + + /// Maps the successful result of the parser. + fn map_ok(&self, ok: Self::OriginalOutput) -> Result; + + /// Maps the soft error of the parser. + /// By default, the error is returned as-is. However, it is possible to override this behavior. + fn map_soft_error(&self, err: Self::Error) -> Result { + Err(err) + } +} + +/// Marker trait for `MapDecorator`. +/// Allows for blanket trait implementation of `Parser`. +pub trait MapDecoratorMarker {} + +impl Parser for D +where + I: InputTrait, + D: MapDecoratorMarker + MapDecorator, +{ + type Output = D::Output; + type Error = D::Error; + + fn parse(&mut self, input: &mut I) -> Result { + match self.decorated().parse(input) { + Ok(ok) => self.map_ok(ok), + Err(err) if err.is_soft() => self.map_soft_error(err), + Err(err) => Err(err), + } + } + + fn set_context(&mut self, ctx: &C) { + self.decorated().set_context(ctx) + } +} diff --git a/rusty_pc/src/map_err.rs b/rusty_pc/src/map_err.rs deleted file mode 100644 index e04213b1..00000000 --- a/rusty_pc/src/map_err.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::{InputTrait, Parser, ParserErrorTrait}; - -/// A parser that maps the error of the decorated parser -/// using the given mapper. -pub struct MapErrParser { - parser: P, - mapper: M, -} - -impl MapErrParser { - pub(crate) fn new(parser: P, mapper: M) -> Self { - Self { parser, mapper } - } -} - -impl Parser for MapErrParser -where - I: InputTrait, - P: Parser, - M: ErrorMapper, -{ - type Output = P::Output; - type Error = P::Error; - - fn parse(&mut self, input: &mut I) -> Result { - match self.parser.parse(input) { - Ok(value) => Ok(value), - Err(err) => Err(self.mapper.map(err)), - } - } - - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) - } -} - -/// Maps the error of the parser into a different error. -pub trait ErrorMapper -where - E: ParserErrorTrait, -{ - fn map(&self, err: E) -> E; -} - -/// Converts a soft error into a fatal equivalent. -pub struct ToFatalErrorMapper; - -impl ErrorMapper for ToFatalErrorMapper -where - E: ParserErrorTrait, -{ - fn map(&self, err: E) -> E { - err.to_fatal() - } -} - -/// Overrides a soft error with the given value. -pub struct SoftErrorOverrider(E); - -impl SoftErrorOverrider { - pub fn new(err: E) -> Self { - Self(err) - } -} - -impl ErrorMapper for SoftErrorOverrider -where - E: ParserErrorTrait, -{ - fn map(&self, err: E) -> E { - if err.is_soft() { self.0.clone() } else { err } - } -} - -/// Overrides a fatal error with the given value. -pub struct FatalErrorOverrider(E); - -impl FatalErrorOverrider { - pub fn new(err: E) -> Self { - Self(err) - } -} - -impl ErrorMapper for FatalErrorOverrider -where - E: ParserErrorTrait, -{ - fn map(&self, err: E) -> E { - if err.is_fatal() { self.0.clone() } else { err } - } -} diff --git a/rusty_pc/src/map_fatal_err.rs b/rusty_pc/src/map_fatal_err.rs new file mode 100644 index 00000000..204e9aa1 --- /dev/null +++ b/rusty_pc/src/map_fatal_err.rs @@ -0,0 +1,35 @@ +use crate::{InputTrait, Parser, ParserErrorTrait}; + +/// A parser that maps the error of the decorated parser +/// using the given mapper. +pub struct MapFatalErrParser { + parser: P, + err: E, +} + +impl MapFatalErrParser { + pub(crate) fn new(parser: P, err: E) -> Self { + Self { parser, err } + } +} + +impl Parser for MapFatalErrParser +where + I: InputTrait, + P: Parser, + E: ParserErrorTrait, +{ + type Output = P::Output; + type Error = P::Error; + + fn parse(&mut self, input: &mut I) -> Result { + match self.parser.parse(input) { + Ok(value) => Ok(value), + Err(_) => Err(self.err.clone()), + } + } + + fn set_context(&mut self, ctx: &C) { + self.parser.set_context(ctx) + } +} diff --git a/rusty_pc/src/map_soft_err.rs b/rusty_pc/src/map_soft_err.rs new file mode 100644 index 00000000..1553c8db --- /dev/null +++ b/rusty_pc/src/map_soft_err.rs @@ -0,0 +1,40 @@ +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; +use crate::{InputTrait, Parser, ParserErrorTrait}; + +pub struct MapSoftErrParser { + parser: P, + err: E, +} + +impl MapSoftErrParser { + pub(crate) fn new(parser: P, err: E) -> Self { + Self { parser, err } + } +} + +impl MapDecorator for MapSoftErrParser +where + I: InputTrait, + P: Parser, + E: ParserErrorTrait, +{ + type OriginalOutput = P::Output; + type Output = P::Output; + type Error = E; + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser + } + + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) + } + + fn map_soft_error(&self, _err: Self::Error) -> Result { + Err(self.err.clone()) + } +} + +impl MapDecoratorMarker for MapSoftErrParser {} diff --git a/rusty_pc/src/or_default.rs b/rusty_pc/src/or_default.rs index 3d3badf2..f9c0f15e 100644 --- a/rusty_pc/src/or_default.rs +++ b/rusty_pc/src/or_default.rs @@ -1,30 +1,39 @@ -use crate::{InputTrait, Parser, ParserErrorTrait}; +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; +use crate::{InputTrait, Parser}; pub struct OrDefaultParser

{ parser: P, } + impl

OrDefaultParser

{ pub(crate) fn new(parser: P) -> Self { Self { parser } } } -impl Parser for OrDefaultParser

+ +impl MapDecorator for OrDefaultParser

where I: InputTrait, P: Parser, P::Output: Default, { + type OriginalOutput = P::Output; type Output = P::Output; type Error = P::Error; - fn parse(&mut self, input: &mut I) -> Result { - match self.parser.parse(input) { - Ok(value) => Ok(value), - Err(err) if err.is_soft() => Ok(P::Output::default()), - Err(err) => Err(err), - } + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) + } + + fn map_soft_error(&self, _err: Self::Error) -> Result { + Ok(P::Output::default()) } } + +impl

MapDecoratorMarker for OrDefaultParser

{} diff --git a/rusty_pc/src/parser.rs b/rusty_pc/src/parser.rs index cd2fe564..f2559433 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -10,12 +10,12 @@ use crate::flatten::FlattenParser; use crate::many::{ManyCombiner, ManyParser, VecManyCombiner}; use crate::map::{MapParser, MapToUnitParser}; use crate::map_ctx::MapCtxParser; -use crate::map_err::{ - ErrorMapper, FatalErrorOverrider, MapErrParser, SoftErrorOverrider, ToFatalErrorMapper -}; +use crate::map_fatal_err::MapFatalErrParser; +use crate::map_soft_err::MapSoftErrParser; use crate::no_context::NoContextParser; use crate::or_default::OrDefaultParser; use crate::peek::PeekParser; +use crate::to_fatal::ToFatalParser; use crate::to_option::ToOptionParser; /// A parser uses the given input in order to produce a result. @@ -290,59 +290,68 @@ where } // ======================================================================= - // MapErr + // MapFatalErr // ======================================================================= - /// Maps the error of this parser. + /// Maps the fatal error of this parser. /// If the parser is successful, the value is returned as-is. - /// If the parser returns an error, the given mapper is used to map the error - /// to a new error. - fn map_err(self, mapper: F) -> MapErrParser + /// If the parser returns a soft error, the error is returned as-is. + /// If the parser returns a fatal error, it is replaced by the given error. + fn map_fatal_err(self, err: Self::Error) -> MapFatalErrParser where Self: Sized, - F: ErrorMapper, { - MapErrParser::new(self, mapper) + assert!(err.is_fatal()); + MapFatalErrParser::new(self, err) } + // ======================================================================= + // MapSoftErr + // ======================================================================= + /// If this parser returns a soft error, the soft error will be replaced by /// the given error (which might be soft or fatal). - fn with_soft_err(self, err: Self::Error) -> MapErrParser> + fn with_soft_err(self, err: Self::Error) -> MapSoftErrParser where Self: Sized, { - self.map_err(SoftErrorOverrider::new(err)) + MapSoftErrParser::new(self, err) } - /// If this parser returns a soft error, the soft error will be replaced by - /// the given error, which must be fatal. - fn or_fail(self, err: Self::Error) -> MapErrParser> + /// If this parser returns a soft error, the soft error will be replaced + /// by transforming the given message into an error. + /// + /// The parameter will be converted with the standard `From` trait. + /// It is expected that the conversion returns a soft error. + fn with_expected_message(self, msg: E) -> MapSoftErrParser where Self: Sized, + Self::Error: From, { - assert!(err.is_fatal()); - self.with_soft_err(err) + self.with_soft_err(Self::Error::from(msg)) } - /// If this parser returns a fatal error, the fatal error will be replaced by the given error - /// (which must be fatal too). - fn with_fatal_err( - self, - err: Self::Error, - ) -> MapErrParser> + /// If this parser returns a soft error, the soft error will be replaced by + /// the given error, which must be fatal. + fn or_fail(self, err: Self::Error) -> MapSoftErrParser where Self: Sized, { assert!(err.is_fatal()); - self.map_err(FatalErrorOverrider::new(err)) + self.with_soft_err(err) } - /// If this parser returns a soft error, it will be converted to a fatal error. - fn to_fatal(self) -> MapErrParser + /// Converts the soft errors of this parser to fatal errors + /// based on the given error message. + /// + /// The message parameter will be converted with the standard `From` trait. + /// The resulting error is converted into a fatal one. + fn or_expected(self, msg: E) -> MapSoftErrParser where Self: Sized, + Self::Error: From, { - self.map_err(ToFatalErrorMapper) + self.with_soft_err(Self::Error::from(msg).to_fatal()) } // ======================================================================= @@ -413,6 +422,18 @@ where ThenWithContextParser::new(self, other, combiner) } + // ======================================================================= + // ToFatal + // ======================================================================= + + /// If this parser returns a soft error, it will be converted to a fatal error. + fn to_fatal(self) -> ToFatalParser + where + Self: Sized, + { + ToFatalParser::new(self) + } + // ======================================================================= // ToOption // ======================================================================= diff --git a/rusty_pc/src/to_fatal.rs b/rusty_pc/src/to_fatal.rs new file mode 100644 index 00000000..e00f619f --- /dev/null +++ b/rusty_pc/src/to_fatal.rs @@ -0,0 +1,38 @@ +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; +use crate::{InputTrait, Parser, ParserErrorTrait}; + +pub struct ToFatalParser

{ + parser: P, +} + +impl

ToFatalParser

{ + pub(crate) fn new(parser: P) -> Self { + Self { parser } + } +} + +impl MapDecorator for ToFatalParser

+where + I: InputTrait, + P: Parser, +{ + type OriginalOutput = P::Output; + type Output = P::Output; + type Error = P::Error; + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser + } + + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) + } + + fn map_soft_error(&self, err: Self::Error) -> Result { + Err(err.to_fatal()) + } +} + +impl

MapDecoratorMarker for ToFatalParser

{} diff --git a/rusty_pc/src/to_option.rs b/rusty_pc/src/to_option.rs index ef2f50b1..d2182683 100644 --- a/rusty_pc/src/to_option.rs +++ b/rusty_pc/src/to_option.rs @@ -1,29 +1,38 @@ -use crate::{InputTrait, Parser, ParserErrorTrait}; +use crate::map_decorator::{MapDecorator, MapDecoratorMarker}; +use crate::{InputTrait, Parser}; pub struct ToOptionParser

{ parser: P, } + impl

ToOptionParser

{ pub(crate) fn new(parser: P) -> Self { Self { parser } } } -impl Parser for ToOptionParser

+ +impl MapDecorator for ToOptionParser

where I: InputTrait, P: Parser, { + type OriginalOutput = P::Output; type Output = Option; type Error = P::Error; - fn parse(&mut self, input: &mut I) -> Result { - match self.parser.parse(input) { - Ok(value) => Ok(Some(value)), - Err(err) if err.is_soft() => Ok(None), - Err(err) => Err(err), - } + + fn decorated( + &mut self, + ) -> &mut impl Parser { + &mut self.parser } - fn set_context(&mut self, ctx: &C) { - self.parser.set_context(ctx) + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(Some(ok)) + } + + fn map_soft_error(&self, _err: Self::Error) -> Result { + Ok(None) } } + +impl

MapDecoratorMarker for ToOptionParser

{}