module Semantics ( Semantics , mkSemantics , lookup , pushFingerprint , popFingerprint , toggleOverlay , addOverlay , removeOverlay ) where import Prelude hiding (lookup) import Control.Monad.State.Strict import Data.Char (ord) import Data.I import Data.Labeled import Data.Map (Map) import qualified Data.Map as Map import Mode ----------------------------------------------------------- type Instruction env i = StateT (env i) IO type InfMap k v = (k -> Maybe v, Map k (Maybe v)) ----------------------------------------------------------- data Semantics env i = S { baseInstrs :: Map i (Instruction env i ()) , fingerInstrs :: Map i [Instruction env i ()] , overlayInstrs :: [Labeled Mode (InfMap i (Instruction env i ()))] } mkSemantics :: (I i) => Map i (Instruction env i ()) -> Semantics env i mkSemantics base = S { baseInstrs = base , fingerInstrs = Map.fromList $ zip [fromIntegral $ ord c | c <- ['A'..'Z']] $ repeat [] , overlayInstrs = [] } lookup :: (I i) => i -> Semantics env i -> Maybe (Instruction env i ()) lookup i sem = case lookupOverlay i $ map unlabel $ overlayInstrs sem of Just instr -> Just instr Nothing -> case lookupFinger i $ fingerInstrs sem of Just instr -> Just instr Nothing -> lookupBase i $ baseInstrs sem lookupOverlay :: (I i) => i -> [InfMap i (Instruction env i ())] -> Maybe (Instruction env i ()) lookupOverlay _ [] = Nothing lookupOverlay i ((f, m) : ms) = case Map.lookup i m of Just mInstr -> case mInstr of Just instr -> Just instr Nothing -> lookupOverlay i ms Nothing -> case f i of Just instr -> Just instr Nothing -> lookupOverlay i ms lookupFinger :: (I i) => i -> Map i [Instruction env i ()] -> Maybe (Instruction env i ()) lookupFinger i m = case Map.lookup i m of Nothing -> Nothing Just [] -> Nothing Just (instr:_) -> Just instr lookupBase :: (I i) => i -> Map i (Instruction env i ()) -> Maybe (Instruction env i ()) lookupBase = Map.lookup pushFingerprint :: (I i) => [(i, Instruction env i ())] -> Semantics env i -> Semantics env i pushFingerprint assocs sem = sem { fingerInstrs = m' } where m = fingerInstrs sem m' = foldr add m assocs add (i, instr) = Map.adjust (instr:) i popFingerprint :: (I i) => [(i, Instruction env i ())] -> Semantics env i -> Semantics env i popFingerprint assocs sem = sem { fingerInstrs = m' } where m = fingerInstrs sem m' = foldr (remove . fst) m assocs remove = Map.adjust tail addOverlay :: (I i) => Mode -> (i -> Maybe (Instruction env i ()), Map i (Maybe (Instruction env i ()))) -> Semantics env i -> Semantics env i addOverlay mode f_m sem = if mode `elem` map getLabel (overlayInstrs sem) then sem else addOverlay' mode f_m sem addOverlay' :: (I i) => Mode -> (i -> Maybe (Instruction env i ()), Map i (Maybe (Instruction env i ()))) -> Semantics env i -> Semantics env i addOverlay' mode f_m sem = sem { overlayInstrs = imap : overlayInstrs sem } where imap = label mode f_m removeOverlay :: (I i) => Mode -> Semantics env i -> Semantics env i removeOverlay mode sem = sem { overlayInstrs = removeOverlay' mode $ overlayInstrs sem } removeOverlay' :: (I i) => Mode -> [Labeled Mode (InfMap i (Instruction env i ()))] -> [Labeled Mode (InfMap i (Instruction env i ()))] removeOverlay' _ [] = [] removeOverlay' mode (m:ms) = if getLabel m == mode then ms else m : removeOverlay' mode ms toggleOverlay :: (I i) => Mode -> (i -> Maybe (Instruction env i ()), Map i (Maybe (Instruction env i ()))) -> Semantics env i -> Semantics env i toggleOverlay mode f_m sem = if mode `elem` map getLabel (overlayInstrs sem) then removeOverlay mode sem else addOverlay' mode f_m sem