1-- | This module provides support for parsing values from Text
2-- 'InputStream's using @attoparsec@. /Since: 1.4.0.0./
3
4module System.IO.Streams.Attoparsec.Text
5  ( -- * Parsing
6    parseFromStream
7  , parserToInputStream
8  , ParseException(..)
9  ) where
10
11------------------------------------------------------------------------------
12import           Data.Attoparsec.Text                  (Parser)
13import           Data.Text                             (Text)
14------------------------------------------------------------------------------
15import           System.IO.Streams.Internal            (InputStream)
16import qualified System.IO.Streams.Internal            as Streams
17import           System.IO.Streams.Internal.Attoparsec (ParseData (..), ParseException (..), parseFromStreamInternal)
18
19
20------------------------------------------------------------------------------
21-- | Supplies an @attoparsec@ 'Parser' with an 'InputStream', returning the
22-- final parsed value or throwing a 'ParseException' if parsing fails.
23--
24-- 'parseFromStream' consumes only as much input as necessary to satisfy the
25-- 'Parser': any unconsumed input is pushed back onto the 'InputStream'.
26--
27-- If the 'Parser' exhausts the 'InputStream', the end-of-stream signal is sent
28-- to attoparsec.
29--
30-- Example:
31--
32-- @
33-- ghci> import "Data.Attoparsec.Text"
34-- ghci> is <- 'System.IO.Streams.fromList' [\"12345xxx\" :: 'Text']
35-- ghci> 'parseFromStream' ('Data.Attoparsec.Text.takeWhile' 'Data.Char.isDigit') is
36-- \"12345\"
37-- ghci> 'System.IO.Streams.read' is
38-- Just \"xxx\"
39-- @
40parseFromStream :: Parser r
41                -> InputStream Text
42                -> IO r
43parseFromStream = parseFromStreamInternal parse feed
44
45------------------------------------------------------------------------------
46-- | Given a 'Parser' yielding values of type @'Maybe' r@, transforms an
47-- 'InputStream' over byte strings to an 'InputStream' yielding values of type
48-- @r@.
49--
50-- If the parser yields @Just x@, then @x@ will be passed along downstream, and
51-- if the parser yields @Nothing@, that will be interpreted as end-of-stream.
52--
53-- Upon a parse error, 'parserToInputStream' will throw a 'ParseException'.
54--
55-- Example:
56--
57-- @
58-- ghci> import "Control.Applicative"
59-- ghci> import "Data.Attoparsec.Text"
60-- ghci> is <- 'System.IO.Streams.fromList' [\"1 2 3 4 5\" :: 'Text']
61-- ghci> let parser = ('Data.Attoparsec.Text.endOfInput' >> 'Control.Applicative.pure' 'Nothing') \<|\> (Just \<$\> ('Data.Attoparsec.Text.skipWhile' 'Data.Attoparsec.Text.isSpace' *> 'Data.Attoparsec.Text.decimal'))
62-- ghci> 'parserToInputStream' parser is >>= 'System.IO.Streams.toList'
63-- [1,2,3,4,5]
64-- ghci> is' \<- 'System.IO.Streams.fromList' [\"1 2xx3 4 5\" :: 'Text'] >>= 'parserToInputStream' parser
65-- ghci> 'read' is'
66-- Just 1
67-- ghci> 'read' is'
68-- Just 2
69-- ghci> 'read' is'
70-- *** Exception: Parse exception: Failed reading: takeWhile1
71-- @
72parserToInputStream :: Parser (Maybe r)
73                    -> InputStream Text
74                    -> IO (InputStream r)
75parserToInputStream = (Streams.makeInputStream .) . parseFromStream
76{-# INLINE parserToInputStream #-}
77