packages feed

eflint-4.1.0.1: src/Language/EFLINT/State.hs

{-# LANGUAGE TupleSections #-}

module Language.EFLINT.State where

import Language.EFLINT.Spec

import Data.Maybe (isJust)
import qualified Data.Map as M

import Control.Applicative (empty)

data Info   = Info {
                value :: Bool
              , from_sat :: Bool -- whether assignment came from saturation process
              }
              deriving (Eq, Read, Show)

data State =  State {
                  contents :: M.Map Tagged Info  -- meta-info about components
              ,   time :: Int
              }
              deriving Eq

data Transition = Transition {
                    tagged :: Tagged
                  , exist  :: Bool
                  }  
                  deriving (Ord, Eq, Show, Read)

type Store = M.Map Tagged Assignment 

data Assignment = HoldsTrue
                | HoldsFalse
                | Unknown
                deriving (Eq, Ord, Show, Read)

toAssignment :: Maybe Bool -> Assignment
toAssignment (Just True) = HoldsTrue
toAssignment (Just False) = HoldsFalse
toAssignment Nothing = Unknown

emptyStore = M.empty

-- | biased union over stores, precedence HoldsTrue > HoldsFalse > Unknown
store_union :: Store -> Store -> Store
store_union = M.unionWith op
  where op HoldsTrue _      = HoldsTrue
        op _ HoldsTrue      = HoldsTrue
        op HoldsFalse _     = HoldsFalse
        op _ HoldsFalse     = HoldsFalse
        op Unknown Unknown  = Unknown
store_unions :: [Store] -> Store
store_unions = foldr store_union emptyStore

missing_assignments :: [Tagged] -> [Tagged] -> [Tagged] -> Maybe Restriction -> MissingInput
missing_assignments trues falses unknowns mres = MissingAssignments (M.unions
  [M.fromList $ map (,HoldsTrue) trues 
  ,M.fromList $ map (,HoldsFalse) falses 
  ,M.fromList $ map (,Unknown) unknowns]) mres

make_assignments :: Spec -> Store -> State -> State
make_assignments spec = flip (M.foldrWithKey op)
  where op te@(_,d) HoldsTrue = case restriction_of spec d of
              Just VarRestriction      -> var_assignment te
              Just FunctionRestriction -> function_assignment te
              _                        -> create te
        op te HoldsFalse  = terminate te
        op te Unknown     = obfuscate te

        create :: Tagged -> State -> State
        create te s = s { contents = M.insert te Info{ value = True, from_sat = False } (contents s) }

        terminate :: Tagged -> State -> State
        terminate te s = s { contents = M.insert te Info{ value = False, from_sat = False } (contents s) }

        obfuscate :: Tagged -> State -> State
        obfuscate te s = s { contents = M.delete te (contents s) }

        var_assignment :: Tagged -> State -> State
        var_assignment te@(_,d) s = create te $ s { contents = M.mapWithKey op (contents s) }
          where op te@(_,d') i | d == d'   = i { value = False, from_sat = False }
                               | otherwise = i

        function_assignment :: Tagged -> State -> State
        function_assignment te@(Product [f,t], d) s = 
          create te $ s { contents = M.mapWithKey op (contents s) }
          where op (Product [f',t'], d') i | d == d' && f == f' = i { value = False, from_sat = False }
                op _ i = i
        function_assignment _ s = s


derive :: Tagged -> State -> State
derive te s = s { contents = M.alter adj te (contents s) }
  where adj Nothing     = Just $ Info{ value = True, from_sat = True }
        adj (Just info) = Just info

derive_all :: [Tagged] -> State -> State
derive_all = flip (foldr derive)

-- | assumes the instance of a closed type
holds :: Tagged -> State -> Bool
holds te s = maybe False ((==True) . value) (M.lookup te (contents s))

emptyState = State { contents = M.empty, time = 0 }

increment_time state = state { time = 1 + (time state) }

instance Show State where
  show state = unlines $ 
      [ show_component c ++ " = " ++ show (value m)
      | (c,m) <- M.assocs (contents state)
      ]

-- instance ToJSON State where
-- toJSON state = toJSON (map TaggedJSON (state_holds state)) 

state_holds :: State -> [Tagged]
state_holds state = [ te | (te, m) <- M.assocs (contents state), True == value m ]

state_not_holds :: State -> [Tagged]
state_not_holds state = [ te | (te, m) <- M.assocs (contents state), False == value m ]

assigned_instances :: State -> DomId -> ([Tagged], [Tagged])
assigned_instances state d = 
  ([ te | (te@(_,d'), m) <- M.assocs (contents state), d == d', value m == True ] 
  ,[ te | (te@(_,d'), m) <- M.assocs (contents state), d == d', value m == False ] 
  )

data Context = Context {
                  ctx_spec        :: Spec --mutable, fixed?
                , ctx_state       :: State --mutable 
                , ctx_transitions :: [Transition] -- (label * violated?) -- replaceable
                , ctx_duties      :: [Tagged] -- replaceable
                }

-- mutable means c0 ; c1 results in c1 adding to c0 with possible override
-- appendable means c0 ; c1 results in effects of c0 and c1 being concatenated
-- replaceable means c0 ; c1 results in effect of c1

emptyContext spec = 
               Context { 
                  ctx_spec = spec
                , ctx_state = emptyState
                , ctx_transitions = empty
                , ctx_duties = empty }

data TransInfo = TransInfo {
                  trans_tagged      :: Tagged 
                , trans_assignments :: Store  -- includes sync'ed effects
                , trans_forced      :: Bool -- whether it causes a violation (e.g., is disabled and institutional) 
                , trans_disabled    :: Bool -- whether this, or a sync'ed transition, is not enabled
                , trans_actor       :: Maybe Tagged
                , trans_syncs       :: [TransInfo] -- the transitions this transitions sync'ed with 
                }
                deriving (Eq, Ord, Show, Read) 

trans_is_action :: TransInfo -> Bool
trans_is_action = isJust . trans_actor

-- | Get all the TransInfo nodes in the tree represented by the given root
trans_all_infos :: TransInfo -> [TransInfo]
trans_all_infos info = info : concatMap trans_all_infos (trans_syncs info)

data Violation = DutyViolation      Tagged
               | TriggerViolation   TransInfo 
               | InvariantViolation DomId
               deriving (Ord, Eq, Show, Read) 

data QueryRes = QuerySuccess
              | QueryFailure
              deriving (Ord, Eq, Show, Read)

data Error = -- trigger errors
             NotTriggerable DomId 
           | CompilationError String
           | RuntimeError RuntimeError
           deriving (Eq, Ord, Show, Read) 

data RuntimeError
      = MissingInput MissingInput 
      | InternalError InternalError
      deriving (Eq, Ord, Show, Read) 

data MissingInput 
      = MissingAssignments  Store (Maybe Restriction)  -- all Tagged have same DomId component, complete wrt finite dom
      | MissingInstances    DomId MDomain (Maybe Restriction)
      deriving (Eq, Ord, Show, Read) 

data MDomain    = MAnyString
                | MAnyInt
                | MStrings [String]
                | MInts [Int]
                | MProducts [(DomId, MDomain)]
                deriving (Ord, Eq, Show, Read)

data InternalError 
      = EnumerateInfiniteDomain DomId Domain 
      | MissingSubstitution Var
      | PrimitiveApplication DomId
      | UndeclaredType DomId 
      deriving (Eq, Ord, Show, Read)

print_error :: Error -> String
print_error (NotTriggerable d) = "not a triggerable (act- or event-) type: " ++ d
print_error (CompilationError err) = err
print_error (RuntimeError err) = print_runtime_error err

print_runtime_error :: RuntimeError -> String
print_runtime_error (MissingInput miss) = case miss of
  MissingAssignments tes _ -> "missing input assignments for: " ++ show (map ppTagged (M.keys tes))
  MissingInstances domid dom _ -> "missing input assignments for type: " ++ domid
print_runtime_error (InternalError err) = "INTERNAL ERROR " ++ print_internal_error err

print_internal_error :: InternalError -> String
print_internal_error (EnumerateInfiniteDomain d AnyString) = "cannot enumerate all strings of type: " ++ d
print_internal_error (EnumerateInfiniteDomain d AnyInt) = "cannot enumerate all integers of type: " ++ d
print_internal_error (EnumerateInfiniteDomain d _) = "cannot enumerate all instances of type: " ++ d
print_internal_error (MissingSubstitution (Var base dec)) = "variable " ++ base ++ dec ++ " not bound"
print_internal_error (PrimitiveApplication d) = "application of primitive type: " ++ d
print_internal_error (UndeclaredType d) = "undeclared type: " ++ d