module Data.LLVM.BitCode.GetBits (
GetBits
, runGetBits
, fixed, align32bits
, label
, isolate
, try
, skip
) where
import Data.LLVM.BitCode.BitString
import Control.Applicative (Applicative(..),Alternative(..),(<$>))
import Control.Arrow (first)
import Control.Monad (MonadPlus(..))
import Data.Bits (shiftR)
import Data.Monoid (mempty,mappend)
import Data.Word (Word32)
import qualified Data.Serialize as C
newtype GetBits a = GetBits { unGetBits :: SubWord -> C.Get (a,SubWord) }
runGetBits :: GetBits a -> C.Get a
runGetBits m = fst `fmap` unGetBits m Aligned
instance Functor GetBits where
fmap f m = GetBits (\ off -> first f <$> unGetBits m off)
instance Applicative GetBits where
pure x = GetBits (\ off -> return (x,off))
f <*> x = GetBits $ \ off0 -> do
(g,off1) <- unGetBits f off0
(y,off2) <- unGetBits x off1
return (g y,off2)
instance Monad GetBits where
return = pure
m >>= f = GetBits $ \ off0 -> do
(x,off1) <- unGetBits m off0
unGetBits (f x) off1
fail str = GetBits (\ _ -> fail str)
instance Alternative GetBits where
empty = GetBits (\_ -> mzero)
a <|> b = GetBits (\ off -> unGetBits a off <|> unGetBits b off)
instance MonadPlus GetBits where
mzero = empty
mplus = (<|>)
data SubWord
= SubWord !Int !Word32
| Aligned
deriving (Show)
splitWord :: Int -> Int -> Word32 -> (BitString,Either Int SubWord)
splitWord n l w = case compare n l of
LT -> (toBitString n (fromIntegral w), Right (SubWord (l n) (w `shiftR` n)))
EQ -> (toBitString n (fromIntegral w), Right Aligned)
GT -> (toBitString l (fromIntegral w), Left (n l))
getBitString :: Int -> C.Get (BitString,SubWord)
getBitString 0 = return (mempty,Aligned)
getBitString n = getBitStringPartial n 32 =<< C.getWord32le
getBitStringPartial :: Int -> Int -> Word32 -> C.Get (BitString,SubWord)
getBitStringPartial n l w = case splitWord n l w of
(bs,Right off) -> return (bs, off)
(bs,Left n') -> do
(rest,off) <- getBitString n'
return (bs `mappend` rest, off)
align32bits :: GetBits ()
align32bits = GetBits $ \ off -> case off of
Aligned -> return ((),Aligned)
SubWord _ 0 -> return ((),Aligned)
SubWord _ _ -> fail "alignment padding was not zeros"
fixed :: Int -> GetBits BitString
fixed n = GetBits $ \ off -> case off of
Aligned -> getBitString n
SubWord l w -> getBitStringPartial n l w
label :: String -> GetBits a -> GetBits a
label l m = GetBits (\ off -> C.label l (unGetBits m off))
isolate :: Int -> GetBits a -> GetBits a
isolate ws m = GetBits (\ off -> C.isolate (ws * 4) (unGetBits m off))
try :: GetBits a -> GetBits (Maybe a)
try m = (Just <$> m) `mplus` return Nothing
skip :: Int -> GetBits ()
skip n = do
_ <- fixed n
return ()