git.iko.soy/typeable/attoparsec
on master help sign in
Snapshot.
6400b21Bryan O'Sullivan
LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright (c) Lennart Kolmodin
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions
7+are met:
8+
9+1. Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+2. Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+3. Neither the name of the author nor the names of his contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
21+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
24+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+POSSIBILITY OF SUCH DAMAGE.
bytestringparser.cabal+4−3
@@ -8,16 +8,16 @@ stability: experimental
8synopsis: Combinator parsing with Data.ByteString.Lazy
8synopsis: Combinator parsing with Data.ByteString.Lazy
9cabal-version: >= 1.2
9cabal-version: >= 1.2
10
10
11−flag bytestring-in-base
11+flag split-base
12flag applicative-in-base
12flag applicative-in-base
13
13
14library
14library
15− if flag(bytestring-in-base)
15+ if flag(split-base)
16 -- bytestring was in base-2.0 and 2.1.1
16 -- bytestring was in base-2.0 and 2.1.1
17 build-depends: base >= 2.0 && < 2.2
17 build-depends: base >= 2.0 && < 2.2
18 else
18 else
19 -- in base 1.0 and 3.0 bytestring is a separate package
19 -- in base 1.0 and 3.0 bytestring is a separate package
20− build-depends: base < 2.0 || >= 3, bytestring >= 0.9
20+ build-depends: base < 2.0 || >= 3, bytestring >= 0.9, containers >= 0.1.0.1
21
21
22 if flag(applicative-in-base)
22 if flag(applicative-in-base)
23 build-depends: base >= 2.0
23 build-depends: base >= 2.0
@@ -25,6 +25,7 @@ library
25 else
25 else
26 build-depends: base < 2.0
26 build-depends: base < 2.0
27
27
28+ extensions: CPP
28 exposed-modules: Text.ParserCombinators.ByteStringParser
29 exposed-modules: Text.ParserCombinators.ByteStringParser
29 hs-source-dirs: src
30 hs-source-dirs: src
30 ghc-options: -O2 -Wall -Werror
31 ghc-options: -O2 -Wall -Werror
src/Text/ParserCombinators/ByteStringParser.hs+110−42
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
2-----------------------------------------------------------------------------
1-----------------------------------------------------------------------------
3-- |
2-- |
4-- Module : Text.ParserCombinators.ByteStringParser
3-- Module : Text.ParserCombinators.ByteStringParser
@@ -9,7 +8,8 @@
9-- Stability : experimental
8-- Stability : experimental
10-- Portability : unknown
9-- Portability : unknown
11--
10--
12−-- Primitive parser combinators for ByteStrings loosely based on Parsec.
11+-- Simple, efficient parser combinators for lazy 'C.ByteString'
12+-- values, loosely based on 'Text.ParserCombinators.Parsec'.
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15module Text.ParserCombinators.ByteStringParser
15module Text.ParserCombinators.ByteStringParser
@@ -20,6 +20,7 @@ module Text.ParserCombinators.ByteStringParser
20
20
21 -- * Running parsers
21 -- * Running parsers
22 , parse
22 , parse
23+ , parseAt
23 , parseTest
24 , parseTest
24
25
25 -- * Combinators
26 -- * Combinators
@@ -35,6 +36,10 @@ module Text.ParserCombinators.ByteStringParser
35 , eof
36 , eof
36 , skipMany
37 , skipMany
37 , skipMany1
38 , skipMany1
39+ , count
40+ , lookAhead
41+ , sepBy
42+ , sepBy1
38
43
39 -- * Things like in @Parsec.Char@
44 -- * Things like in @Parsec.Char@
40 , satisfy
45 , satisfy
@@ -44,22 +49,30 @@ module Text.ParserCombinators.ByteStringParser
44 , space
49 , space
45 , char
50 , char
46 , string
51 , string
52+ , stringCI
53+ , byteString
54+ , byteStringCI
47
55
48 -- * Miscellaneous functions.
56 -- * Miscellaneous functions.
49 , getInput
57 , getInput
50 , getConsumed
58 , getConsumed
51 , takeWhile
59 , takeWhile
60+ , takeWhile1
61+ , takeAll
52 , skipWhile
62 , skipWhile
63+ , skipSpace
64+ , notEmpty
65+ , match
66+ , inClass
67+ , notInClass
53 ) where
68 ) where
54
69
55−#ifdef APPLICATIVE_IN_BASE
56import Control.Applicative (Applicative(..))
70import Control.Applicative (Applicative(..))
57−#endif
58−
59−import Control.Monad (MonadPlus(..), ap)
71+import Control.Monad (MonadPlus(..), ap, liftM2)
60import qualified Data.ByteString.Lazy.Char8 as C
72import qualified Data.ByteString.Lazy.Char8 as C
61−import Data.Char (isDigit, isLetter, isSpace)
73+import Data.Char (isDigit, isLetter, isSpace, toLower)
62import Data.Int (Int64)
74import Data.Int (Int64)
75+import qualified Data.Set as S
63import Prelude hiding (takeWhile)
76import Prelude hiding (takeWhile)
64
77
65type ParseError = (C.ByteString, String)
78type ParseError = (C.ByteString, String)
@@ -114,6 +127,7 @@ infixr 1 <|>
114-- | Choice.
127-- | Choice.
115(<|>) :: Parser a -> Parser a -> Parser a
128(<|>) :: Parser a -> Parser a -> Parser a
116(<|>) = mplus
129(<|>) = mplus
130+{-# INLINE (<|>) #-}
117
131
118-- | Name the parser.
132-- | Name the parser.
119(<?>) :: Parser a -> String -> Parser a
133(<?>) :: Parser a -> String -> Parser a
@@ -122,35 +136,31 @@ p <?> msg =
122 case unParser p s of
136 case unParser p s of
123 (Left _) -> Left (bs, [msg])
137 (Left _) -> Left (bs, [msg])
124 ok -> ok
138 ok -> ok
139+{-# INLINE (<?>) #-}
125
140
126-- | Get remaining input.
141-- | Get remaining input.
127getInput :: Parser C.ByteString
142getInput :: Parser C.ByteString
128getInput = Parser $ \s@(S bs _) -> Right (bs, s)
143getInput = Parser $ \s@(S bs _) -> Right (bs, s)
129
144
130−-- | Get remaining input.
145+-- | Get number of bytes consumed so far.
131getConsumed :: Parser Int64
146getConsumed :: Parser Int64
132getConsumed = Parser $ \s@(S _ n) -> Right (n, s)
147getConsumed = Parser $ \s@(S _ n) -> Right (n, s)
133
148
134−
135-- | Character parser.
149-- | Character parser.
136satisfy :: (Char -> Bool) -> Parser Char
150satisfy :: (Char -> Bool) -> Parser Char
137satisfy f =
151satisfy f =
138 Parser $ \(S bs n) ->
152 Parser $ \(S bs n) ->
139− if C.null bs
153+ case C.uncons bs of
140− then Left (bs, [])
141− else let Just (s, bs') = C.uncons bs in
142− if f s
143− then Right (s, S bs' (n + 1))
154+ Just (s, bs') | f s -> Right (s, S bs' (n + 1))
144− else Left (bs, [])
155+ _ -> Left (bs, [])
145{-# INLINE satisfy #-}
156{-# INLINE satisfy #-}
146
157
147−
148letter :: Parser Char
158letter :: Parser Char
149−letter = satisfy isLetter
159+letter = satisfy isLetter <?> "letter"
150{-# INLINE letter #-}
160{-# INLINE letter #-}
151
161
152digit :: Parser Char
162digit :: Parser Char
153−digit = satisfy isDigit
163+digit = satisfy isDigit <?> "digit"
154{-# INLINE digit #-}
164{-# INLINE digit #-}
155
165
156anyChar :: Parser Char
166anyChar :: Parser Char
@@ -158,19 +168,64 @@ anyChar = satisfy $ const True
158{-# INLINE anyChar #-}
168{-# INLINE anyChar #-}
159
169
160space :: Parser Char
170space :: Parser Char
161−space = satisfy isSpace
171+space = satisfy isSpace <?> "space"
162{-# INLINE space #-}
172{-# INLINE space #-}
163
173
164-- | Satisfy a specific character.
174-- | Satisfy a specific character.
165−
166char :: Char -> Parser Char
175char :: Char -> Parser Char
167char c = satisfy (== c) <?> [c]
176char c = satisfy (== c) <?> [c]
168{-# INLINE char #-}
177{-# INLINE char #-}
169
178
179+charClass :: String -> S.Set Char
180+charClass s = S.fromList (go s)
181+ where go (a:'-':b:xs) = [a..b] ++ go xs
182+ go (x:xs) = x : go xs
183+ go _ = ""
184+
185+inClass :: String -> Char -> Bool
186+inClass s = (`S.member` set)
187+ where set = charClass s
188+
189+notInClass :: String -> Char -> Bool
190+notInClass s = (`S.notMember` set)
191+ where set = charClass s
192+
193+sepBy :: Parser a -> Parser s -> Parser [a]
194+sepBy p s = liftM2 (:) p ((s >> sepBy1 p s) <|> return []) <|> return []
195+
196+sepBy1 :: Parser a -> Parser s -> Parser [a]
197+sepBy1 p s = liftM2 (:) p ((s >> sepBy1 p s) <|> return [])
198+
199+-- | Satisfy a literal string.
200+byteString :: C.ByteString -> Parser C.ByteString
201+byteString s = Parser $ \(S bs n) ->
202+ let l = C.length s
203+ (h, t) = C.splitAt l bs
204+ in if s == h
205+ then Right (s, S t (n + l))
206+ else Left (bs, [])
207+{-# INLINE byteString #-}
208+
209+-- | Satisfy a literal string.
210+byteStringCI :: C.ByteString -> Parser C.ByteString
211+byteStringCI s = Parser $ \(S bs n) ->
212+ let l = C.length s
213+ (h, t) = C.splitAt l bs
214+ in if ls == C.map toLower h
215+ then Right (s, S t (n + l))
216+ else Left (bs, [])
217+ where ls = C.map toLower s
218+{-# INLINE byteStringCI #-}
219+
170string :: String -> Parser String
220string :: String -> Parser String
171−string s = mapM char s <?> show s
221+string s = byteString (C.pack s) >> return s
172{-# INLINE string #-}
222{-# INLINE string #-}
173
223
224+stringCI :: String -> Parser String
225+stringCI s = byteStringCI (C.pack s) >> return s
226+{-# INLINE stringCI #-}
227+
228+-- | Apply the given parser repeatedly, returning every parse result.
174count :: Int -> Parser a -> Parser [a]
229count :: Int -> Parser a -> Parser [a]
175count n p = sequence (replicate n p)
230count n p = sequence (replicate n p)
176{-# INLINE count #-}
231{-# INLINE count #-}
@@ -187,15 +242,33 @@ eof = Parser $ \s@(S bs _) -> if C.null bs
187 then Right ((), s)
242 then Right ((), s)
188 else Left (bs, ["EOF"])
243 else Left (bs, ["EOF"])
189
244
245+takeAll :: Parser C.ByteString
246+takeAll = Parser $ \(S bs n) -> Right (bs, S C.empty (n + C.length bs))
247+
190-- | Consume characters while the predicate is true.
248-- | Consume characters while the predicate is true.
191takeWhile :: (Char -> Bool) -> Parser C.ByteString
249takeWhile :: (Char -> Bool) -> Parser C.ByteString
192takeWhile f = Parser $ \(S bs n) ->
250takeWhile f = Parser $ \(S bs n) ->
193 let (h, bs') = C.span f bs
251 let (h, bs') = C.span f bs
194 in Right (h, S bs' (n + C.length h))
252 in Right (h, S bs' (n + C.length h))
253+{-# INLINE takeWhile #-}
254+
255+takeWhile1 :: (Char -> Bool) -> Parser C.ByteString
256+takeWhile1 f = Parser $ \(S bs n) ->
257+ let (h, bs') = C.span f bs
258+ in if C.null h
259+ then Left (bs, [])
260+ else Right (h, S bs' (n + C.length h))
261+{-# INLINE takeWhile1 #-}
195
262
196-- | Skip over characters while the predicate is true.
263-- | Skip over characters while the predicate is true.
197skipWhile :: (Char -> Bool) -> Parser ()
264skipWhile :: (Char -> Bool) -> Parser ()
198skipWhile p = takeWhile p >> return ()
265skipWhile p = takeWhile p >> return ()
266+{-# INLINE skipWhile #-}
267+
268+-- | Skip over white space.
269+skipSpace :: Parser ()
270+skipSpace = takeWhile isSpace >> return ()
271+{-# INLINE skipSpace #-}
199
272
200-- | Take zero or more instances of the parser.
273-- | Take zero or more instances of the parser.
201many :: Parser a -> Parser [a]
274many :: Parser a -> Parser [a]
@@ -206,24 +279,16 @@ many p = scan id
206
279
207-- | Take one or more instances of the parser.
280-- | Take one or more instances of the parser.
208many1 :: Parser a -> Parser [a]
281many1 :: Parser a -> Parser [a]
209−many1 p =
282+many1 p = liftM2 (:) p (many p)
210− do x <- p
211− xs <- many p
212− return (x:xs)
213
283
214manyTill :: Parser a -> Parser b -> Parser [a]
284manyTill :: Parser a -> Parser b -> Parser [a]
215manyTill p end = scan
285manyTill p end = scan
216− where scan = do end; return []
286+ where scan = (end >> return []) <|> liftM2 (:) p scan
217− <|>
218− do x <- p
219− xs <- scan
220− return (x:xs)
221
287
222-- |'skipMany' - skip zero or many instances of the parser
288-- |'skipMany' - skip zero or many instances of the parser
223skipMany :: Parser a -> Parser ()
289skipMany :: Parser a -> Parser ()
224skipMany p = scan
290skipMany p = scan
225− where
226− scan = (p >> scan) <|> return ()
291+ where scan = (p >> scan) <|> return ()
227
292
228-- |'skipMany1' - skip one or many instances of the parser
293-- |'skipMany1' - skip one or many instances of the parser
229skipMany1 :: Parser a -> Parser ()
294skipMany1 :: Parser a -> Parser ()
@@ -248,24 +313,27 @@ match p = do bs <- getInput
248 end <- getConsumed
313 end <- getConsumed
249 return (C.take (end - start) bs)
314 return (C.take (end - start) bs)
250
315
251−lookAhead :: Parser a -> Parser a
316+lookAhead :: Parser a -> Parser (Maybe a)
252−
253−lookAhead p = Parser $ \s@(S bs _) ->
317+lookAhead p = Parser $ \s ->
254 case unParser p s of
318 case unParser p s of
255− Left (_, msgs) -> Left (bs, msgs)
319+ Right (m, _) -> Right (Just m, s)
256− Right (m, _) -> Right (m, s)
320+ _ -> Right (Nothing, s)
257
321
258−-- | Run a parser.
259−parse :: Parser a -> C.ByteString
322+parseAt :: Parser a -> C.ByteString -> Int64
260− -> Either ParseError (a, C.ByteString)
323+ -> Either ParseError (a, C.ByteString)
261−parse p bs =
324+parseAt p bs n =
262− case unParser p (S bs 0) of
325+ case unParser p (S bs n) of
263 Left (bs', msg) -> Left (bs', showError msg)
326 Left (bs', msg) -> Left (bs', showError msg)
264 Right (a, S bs' _) -> Right (a, bs')
327 Right (a, S bs' _) -> Right (a, bs')
265 where
328 where
266 showError [msg] = "Parser error, expected:\n" ++ msg ++ "\n"
329 showError [msg] = "Parser error, expected:\n" ++ msg ++ "\n"
267 showError msgs = "Parser error, expected one of:\n" ++ unlines msgs
330 showError msgs = "Parser error, expected one of:\n" ++ unlines msgs
268
331
332+-- | Run a parser.
333+parse :: Parser a -> C.ByteString
334+ -> Either ParseError (a, C.ByteString)
335+parse p bs = parseAt p bs 0
336+
269parseTest :: (Show a) => Parser a -> C.ByteString -> IO ()
337parseTest :: (Show a) => Parser a -> C.ByteString -> IO ()
270parseTest p s =
338parseTest p s =
271 case parse p s of
339 case parse p s of