@@ -0,0 +1,89 @@
1+-- |
2+-- Module : Data.Attoparsec.Lazy
3+-- Copyright : Bryan O'Sullivan 2010
4+-- License : BSD3
5+--
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : unknown
9+--
10+-- Simple, efficient combinator parsing for lazy 'ByteString'
11+-- strings, loosely based on the Parsec library.
12+--
13+-- This is essentially the same code as in the 'Data.Attoparsec'
14+-- module, only with a 'parse' function that can consume a lazy
15+-- 'ByteString' incrementally, and a 'Result' type that does not allow
16+-- more input to be fed in. Think of this as suitable for use with a
17+-- lazily read file, e.g. via 'L.readFile' or 'L.hGetContents'.
18+--
19+-- Behind the scenes, strict 'B.ByteString' values are still used
20+-- internally to store parser input and handle it efficiently.
21+
22+module Data.Attoparsec.Lazy
23+ (
24+ Result(..)
25+ , module Data.Attoparsec
26+ -- * Running parsers
27+ , parse
28+ , parseTest
29+ -- ** Result conversion
30+ , maybeResult
31+ , eitherResult
32+ ) where
33+
34+import Data.ByteString.Lazy.Internal (ByteString(..), chunk)
35+import qualified Data.ByteString.Lazy as L
36+import qualified Data.ByteString as B
37+import qualified Data.Attoparsec as A
38+import Data.Attoparsec hiding (Result(..), eitherResult, maybeResult,
39+ parse, parseWith, parseTest)
40+
41+-- | The result of a parse.
42+data Result r = Fail ByteString [String] String
43+ -- ^ The parse failed. The 'ByteString' is the input
44+ -- that had not yet been consumed when the failure
45+ -- occurred. The @[@'String'@]@ is a list of contexts
46+ -- in which the error occurred. The 'String' is the
47+ -- message describing the error, if any.
48+ | Done ByteString r
49+ -- ^ The parse succeeded. The 'ByteString' is the
50+ -- input that had not yet been consumed (if any) when
51+ -- the parse succeeded.
52+
53+instance Show r => Show (Result r) where
54+ show (Fail bs stk msg) =
55+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg
56+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r
57+
58+fmapR :: (a -> b) -> Result a -> Result b
59+fmapR _ (Fail st stk msg) = Fail st stk msg
60+fmapR f (Done bs r) = Done bs (f r)
61+
62+instance Functor Result where
63+ fmap = fmapR
64+
65+-- | Run a parser and return its result.
66+parse :: A.Parser a -> ByteString -> Result a
67+parse p s = case s of
68+ Chunk x xs -> go (A.parse p x) xs
69+ empty -> go (A.parse p B.empty) empty
70+ where
71+ go (A.Fail x stk msg) ys = Fail (chunk x ys) stk msg
72+ go (A.Done x r) ys = Done (chunk x ys) r
73+ go (A.Partial k) (Chunk y ys) = go (k y) ys
74+ go (A.Partial k) empty = go (k B.empty) empty
75+
76+-- | Run a parser and print its result to standard output.
77+parseTest :: (Show a) => A.Parser a -> ByteString -> IO ()
78+parseTest p s = print (parse p s)
79+
80+-- | Convert a 'Result' value to a 'Maybe' value.
81+maybeResult :: Result r -> Maybe r
82+maybeResult (Done _ r) = Just r
83+maybeResult _ = Nothing
84+
85+-- | Convert a 'Result' value to an 'Either' value.
86+eitherResult :: Result r -> Either String r
87+eitherResult (Done _ r) = Right r
88+eitherResult (Fail _ _ msg) = Left msg
89+eitherResult _ = Left "Result: incomplete input"