1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
4 -- Module : Text.ParserCombinators.ReadP
5 -- Copyright : (c) The University of Glasgow 2002
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : libraries@haskell.org
9 -- Stability : provisional
10 -- Portability : portable
12 -- "ReadP" is a library of parser combinators, originally written by Koen Claessen.
13 -- It parses all alternatives in parallel, so it never keeps hold of
14 -- the beginning of the input string, a common source of space leaks with
15 -- other parsers. The '(+++)' choice combinator is genuinely commutative;
16 -- it makes no difference which branch is "shorter".
18 -----------------------------------------------------------------------------
20 module Text.ParserCombinators.ReadP
23 ReadP, -- :: * -> *; instance Functor, Monad, MonadPlus
25 -- * Primitive operations
27 look, -- :: ReadP String
28 (+++), -- :: ReadP a -> ReadP a -> ReadP a
29 gather, -- :: ReadP a -> ReadP (String, a)
33 satisfy, -- :: (Char -> Bool) -> ReadP Char
34 char, -- :: Char -> ReadP Char
35 string, -- :: String -> ReadP String
36 munch, -- :: (Char -> Bool) -> ReadP String
37 munch1, -- :: (Char -> Bool) -> ReadP String
38 skipSpaces, -- :: ReadP ()
39 choice, -- :: [ReadP a] -> ReadP a
42 readP_to_S, -- :: ReadP a -> ReadS a
43 readS_to_P, -- :: ReadS a -> ReadP a
47 import Control.Monad( MonadPlus(..) )
48 import GHC.Show( isSpace )
51 -- ---------------------------------------------------------------------------
54 newtype ReadP a = R (forall b . (a -> P b) -> P b)
58 | Look (String -> P a)
63 -- We define a local version of ReadS here,
64 -- because its "real" definition site is in GHC.Read
65 type ReadS a = String -> [(a,String)]
67 -- Functor, Monad, MonadPlus
69 instance Functor ReadP where
70 fmap h (R f) = R (\k -> f (k . h))
72 instance Monad ReadP where
73 return x = R (\k -> k x)
74 fail _ = R (\_ -> Fail)
75 R m >>= f = R (\k -> m (\a -> let R m' = f a in m' k))
77 instance MonadPlus ReadP where
81 -- ---------------------------------------------------------------------------
82 -- Operations over ReadP
88 look = R (\k -> Look k)
90 (+++) :: ReadP a -> ReadP a -> ReadP a
91 R f1 +++ R f2 = R (\k -> f1 k >|< f2 k)
93 gather :: ReadP a -> ReadP (String, a)
94 -- ^ Transforms a parser into one that does the same, but
95 -- in addition returns the exact characters read.
96 -- IMPORTANT NOTE: 'gather' gives a runtime error if its first argument
97 -- is built using any occurrences of readS_to_P.
99 = R (\k -> gath id (m (\a -> Result (\s -> k (s,a)) Fail)))
101 gath l (Get f) = Get (\c -> gath (l.(c:)) (f c))
103 gath l (Look f) = Look (\s -> gath l (f s))
104 gath l (Result k p) = k (l []) >|< gath l p
105 gath l (ReadS r) = error "do not use ReadS in gather!"
107 (>|<) :: P a -> P a -> P a
108 -- Not exported! Works over the representation type
109 Get f1 >|< Get f2 = Get (\c -> f1 c >|< f2 c)
112 Look f >|< Look g = Look (\s -> f s >|< g s)
113 Result x p >|< q = Result x (p >|< q)
114 p >|< Result x q = Result x (p >|< q)
115 Look f >|< p = Look (\s -> f s >|< p)
116 p >|< Look f = Look (\s -> p >|< f s)
117 p >|< q = ReadS (\s -> run p s ++ run q s)
119 run :: P a -> ReadS a
121 run (Get f) (c:s) = run (f c) s
122 run (Look f) s = run (f s) s
123 run (Result x p) s = (x,s) : run p s
124 run (ReadS r) s = r s
127 -- ---------------------------------------------------------------------------
128 -- Derived operations
133 satisfy :: (Char -> Bool) -> ReadP Char
134 satisfy p = do c <- get; if p c then return c else pfail
136 char :: Char -> ReadP Char
137 char c = satisfy (c ==)
139 string :: String -> ReadP String
142 scan [] = do return s
143 scan (c:cs) = do char c; scan cs
145 munch :: (Char -> Bool) -> ReadP String
146 -- (munch p) parses the first zero or more characters satisfying p
151 scan (c:cs) | p c = do get; s <- scan cs; return (c:s)
152 scan _ = do return ""
154 munch1 :: (Char -> Bool) -> ReadP String
155 -- (munch p) parses the first one or more characters satisfying p
158 if p c then do s <- munch p; return (c:s) else pfail
160 choice :: [ReadP a] -> ReadP a
161 choice ps = foldr (+++) pfail ps
163 skipSpaces :: ReadP ()
168 skip (c:s) | isSpace c = do get; skip s
169 skip _ = do return ()
171 -- ---------------------------------------------------------------------------
172 -- Converting between ReadP and Read
174 readP_to_S :: ReadP a -> ReadS a
175 readP_to_S (R f) = run (f (\x -> Result x Fail))
177 readS_to_P :: ReadS a -> ReadP a
178 readS_to_P r = R (\k -> ReadS (\s -> [ bs''
180 , bs'' <- run (k a) s'