picoparsec 0.1.1 → 0.1.2
raw patch · 5 files changed
+66/−20 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Picoparsec.Combinator: lookAhead :: Monoid i => Parser i a -> Parser i a
+ Data.Picoparsec.Combinator: notFollowedBy :: (Monoid i, Show a) => Parser i a -> Parser i ()
Files
- Data/Picoparsec/Combinator.hs +17/−6
- Data/Picoparsec/Internal.hs +18/−9
- Data/Picoparsec/Internal/Types.hs +7/−4
- picoparsec.cabal +1/−1
- tests/QC/Combinator.hs +23/−0
Data/Picoparsec/Combinator.hs view
@@ -32,6 +32,8 @@ , feed , endOfInput , atEnd+ , lookAhead+ , notFollowedBy ) where import Prelude hiding (succ)@@ -39,8 +41,9 @@ import Control.Applicative (Alternative(..), Applicative(..), empty, liftA2, many, (<|>), (*>), (<$>)) import Control.Monad (MonadPlus(..))-import Data.Picoparsec.Internal.Types (Parser(..))-import Data.Picoparsec.Internal (atEnd, endOfInput, feed)+import Data.Monoid (Monoid(mappend))+import Data.Picoparsec.Internal.Types (Parser(..), IResult(..))+import Data.Picoparsec.Internal (atEnd, endOfInput, lookAhead, notFollowedBy) import Data.ByteString (ByteString) import Data.Text (Text) import qualified Data.Picoparsec.Zepto as Z@@ -127,7 +130,7 @@ -- | @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 ",")+-- > commaSep p = p `sepBy` (char ',') sepBy :: Alternative f => f a -> f s -> f [a] sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure [] {-# SPECIALIZE sepBy :: Parser ByteString a -> Parser ByteString s@@ -140,7 +143,7 @@ -- by @sep@. Returns a list of the values returned by @p@. The value -- returned by @p@ is forced to WHNF. ----- > commaSep p = p `sepBy'` (symbol ",")+-- > commaSep p = p `sepBy'` (char ',') sepBy' :: (MonadPlus m) => m a -> m s -> m [a] sepBy' p s = scan `mplus` return [] where scan = liftM2' (:) p ((s >> sepBy1' p s) `mplus` return [])@@ -152,7 +155,7 @@ -- | @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 `sepBy1` (symbol ",")+-- > commaSep p = p `sepBy1` (char ',') sepBy1 :: Alternative f => f a -> f s -> f [a] sepBy1 p s = scan where scan = liftA2 (:) p ((s *> scan) <|> pure [])@@ -166,7 +169,7 @@ -- by @sep@. Returns a list of the values returned by @p@. The value -- returned by @p@ is forced to WHNF. ----- > commaSep p = p `sepBy1'` (symbol ",")+-- > commaSep p = p `sepBy1'` (char ',') sepBy1' :: (MonadPlus m) => m a -> m s -> m [a] sepBy1' p s = scan where scan = liftM2' (:) p ((s >> scan) `mplus` return [])@@ -240,3 +243,11 @@ eitherP :: (Alternative f) => f a -> f b -> f (Either a b) eitherP a b = (Left <$> a) <|> (Right <$> b) {-# INLINE eitherP #-}++-- | If a parser has returned a 'T.Partial' result, supply it with more+-- input.+feed :: Monoid i => IResult i r -> i -> IResult i r+feed (Fail t ctxs msg) d = Fail (mappend t d) ctxs msg+feed (Partial k) d = k d+feed (Done t r) d = Done (mappend t d) r+{-# INLINE feed #-}
Data/Picoparsec/Internal.hs view
@@ -19,16 +19,17 @@ , prompt , demandInput , wantInput- , feed , endOfInput , atEnd+ , lookAhead+ , notFollowedBy ) where import Prelude hiding (null) import Control.Applicative ((<$>)) import Data.Picoparsec.Internal.Types-import Data.Monoid (Monoid(mappend), (<>))+import Data.Monoid (Monoid, mempty, (<>)) import Data.Monoid.Null (MonoidNull(null)) -- | Compare two 'IResult' values for equality.@@ -110,10 +111,18 @@ atEnd = not <$> wantInput {-# INLINE atEnd #-} --- | If a parser has returned a 'T.Partial' result, supply it with more--- input.-feed :: Monoid i => IResult i r -> i -> IResult i r-feed f@(Fail _ _ _) _ = f-feed (Partial k) d = k d-feed (Done t r) d = Done (mappend t d) r-{-# INLINE feed #-}+-- | Apply a parser without consuming any input.+lookAhead :: Monoid i => Parser i a -> Parser i a+lookAhead p = Parser $ \i a more kf ks ->+ let ks' _i' a' more' = ks (i <> I (unA a')) (a <> a') (more <> more')+ kf' _i' a' more' = kf i (a <> a') (more <> more')+ in runParser p i mempty more kf' ks'+{-# INLINE lookAhead #-}++-- | Apply a parser without consuming any input, and succeed if and only if the parser fails.+notFollowedBy :: (Monoid i, Show a) => Parser i a -> Parser i ()+notFollowedBy p = Parser $ \i a more kf ks ->+ let ks' _i' a' more' r = kf i (a <> a') (more <> more') [] ("notFollowedBy " ++ show r)+ kf' _i' a' more' _ _ = ks (i <> I (unA a')) (a <> a') (more <> more') ()+ in runParser p i mempty more kf' ks'+{-# INLINE notFollowedBy #-}
Data/Picoparsec/Internal/Types.hs view
@@ -52,10 +52,13 @@ -- not yet been consumed (if any) when the parse succeeded. instance (Show i, Show r) => Show (IResult i r) where- show (Fail t stk msg) =- unwords [ "Fail", show t, show stk, show msg]- show (Partial _) = "Partial _"- show (Done t r) = unwords ["Done", show t, show r]+ showsPrec d ir = showParen (d > 10) $+ case ir of+ (Fail t stk msg) -> showString "Fail" . f t . f stk . f msg+ (Partial _) -> showString "Partial _"+ (Done t r) -> showString "Done" . f t . f r+ where f :: Show a => a -> ShowS+ f x = showChar ' ' . showsPrec 11 x instance (NFData i, NFData r) => NFData (IResult i r) where rnf (Fail t stk msg) = rnf t `seq` rnf stk `seq` rnf msg
picoparsec.cabal view
@@ -1,5 +1,5 @@ name: picoparsec-version: 0.1.1+version: 0.1.2 license: BSD3 license-file: LICENSE category: Text, Parsing
tests/QC/Combinator.hs view
@@ -1,6 +1,10 @@+{-# LANGUAGE OverloadedStrings #-}+ module QC.Combinator where import Control.Applicative ((<$>), (<*>))+import Data.List (isPrefixOf)+import Data.Maybe (fromJust, isJust) import Data.Monoid (mempty) import Data.Word (Word8) import QC.Common (Repack, parse, repackBS, toStrictBS)@@ -24,6 +28,23 @@ (length <$> parse (C.count n (P.string s)) (BL.toStrict input)) == Just n where input = repackBS rs (B8.concat (replicate (n+1) s)) +lookAhead :: NonEmptyList Word8 -> Bool+lookAhead (NonEmpty xs) =+ let ys = B.pack xs+ withLookAheadThenConsume = (,) <$> C.lookAhead (P.string ys) <*> P.string ys+ mr = parse withLookAheadThenConsume ys+ in isJust mr && fst (fromJust mr) == snd (fromJust mr)++notFollowedBy :: NonEmptyList Word8 -> NonEmptyList Word8 -> Bool+notFollowedBy (NonEmpty xs) (NonEmpty ys) =+ let xs' = B.pack xs+ ys' = B.pack ys+ withNotFollowedByThenConsume = (,) <$> C.notFollowedBy (P.string xs') <*> P.string ys'+ mr = parse withNotFollowedByThenConsume ys'+ in mr == if xs `isPrefixOf` ys || ys `isPrefixOf` xs+ then Nothing+ else Just ((), ys')+ {- match :: Int -> NonNegative Int -> NonNegative Int -> Repack -> Bool match n (NonNegative x) (NonNegative y) rs =@@ -40,4 +61,6 @@ testProperty "choice" choice , testProperty "count" count -- , testProperty "match" match+ , testProperty "lookAhead" lookAhead+ , testProperty "notFollowedBy" notFollowedBy ]