module Sound.MIDI.Parser.ByteString
(T(..), run, runIncomplete,
PossiblyIncomplete, UserMessage, ) where
import qualified Data.ByteString.Lazy as B
import qualified Data.Binary.Get as Binary
import Data.Binary.Get (Get, runGet, )
import Control.Monad.Trans.Class (lift, )
import qualified Sound.MIDI.Parser.Report as Report
import qualified Sound.MIDI.Parser.Class as Parser
import Sound.MIDI.Parser.Class (UserMessage, PossiblyIncomplete, )
import qualified Sound.MIDI.Parser.Exception as Exception
import qualified Sound.MIDI.Parser.Warning as Warning
import Data.Int (Int64)
import qualified Numeric.NonNegative.Wrapper as NonNeg
import Prelude hiding (replicate, until, )
newtype T a = Cons {decons :: Warning.T Get a}
run :: Parser.Fallible T a -> B.ByteString -> Report.T a
run parser input =
flip runGet input $ Warning.run $ decons $ Exception.run $
(do a <- parser
lift $
Parser.isEnd >>= \end ->
Parser.warnIf (not end) "unparsed data left over"
return a)
runIncomplete ::
Parser.Partial (Parser.Fallible T) a -> B.ByteString -> Report.T a
runIncomplete parser input =
flip run input $
lift . Parser.warnIncomplete =<< parser
fromGet :: Get a -> T a
fromGet p =
Cons $ lift p
instance Monad T where
return = Cons . return
x >>= y = Cons $ decons . y =<< decons x
instance Parser.EndCheck T where
isEnd = fromGet Binary.isEmpty
instance Parser.C T where
getByte =
do end <- lift $ fromGet Binary.isEmpty
if end
then Parser.giveUp "unexpected end of ByteString"
else lift $ fromGet Binary.getWord8
skip n =
let toSize x =
let y = if x > fromIntegral (maxBound `asTypeOf` y)
then error "skip: number too big"
else fromIntegral x
in y
in lift $ fromGet $ skip $ toSize $ NonNeg.toNumber n
warn = Cons . Warning.warn
skip :: Int64 -> Get ()
skip n = Binary.getLazyByteString n >> return ()