Simplify Content abstracting over MonadParser for no reason and provide instead an parse that's in MonadFail to avoid having to handle Either outside

This commit is contained in:
Tissevert 2020-03-08 22:16:23 +01:00
parent 673321bf0a
commit f2986da96d

View file

@ -12,13 +12,13 @@ module PDF.Content (
, Id(..) , Id(..)
, Indexed , Indexed
, TextContext , TextContext
, content
, parse , parse
) where ) where
import Control.Applicative ((<|>)) import Control.Applicative ((<|>))
import Control.Monad.Fail (MonadFail)
import Control.Monad.Reader (asks, runReader) import Control.Monad.Reader (asks, runReader)
import Control.Monad.State (MonadState, evalStateT, gets, modify, runStateT) import Control.Monad.State (evalStateT, gets, modify)
import Data.Attoparsec.ByteString.Char8 (sepBy) import Data.Attoparsec.ByteString.Char8 (sepBy)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Map (Map, (!)) import Data.Map (Map, (!))
@ -27,7 +27,7 @@ import PDF.Box (Box(..))
import PDF.Content.Operator (Instruction, operator) import PDF.Content.Operator (Instruction, operator)
import PDF.Object (blank, directObject) import PDF.Object (blank, directObject)
import PDF.Output (Output(..), line) import PDF.Output (Output(..), line)
import PDF.Parser (MonadParser, evalParser, string) import PDF.Parser (Parser, runParser, string)
newtype Id a = Id Int deriving (Eq, Ord, Show) newtype Id a = Id Int deriving (Eq, Ord, Show)
data Instructions = Instructions data Instructions = Instructions
@ -47,27 +47,26 @@ data Content = Content {
, indexedInstructions :: Indexed Instruction , indexedInstructions :: Indexed Instruction
} deriving Show } deriving Show
type InstructionParser m = (MonadParser m, MonadState (Indexed Instruction) m) type InstructionParser = Parser (Indexed Instruction)
instance Monad m => Box m Instructions Content (Indexed Instruction) where instance Monad m => Box m Instructions Content (Indexed Instruction) where
r Instructions = return . indexedInstructions r Instructions = return . indexedInstructions
w Instructions indexedInstructions someContent = w Instructions indexedInstructions someContent =
return $ someContent {indexedInstructions} return $ someContent {indexedInstructions}
register :: MonadState (Indexed Instruction) m => Instruction -> m (Id Instruction) register :: Instruction -> InstructionParser (Id Instruction)
register newInstruction = do register newInstruction = do
newInstructionID <- gets (Id . Map.size) newInstructionID <- gets (Id . Map.size)
modify (Map.insert newInstructionID newInstruction) modify (Map.insert newInstructionID newInstruction)
return newInstructionID return newInstructionID
content :: MonadParser m => m Content parse :: MonadFail m => ByteString -> m Content
content = do parse =
(contentUnits, indexedInstructions) <- runInstructionParser either fail (return . uncurry Content) . runParser contentUnits Map.empty
return $ Content {contentUnits, indexedInstructions}
where where
runInstructionParser = runStateT (contentUnit `sepBy` blank) Map.empty contentUnits = contentUnit `sepBy` blank
contentUnit :: InstructionParser m => m ContentUnit contentUnit :: InstructionParser ContentUnit
contentUnit = contentUnit =
(GraphicContext <$> graphicContext) (GraphicContext <$> graphicContext)
<|> (TextContext <$> textContext) <|> (TextContext <$> textContext)
@ -75,21 +74,18 @@ contentUnit =
graphicContext = graphicContext =
string "q" *> blank *> graphicContextUnit `sepBy` blank <* blank <* string "Q" string "q" *> blank *> graphicContextUnit `sepBy` blank <* blank <* string "Q"
graphicContextUnit :: InstructionParser m => m GraphicContextUnit graphicContextUnit :: InstructionParser GraphicContextUnit
graphicContextUnit = graphicContextUnit =
(GraphicInstruction <$> instruction) (GraphicInstruction <$> instruction)
<|> (ContentUnit <$> contentUnit) <|> (ContentUnit <$> contentUnit)
instruction :: InstructionParser m => m (Id Instruction) instruction :: InstructionParser (Id Instruction)
instruction = evalStateT stackParser [] >>= register instruction = evalStateT stackParser [] >>= register
where where
stackParser = ((directObject <* blank) >>= push) <|> operator stackParser = ((directObject <* blank) >>= push) <|> operator
push arg = modify (arg:) *> stackParser push arg = modify (arg:) *> stackParser
parse :: ByteString -> Either String Content textContext :: InstructionParser TextContext
parse = evalParser content ()
textContext :: InstructionParser m => m TextContext
textContext = textContext =
string "BT" *> blank *> instruction `sepBy` blank <* blank <* string "ET" string "BT" *> blank *> instruction `sepBy` blank <* blank <* string "ET"