From 6dfc3d09f6a28c805dbb1fd980f72907ede931c1 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 12:16:30 +0100 Subject: [PATCH 01/12] refactor(pc): Introducing MapDecorator Makes parsers that rely on a single underlying parser and only map the successful result of that parser slightly less boilerplate in the implementation. Using a marker trait MapDecoratorMarker to resolve conflicts in blanket trait implementation of Parser. --- rusty_pc/src/lib.rs | 1 + rusty_pc/src/map.rs | 31 +++++++++++++------------ rusty_pc/src/map_decorator.rs | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 rusty_pc/src/map_decorator.rs diff --git a/rusty_pc/src/lib.rs b/rusty_pc/src/lib.rs index d0d0ebdf..7cca4fab 100644 --- a/rusty_pc/src/lib.rs +++ b/rusty_pc/src/lib.rs @@ -15,6 +15,7 @@ pub mod many; pub mod many_ctx; pub mod map; pub mod map_ctx; +pub mod map_decorator; pub mod map_err; pub mod no_context; mod or; diff --git a/rusty_pc/src/map.rs b/rusty_pc/src/map.rs index 72024058..51d8d5fd 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) -> U { + (self.mapper)(ok) } } +impl MapDecoratorMarker for MapParser {} + /// MapToUnitParser is the same as `.map(|_| ())`. pub struct MapToUnitParser

{ parser: P, @@ -39,22 +44,20 @@ 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) {} } + +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..8fc7f9e5 --- /dev/null +++ b/rusty_pc/src/map_decorator.rs @@ -0,0 +1,43 @@ +use crate::{InputTrait, Parser, ParserErrorTrait}; + +/// A parser decorator that maps the result 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) -> Self::Output; +} + +/// 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) => Ok(self.map_ok(ok)), + Err(err) => Err(err), + } + } + + fn set_context(&mut self, ctx: &C) { + self.decorated().set_context(ctx) + } +} From 3d02d96e642fc34156519e9deb79dcea5fabac00 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 15:13:19 +0100 Subject: [PATCH 02/12] Migrated OrDefaultParser to MapDecorator --- rusty_pc/src/map_decorator.rs | 7 +++++++ rusty_pc/src/or_default.rs | 29 +++++++++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/rusty_pc/src/map_decorator.rs b/rusty_pc/src/map_decorator.rs index 8fc7f9e5..72f16a3d 100644 --- a/rusty_pc/src/map_decorator.rs +++ b/rusty_pc/src/map_decorator.rs @@ -16,6 +16,12 @@ where /// Maps the successful result of the parser. fn map_ok(&self, ok: Self::OriginalOutput) -> Self::Output; + + /// 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`. @@ -33,6 +39,7 @@ where fn parse(&mut self, input: &mut I) -> Result { match self.decorated().parse(input) { Ok(ok) => Ok(self.map_ok(ok)), + Err(err) if err.is_soft() => self.map_soft_error(err), Err(err) => Err(err), } } diff --git a/rusty_pc/src/or_default.rs b/rusty_pc/src/or_default.rs index 3d3badf2..d9a8c6cd 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) -> Self::Output { + ok + } + + fn map_soft_error(&self, _err: Self::Error) -> Result { + Ok(P::Output::default()) } } + +impl

MapDecoratorMarker for OrDefaultParser

{} From eac75c755cbfb0142a2e2cad79112333aa330ed2 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 15:19:14 +0100 Subject: [PATCH 03/12] Migrated ToOptionParser to MapDecorator --- rusty_pc/src/to_option.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/rusty_pc/src/to_option.rs b/rusty_pc/src/to_option.rs index ef2f50b1..0c044a05 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) -> Self::Output { + Some(ok) + } + + fn map_soft_error(&self, _err: Self::Error) -> Result { + Ok(None) } } + +impl

MapDecoratorMarker for ToOptionParser

{} From 06e9d370ba6f1af117c8942171e2512b44d86fa8 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 15:26:01 +0100 Subject: [PATCH 04/12] Migrated AndThenErrParser to MapDecorator --- rusty_pc/src/and_then_err.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/rusty_pc/src/and_then_err.rs b/rusty_pc/src/and_then_err.rs index 0a57b382..999e48a6 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) -> Self::Output { + 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 {} From 93fa688e635e435956cb6176e43192c226fc59ae Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 15:36:28 +0100 Subject: [PATCH 05/12] Migrated AndThenParser to MapDecorator --- rusty_pc/src/and_then.rs | 17 ++++++++++++----- rusty_pc/src/and_then_err.rs | 4 ++-- rusty_pc/src/map.rs | 8 +++++--- rusty_pc/src/map_decorator.rs | 8 +++++--- rusty_pc/src/or_default.rs | 4 ++-- rusty_pc/src/to_option.rs | 4 ++-- 6 files changed, 28 insertions(+), 17 deletions(-) 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 999e48a6..7b0a329d 100644 --- a/rusty_pc/src/and_then_err.rs +++ b/rusty_pc/src/and_then_err.rs @@ -28,8 +28,8 @@ where &mut self.parser } - fn map_ok(&self, ok: Self::OriginalOutput) -> Self::Output { - ok + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) } fn map_soft_error(&self, err: Self::Error) -> Result { diff --git a/rusty_pc/src/map.rs b/rusty_pc/src/map.rs index 51d8d5fd..25b47c1f 100644 --- a/rusty_pc/src/map.rs +++ b/rusty_pc/src/map.rs @@ -26,8 +26,8 @@ where &mut self.parser } - fn map_ok(&self, ok: P::Output) -> U { - (self.mapper)(ok) + fn map_ok(&self, ok: P::Output) -> Result { + Ok((self.mapper)(ok)) } } @@ -57,7 +57,9 @@ where &mut self.parser } - fn map_ok(&self, _ok: P::Output) {} + 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 index 72f16a3d..5d178c80 100644 --- a/rusty_pc/src/map_decorator.rs +++ b/rusty_pc/src/map_decorator.rs @@ -1,6 +1,8 @@ use crate::{InputTrait, Parser, ParserErrorTrait}; -/// A parser decorator that maps the result of the decorated parser. +/// A parser decorator that maps the successful result +/// and optionally the soft error +/// of the decorated parser. pub trait MapDecorator where I: InputTrait, @@ -15,7 +17,7 @@ where ) -> &mut impl Parser; /// Maps the successful result of the parser. - fn map_ok(&self, ok: Self::OriginalOutput) -> Self::Output; + 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. @@ -38,7 +40,7 @@ where fn parse(&mut self, input: &mut I) -> Result { match self.decorated().parse(input) { - Ok(ok) => Ok(self.map_ok(ok)), + Ok(ok) => self.map_ok(ok), Err(err) if err.is_soft() => self.map_soft_error(err), Err(err) => Err(err), } diff --git a/rusty_pc/src/or_default.rs b/rusty_pc/src/or_default.rs index d9a8c6cd..f9c0f15e 100644 --- a/rusty_pc/src/or_default.rs +++ b/rusty_pc/src/or_default.rs @@ -27,8 +27,8 @@ where &mut self.parser } - fn map_ok(&self, ok: Self::OriginalOutput) -> Self::Output { - ok + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(ok) } fn map_soft_error(&self, _err: Self::Error) -> Result { diff --git a/rusty_pc/src/to_option.rs b/rusty_pc/src/to_option.rs index 0c044a05..d2182683 100644 --- a/rusty_pc/src/to_option.rs +++ b/rusty_pc/src/to_option.rs @@ -26,8 +26,8 @@ where &mut self.parser } - fn map_ok(&self, ok: Self::OriginalOutput) -> Self::Output { - Some(ok) + fn map_ok(&self, ok: Self::OriginalOutput) -> Result { + Ok(Some(ok)) } fn map_soft_error(&self, _err: Self::Error) -> Result { From 1e84fddc24c90fcc2a7fa3dc767c9b7b2212dba2 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Mon, 16 Feb 2026 15:58:07 +0100 Subject: [PATCH 06/12] Migrated LazyParser to MapDecorator --- rusty_pc/src/lazy.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) 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 {} From d704115262913c1c847c30b99170c7d8b59b134d Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 20:33:03 +0100 Subject: [PATCH 07/12] Renamed `specific_trait` to `or_expected` --- rusty_parser/src/pc_specific/mod.rs | 4 ++-- .../src/pc_specific/{specific_trait.rs => or_expected.rs} | 0 rusty_parser/src/pc_specific/with_pos.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) rename rusty_parser/src/pc_specific/{specific_trait.rs => or_expected.rs} (100%) diff --git a/rusty_parser/src/pc_specific/mod.rs b/rusty_parser/src/pc_specific/mod.rs index dd578791..d43ee8d0 100644 --- a/rusty_parser/src/pc_specific/mod.rs +++ b/rusty_parser/src/pc_specific/mod.rs @@ -7,7 +7,7 @@ mod whitespace; #[cfg(debug_assertions)] pub mod logging; -mod specific_trait; +mod or_expected; mod with_expected_message; mod with_pos; @@ -15,7 +15,7 @@ pub use self::csv::*; pub use self::in_parenthesis::*; pub use self::keyword::*; pub use self::keyword_map::*; -pub use self::specific_trait::*; +pub use self::or_expected::*; pub use self::whitespace::*; pub use self::with_expected_message::*; pub use self::with_pos::*; diff --git a/rusty_parser/src/pc_specific/specific_trait.rs b/rusty_parser/src/pc_specific/or_expected.rs similarity index 100% rename from rusty_parser/src/pc_specific/specific_trait.rs rename to rusty_parser/src/pc_specific/or_expected.rs 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, From ff94030c2ab352bdd39d03bc69879fdcd44e7017 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 20:45:23 +0100 Subject: [PATCH 08/12] Created dedicated ToFatalParser --- rusty_pc/src/lib.rs | 1 + rusty_pc/src/map_err.rs | 12 ------------ rusty_pc/src/parser.rs | 25 ++++++++++++++----------- rusty_pc/src/to_fatal.rs | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 rusty_pc/src/to_fatal.rs diff --git a/rusty_pc/src/lib.rs b/rusty_pc/src/lib.rs index 7cca4fab..db094aba 100644 --- a/rusty_pc/src/lib.rs +++ b/rusty_pc/src/lib.rs @@ -27,6 +27,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_err.rs b/rusty_pc/src/map_err.rs index e04213b1..12554178 100644 --- a/rusty_pc/src/map_err.rs +++ b/rusty_pc/src/map_err.rs @@ -42,18 +42,6 @@ where 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); diff --git a/rusty_pc/src/parser.rs b/rusty_pc/src/parser.rs index cd2fe564..e8ce0d91 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -10,12 +10,11 @@ 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_err::{ErrorMapper, FatalErrorOverrider, MapErrParser, SoftErrorOverrider}; 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. @@ -337,14 +336,6 @@ where self.map_err(FatalErrorOverrider::new(err)) } - /// If this parser returns a soft error, it will be converted to a fatal error. - fn to_fatal(self) -> MapErrParser - where - Self: Sized, - { - self.map_err(ToFatalErrorMapper) - } - // ======================================================================= // NoContext // ======================================================================= @@ -413,6 +404,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

{} From 504ed2e48776685bfc3bc89f68f2a65c3239e89b Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 20:54:26 +0100 Subject: [PATCH 09/12] Created dedicated MapSoftErrParser --- rusty_parser/src/pc_specific/or_expected.rs | 4 +-- rusty_pc/src/lib.rs | 1 + rusty_pc/src/map_err.rs | 18 ---------- rusty_pc/src/map_soft_err.rs | 40 +++++++++++++++++++++ rusty_pc/src/parser.rs | 11 +++--- 5 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 rusty_pc/src/map_soft_err.rs diff --git a/rusty_parser/src/pc_specific/or_expected.rs b/rusty_parser/src/pc_specific/or_expected.rs index 66f7b51e..8f26d86b 100644 --- a/rusty_parser/src/pc_specific/or_expected.rs +++ b/rusty_parser/src/pc_specific/or_expected.rs @@ -1,4 +1,4 @@ -use rusty_pc::map_err::{MapErrParser, SoftErrorOverrider}; +use rusty_pc::map_soft_err::MapSoftErrParser; use rusty_pc::{Parser, ParserErrorTrait}; use crate::error::ParserError; @@ -11,7 +11,7 @@ where /// 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> { + fn or_expected(self, expectation: &str) -> MapSoftErrParser { self.or_fail(ParserError::expected(expectation).to_fatal()) } } diff --git a/rusty_pc/src/lib.rs b/rusty_pc/src/lib.rs index db094aba..1c56b0fd 100644 --- a/rusty_pc/src/lib.rs +++ b/rusty_pc/src/lib.rs @@ -17,6 +17,7 @@ pub mod map; pub mod map_ctx; pub mod map_decorator; pub mod map_err; +pub mod map_soft_err; pub mod no_context; mod or; pub mod or_default; diff --git a/rusty_pc/src/map_err.rs b/rusty_pc/src/map_err.rs index 12554178..deb5fdf7 100644 --- a/rusty_pc/src/map_err.rs +++ b/rusty_pc/src/map_err.rs @@ -42,24 +42,6 @@ where fn map(&self, err: E) -> E; } -/// 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); 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/parser.rs b/rusty_pc/src/parser.rs index e8ce0d91..66cde2f0 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -10,7 +10,8 @@ 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}; +use crate::map_err::{ErrorMapper, FatalErrorOverrider, MapErrParser}; +use crate::map_soft_err::MapSoftErrParser; use crate::no_context::NoContextParser; use crate::or_default::OrDefaultParser; use crate::peek::PeekParser; @@ -289,7 +290,7 @@ where } // ======================================================================= - // MapErr + // MapSoftErr // ======================================================================= /// Maps the error of this parser. @@ -306,16 +307,16 @@ where /// 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> + fn or_fail(self, err: Self::Error) -> MapSoftErrParser where Self: Sized, { From 0b025946795398cac5314b7dba309ab9076d548d Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 21:04:25 +0100 Subject: [PATCH 10/12] Created dedicated parser for MapFatalErr --- rusty_pc/src/lib.rs | 2 +- rusty_pc/src/map_err.rs | 61 ----------------------------------- rusty_pc/src/map_fatal_err.rs | 35 ++++++++++++++++++++ rusty_pc/src/parser.rs | 33 +++++++------------ 4 files changed, 48 insertions(+), 83 deletions(-) delete mode 100644 rusty_pc/src/map_err.rs create mode 100644 rusty_pc/src/map_fatal_err.rs diff --git a/rusty_pc/src/lib.rs b/rusty_pc/src/lib.rs index 1c56b0fd..638bd32f 100644 --- a/rusty_pc/src/lib.rs +++ b/rusty_pc/src/lib.rs @@ -16,7 +16,7 @@ pub mod many_ctx; pub mod map; pub mod map_ctx; pub mod map_decorator; -pub mod map_err; +pub mod map_fatal_err; pub mod map_soft_err; pub mod no_context; mod or; diff --git a/rusty_pc/src/map_err.rs b/rusty_pc/src/map_err.rs deleted file mode 100644 index deb5fdf7..00000000 --- a/rusty_pc/src/map_err.rs +++ /dev/null @@ -1,61 +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; -} - -/// 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/parser.rs b/rusty_pc/src/parser.rs index 66cde2f0..93c81665 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -10,7 +10,7 @@ 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}; +use crate::map_fatal_err::MapFatalErrParser; use crate::map_soft_err::MapSoftErrParser; use crate::no_context::NoContextParser; use crate::or_default::OrDefaultParser; @@ -290,21 +290,25 @@ where } // ======================================================================= - // MapSoftErr + // 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) -> MapSoftErrParser @@ -324,19 +328,6 @@ where self.with_soft_err(err) } - /// 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> - where - Self: Sized, - { - assert!(err.is_fatal()); - self.map_err(FatalErrorOverrider::new(err)) - } - // ======================================================================= // NoContext // ======================================================================= From 6cb19d8c877230c7a427c9ccdc7dd0862c85dfb4 Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 21:21:51 +0100 Subject: [PATCH 11/12] Implemented `with_expected_message` in pc --- rusty_parser/src/core/dim_name.rs | 5 +- rusty_parser/src/core/param_name.rs | 4 +- rusty_parser/src/error.rs | 16 +++++- rusty_parser/src/pc_specific/keyword.rs | 4 +- rusty_parser/src/pc_specific/mod.rs | 2 - .../src/pc_specific/with_expected_message.rs | 51 ------------------- rusty_parser/src/tokens/any_token.rs | 1 - rusty_pc/src/parser.rs | 11 ++++ 8 files changed, 31 insertions(+), 63 deletions(-) delete mode 100644 rusty_parser/src/pc_specific/with_expected_message.rs 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/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, - 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/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/parser.rs b/rusty_pc/src/parser.rs index 93c81665..a7560130 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -318,6 +318,17 @@ where MapSoftErrParser::new(self, err) } + /// 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. + fn with_expected_message(self, msg: E) -> MapSoftErrParser + where + Self: Sized, + Self::Error: From, + { + self.with_soft_err(Self::Error::from(msg)) + } + /// 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 From 4efbb72b5a0bc08154d8513f89011ba1b299f10d Mon Sep 17 00:00:00 2001 From: Nikolaos Georgiou Date: Wed, 18 Feb 2026 21:39:15 +0100 Subject: [PATCH 12/12] Moved `or_expected` into pc --- rusty_parser/src/core/sub_call.rs | 1 - rusty_parser/src/expr/binary_expression.rs | 2 +- rusty_parser/src/expr/parenthesis.rs | 2 +- rusty_parser/src/expr/parsers.rs | 2 +- rusty_parser/src/expr/property.rs | 1 - rusty_parser/src/expr/unary_expression.rs | 2 +- rusty_parser/src/pc_specific/csv.rs | 1 - rusty_parser/src/pc_specific/mod.rs | 2 -- rusty_parser/src/pc_specific/or_expected.rs | 19 ------------------- rusty_pc/src/parser.rs | 15 +++++++++++++++ 10 files changed, 19 insertions(+), 28 deletions(-) delete mode 100644 rusty_parser/src/pc_specific/or_expected.rs diff --git a/rusty_parser/src/core/sub_call.rs b/rusty_parser/src/core/sub_call.rs index 62766829..4eac98c4 100644 --- a/rusty_parser/src/core/sub_call.rs +++ b/rusty_parser/src/core/sub_call.rs @@ -4,7 +4,6 @@ use rusty_pc::*; use crate::error::ParserError; use crate::expr::{csv_expressions_first_guarded, expression_pos_p, property}; use crate::input::StringView; -use crate::pc_specific::*; use crate::tokens::equal_sign_ws; use crate::*; 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/mod.rs b/rusty_parser/src/pc_specific/mod.rs index 3060a5a4..ca2fe6cb 100644 --- a/rusty_parser/src/pc_specific/mod.rs +++ b/rusty_parser/src/pc_specific/mod.rs @@ -7,13 +7,11 @@ mod whitespace; #[cfg(debug_assertions)] pub mod logging; -mod or_expected; mod with_pos; pub use self::csv::*; pub use self::in_parenthesis::*; pub use self::keyword::*; pub use self::keyword_map::*; -pub use self::or_expected::*; pub use self::whitespace::*; pub use self::with_pos::*; diff --git a/rusty_parser/src/pc_specific/or_expected.rs b/rusty_parser/src/pc_specific/or_expected.rs deleted file mode 100644 index 8f26d86b..00000000 --- a/rusty_parser/src/pc_specific/or_expected.rs +++ /dev/null @@ -1,19 +0,0 @@ -use rusty_pc::map_soft_err::MapSoftErrParser; -use rusty_pc::{Parser, ParserErrorTrait}; - -use crate::error::ParserError; -use crate::input::StringView; - -pub trait OrExpected: 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) -> MapSoftErrParser { - self.or_fail(ParserError::expected(expectation).to_fatal()) - } -} - -impl OrExpected for P where P: Parser {} diff --git a/rusty_pc/src/parser.rs b/rusty_pc/src/parser.rs index a7560130..f2559433 100644 --- a/rusty_pc/src/parser.rs +++ b/rusty_pc/src/parser.rs @@ -320,7 +320,9 @@ where /// 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, @@ -339,6 +341,19 @@ where self.with_soft_err(err) } + /// 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.with_soft_err(Self::Error::from(msg).to_fatal()) + } + // ======================================================================= // NoContext // =======================================================================