module Sound.MIDI.Parser.Class
(C, isEnd, getByte,
warn, giveUp, try,
force, zeroOrMore, zeroOrMoreInc, until, replicate, skip,
PossiblyIncomplete, UserMessage,
) where
import Sound.MIDI.Parser.Report (UserMessage)
import Control.Monad (liftM, liftM2, )
import Data.Word (Word8)
import qualified Numeric.NonNegative.Wrapper as NonNeg
import Sound.MIDI.Utility (mapSnd, )
import Prelude hiding (replicate, until, )
class Monad parser => C parser where
isEnd :: parser Bool
getByte :: parser Word8
skip :: NonNeg.Integer -> parser ()
warn :: UserMessage -> parser ()
giveUp :: UserMessage -> parser a
try :: parser a -> parser (Either UserMessage a)
force :: parser a -> parser a
type PossiblyIncomplete a = (Maybe UserMessage, a)
zeroOrMore :: C parser =>
parser a -> parser (PossiblyIncomplete [a])
zeroOrMore p =
let go =
force $ isEnd >>= \b ->
if b
then return (Nothing, [])
else handleMsg
(\errMsg -> (Just errMsg, []))
(liftM2 (\ x ~(e,xs) -> (e,x:xs)) p go)
in go
zeroOrMoreInc :: C parser =>
parser (PossiblyIncomplete a) -> parser (PossiblyIncomplete [a])
zeroOrMoreInc p =
let go =
force $ isEnd >>= \b ->
if b
then return (Nothing, [])
else handleMsg
(\errMsg -> (Just errMsg, []))
(appendIncomplete p go)
in go
until :: C parser =>
(a -> Bool) -> parser a -> parser (PossiblyIncomplete [a])
until c p =
let go =
force $ isEnd >>= \b ->
if b
then
return (Just "Parser.until: unexpected end of input", [])
else
handleMsg
(\errMsg -> (Just errMsg, [])) $
p >>= \x ->
if c x
then return (Nothing, [])
else liftM (mapSnd (x:)) go
in go
replicate ::
C parser =>
NonNeg.Int ->
parser (PossiblyIncomplete a) ->
parser (PossiblyIncomplete [a])
replicate m p =
let go n =
force $
if n==0
then return (Nothing, [])
else handleMsg
(\errMsg -> (Just errMsg, []))
(appendIncomplete p (go (n1)))
in go m
appendIncomplete ::
C parser =>
parser (PossiblyIncomplete a) ->
parser (PossiblyIncomplete [a]) ->
parser (PossiblyIncomplete [a])
appendIncomplete p ps =
do ~(me, x) <- p
liftM (mapSnd (x:)) $ force $
maybe ps (\_ -> return (me,[])) me
handleMsg ::
C parser =>
(UserMessage -> a) -> parser a -> parser a
handleMsg handler action =
liftM
(either handler id)
(try action)