Skip to content

Commit

Permalink
Allow ‘many’ run parsers that do not consume input
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkkrp committed Dec 26, 2016
1 parent 5aff6e3 commit 5123241
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 7 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,15 @@

* Added `MonadParsec` instance for `RWST`.

* Allowed `many` to run parsers that do not consume input. Previously this
signalled an `error` which was ugly. Of course, in most cases giving
`many` a parser that do not consume input will lead to non-termination
bugs, but there are legal cases when this should be allowed. The test
suite now contains an example of this. Non-termination issues is something
inherited from the power Megaparsec gives (with more power comes more
responsibility), so that `error` case in `many` really does not solve the
problem, it was just a little ah-hoc guard we got from Parsec's past.

## Megaparsec 5.1.2

* Stopped using property tests with `dbg` helper to avoid flood of debugging
Expand Down
9 changes: 2 additions & 7 deletions Text/Megaparsec/Prim.hs
Expand Up @@ -385,14 +385,9 @@ manyAcc p = ParsecT $ \s cok cerr eok _ ->
unParser p s'
(seq xs $ walk $ x:xs) -- consumed-OK
cerr -- consumed-error
manyErr -- empty-OK
(seq xs $ walk $ x:xs) -- empty-OK
(errToHints $ cok (x:xs) s') -- empty-error
in unParser p s (walk []) cerr manyErr (errToHints $ eok [] s)

manyErr :: a
manyErr = error $
"Text.Megaparsec.Prim.many: combinator 'many' is applied to a parser"
++ " that may consume no input."
in unParser p s (walk []) cerr (walk []) (errToHints $ eok [] s)

instance (ErrorComponent e, Stream s)
=> Monad (ParsecT e s m) where
Expand Down
10 changes: 10 additions & 0 deletions tests/Text/Megaparsec/PrimSpec.hs
Expand Up @@ -336,6 +336,16 @@ spec = do
let p = many (char 'a') *> many (char 'b') *> eof
prs p "c" `shouldFailWith` err posI
(utok 'c' <> etok 'a' <> etok 'b' <> eeof)
context "when the argument parser succeeds without consuming" $
it "is run nevertheless" $
property $ \n' -> do
let n = getSmall (getNonNegative n') :: Integer
p = void . many $ do
x <- S.get
if x < n then S.modify (+ 1) else empty
v :: S.State Integer (Either (ParseError Char Dec) ())
v = runParserT p "" ""
S.execState v 0 `shouldBe` n

describe "some" $ do
context "when stream begins with things argument of some parses" $
Expand Down

0 comments on commit 5123241

Please sign in to comment.