packages feed

nanoparsec (empty) → 0.1

raw patch · 6 files changed

+874/−0 lines, 6 filesdep +ListLikedep +basedep +bytestringsetup-changed

Dependencies added: ListLike, base, bytestring

Files

+ Data/Nanoparsec.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE UnicodeSyntax #-}+{-|+Module      : Data.Nanoparsec+Copyright   : © 2011  Maciej Piechotka +License     : BSD3++Maintainer  : uzytkownik2@gmail.com+Stability   : experimental+Portability : unknown++Simple, efficient combinator parsing for 'LL.ListLike' lists based on+Attoparsec library.+-}+module Data.Nanoparsec+  (+    -- * Differences from Attoparsec+    -- $attoparsec+    +    -- * Differences from Parsec+    -- $parsec+    +    -- * Performance considerations+    -- $performance+    +    -- * Parser types+    I.Parser+  , Result(..)+    +    -- ** Typeclass instances+    -- $instances+    +    -- * Running parsers+  , parse+  , feed+  , parseWith+  , parseTest+    +    -- ** Result conversion+  , maybeResult+  , eitherResult+    +    -- * Combinators+  , (I.<?>)+  , I.try+  , module Data.Nanoparsec.Combinator+    +    -- * Parsing infividual elements+  , I.elem+  , I.anyElem+  , I.satisfy+  , I.satisfyWith+  , I.skip+    +    -- * Efficient sublist handling+  , I.string+  , I.skipWhile+  , I.take+  , I.takeWhile+  , I.takeWhile1+  , I.takeTill+    +    -- * State observation and manipulation functions+  , I.endOfInput+  , I.ensure+  )+where++import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as LB+import Data.Monoid+import Data.Nanoparsec.Combinator+import qualified Data.Nanoparsec.Internal as I++-- $attoparsec+--+-- Compared to Attoparsec and Attoparsec-text Nanoparsec is a little (around+-- 6%) slower. However it allows more abstract parsers on similar level as +-- Parsec 3 (except the monad transformation). ++-- $parsec+--+-- Compared to Parsec 3, Nanoparsec makes several tradeoffs.  It is+-- not intended for, or ideal for, all possible uses.+--+-- * While Nanoparsec can consume input incrementally, Parsec cannot.+--   Incremental input is a huge deal for efficient and secure network+--   and system programming, since it gives much more control to users+--   of the library over matters such as resource usage and the I/O+--   model to use.+--+-- * Much of the performance advantage of Nanoparsec is gained via+--   high-performance parsers such as 'I.takeWhile' and 'I.string'.+--   If you use complicated combinators that return lists of elements or+--   characters, there really isn't much performance difference the+--   two libraries.+--+-- * Unlike Parsec 3, Nanoparsec does not support being used as a+--   monad transformer.  This is mostly a matter of the implementor+--   not having needed that functionality.+--+-- * Parsec parsers can produce more helpful error messages than+--   Nanoparsec parsers.  This is a matter of focus: Nanoparsec avoids+--   the extra book-keeping in favour of higher performance.++-- $performance+--+-- If you write an Nanoparsec-based parser carefully, it can be+-- realistic to expect it to perform within a factor of 2.4 of a+-- hand-rolled C parser (measuring megabytes parsed per second).+--+-- To actually achieve high performance, there are a few guidelines+-- that it is useful to follow.+--+-- Use the list-oriented parsers whenever possible,+-- e.g. 'I.takeWhile1' instead of 'many1' 'I.anyWord8'.  There is+-- about a factor of 100 difference in performance between the two+-- kinds of parser.+--+-- Make active use of benchmarking and profiling tools to measure,+-- find the problems with, and improve the performance of your parser.++-- $instances+--+-- The 'I.Parser' type is an instance of the following classes:+--+-- * 'Monad', where 'fail' throws an exception (i.e. fails) with an+--   error message.+--+-- * 'Functor' and 'Applicative', which follow the usual definitions.+--+-- * 'Monoid', where 'mempty' fails (with no error message) and+--   'mappend' executes the right-hand parser if the left-hand one+--   fails.+--+-- * 'MonadPlus' and 'Alternative', which follows 'MonadPlus'.+--+-- The 'Result' type is an instance of 'Functor', where 'fmap'+-- transforms the value in a 'Done' result.++(⊕) ∷ Monoid m ⇒ m → m → m+(⊕) = mappend++data Result δ r = Fail !δ [String] String+                | Partial (δ → Result δ r)+                | Done !δ r++instance (Show δ, Show r) ⇒ Show (Result δ r) where+    show (Fail bs stk msg)+        = "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg+    show (Partial _) = "Partial _"+    show (Done bs r) = "Done " ++ show bs ++ " " ++ show r++feed ∷ Monoid δ ⇒ Result δ r → δ → Result δ r+feed f@(Fail _ _ _) _ = f+feed (Partial k)    d = k d+feed (Done bs r)    d = Done (bs ⊕ d) r+{-# SPECIALIZE feed ∷ Result B.ByteString r → B.ByteString → Result B.ByteString r #-}+{-# SPECIALIZE feed ∷ Result LB.ByteString r → LB.ByteString → Result LB.ByteString r #-}++instance Functor (Result δ) where+    _ `fmap` Fail st stk msg = Fail st stk msg+    f `fmap` Partial k       = Partial (fmap f . k)+    f `fmap` Done bs r       = Done bs (f r)++-- | Run a parser and print its result to standard output.+parseTest ∷ (Show a, Show δ, Monoid δ) ⇒ I.Parser δ a → δ → IO ()+parseTest p s = print (parse p s)+{-# SPECIALIZE parseTest ∷ Show a ⇒ I.Parser B.ByteString a → B.ByteString → IO () #-}+{-# SPECIALIZE parseTest ∷ Show a ⇒ I.Parser LB.ByteString a → LB.ByteString → IO () #-}++translate ∷ I.Result δ a → Result δ a+translate (I.Fail st stk msg) = Fail (I.input st) stk msg+translate (I.Partial k)       = Partial (translate . k)+translate (I.Done r st)       = Done (I.input st) r++-- | Run a parser and return its result.+parse :: Monoid δ ⇒ I.Parser δ a → δ → Result δ a+parse m s = translate (I.parse m s)+{-# INLINE parse #-}+{-# SPECIALIZE parse ∷ I.Parser B.ByteString a → B.ByteString → Result B.ByteString a #-}+{-# SPECIALIZE parse ∷ I.Parser LB.ByteString a → LB.ByteString → Result LB.ByteString a #-}++-- | Run a parser with an initial input string, and a monadic action+-- that can supply more input if needed.+parseWith ∷ (Monad m, Monoid δ)+          ⇒ (m δ)+          -- ^ An action that will be executed to provide the parser+          -- with more input, if necessary.  The action must return an+          -- 'B.empty' string when there is no more input available.+          → I.Parser δ a+          → δ+          -- ^ Initial input for the parser.+          → m (Result δ a)+parseWith refill p s+    = step $ I.parse p s+    where step (I.Fail st stk msg) = return $! Fail (I.input st) stk msg+          step (I.Partial k)       = (step . k) =<< refill+          step (I.Done r st)       = return $! Done (I.input st) r+{-# SPECIALIZE parseWith ∷ Monad m+                         ⇒ (m B.ByteString)+                         → I.Parser B.ByteString a+                         → B.ByteString+                         → m (Result B.ByteString a) #-}+{-# SPECIALIZE parseWith ∷ Monad m+                         ⇒ (m LB.ByteString)+                         → I.Parser LB.ByteString a+                         → LB.ByteString+                         → m (Result LB.ByteString a) #-}++-- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result+-- is treated as failure.+maybeResult ∷ Result δ r → Maybe r+maybeResult (Done _ r) = Just r+maybeResult _          = Nothing++-- | Convert a 'Result' value to an 'Either' value. A 'Partial' result+-- is treated as failure.+eitherResult ∷ Result δ r → Either String r+eitherResult (Done _ r)     = Right r+eitherResult (Fail _ _ msg) = Left msg+eitherResult _              = Left "Result: incomplete input"
+ Data/Nanoparsec/Combinator.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE BangPatterns, CPP #-}+-- |+-- Module      :  Data.Nanoparsec.Combinator+-- Copyright   :  Daan Leijen 1999-2001, Bryan O'Sullivan 2009-2010+-- License     :  BSD3+-- +-- Maintainer  :  bos@serpentine.com+-- Stability   :  experimental+-- Portability :  portable+--+-- Useful parser combinators, similar to those provided by Parsec.+module Data.Nanoparsec.Combinator+  (+    choice+  , count+  , option+  , many1+  , manyTill+  , sepBy+  , sepBy1+  , skipMany+  , skipMany1+  , eitherP+    +    -- * Inlined implementations of existing functions+    --+    -- These are exact duplicates of functions already exported by the+    -- 'Control.Applicative' module, but whose definitions are+    -- inlined.  In many cases, this leads to 2x performance+    -- improvements.+  , many+  ) where++import Control.Applicative (Alternative, Applicative(..), empty, liftA2,+                                                        (<|>), (*>), (<$>))+  +-- | @choice ps@ tries to apply the actions in the list @ps@ in order,+-- until one of them succeeds. Returns the value of the succeeding+-- action.+choice :: Alternative f => [f a] -> f a+choice = foldr (<|>) empty++-- | @option x p@ tries to apply action @p@. If @p@ fails without+-- consuming input, it returns the value @x@, otherwise the value+-- returned by @p@.+--+-- > priority  = option 0 (digitToInt <$> digit)+option :: Alternative f => a -> f a -> f a+option x p = p <|> pure x++-- | @many1 p@ applies the action @p@ /one/ or more times. Returns a+-- list of the returned values of @p@.+--+-- >  word  = many1 letter+many1 :: Alternative f => f a -> f [a]+many1 p = liftA2 (:) p (many p)+{-# INLINE many1 #-}++-- | @sepBy p sep@ applies /zero/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@.+--+-- > commaSep p  = p `sepBy` (symbol ",")+sepBy :: Alternative f => f a -> f s -> f [a]+sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure []++-- | @sepBy1 p sep@ applies /one/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@.+--+-- > commaSep p  = p `sepBy` (symbol ",")+sepBy1 :: Alternative f => f a -> f s -> f [a]+sepBy1 p s = scan+    where scan = liftA2 (:) p ((s *> scan) <|> pure [])+          +          -- | @manyTill p end@ applies action @p@ /zero/ or more times until+-- action @end@ succeeds, and returns the list of values returned by+-- @p@.  This can be used to scan comments:+--+-- >  simpleComment   = string "<!--" *> manyTill anyChar (try (string "-->"))+--+-- Note the overlapping parsers @anyChar@ and @string \"<!--\"@, and+-- therefore the use of the 'try' combinator.+manyTill :: Alternative f => f a -> f b -> f [a]+manyTill p end = scan+    where scan = (end *> pure []) <|> liftA2 (:) p scan+          +          -- | Skip zero or more instances of an action.+skipMany :: Alternative f => f a -> f ()+skipMany p = scan+    where scan = (p *> scan) <|> pure ()+          +          -- | Skip one or more instances of an action.+skipMany1 :: Alternative f => f a -> f ()+skipMany1 p = p *> skipMany p++-- | Apply the given action repeatedly, returning every result.+count :: Monad m => Int -> m a -> m [a]+count n p = sequence (replicate n p)+{-# INLINE count #-}++-- | Combine two alternatives.+eitherP :: (Alternative f) => f a -> f b -> f (Either a b)+eitherP a b = (Left <$> a) <|> (Right <$> b)+{-# INLINE eitherP #-}++-- | Zero or more.+many :: (Alternative f) => f a -> f [a]+many v = many_v+         where many_v = some_v <|> pure []+               some_v = (:) <$> v <*> many_v+{-# INLINE many #-}
+ Data/Nanoparsec/Internal.hs view
@@ -0,0 +1,490 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE UnicodeSyntax #-}+{-|+Module      : Data.Nanoparsec.Internal+Copyright   : © 2011  Maciej Piechotka+License     : BSD3++Maintainer  : uzytkownik2@gmail.com+Stability   : experimental+Portability :+-}+module Data.Nanoparsec.Internal+  (+    -- * Parser types+    Parser+  , Result(..)+  , S(input)+    +    -- * Running parsers+  , parse+    +    -- * Combinators+  , (<?>)+  , try  +    +    -- * Parsing individual elements+  , satisfy+  , satisfyWith+  , anyElem+  , skip+  , elem+  , notElem+  , elem'+  , notElem'+    +    -- * Efficient substring handling+  , skipWhile+  , string+  , stringTransform+  , take+  , takeWhile+  , takeWhile1+  , takeTill+    +    -- * State observation and manipulation functions+  , endOfInput+  , ensure+  )+where++import Control.Applicative+import Control.Monad+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as LB+import Data.Monoid+import qualified Data.ListLike as LL+import Data.Word+import Prelude hiding (take, takeWhile, elem, notElem)++(⊕) ∷ Monoid m ⇒ m → m → m+(⊕) = mappend+{-# INLINE (⊕) #-}++ø ∷ Monoid m ⇒ m+ø = mempty+{-# INLINE ø #-}+      +(≡) ∷ Eq a ⇒ a → a → Bool+(≡) = (==)+{-# INLINE (≡) #-}++(≢) ∷ Eq a ⇒ a → a → Bool+(≢) = (/=)+{-# INLINE (≢) #-}++(≥) ∷ Ord a ⇒ a → a → Bool+(≥) = (>=)+{-# INLINE (≥) #-}++(≫) ∷ Monad m ⇒ m a → m b → m b+(≫) = (>>)+{-# INLINE (≫) #-}++data Result δ r+    = Fail (S δ) [String] String+    | Partial (δ → Result δ r)+    | Done r (S δ)++newtype Parser δ a+    = Parser { runParser ∷ forall r. S δ+                         → Failure     δ   r+                         → Success     δ a r+                         → Result      δ   r }++type Failure δ   r =     S δ → [String] → String → Result δ r+type Success δ a r = a → S δ →                     Result δ r++data More = Complete | Incomplete deriving (Eq, Show)++instance Monoid More where+    mappend Complete _        = Complete+    mappend _        Complete = Complete+    mappend _        _        = Incomplete+    mempty                    = Incomplete+    {-# INLINE mappend #-}++data S δ = S { input ∷ !δ+             , _added ∷ !δ+             , more ∷ !More+             } deriving (Show)++instance (Show δ, Show r) ⇒ Show (Result δ r) where+    show (Fail _ stack msg) = "Fail " ++ show stack ++ " " ++ show msg+    show (Partial _)        = "Partial _"+    show (Done str r)       = "Done " ++ show str ++ " " ++ show r++instance Monoid δ ⇒ Monoid (S δ) where+    mempty = S mempty mempty mempty+    {-# INLINE mempty #-}+    {-# SPECIALIZE mempty ∷ S B.ByteString #-}+    {-# SPECIALIZE mempty ∷ S LB.ByteString #-}+    mappend (S inp add mor) (S _ add' mor')+        = S (inp ⊕ add') (add ⊕ add') (mor ⊕ mor')+    {-# INLINE mappend #-}+    {-# SPECIALIZE mappend ∷ S B.ByteString → S B.ByteString → S B.ByteString #-}+    {-# SPECIALIZE mappend ∷ S LB.ByteString → S LB.ByteString → S LB.ByteString #-}++instance Functor (Parser δ) where+    f `fmap` Parser p = Parser $ \s fa su → p s fa (su . f)+    {-# INLINE fmap #-}++instance Monoid δ ⇒ Applicative (Parser δ) where+    pure = return+    {-# INLINE pure #-}+    {-# SPECIALIZE pure ∷ a → Parser B.ByteString a #-}+    {-# SPECIALIZE pure ∷ a → Parser LB.ByteString a #-}+    (<*>) = ap+    {-# INLINE (<*>) #-}+    {-# SPECIALIZE (<*>) ∷ Parser B.ByteString (a → b) → Parser B.ByteString a → Parser B.ByteString b #-}+    {-# SPECIALIZE (<*>) ∷ Parser LB.ByteString (a → b) → Parser LB.ByteString a → Parser LB.ByteString b #-}+    (*>) = (>>)+    {-# INLINE (*>) #-}+    {-# SPECIALIZE (*>) ∷ Parser B.ByteString a → Parser B.ByteString b → Parser B.ByteString b #-}+    {-# SPECIALIZE (*>) ∷ Parser LB.ByteString a → Parser LB.ByteString b → Parser LB.ByteString b #-}+    x <* y = x >>= \a → y >> return a+    {-# INLINE (<*) #-}+    {-# SPECIALIZE (<*) ∷ Parser B.ByteString a → Parser B.ByteString b → Parser B.ByteString a #-}+    {-# SPECIALIZE (<*) ∷ Parser LB.ByteString a → Parser LB.ByteString b → Parser LB.ByteString a #-}++instance Monoid δ ⇒ Monad (Parser δ) where+    return x = Parser $ \s _ su → su x s+    {-# INLINE return #-}+    {-# SPECIALIZE return ∷ a → Parser B.ByteString a #-}+    {-# SPECIALIZE return ∷ a → Parser LB.ByteString a #-}+    Parser p >>= g+        = Parser $ \s fa su → p s fa (\a s' → runParser (g a) s' fa su)+    {-# INLINE (>>=) #-}+    {-# SPECIALIZE (>>=) ∷ Parser B.ByteString a → (a → Parser B.ByteString b) → Parser B.ByteString b #-}+    {-# SPECIALIZE (>>=) ∷ Parser LB.ByteString a → (a → Parser LB.ByteString b) → Parser LB.ByteString b #-}+    Parser p >> Parser r+        = Parser $ \s fa su → p s fa (\_ s' → r s' fa su)+    {-# INLINE (>>) #-}+    {-# SPECIALIZE (>>) ∷ Parser B.ByteString a → Parser B.ByteString b → Parser B.ByteString b #-}+    {-# SPECIALIZE (>>) ∷ Parser LB.ByteString a → Parser LB.ByteString b → Parser LB.ByteString b #-}+    fail err = Parser (\s fa _ → fa s [] ("Failed reading: " ++ err))+    {-# INLINE fail #-}+    {-# SPECIALIZE fail ∷ String → Parser B.ByteString a #-}+    {-# SPECIALIZE fail ∷ String → Parser LB.ByteString a #-}++instance Monoid δ ⇒ Monoid (Parser δ a) where+    mempty = fail "mempty"+    {-# INLINE mempty #-}+    {-# SPECIALIZE mempty ∷ Parser B.ByteString a #-}+    {-# SPECIALIZE mempty ∷ Parser LB.ByteString a #-}+    Parser p `mappend` Parser r+        = Parser $ \s fa su → let fa' s' _ _ = r (s ⊕ s') fa su+                                  !s'' = noAdds s+                              in p s'' fa' su+    {-# INLINE mappend #-}+    {-# SPECIALIZE mappend ∷ Parser B.ByteString a → Parser B.ByteString a → Parser B.ByteString a #-}+    {-# SPECIALIZE mappend ∷ Parser LB.ByteString a → Parser LB.ByteString a → Parser LB.ByteString a #-}++instance Monoid δ ⇒ Alternative (Parser δ) where+    empty = fail "empty"+    {-# INLINE empty #-}+    {-# SPECIALIZE empty ∷ Parser B.ByteString a #-}+    {-# SPECIALIZE empty ∷ Parser LB.ByteString a #-}+    (<|>) = mappend+    {-# INLINE (<|>) #-}+    {-# SPECIALIZE (<|>) ∷ Parser B.ByteString a → Parser B.ByteString a → Parser B.ByteString a #-}+    {-# SPECIALIZE (<|>) ∷ Parser LB.ByteString a → Parser LB.ByteString a → Parser LB.ByteString a #-}++instance Monoid δ ⇒ MonadPlus (Parser δ) where+    mzero = fail "mzero"+    {-# INLINE mzero #-}+    {-# SPECIALIZE mzero ∷ Parser B.ByteString a #-}+    {-# SPECIALIZE mzero ∷ Parser LB.ByteString a #-}+    mplus = mappend+    {-# INLINE mplus #-}+    {-# SPECIALIZE mplus ∷ Parser B.ByteString a → Parser B.ByteString a → Parser B.ByteString a #-}+    {-# SPECIALIZE mplus ∷ Parser LB.ByteString a → Parser LB.ByteString a → Parser LB.ByteString a #-}+++noAdds ∷ Monoid δ ⇒ S δ → S δ+noAdds (S s _ c) = S s ø c+{-# INLINE noAdds #-}+{-# SPECIALIZE noAdds ∷ S B.ByteString → S B.ByteString #-}+{-# SPECIALIZE noAdds ∷ S LB.ByteString → S LB.ByteString #-}++-- | Succeed only if at least @n@ elements of input are available.+ensure ∷ LL.ListLike δ ε ⇒ Int → Parser δ ()+ensure n = Parser $ \st@(S s _ _) fa su →+    if LL.length s ≥ n+        then su () st+        else runParser (demandInput ≫ ensure n) st fa su+{-# SPECIALIZE ensure ∷ Int → Parser B.ByteString () #-}+{-# SPECIALIZE ensure ∷ Int → Parser LB.ByteString () #-}++-- | Ask for input.  If we receive any, pass it to a success+-- continuation, otherwise to a failure continuation.+prompt ∷ LL.ListLike δ ε+       ⇒ S δ → (S δ → Result δ r) → (S δ → Result δ r) → Result δ r+prompt (S s a _) fa su = Partial $ \p →+    if LL.null s+        then fa $ S s a Complete+        else su $ S (s ⊕ p) (a ⊕ p) Incomplete+{-# SPECIALIZE prompt ∷ S B.ByteString+                      → (S B.ByteString → Result B.ByteString r)+                      → (S B.ByteString → Result B.ByteString r)+                      → Result B.ByteString r #-}+{-# SPECIALIZE prompt ∷ S LB.ByteString+                      → (S LB.ByteString → Result LB.ByteString r)+                      → (S LB.ByteString → Result LB.ByteString r)+                      → Result LB.ByteString r #-}++-- | Immediately demand more input via a 'Partial' continuation+-- result.+demandInput ∷ LL.ListLike δ ε ⇒ Parser δ ()+demandInput = Parser $ \st fa su →+    if more st ≡ Complete+        then fa st ["demandInput"] "not enough characters"+        else prompt st (\st' → fa st' ["demandInput"] "not enough characters")+                       (su ())+{-# SPECIALIZE demandInput ∷ Parser B.ByteString () #-}+{-# SPECIALIZE demandInput ∷ Parser LB.ByteString () #-}++-- | This parser always succeeds.  It returns 'True' if any input is+-- available either immediately or on demand, and 'False' if the end+-- of all input has been reached.+wantInput ∷ LL.ListLike δ ε ⇒ Parser δ Bool+wantInput = Parser $ \st@(S s _ c) _ su → case () of+  _ | not (LL.null s) → su True st+    | c ≡ Complete    → su False st+    | otherwise       → prompt st (su False) (su True)+{-# SPECIALIZE wantInput ∷ Parser B.ByteString Bool #-}+{-# SPECIALIZE wantInput ∷ Parser LB.ByteString Bool #-}++get ∷ Parser δ δ+get = Parser (\st _ su → su (input st) st)++put ∷ δ → Parser δ ()+put s = Parser (\(S _ a c) _ su → su () (S s a c))++-- | Attempt a parse, and if it fails, rewind the input so that no+-- input appears to have been consumed.+--+-- This combinator is useful in cases where a parser might consume+-- some input before failing, i.e. the parser needs arbitrary+-- lookahead.  The downside to using this combinator is that it can+-- retain input for longer than is desirable.+try ∷ Monoid δ ⇒ Parser δ a → Parser δ a+try p = Parser (\st fa su → runParser p (noAdds st) (fa . (st ⊕)) su)+{-# SPECIALIZE try ∷ Parser B.ByteString a → Parser B.ByteString a #-}+{-# SPECIALIZE try ∷ Parser LB.ByteString a → Parser LB.ByteString a #-}++-- | The parser @satisfy p@ succeeds for any element for which the+-- predicate @p@ returns 'True'. Returns the element that is actually+-- parsed.+--+-- >digit = satisfy isDigit+-- >    where isDigit w = w >= 48 && w <= 57+satisfy ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ ε+satisfy p = do+    ensure 1+    s ← get+    let w = LL.head s+    if p w+        then put (LL.tail s) ≫ return w+        else fail "satisfy"+{-# SPECIALIZE satisfy ∷ (Word8 → Bool) → Parser B.ByteString Word8 #-}+{-# SPECIALIZE satisfy ∷ (Word8 → Bool) → Parser LB.ByteString Word8 #-}++-- | The parser @skip p@ succeeds for any element for which the predicate+-- @p@ returns 'True'.+--+-- >space = skip isSpace+-- >    where isDigit w = w == 9 || w == 10 || w == 13 || w == 32+skip ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ ()+skip p = do+  ensure 1+  s ← get+  if p (LL.head s)+      then put (LL.tail s)+      else fail "skip"+{-# SPECIALIZE skip ∷ (Word8 → Bool) → Parser B.ByteString () #-}+{-# SPECIALIZE skip ∷ (Word8 → Bool) → Parser LB.ByteString () #-}++-- | The parser @satisfyWith f p@ transforms an element, and succeeds if+-- the predicate @p@ returns 'True' on the transformed value. The+-- parser returns the transformed element that was parsed.+satisfyWith ∷ LL.ListLike δ ε ⇒ (ε → a) → (a → Bool) → Parser δ a+satisfyWith f p = do+    ensure 1+    s ← get+    let c = f (LL.head s)+    if p c+        then put (LL.tail s) ≫ return c+        else fail "satisfyWith"+{-# SPECIALIZE satisfyWith ∷ (Word8 → a) → (a → Bool) → Parser B.ByteString a #-}+{-# SPECIALIZE satisfyWith ∷ (Word8 → a) → (a → Bool) → Parser LB.ByteString a #-}++-- | Consume @n@ element of input, but succeed only if the predicate+-- returns 'True'.+takeWith ∷ LL.ListLike δ ε ⇒ Int → (δ → Bool) → Parser δ δ+takeWith n p = do+    ensure n+    s ← get+    let (h, t) = LL.splitAt n s+    if p h+        then put t ≫ return h+        else fail "takeWith"+{-# SPECIALIZE takeWith ∷ Int → (B.ByteString → Bool) → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE takeWith ∷ Int → (LB.ByteString → Bool) → Parser LB.ByteString LB.ByteString #-}++-- | Consume exactly @n@ elements of input.+take ∷ LL.ListLike δ ε ⇒ Int → Parser δ δ+take n = takeWith n (const True)+{-# INLINE take #-}+{-# SPECIALIZE take ∷ Int → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE take ∷ Int → Parser LB.ByteString LB.ByteString #-}++-- | @string s@ parses a sequence of elements that identically match+-- @s@. Returns the parsed string (i.e. @s@).  This parser consumes no+-- input if it fails (even if a partial match).+--+-- /Note/: The behaviour of this parser is different to that of the+-- similarly-named parser in Parsec, as this one is all-or-nothing.+-- To illustrate the difference, the following parser will fail under+-- Parsec given an input of @"for"@:+--+-- >string "foo" <|> string "for"+--+-- The reason for its failure is that that the first branch is a+-- partial match, and will consume the letters @\'f\'@ and @\'o\'@+-- before failing.  In Nnaoparsec, the above parser will /succeed/ on+-- that input, because the failed first branch will consume nothing.+string ∷ (Eq δ, LL.ListLike δ ε) ⇒ δ → Parser δ δ+string s = takeWith (LL.length s) (≡ s)+{-# INLINE string #-}+{-# SPECIALIZE string ∷ B.ByteString → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE string ∷ LB.ByteString → Parser LB.ByteString LB.ByteString #-}++stringTransform ∷ (LL.ListLike δ ε, Eq δ) ⇒ (δ → δ) → δ → Parser δ δ+stringTransform f s = takeWith (LL.length s) ((≡ f s) . f)+{-# INLINE stringTransform #-}+{-# SPECIALIZE stringTransform ∷ (B.ByteString → B.ByteString) → B.ByteString → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE stringTransform ∷ (LB.ByteString → LB.ByteString) → LB.ByteString → Parser LB.ByteString LB.ByteString #-}++skipWhile ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ ()+skipWhile p = go+              where go = do+                      _ ← wantInput+                      t ← LL.dropWhile p <$> get+                      put t+                      when (LL.null t) go+{-# SPECIALIZE skipWhile ∷ (Word8 → Bool) → Parser B.ByteString () #-}+{-# SPECIALIZE skipWhile ∷ (Word8 → Bool) → Parser LB.ByteString () #-}++-- | Consume input as long as the predicate returns 'False'+-- (i.e. until it returns 'True'), and return the consumed input.+--+-- This parser does not fail.  It will return an empty string if the+-- predicate returns 'True' on the first element of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs.  Careless use will thus result in an infinite loop.+takeTill ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ δ+takeTill p = takeWhile (not . p)+{-# INLINE takeTill #-}+{-# SPECIALIZE takeTill ∷ (Word8 → Bool) → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE takeTill ∷ (Word8 → Bool) → Parser LB.ByteString LB.ByteString #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser does not fail.  It will return an empty string if the+-- predicate returns 'False' on the first element of input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs.  Careless use will thus result in an infinite loop.+takeWhile ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ δ+takeWhile p = go ø+              where go acc = do+                      inp <- wantInput+                      if inp+                          then do+                            (h, t) ← LL.span p <$> get+                            put t+                            if (LL.null t)+                                then go (h ⊕ acc)+                                else return h+                          else return ø+{-# SPECIALIZE takeWhile ∷ (Word8 → Bool) → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE takeWhile ∷ (Word8 → Bool) → Parser LB.ByteString LB.ByteString #-}++-- | Consume input as long as the predicate returns 'True', and return+-- the consumed input.+--+-- This parser requires the predicate to succeed on at least one element+-- of input: it will fail if the predicate never returns 'True' or if+-- there is no input left.+takeWhile1 ∷ LL.ListLike δ ε ⇒ (ε → Bool) → Parser δ δ+takeWhile1 p = do+  (`when` demandInput) =<< LL.null <$> get+  (h, t) ← LL.span p <$> get+  when (LL.null h) $ fail "takeWhile1"+  put t+  if LL.null t+      then (h ⊕) `fmap` takeWhile p+      else return h+{-# SPECIALIZE takeWhile1 ∷ (Word8 → Bool) → Parser B.ByteString B.ByteString #-}+{-# SPECIALIZE takeWhile1 ∷ (Word8 → Bool) → Parser LB.ByteString LB.ByteString #-}++anyElem ∷ LL.ListLike δ ε ⇒ Parser δ ε+anyElem = satisfy (const True)+{-# INLINE anyElem #-}+{-# SPECIALIZE anyElem ∷ Parser B.ByteString Word8 #-}+{-# SPECIALIZE anyElem ∷ Parser LB.ByteString Word8 #-}++elem ∷ (Eq ε, Show ε, LL.ListLike δ ε) ⇒ ε → Parser δ ε+elem x = elem' (show x) x+{-# INLINE elem #-}+{-# SPECIALIZE elem ∷ Word8 → Parser B.ByteString Word8 #-}+{-# SPECIALIZE elem ∷ Word8 → Parser LB.ByteString Word8 #-}++notElem ∷ (Eq ε, Show ε, LL.ListLike δ ε) ⇒ ε → Parser δ ε+notElem x = notElem' ("not " ⊕ show x) x+{-# INLINE notElem #-}+{-# SPECIALIZE notElem ∷ Word8 → Parser B.ByteString Word8 #-}+{-# SPECIALIZE notElem ∷ Word8 → Parser LB.ByteString Word8 #-}++elem' ∷ (Eq ε, LL.ListLike δ ε) ⇒ String → ε → Parser δ ε+elem' p c = satisfy (≡ c) <?> p+{-# INLINE elem' #-}+{-# SPECIALIZE elem' ∷ String → Word8 → Parser B.ByteString Word8 #-}+{-# SPECIALIZE elem' ∷ String → Word8 → Parser LB.ByteString Word8 #-}++notElem' ∷ (Eq ε, LL.ListLike δ ε) ⇒ String → ε → Parser δ ε+notElem' p c = satisfy (≢ c) <?> p+{-# INLINE notElem' #-}+{-# SPECIALIZE notElem' ∷ String → Word8 → Parser B.ByteString Word8 #-}+{-# SPECIALIZE notElem' ∷ String → Word8 → Parser LB.ByteString Word8 #-}++-- | Match only if all input has been consumed.+endOfInput ∷ LL.ListLike δ ε ⇒ Parser δ ()+endOfInput = Parser $ \st@(S i _ mo) fa su → case () of+    _ | not (LL.null i) → fa    st [] "endOfInput"+      | mo ≡ Complete   → su () st+      | otherwise       → let su' _ st'     = su () (st ⊕ st')+                              fa'   st' _ _ = fa    (st ⊕ st') [] "endOfInput"+                          in runParser demandInput st fa' su'+{-# SPECIALIZE endOfInput ∷ Parser B.ByteString () #-}+{-# SPECIALIZE endOfInput ∷ Parser LB.ByteString () #-}++-- | Match either a single newline character @\'\\n\'@, or a carriage+-- return followed by a newline character @\"\\r\\n\"@.+(<?>) ∷ Parser δ a → String → Parser δ a+p <?> ms = Parser $ \s fa su → runParser p s (\s' sts m → fa s' (ms:sts) m) su+{-# INLINE (<?>) #-}+infix 0 <?>++-- | Run a parser.+parse ∷ Monoid δ ⇒ Parser δ a → δ → Result δ a+parse m s = runParser m (S s ø Incomplete) Fail Done+{-# INLINE parse #-}+{-# SPECIALIZE parse ∷ Parser B.ByteString a → B.ByteString → Result B.ByteString a #-}+{-# SPECIALIZE parse ∷ Parser LB.ByteString a → LB.ByteString → Result LB.ByteString a #-}
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Maciej Piechotka++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Maciej Piechotka nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ nanoparsec.cabal view
@@ -0,0 +1,21 @@+Name:                nanoparsec+Version:             0.1+Synopsis:            An implementation of attoparsec-like parser around list-like+Description:         An implementation of attoparsec-like parser around list-like+License:             BSD3+License-file:        LICENSE+Author:              Maciej Piechotka+Maintainer:          uzytkownik2@gmail.com+Copyright:           (c) 2011  Maciej Piechotka+Category:            Text+Build-type:          Simple+Cabal-version:       >=1.6++Library+  Exposed-modules:   Data.Nanoparsec,+                     Data.Nanoparsec.Combinator+  Other-modules:     Data.Nanoparsec.Internal+  Build-depends:     base >= 4.3 && < 5,+                     bytestring == 0.9.*,+                     ListLike == 2.0.*+  Ghc-options:       -Wall -O2