Add parserTrace and parserTraced functions (#85)
authorgbaz <gershomb@gmail.com>
Sun, 31 Dec 2017 08:56:57 +0000 (03:56 -0500)
committerHerbert Valerio Riedel <hvr@gnu.org>
Sun, 31 Dec 2017 08:56:57 +0000 (09:56 +0100)
`parserTrace label` is an impure function, implemented with "Debug.Trace" that
prints to the console the remaining parser state at the time it is invoked.
It is intended to be used for debugging parsers by inspecting their intermediate states.

These are simple yet helpful helpers for debugging Parsec parsers.

Closes #63

ChangeLog.md
src/Text/Parsec.hs
src/Text/Parsec/Combinator.hs

index bc13369..e8d6a2f 100644 (file)
@@ -3,6 +3,7 @@
 - Add `MonadFail` instance for `ParsecT`
 - Add `Semigroup`/`Monoid` instances for `ParsecT` (#80,#82)
 - Fix space leak in Applicative/Monad interface (#37)
+- Add `parserTrace` and `parserTraced` combinators for debugging.
 
 ### 3.1.11
 
index 18684d6..c7400a9 100644 (file)
@@ -82,6 +82,8 @@ module Text.Parsec
     , sourceName, sourceLine, sourceColumn
     , incSourceLine, incSourceColumn
     , setSourceLine, setSourceColumn, setSourceName
+     -- * Debugging
+    , parserTrace, parserTraced
      -- * Low-level operations
     , manyAccum
     , tokenPrim
index fc0dad1..3df7f37 100644 (file)
@@ -30,10 +30,13 @@ module Text.Parsec.Combinator
     , eof, notFollowedBy
     -- tricky combinators
     , manyTill, lookAhead, anyToken
+    -- * Debugging
+    , parserTrace, parserTraced
     ) where
 
 import Control.Monad
 import Text.Parsec.Prim
+import Debug.Trace (trace)
 
 -- | @choice ps@ tries to apply the parsers in the list @ps@ in order,
 -- until one of them succeeds. Returns the value of the succeeding
@@ -289,3 +292,38 @@ manyTill p end      = scan
                       scan  = do{ _ <- end; return [] }
                             <|>
                               do{ x <- p; xs <- scan; return (x:xs) }
+
+-- | @parserTrace label@ is an impure function, implemented with "Debug.Trace" that
+-- prints to the console the remaining parser state at the time it is invoked.
+-- It is intended to be used for debugging parsers by inspecting their intermediate states.
+--
+-- > *> parseTest (oneOf "aeiou"  >> parserTrace "label") "atest"
+-- > label: "test"
+-- > ...
+--
+-- @since 3.1.12.0
+parserTrace :: (Show t, Stream s m t) => String -> ParsecT s u m ()
+parserTrace s = pt <|> return ()
+    where
+        pt = try $ do
+           x <- try $ many1 anyToken
+           trace (s++": " ++ show x) $ try $ eof
+           fail (show x)
+
+-- | @parserTraced label p@ is an impure function, implemented with "Debug.Trace" that
+-- prints to the console the remaining parser state at the time it is invoked.
+-- It then continues to apply parser @p@, and if @p@ fails will indicate that
+-- the label has been backtracked.
+-- It is intended to be used for debugging parsers by inspecting their intermediate states.
+--
+-- > *>  parseTest (oneOf "aeiou"  >> parserTraced "label" (oneOf "nope")) "atest"
+-- > label: "test"
+-- > label backtracked
+-- > parse error at (line 1, column 2):
+-- > ...
+--
+-- @since 3.1.12.0
+parserTraced :: (Stream s m t, Show t) => String -> ParsecT s u m b -> ParsecT s u m b
+parserTraced s p = do
+  parserTrace s
+  p <|> trace (s ++ " backtracked") (fail s)