Repository: Geal/nom
Pull request #1363 (2021-08-15 16:03:50)

Add fail parser
This PR introduces a `fail` parser that works as the inverse of the `success` parser. It always fails regardless of what input was passed to it. This complements the `success` parser and allows specifying default cases to return an error instead.

I have come across one use case as part of my precedence parser #1362. It requires three parser for prefix, postfix and binary operators respectively. But some languages might not have any prefix or postfix operators so the respective parser should just fail. 

Compared to a workaround like `verify(tag(""), |_: &str| false)`, `fail` is easier to read and makes the intent more clear when a parser is required (e.g. as part of a parameter) but should just fail because its not needed in the context.

Stargateur: this return unrecoverable error, since nom have 2 level or failure I would name this function, unrecoverable, not fail. Specially since the `Failure` variant of `Err` misleading name.
Stargateur: Ah, funny I actually again mix up what is what, so this return a recoverable error, thus fail is ok tier, why not full `failure` word like `success` ?
cenodis: Its not unrecoverable. Its the normal `nom::Err::Error`. Though I guess the name `fail` could be confused with the unrecoverable `Failure` variant. But I dont want yet another thing called "error" in nom considering that there are already 4 or 5 things with the name "error". Any other suggestions?
Stargateur: Well, `failure` should be ok want we will rename the error type in nom, for not it's probably confusing. Maybe for now `forward` ? Cause I still wonder how to rename `Err::Error` to either `Failure` or `Forward`

Patch:
diff --git a/doc/choosing_a_combinator.md b/doc/choosing_a_combinator.md
index ebc62a3..8837da7 100644
--- a/doc/choosing_a_combinator.md
+++ b/doc/choosing_a_combinator.md
@@ -109,6 +109,7 @@ The following parsers could be found on [docs.rs number section](https://docs.rs
 ## Remaining combinators
 
 - [`success`](https://docs.rs/nom/latest/nom/combinator/fn.success.html): Returns a value without consuming any input, always succeeds
+- [`fail`](https://docs.rs/nom/latest/nom/combinator/fn.fail.html): Inversion of `success`. Always fails.
 
 ## Character test functions
 
diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs
index be261bf..8a8349c 100644
--- a/src/combinator/mod.rs
+++ b/src/combinator/mod.rs
@@ -772,3 +772,16 @@ enum State<E> {
 pub fn success<I, O: Clone, E: ParseError<I>>(val: O) -> impl Fn(I) -> IResult<I, O, E> {
   move |input: I| Ok((input, val.clone()))
 }
+
+/// A parser which always fails.
+/// 
+/// ```rust
+/// # use nom::{Err, error::ErrorKind, IResult};
+/// use nom::combinator::fail;
+/// 
+/// let s = "string";
+/// assert_eq!(fail::<_, &str, _>(s), Err(Err::Error((s, ErrorKind::Fail))));
+/// ```
+pub fn fail<I, O, E: ParseError<I>>(i: I) -> IResult<I, O, E> {
+  Err(Err::Error(E::from_error_kind(i, ErrorKind::Fail)))
+}
\ No newline at end of file
diff --git a/src/error.rs b/src/error.rs
index d9962f1..498b5e1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -416,6 +416,7 @@ pub enum ErrorKind {
   Many1Count,
   Float,
   Satisfy,
+  Fail,
 }
 
 #[rustfmt::skip]
@@ -475,6 +476,7 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 {
     ErrorKind::Many1Count                => 72,
     ErrorKind::Float                     => 73,
     ErrorKind::Satisfy                   => 74,
+    ErrorKind::Fail                      => 75,
   }
 }
 
@@ -536,6 +538,7 @@ impl ErrorKind {
       ErrorKind::Many1Count                => "Count occurrence of >=1 patterns",
       ErrorKind::Float                     => "Float",
       ErrorKind::Satisfy                   => "Satisfy",
+      ErrorKind::Fail                      => "Fail",
     }
   }
 }
diff --git a/src/multi/mod.rs b/src/multi/mod.rs
index 180692a..5a7e948 100644
--- a/src/multi/mod.rs
+++ b/src/multi/mod.rs
@@ -890,6 +890,7 @@ where
 /// `length_value` will return an error.
 /// # Arguments
 /// * `f` The parser to apply.
+/// * `g` The parser to apply on the subslice.
 /// ```rust
 /// # #[macro_use] extern crate nom;
 /// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};


Test patch:
diff --git a/src/combinator/tests.rs b/src/combinator/tests.rs
index b8c1c6c..3509fbc 100644
--- a/src/combinator/tests.rs
+++ b/src/combinator/tests.rs
@@ -264,3 +264,12 @@ fn verify_test() {
   );
   assert_eq!(test(&b"abcdefg"[..]), Ok((&b"fg"[..], &b"abcde"[..])));
 }
+
+#[test]
+fn fail_test() {
+  let a = "string";
+  let b = "another string";
+  
+  assert_eq!(fail::<_, &str, _>(a), Err(Err::Error((a, ErrorKind::Fail))));
+  assert_eq!(fail::<_, &str, _>(b), Err(Err::Error((b, ErrorKind::Fail))));
+}
\ No newline at end of file