module Darcs.Util.Parser ( Parser , anyChar , char , checkConsumes , choice , endOfInput , int , lexChar , lexString , linesStartingWith , linesStartingWithEndingWith , lexWord , option , optional , parse , skipSpace , skipWhile , string , take , takeTill , takeTillChar ) where import Control.Applicative ( empty, many, optional, (<|>) ) import Darcs.Prelude hiding ( lex, take ) import qualified Data.Attoparsec.ByteString as A import Data.Attoparsec.ByteString.Char8 hiding ( parse, char, string ) import qualified Data.Attoparsec.ByteString.Char8 as AC import qualified Data.ByteString as B parse :: Parser a -> B.ByteString -> Either String (a, B.ByteString) parse p bs = case AC.parse p bs of Fail _ ss s -> Left $ unlines (s:ss) Partial k -> case k B.empty of Fail _ ss s -> Left $ unlines (s:ss) Partial _ -> error "impossible" Done i r -> Right (r, i) Done i r -> Right (r, i) {-# INLINE skip #-} skip :: Parser a -> Parser () skip p = p >> return () {-# INLINE lex #-} lex :: Parser a -> Parser a lex p = skipSpace >> p {-# INLINE lexWord #-} lexWord :: Parser B.ByteString lexWord = lex (A.takeWhile1 (not . isSpace_w8)) {-# INLINE lexChar #-} lexChar :: Char -> Parser () lexChar c = lex (char c) {-# inline lexString #-} lexString :: B.ByteString -> Parser () lexString s = lex (string s) {-# INLINE char #-} char :: Char -> Parser () char = skip . AC.char {-# INLINE string #-} string :: B.ByteString -> Parser () string = skip . AC.string {-# INLINE int #-} int :: Parser Int int = lex (signed decimal) {-# INLINE takeTillChar #-} takeTillChar :: Char -> Parser B.ByteString takeTillChar c = takeTill (== c) {-# INLINE checkConsumes #-} checkConsumes :: Parser a -> Parser a checkConsumes parser = do (consumed, result) <- match parser if B.null consumed then empty else return result {-# INLINE linesStartingWith #-} linesStartingWith :: Char -> Parser [B.ByteString] linesStartingWith c = many $ do char c r <- takeTillChar '\n' skip (char '\n') <|> endOfInput return r {-# INLINE linesStartingWithEndingWith #-} linesStartingWithEndingWith :: Char -> Char -> Parser [B.ByteString] linesStartingWithEndingWith st en = do ls <- linesStartingWith st char en return ls