Pugs-6.2.13.1: src/Pugs/AST/Pad.hs
{-# OPTIONS_GHC -fglasgow-exts -fparr #-}
module Pugs.AST.Pad (
mkPad, unionPads, padKeys, filterPad, adjustPad, mergePadEntry,
mergeLexPads, readMPad, writeMPad, appendMPad, modifyMPad, newMPad
) where
import Pugs.Internals
import Pugs.AST.SIO
import Pugs.AST.Internals
import Pugs.Types
import qualified Data.Map as Map
import qualified Data.Set as Set
instance Monoid Pad where
mempty = emptyPad
mappend = unionPads
mconcat = MkPad . Map.unionsWith mergePadEntry . map padEntries
{-|
Produce a 'Pad' from a list of bindings. The inverse of 'padToList'.
Not to be confused with the actual 'Pad' constructor @MkPad@.
-}
mkPad :: [(Var, PadEntry)] -> Pad
mkPad = listToPad
{-|
Merge multiple (possibly mutable) pads into one.
-}
mergeLexPads :: MonadSTM m => LexPads -> m Pad
mergeLexPads chain = stm $ do
pads <- forM chain $ \lpad -> case lpad of
PRuntime p -> return p
PCompiling p -> readMPad p
return . MkPad $ Map.unionsWith mergePadEntry (map padEntries pads)
readMPad :: MonadSTM m => MPad -> m Pad
readMPad = stm . readTVar . mp_pad
writeMPad :: MonadSTM m => MPad -> Pad -> m ()
writeMPad mp p = stm $ writeTVar (mp_pad mp) p
appendMPad :: MonadSTM m => MPad -> Pad -> m ()
appendMPad mp p = stm $ modifyTVar (mp_pad mp) (`unionPads` p)
modifyMPad :: MonadSTM m => MPad -> (Pad -> Pad) -> m ()
modifyMPad mp f = stm $ modifyTVar (mp_pad mp) f
newMPad :: MonadSTM m => Pad -> m MPad
newMPad p = do
tvar <- stm $ newTVar p
return $ MkMPad (addressOf tvar) tvar
{-
{-|
Return the difference between two 'Pad's.
Any keys found in both pads that has identical values are removed from the
resulting pad. Keys found only in the second pad are ignored.
-}
diffPads :: Pad -> Pad -> Pad
diffPads (MkPad map1) (MkPad map2) = MkPad $ Map.differenceWith diffPadEntry map1 map2
where
diffPadEntry x y | x == y = Nothing
| otherwise = Just x
-}
{-|
Return the key-wise union of two 'Pad's.
If the same key is found in both pads, merging multi subs into one.
-}
unionPads :: Pad -> Pad -> Pad
unionPads (MkPad map1) (MkPad map2) = MkPad $ Map.unionWith mergePadEntry map1 map2
adjustPad :: (PadEntry -> PadEntry) -> Var -> Pad -> Pad
adjustPad f v (MkPad p) = MkPad (Map.adjust f v p)
mergePadEntry :: PadEntry -> PadEntry -> PadEntry
mergePadEntry
PEConstant{ pe_proto = MkRef (ICode newCV), pe_flags = flags }
PEConstant{ pe_proto = MkRef (ICode oldCV) }
| Just (newMC :: VMultiCode) <- fromTypeable newCV
, Just (oldMC :: VMultiCode) <- fromTypeable oldCV
= PEConstant
{ pe_type = mc_type newMC -- XXX - Select a narrower type?
, pe_proto = MkRef . ICode $! MkMultiCode
{ mc_type = mc_type newMC
, mc_subtype = mc_subtype newMC
, mc_assoc = code_assoc newMC `mappend` code_assoc oldMC
, mc_signature = if length (mc_signature newMC) == length (code_params oldMC)
then code_params newMC
else [defaultArrayParam]
, mc_variants = mc_variants newMC `Set.union` mc_variants oldMC
}
, pe_flags = flags
}
mergePadEntry x _ = x
padKeys :: Pad -> Set Var
padKeys (MkPad pad) = Map.keysSet pad
filterPad :: (Var -> Bool) -> Pad -> Pad
filterPad f (MkPad pad) = MkPad (Map.filterWithKey (\k _ -> f k) pad)