{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DataKinds #-} -- -- Monad.hs --- Bit field modification Monad. -- -- Copyright (C) 2013, Galois, Inc. -- All Rights Reserved. -- module Ivory.Language.BitData.Monad where import Prelude () import Prelude.Compat import Data.List (intercalate) import qualified MonadLib as M import Ivory.Language.BitData.Bits import Ivory.Language.BitData.BitData import Ivory.Language.Cast import Ivory.Language.Ref import Ivory.Language.Area import Ivory.Language.Monad import Ivory.Language.Comment -- | An action that modifies a bit data value of type "d" and returns -- a "a" in the "Ivory s r" monad. Values of this type are passed as -- the "body" argument to "withBits" etc. newtype BitDataM d a = BitDataM { runBitDataM :: M.StateT d (M.WriterT [String] M.Id) a } deriving (Functor, Monad, Applicative) -- | Clear the value of the current bit data value. clear :: BitData d => BitDataM d () clear = return () -- BitDataM $ M.set 0 -- XXX add getField and getBit? it might get confusing if they are in -- the monad. -- | Set a single bit field in the current bit data value. setBit :: BitData d => BitDataField d Bit -> BitDataM d () setBit f = BitDataM $ do M.put ["setBit " ++ bitDataFieldName f] M.sets_ (setBitDataBit f) -- | Clear a single bit. clearBit :: BitData d => BitDataField d Bit -> BitDataM d () clearBit f = BitDataM $ do M.put ["clearBit " ++ bitDataFieldName f] M.sets_ (clearBitDataBit f) -- | Set a field to a value. setField :: (BitData d, BitData b, SafeCast (BitDataRep b) (BitDataRep d)) => BitDataField d b -> b -> BitDataM d () setField f x = BitDataM $ do M.put ["setField " ++ bitDataFieldName f] M.sets_ (\v -> setBitDataField f v x) -- | Execute a bitdata action given an initial value, returning the -- new bitdata value and the result of the action. runBits :: BitData d => BitDataRep d -> BitDataM d a -> (a, BitDataRep d, [String]) runBits rep mf = (res, toRep val, s) where ((res, val), s) = M.runId $ M.runWriterT $ M.runStateT (fromRep rep) (runBitDataM mf) -- | Execute a bitdata action given an initial value, returning the -- new bitdata value. withBits :: BitData d => BitDataRep d -> BitDataM d () -> BitDataRep d withBits rep mf = let (_, r, _) = runBits rep mf in r -- | Execute a bit data action given a reference to a value, writing -- the resulting value back to the reference upon completion and -- returning the result of the action. withBitsRef :: BitData d => Ref s1 ('Stored (BitDataRep d)) -> BitDataM d a -> Ivory eff a withBitsRef ref mf = do rep <- deref ref let (res, rep', ss) = runBits rep mf comment ("withBitsRef: " ++ intercalate ", " ss) store ref rep' return res