------------------------------------------------------------------------------
--- A Monad for Parsers
---
--- @author Jasper Sikorra - jsi@informatik.uni-kiel.de
--- @version January 2014
------------------------------------------------------------------------------
module ParseMonad where
import ParseError
import ParseWarning
import ParsePos
--- Combining ParseResult and Warnings monads into a new monad
type PM a = WM (PR a)
--- Encapsulate an Error Monad with a Warning Monad creating a PM Monad
warnPM :: PR a -> [Warning] -> PM a
warnPM x w = returnWM x w
--- Bind
bindPM :: PM a -> (a -> PM b) -> PM b
bindPM m f = bindWM m $ \b -> case b of
Errors p -> cleanWM (Errors p)
OK x -> f x
--- Lift
liftPM :: (a -> b) -> PM a -> PM b
liftPM f m = bindPM m (cleanPM . f)
--- Return without Warnings or Errors
cleanPM :: a -> PM a
cleanPM x = warnOKPM x []
--- Return without Errors but with Warnings
warnOKPM :: a -> [Warning] -> PM a
warnOKPM x = warnPM (okPR x)
--- Return without Warnings but with Errors
throwPM :: Pos -> String -> PM _
throwPM p s = cleanWM (throwPMsg p s)
throwMultiPM :: Pos -> [String] -> PM _
throwMultiPM p strs = cleanWM (throwPR (map (\s -> (PError p s)) strs))
--- Return without Errors but with one Warning
singlePM :: a -> Warning -> PM a
singlePM x w = warnOKPM x [w]
--- Remove the Warning Monad from PM
discardWarningsPM :: PM a -> PR a
discardWarningsPM = discardWarnings
--- Extract the Warnings
getWarningsPM :: PM a -> [Warning]
getWarningsPM = getWarnings
--- Apply a function on each Warning
mapWarnsPM :: (Warning -> Warning) -> PM a -> PM a
mapWarnsPM = mapWarns
--- Crumple two Parser Monads
crumplePM :: PM (PM a) -> PM a
crumplePM m = bindPM m id
--- Swap the PM and the IO Monad
swapIOPM :: PM (IO a) -> IO (PM a)
swapIOPM m = swapIOPR (discardWarningsPM m)
>>= return . flip warnPM (getWarningsPM m)
--- Join multiple Parser Monads into one
sequencePM :: [PM a] -> PM [a]
sequencePM ms = warnPM (sequencePR (map discardWarnings ms))
(foldr (++) [] (map getWarnings ms))
--- fst defined on PM
fstPM :: PM (a,b) -> PM a
fstPM = liftPM fst
--- snd defined on PM
sndPM :: PM (a,b) -> PM b
sndPM = liftPM snd
--- combines two PMs by function f, throws error if at least one of
--- the two carries an error
combinePMs :: (a -> b -> c) -> PM a -> PM b -> PM c
combinePMs f p1 p2 = warnPM (combinePRs f (discardWarningsPM p1)
(discardWarningsPM p2))
(concatWarns p1 p2)
where
concatWarns (WM _ w1) (WM _ w2) = w1 ++ w2