git.iko.soy/typeable/attoparsec
on master help sign in
WIP
commit1abf7ed2e3f66dfffb9a38d2b4eb559830098788 authorBryan O'Sullivan <bos@serpentine.com> dateFri 9 Jan 2009, 07:53 (18 years ago) parent522fd53
8 files changed+333−176
attoparsec.cabal+5 src/Data/ParserCombinators/Attoparsec.hs−1 src/Data/ParserCombinators/Attoparsec/Char8.hs+5−67 src/Data/ParserCombinators/Attoparsec/Char8Boilerplate.h+66 src/Data/ParserCombinators/Attoparsec/Incremental.hs+83−40 src/Data/ParserCombinators/Attoparsec/Incremental/Char8.hs+103 src/Data/ParserCombinators/Attoparsec/Internal.hs+11−68 src/Data/ParserCombinators/Attoparsec/Word8Boilerplate.h+60
attoparsec.cabal+5
@@ -6,11 +6,15 @@ category: Text, Parsing
66author: Bryan O'Sullivan <bos@serpentine.com>
77maintainer: Bryan O'Sullivan <bos@serpentine.com>
88stability: experimental
9+tested-with: GHC == 6.8.3, GHC == 6.10.1
910synopsis: Fast combinator parsing with Data.ByteString.Lazy
1011description: Fast combinator parsing with Data.ByteString.Lazy
1112cabal-version: >= 1.2
1213build-type: Simple
1314description: Fast, flexible text-oriented parsing of lazy ByteStrings.
15+extra-source-files:
16+ src/Data/ParserCombinators/Attoparsec/Char8Boilerplate.h
17+ src/Data/ParserCombinators/Attoparsec/Word8Boilerplate.h
1418
1519flag split-base
1620flag applicative-in-base
@@ -35,6 +39,7 @@ library
3539 exposed-modules: Data.ParserCombinators.Attoparsec
3640 Data.ParserCombinators.Attoparsec.Char8
3741 Data.ParserCombinators.Attoparsec.Incremental
42+ Data.ParserCombinators.Attoparsec.Incremental.Char8
3843 Data.ParserCombinators.Attoparsec.FastSet
3944 Data.ParserCombinators.Attoparsec.Internal
4045 hs-source-dirs: src
src/Data/ParserCombinators/Attoparsec.hs−1
@@ -28,7 +28,6 @@ module Data.ParserCombinators.Attoparsec
2828
2929 -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
3030 , try
31− , many
3231 , many1
3332 , manyTill
3433 , eof
src/Data/ParserCombinators/Attoparsec/Char8.hs+5−67
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12-----------------------------------------------------------------------------
23-- |
34-- Module : Data.ParserCombinators.Attoparsec.Char8
@@ -28,7 +29,6 @@ module Data.ParserCombinators.Attoparsec.Char8
2829
2930 -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
3031 , try
31− , many
3232 , many1
3333 , manyTill
3434 , eof
@@ -88,84 +88,19 @@ import Data.ParserCombinators.Attoparsec.Internal
8888 (Parser, ParseError, (<?>), parse, parseAt, parseTest, try, manyTill, eof,
8989 skipMany, skipMany1, count, lookAhead, peek, sepBy, sepBy1, string,
9090 eitherP, getInput, getConsumed, takeAll, takeCount, notEmpty, match,
91− endOfLine, setInput, many, many1)
91+ endOfLine, setInput, many1)
9292import Data.ByteString.Lex.Lazy.Double (readDouble)
9393import Prelude hiding (takeWhile)
9494
95−-- | Character parser.
96−satisfy :: (Char -> Bool) -> Parser Char
97−satisfy p = w2c <$> I.satisfy (p . w2c)
98−{-# INLINE satisfy #-}
99−
100−letter :: Parser Char
101−letter = satisfy isLetter <?> "letter"
102−{-# INLINE letter #-}
103−
104−digit :: Parser Char
105−digit = satisfy isDigit <?> "digit"
106−{-# INLINE digit #-}
107−
108−anyChar :: Parser Char
109−anyChar = satisfy $ const True
110−{-# INLINE anyChar #-}
111−
112−space :: Parser Char
113−space = satisfy isSpace <?> "space"
114−{-# INLINE space #-}
115−
116−-- | Satisfy a specific character.
117−char :: Char -> Parser Char
118−char c = satisfy (== c) <?> [c]
119−{-# INLINE char #-}
120−
121−-- | Satisfy a specific character.
122−notChar :: Char -> Parser Char
123−notChar c = satisfy (/= c) <?> "not " ++ [c]
124−{-# INLINE notChar #-}
125−
126−charClass :: String -> FastSet
127−charClass = set . SB.pack . go
128− where go (a:'-':b:xs) = [a..b] ++ go xs
129− go (x:xs) = x : go xs
130− go _ = ""
131−
132−inClass :: String -> Char -> Bool
133−inClass s = (`memberChar` myset)
134− where myset = charClass s
135−{-# INLINE inClass #-}
136−
137−notInClass :: String -> Char -> Bool
138−notInClass s = not . inClass s
139−{-# INLINE notInClass #-}
140−
14195-- | Satisfy a literal string, ignoring case.
14296stringCI :: LB.ByteString -> Parser LB.ByteString
14397stringCI = I.stringTransform (LB.map toLower)
14498{-# INLINE stringCI #-}
14599
146−-- | Consume characters while the predicate is true.
147−takeWhile :: (Char -> Bool) -> Parser LB.ByteString
148−takeWhile p = I.takeWhile (p . w2c)
149−{-# INLINE takeWhile #-}
150−
151−takeTill :: (Char -> Bool) -> Parser LB.ByteString
152−takeTill p = I.takeTill (p . w2c)
153−{-# INLINE takeTill #-}
154−
155100takeWhile1 :: (Char -> Bool) -> Parser LB.ByteString
156101takeWhile1 p = I.takeWhile1 (p . w2c)
157102{-# INLINE takeWhile1 #-}
158103
159−-- | Skip over characters while the predicate is true.
160−skipWhile :: (Char -> Bool) -> Parser ()
161−skipWhile p = I.skipWhile (p . w2c)
162−{-# INLINE skipWhile #-}
163−
164−-- | Skip over white space.
165−skipSpace :: Parser ()
166−skipSpace = takeWhile isSpace >> return ()
167−{-# INLINE skipSpace #-}
168−
169104numeric :: String -> (LB.ByteString -> Maybe (a,LB.ByteString)) -> Parser a
170105numeric desc f = do
171106 s <- getInput
@@ -184,3 +119,6 @@ integer = numeric "Integer" LB.readInteger
184119-- | Parse a Double. The position counter is not updated.
185120double :: Parser Double
186121double = numeric "Double" readDouble
122+
123+#define PARSER Parser
124+#include "Char8Boilerplate.h"
src/Data/ParserCombinators/Attoparsec/Char8Boilerplate.hnew file+66
@@ -0,0 +1,66 @@
1+-- -*- haskell -*-
2+
3+-- | Character parser.
4+satisfy :: (Char -> Bool) -> PARSER Char
5+satisfy p = w2c <$> I.satisfy (p . w2c)
6+{-# INLINE satisfy #-}
7+
8+letter :: PARSER Char
9+letter = satisfy isLetter <?> "letter"
10+{-# INLINE letter #-}
11+
12+digit :: PARSER Char
13+digit = satisfy isDigit <?> "digit"
14+{-# INLINE digit #-}
15+
16+anyChar :: PARSER Char
17+anyChar = satisfy $ const True
18+{-# INLINE anyChar #-}
19+
20+space :: PARSER Char
21+space = satisfy isSpace <?> "space"
22+{-# INLINE space #-}
23+
24+-- | Satisfy a specific character.
25+char :: Char -> PARSER Char
26+char c = satisfy (== c) <?> [c]
27+{-# INLINE char #-}
28+
29+-- | Satisfy a specific character.
30+notChar :: Char -> PARSER Char
31+notChar c = satisfy (/= c) <?> "not " ++ [c]
32+{-# INLINE notChar #-}
33+
34+charClass :: String -> FastSet
35+charClass = set . SB.pack . go
36+ where go (a:'-':b:xs) = [a..b] ++ go xs
37+ go (x:xs) = x : go xs
38+ go _ = ""
39+
40+inClass :: String -> Char -> Bool
41+inClass s = (`memberChar` myset)
42+ where myset = charClass s
43+{-# INLINE inClass #-}
44+
45+notInClass :: String -> Char -> Bool
46+notInClass s = not . inClass s
47+{-# INLINE notInClass #-}
48+
49+-- | Consume characters while the predicate is true.
50+takeWhile :: (Char -> Bool) -> PARSER LB.ByteString
51+takeWhile p = I.takeWhile (p . w2c)
52+{-# INLINE takeWhile #-}
53+
54+takeTill :: (Char -> Bool) -> PARSER LB.ByteString
55+takeTill p = I.takeTill (p . w2c)
56+{-# INLINE takeTill #-}
57+
58+-- | Skip over characters while the predicate is true.
59+skipWhile :: (Char -> Bool) -> PARSER ()
60+skipWhile p = I.skipWhile (p . w2c)
61+{-# INLINE skipWhile #-}
62+
63+-- | Skip over white space.
64+skipSpace :: PARSER ()
65+skipSpace = takeWhile isSpace >> return ()
66+{-# INLINE skipSpace #-}
src/Data/ParserCombinators/Attoparsec/Incremental.hs+83−40
@@ -1,3 +1,4 @@
1+{-# LANGUAGE BangPatterns, CPP #-}
12-----------------------------------------------------------------------------
23-- |
34-- Module : Data.ParserCombinators.Attoparsec.Incremental
@@ -11,8 +12,8 @@
1112-- Simple, efficient parser combinators for lazy 'LB.ByteString'
1213-- strings, loosely based on 'Text.ParserCombinators.Parsec'.
1314--
14−-- Heavily influenced by Adam Langley's incremental parser in the
15−-- binary-strict package.
15+-- This module is heavily influenced by Adam Langley's incremental
16+-- parser in his binary-strict package.
1617--
1718-----------------------------------------------------------------------------
1819module Data.ParserCombinators.Attoparsec.Incremental
@@ -21,14 +22,31 @@ module Data.ParserCombinators.Attoparsec.Incremental
2122 , Result(..)
2223 , parse
2324
25+ , (<?>)
2426 , takeWhile
2527 , takeTill
28+ , takeCount
2629 , string
30+ , satisfy
31+ , pushBack
32+
33+ , word8
34+ , notWord8
35+ , anyWord8
36+
37+ , many1
38+ , skipWhile
39+ , skipMany
40+ , skipMany1
41+ , sepBy
42+ , sepBy1
43+ , manyTill
44+ , count
2745
2846 , yield
2947 ) where
3048
31−import Control.Applicative (Alternative(..), Applicative(..))
49+import Control.Applicative
3250import Control.Monad (MonadPlus(..), ap)
3351import Data.ParserCombinators.Attoparsec.Internal ((+:))
3452import Data.Word (Word8)
@@ -121,17 +139,16 @@ plus p1 p2 =
121139instance Functor (Parser r) where
122140 fmap f m = Parser $ \s cont -> unParser m s (cont . f)
123141
124−instance MonadPlus (Parser r) where
125− mzero = zero
126− mplus = plus
142+infix 0 <?>
127143
128−instance Applicative (Parser r) where
129− pure = return
130− (<*>) = ap
131−
132−instance Alternative (Parser r) where
133− empty = zero
134− (<|>) = plus
144+-- | Name the parser.
145+(<?>) :: Parser r a -> String -> Parser r a
146+{-# INLINE (<?>) #-}
147+p <?> msg =
148+ Parser $ \st k ->
149+ case unParser p st k of
150+ IFailed st' _ -> IFailed st' msg
151+ ok -> ok
135152
136153initState :: S.ByteString -> S
137154initState input = S input L.empty [] 0
@@ -158,39 +175,62 @@ takeWith :: (L.ByteString -> (L.ByteString, L.ByteString))
158175 -> Parser r L.ByteString
159176takeWith splitf =
160177 Parser $ \(S sb lb adds failDepth) k ->
161− let bs = sb +: lb
162− (left,rest) = splitf bs
163− in case rest of
164− L.Empty -> IPartial $ \s ->
165− let s' = S s L.empty (addX s adds) failDepth
166− k' a = k (appL left a)
167− in unParser (takeWith splitf) s' k'
168− L.Chunk h t -> k left (S h t adds failDepth)
169−
170−string :: L.ByteString -> Parser r L.ByteString
171−string s = string' s
172− where
173− string' r =
174− Parser $ \st@(S sb lb adds failDepth) k ->
175− let bs = sb +: lb
176− l = L.length r
177− in case L.splitAt l bs of
178− (h,t)
179− | h == r -> k s (mkState t adds failDepth)
180− (h,L.Empty)
181− | h `L.isPrefixOf` r ->
182− IPartial $ \s' ->
183− let st' = S s' L.empty (addX s' adds) failDepth
184− k' a = k (appL h a)
185− in unParser (string (L.drop (L.length h) r)) st' k'
186− _ -> IFailed st "string failed to match"
187−
178+ let (left,rest) = splitf (sb +: lb)
179+ in case rest of
180+ L.Empty -> IPartial $ \s ->
181+ let s' = S s L.empty (addX s adds) failDepth
182+ k' a = k (appL left a)
183+ in unParser (takeWith splitf) s' k'
184+ L.Chunk h t -> k left (S h t adds failDepth)
185+
188186takeWhile :: (Word8 -> Bool) -> Parser r L.ByteString
189187takeWhile = takeWith . L.span
190188
191189takeTill :: (Word8 -> Bool) -> Parser r L.ByteString
192190takeTill = takeWith . L.break
193191
192+takeCount :: Int -> Parser r L.ByteString
193+takeCount = tc . fromIntegral where
194+ tc (!n) = Parser $ \(S sb lb adds failDepth) k ->
195+ let (h,t) = L.splitAt n (sb +: lb)
196+ l = L.length h
197+ in if L.length h == n
198+ then k h (mkState t adds failDepth)
199+ else IPartial $ \s ->
200+ let st = S s L.empty (addX s adds) failDepth
201+ k' a = k (appL h a)
202+ in unParser (tc (n - l)) st k'
203+
204+string :: L.ByteString -> Parser r L.ByteString
205+string s =
206+ Parser $ \st@(S sb lb adds failDepth) k ->
207+ case L.splitAt (L.length s) (sb +: lb) of
208+ (h,t)
209+ | h == s -> k s (mkState t adds failDepth)
210+ (h,L.Empty)
211+ | h `L.isPrefixOf` s ->
212+ IPartial $ \s' ->
213+ let st' = S s' L.empty (addX s' adds) failDepth
214+ k' a = k (appL h a)
215+ r' = L.drop (L.length h) s
216+ in unParser (string r') st' k'
217+ _ -> IFailed st "string failed to match"
218+
219+satisfy :: (Word8 -> Bool) -> Parser r Word8
220+satisfy p =
221+ Parser $ \st@(S sb lb adds failDepth) k ->
222+ case L.uncons (sb +: lb) of
223+ Just (w, lb') | p w -> k w (mkState lb' adds failDepth)
224+ | otherwise -> IFailed st "failed to match"
225+ Nothing -> IPartial $ \s ->
226+ let st' = S s L.empty (addX s adds) failDepth
227+ in unParser (satisfy p) st' k
228+
229+pushBack :: L.ByteString -> Parser r ()
230+pushBack bs =
231+ Parser $ \(S sb lb adds failDepth) k ->
232+ k () (mkState (bs `appL` (sb +: lb)) adds failDepth)
233+
194234toplevelTranslate :: IResult a -> Result a
195235toplevelTranslate (IFailed _ err) = Failed err
196236toplevelTranslate (IDone (S sb lb _ _) value) = Done (sb +: lb) value
@@ -202,3 +242,6 @@ terminalContinuation v s = IDone s v
202242parse :: Parser r r -> S.ByteString -> Result r
203243parse m input =
204244 toplevelTranslate $ unParser m (initState input) terminalContinuation
245+
246+#define PARSER Parser r
247+#include "Word8Boilerplate.h"
src/Data/ParserCombinators/Attoparsec/Incremental/Char8.hsnew file+103
@@ -0,0 +1,103 @@
1+{-# LANGUAGE CPP #-}
2+-----------------------------------------------------------------------------
3+-- |
4+-- Module : Data.ParserCombinators.Attoparsec.Incremental.Char8
5+-- Copyright : Daan Leijen 1999-2001, Jeremy Shaw 2006, Bryan O'Sullivan 2007-2008
6+-- License : BSD3
7+--
8+-- Maintainer : bos@serpentine.com
9+-- Stability : experimental
10+-- Portability : unknown
11+--
12+-- Simple, efficient parser combinators for lazy 'LB.ByteString'
13+-- strings, loosely based on 'Text.ParserCombinators.Parsec'.
14+--
15+-----------------------------------------------------------------------------
16+module Data.ParserCombinators.Attoparsec.Incremental.Char8
17+ (
18+ -- * Parser
19+ Parser
20+ , Result(..)
21+
22+ -- * Running parsers
23+ , parse
24+
25+ -- * Combinators
26+ , (<?>)
27+
28+ -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
29+ , many1
30+ , manyTill
31+ , skipMany
32+ , skipMany1
33+ , count
34+ , sepBy
35+ , sepBy1
36+ , pushBack
37+
38+ -- * Things like in @Parsec.Char@
39+ , satisfy
40+ , letter
41+ , digit
42+ , anyChar
43+ , space
44+ , char
45+ , notChar
46+ , string
47+
48+ -- * Numeric parsers.
49+ , int
50+ , integer
51+ , double
52+
53+ -- * Miscellaneous functions.
54+ , takeWhile
55+ , takeTill
56+ , takeCount
57+ , skipWhile
58+ , skipSpace
59+ , inClass
60+ , notInClass
61+ ) where
62+
63+import Control.Applicative ((<$>))
64+import qualified Data.ByteString.Char8 as SB
65+import qualified Data.ByteString.Lazy.Char8 as LB
66+import Data.ByteString.Internal (w2c)
67+import Data.Char (isDigit, isLetter, isSpace)
68+import Data.ParserCombinators.Attoparsec.FastSet
69+ (FastSet, memberChar, set)
70+import qualified Data.ParserCombinators.Attoparsec.Incremental as I
71+import Data.ParserCombinators.Attoparsec.Incremental
72+ (Parser, Result(..), (<?>), parse, manyTill, pushBack,
73+ skipMany, skipMany1, count, sepBy, sepBy1, string,
74+ takeCount, many1)
75+import Data.ByteString.Lex.Lazy.Double (readDouble)
76+import Prelude hiding (takeWhile)
77+
78+numeric :: String -> (Char -> Bool)
79+ -> (LB.ByteString -> Maybe (a,LB.ByteString)) -> Parser r a
80+numeric desc p f = do
81+ s <- takeWhile p
82+ case f s of
83+ Nothing -> pushBack s >> fail desc
84+ Just (i,s') -> pushBack s' >> return i
85+
86+isIntegral :: Char -> Bool
87+isIntegral c = isDigit c || c == '-'
88+
89+-- | Parse an integer. The position counter is not updated.
90+int :: Parser r Int
91+int = numeric "Int" isIntegral LB.readInt
92+
93+-- | Parse an integer. The position counter is not updated.
94+integer :: Parser r Integer
95+integer = numeric "Integer" isIntegral LB.readInteger
96+
97+-- | Parse a Double. The position counter is not updated.
98+double :: Parser r Double
99+double = numeric "Double" isDouble readDouble
100+ where isDouble c = isIntegral c || c == 'e' || c == '+'
101+
102+#define PARSER Parser r
103+#include "../Char8Boilerplate.h"
src/Data/ParserCombinators/Attoparsec/Internal.hs+11−68
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12-----------------------------------------------------------------------------
23-- |
34-- Module : Data.ParserCombinators.Attoparsec.Internal
@@ -28,7 +29,6 @@ module Data.ParserCombinators.Attoparsec.Internal
2829
2930 -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
3031 , try
31− , many
3232 , many1
3333 , manyTill
3434 , eof
@@ -69,8 +69,8 @@ module Data.ParserCombinators.Attoparsec.Internal
6969 , (+:)
7070 ) where
7171
72−import Control.Applicative (Alternative(..), Applicative(..), (<$>))
73−import Control.Monad (MonadPlus(..), ap, liftM2)
72+import Control.Applicative
73+import Control.Monad (MonadPlus(..), ap)
7474import Control.Monad.Fix (MonadFix(..))
7575import qualified Data.ByteString as SB
7676import qualified Data.ByteString.Lazy as LB
@@ -132,18 +132,6 @@ plus p1 p2 =
132132 ok -> ok
133133{-# INLINE plus #-}
134134
135−instance MonadPlus Parser where
136− mzero = zero
137− mplus = plus
138−
139−instance Applicative Parser where
140− pure = return
141− (<*>) = ap
142−
143−instance Alternative Parser where
144− empty = zero
145− (<|>) = plus
146−
147135mkState :: LB.ByteString -> Int64 -> S
148136mkState s = case s of
149137 LB.Empty -> S SB.empty s
@@ -194,26 +182,6 @@ satisfy p =
194182 Nothing -> unParser (nextChunk >> satisfy p) s
195183{-# INLINE satisfy #-}
196184
197−anyWord8 :: Parser Word8
198−anyWord8 = satisfy $ const True
199−{-# INLINE anyWord8 #-}
200−
201−-- | Satisfy a specific character.
202−word8 :: Word8 -> Parser Word8
203−word8 c = satisfy (== c) <?> show c
204−{-# INLINE word8 #-}
205−
206−-- | Satisfy a specific character.
207−notWord8 :: Word8 -> Parser Word8
208−notWord8 c = satisfy (/= c) <?> "not " ++ show c
209−{-# INLINE notWord8 #-}
210−
211−sepBy :: Parser a -> Parser s -> Parser [a]
212−sepBy p s = liftM2 (:) p ((s >> sepBy1 p s) <|> return []) <|> return []
213−
214−sepBy1 :: Parser a -> Parser s -> Parser [a]
215−sepBy1 p s = liftM2 (:) p ((s >> sepBy1 p s) <|> return [])
216−
217185-- | Satisfy a literal string.
218186string :: LB.ByteString -> Parser LB.ByteString
219187string s = Parser $ \(S sb lb n) ->
@@ -253,11 +221,6 @@ stringTransform f s = Parser $ \(S sb lb n) ->
253221 where fs = f s
254222{-# INLINE stringTransform #-}
255223
256−-- | Apply the given parser repeatedly, returning every parse result.
257−count :: Int -> Parser a -> Parser [a]
258−count n p = sequence (replicate n p)
259−{-# INLINE count #-}
260−
261224try :: Parser a -> Parser a
262225try p = Parser $ \s@(S sb lb _) ->
263226 case unParser p s of
@@ -275,13 +238,14 @@ takeAll = Parser $ \(S sb lb n) ->
275238 let bs = sb +: lb
276239 in Right (bs, mkState LB.empty (n + LB.length bs))
277240
278−takeCount :: Int64 -> Parser LB.ByteString
241+takeCount :: Int -> Parser LB.ByteString
279242takeCount k =
280243 Parser $ \(S sb lb n) ->
281244 let bs = sb +: lb
282− (h,t) = LB.splitAt k bs
283− in if LB.length h == k
284− then Right (h, mkState t (n + k))
245+ k' = fromIntegral k
246+ (h,t) = LB.splitAt k' bs
247+ in if LB.length h == k'
248+ then Right (h, mkState t (n + k'))
285249 else Left (bs, [show k ++ " bytes"])
286250
287251-- | Consume characters while the predicate is true.
@@ -308,30 +272,6 @@ takeWhile1 p =
308272 | otherwise -> Right (h, mkState t (n + LB.length h))
309273{-# INLINE takeWhile1 #-}
310274
311−-- | Skip over characters while the predicate is true.
312−skipWhile :: (Word8 -> Bool) -> Parser ()
313−skipWhile p = takeWhile p >> return ()
314−{-# INLINE skipWhile #-}
315−
316−manyTill :: Parser a -> Parser b -> Parser [a]
317−manyTill p end = scan
318− where scan = (end >> return []) <|> liftM2 (:) p scan
319−
320−many :: Parser a -> Parser [a]
321−many p = ((:) <$> p <*> many p) <|> return []
322−
323−many1 :: Parser a -> Parser [a]
324−many1 p = (:) <$> p <*> many p
325−
326−-- |'skipMany' - skip zero or many instances of the parser
327−skipMany :: Parser a -> Parser ()
328−skipMany p = scan
329− where scan = (p >> scan) <|> return ()
330−
331−-- |'skipMany1' - skip one or many instances of the parser
332−skipMany1 :: Parser a -> Parser ()
333−skipMany1 p = p >> skipMany p
334−
335275-- | Test that a parser returned a non-null ByteString.
336276notEmpty :: Parser LB.ByteString -> Parser LB.ByteString
337277notEmpty p = Parser $ \s ->
@@ -391,3 +331,6 @@ parseTest p s =
391331 case parse p s of
392332 (st, Left msg) -> putStrLn $ msg ++ "\nGot:\n" ++ show st
393333 (_, Right r) -> print r
334+
335+#define PARSER Parser
336+#include "Word8Boilerplate.h"
src/Data/ParserCombinators/Attoparsec/Word8Boilerplate.hnew file+60
@@ -0,0 +1,60 @@
1+-- -*- haskell -*-
2+-- This file is intended to be #included by other source files.
3+
4+instance MonadPlus (PARSER) where
5+ mzero = zero
6+ mplus = plus
7+
8+instance Applicative (PARSER) where
9+ pure = return
10+ (<*>) = ap
11+
12+instance Alternative (PARSER) where
13+ empty = zero
14+ (<|>) = plus
15+
16+-- | Skip over characters while the predicate is true.
17+skipWhile :: (Word8 -> Bool) -> PARSER ()
18+skipWhile p = takeWhile p *> pure ()
19+{-# INLINE skipWhile #-}
20+
21+many1 :: PARSER a -> PARSER [a]
22+many1 p = liftA2 (:) p (many p)
23+
24+sepBy :: PARSER a -> PARSER s -> PARSER [a]
25+sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure []
26+
27+sepBy1 :: PARSER a -> PARSER s -> PARSER [a]
28+sepBy1 p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure [])
29+
30+manyTill :: PARSER a -> PARSER b -> PARSER [a]
31+manyTill p end = scan
32+ where scan = (end *> pure []) <|> liftA2 (:) p scan
33+
34+-- | Skip zero or more instances of the parser.
35+skipMany :: PARSER a -> PARSER ()
36+skipMany p = scan
37+ where scan = (p >> scan) <|> return ()
38+
39+-- | Skip one or more instances of the parser.
40+skipMany1 :: PARSER a -> PARSER ()
41+skipMany1 p = p >> skipMany p
42+
43+-- | Apply the given parser repeatedly, returning every parse result.
44+count :: Int -> PARSER a -> PARSER [a]
45+count n p = sequence (replicate n p)
46+{-# INLINE count #-}
47+
48+anyWord8 :: PARSER Word8
49+anyWord8 = satisfy $ const True
50+{-# INLINE anyWord8 #-}
51+
52+-- | Satisfy a specific character.
53+word8 :: Word8 -> PARSER Word8
54+word8 c = satisfy (== c) <?> show c
55+{-# INLINE word8 #-}
56+
57+-- | Satisfy a specific character.
58+notWord8 :: Word8 -> PARSER Word8
59+notWord8 c = satisfy (/= c) <?> "not " ++ show c
60+{-# INLINE notWord8 #-}