99 lines
2.5 KiB
Haskell
99 lines
2.5 KiB
Haskell
module PDF.Parser (
|
|
Parser
|
|
, (<?>)
|
|
, block
|
|
, char
|
|
, choice
|
|
, count
|
|
, decNumber
|
|
, hexNumber
|
|
, many
|
|
, octDigit
|
|
, on
|
|
, oneOf
|
|
, option
|
|
, runParser
|
|
, sepBy
|
|
, string
|
|
, takeAll
|
|
, takeAll1
|
|
) where
|
|
|
|
import Control.Applicative ((<|>), empty)
|
|
import Control.Monad.State (StateT(..), evalStateT)
|
|
import Control.Monad.Trans (lift)
|
|
import qualified Data.Attoparsec.ByteString.Char8 as Atto (
|
|
Parser, char, parseOnly, satisfy, string, take, takeWhile, takeWhile1
|
|
)
|
|
import Data.ByteString (ByteString)
|
|
import Data.Char (toLower)
|
|
import Data.Set (Set)
|
|
import qualified Data.Set as Set (fromList, member, unions)
|
|
|
|
type Parser s = StateT s Atto.Parser
|
|
|
|
(<?>) :: Parser s a -> String -> Parser s a
|
|
(<?>) parser debugMessage = parser <|> fail debugMessage
|
|
|
|
block :: Int -> Parser s ByteString
|
|
block = lift . Atto.take
|
|
|
|
char :: Char -> Parser s Char
|
|
char = lift . Atto.char
|
|
|
|
choice :: [Parser s a] -> Parser s a
|
|
choice = foldr (<|>) empty
|
|
|
|
count :: Int -> Parser s a -> Parser s [a]
|
|
count 0 _ = return []
|
|
count n p = (:) <$> p <*> count (n-1) p
|
|
|
|
decNumber :: Parser s ByteString
|
|
decNumber = lift $ Atto.takeWhile1 (`Set.member` digits)
|
|
|
|
digits :: Set Char
|
|
digits = Set.fromList ['0'..'9']
|
|
|
|
hexDigits :: Set Char
|
|
hexDigits = Set.unions [digits, Set.fromList af, Set.fromList $ toLower <$> af]
|
|
where
|
|
af = ['A'..'F']
|
|
|
|
hexNumber :: Parser s ByteString
|
|
hexNumber = lift $ Atto.takeWhile1 (`Set.member` hexDigits)
|
|
|
|
many :: Parser s a -> Parser s [a]
|
|
many parser = (:) <$> parser <*> many parser <|> return []
|
|
|
|
octDigit :: Parser s Char
|
|
octDigit = oneOf ['0'..'7']
|
|
|
|
on :: Parser s a -> ByteString -> Parser s (Either String a)
|
|
on (StateT parserF) input = StateT $ \state ->
|
|
case Atto.parseOnly (parserF state) input of
|
|
Left errorMsg -> return (Left errorMsg, state)
|
|
Right (result, newState) -> return (Right result, newState)
|
|
|
|
oneOf :: String -> Parser s Char
|
|
oneOf charSet = lift $ Atto.satisfy (`elem` charSet)
|
|
|
|
option :: a -> Parser s a -> Parser s a
|
|
option defaultValue p = p <|> pure defaultValue
|
|
|
|
runParser :: Parser s a -> s -> ByteString -> Either String a
|
|
runParser parser initState =
|
|
Atto.parseOnly (evalStateT parser initState)
|
|
|
|
sepBy :: Parser s a -> Parser s b -> Parser s [a]
|
|
sepBy parser separator =
|
|
option [] $ (:) <$> parser <*> many (separator *> parser)
|
|
|
|
string :: ByteString -> Parser s ByteString
|
|
string = lift . Atto.string
|
|
|
|
takeAll :: (Char -> Bool) -> Parser s ByteString
|
|
takeAll = lift . Atto.takeWhile
|
|
|
|
takeAll1 :: (Char -> Bool) -> Parser s ByteString
|
|
takeAll1 = lift . Atto.takeWhile1
|