{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
module Language.Verification.Conditions
(
Assignment(..)
, AnnSeq(..)
, Triplet
, skipVCs
, assignVCs
, sequenceVCs
, ifVCs
, multiIfVCs
, whileVCs
, subAssignment
, chainSub
, joinAnnSeq
, JoinAnnSeq(..)
, joiningAnnSeq
, emptyAnnSeq
, propAnnSeq
, cmdAnnSeq
, module Language.Expression.Prop
) where
import Data.List (intersperse)
import Data.Semigroup (Semigroup(..))
import Data.Monoid (Endo (..))
import Control.Monad.Writer (MonadWriter (tell))
import Language.Expression.Pretty
import Language.Expression.Prop
import Language.Verification
data Assignment expr var where
Assignment :: var a -> expr var a -> Assignment expr var
instance (Pretty1 var, Pretty2 expr) => Pretty (Assignment expr var) where
prettysPrec p (Assignment v e) = showParen (p > 9) $
prettys1Prec 10 v . showString " := " . prettys2Prec 10 e
data AnnSeq expr var cmd
= JustAssign [Assignment expr var]
| CmdAssign cmd [Assignment expr var]
| Annotation (AnnSeq expr var cmd) (Prop (expr var) Bool) (AnnSeq expr var cmd)
deriving (Functor, Foldable, Traversable)
instance (Pretty2 expr, Pretty1 var, Pretty cmd) => Pretty (AnnSeq expr var cmd) where
prettysPrec _ (JustAssign as)
= appEndo . mconcat
. intersperse (Endo (showString "; "))
. map (Endo . prettysPrec 10)
$ as
prettysPrec _ (CmdAssign cmd as)
= appEndo . mconcat
. intersperse (Endo (showString "; "))
. (Endo (prettysPrec 10 cmd) :)
. map (Endo . prettysPrec 10)
$ as
prettysPrec _ (Annotation l p r)
= prettysPrec 10 l
. showString "; {"
. prettysPrec 10 p
. showString "}"
. prettysPrec 10 r
subAssignment
:: (HMonad expr, VerifiableVar v)
=> Assignment expr v -> Prop (expr v) a -> Prop (expr v) a
subAssignment (Assignment targetVar newExpr) = hmap (^>>= subVar newExpr targetVar)
chainSub
:: (HMonad expr, VerifiableVar v)
=> Prop (expr v) Bool -> [Assignment expr v] -> Prop (expr v) Bool
chainSub prop [] = prop
chainSub prop (a : as) = subAssignment a (chainSub prop as)
joinAnnSeq :: AnnSeq expr var cmd -> AnnSeq expr var cmd -> Maybe (AnnSeq expr var cmd)
joinAnnSeq (JustAssign xs) (JustAssign ys) = return $ JustAssign (xs ++ ys)
joinAnnSeq (CmdAssign cmd xs) (JustAssign ys) = return $ CmdAssign cmd (xs ++ ys)
joinAnnSeq s (JustAssign []) = return s
joinAnnSeq (JustAssign []) s = return s
joinAnnSeq (Annotation l p r) r' = Annotation l p <$> joinAnnSeq r r'
joinAnnSeq l' (Annotation l p r) = (\l'' -> Annotation l'' p r) <$> joinAnnSeq l' l
joinAnnSeq _ _ = Nothing
emptyAnnSeq :: AnnSeq expr var cmd
emptyAnnSeq = JustAssign []
propAnnSeq :: Prop (expr var) Bool -> AnnSeq expr var cmd
propAnnSeq p = Annotation emptyAnnSeq p emptyAnnSeq
cmdAnnSeq :: cmd -> AnnSeq expr var cmd
cmdAnnSeq c = CmdAssign c []
newtype JoinAnnSeq expr var cmd = JoinAnnSeq { tryJoinAnnSeq :: Maybe (AnnSeq expr var cmd) }
joiningAnnSeq :: AnnSeq expr var cmd -> JoinAnnSeq expr var cmd
joiningAnnSeq = JoinAnnSeq . Just
instance Semigroup (JoinAnnSeq expr var cmd) where
JoinAnnSeq (Just x) <> JoinAnnSeq (Just y) = JoinAnnSeq (x `joinAnnSeq` y)
_ <> _ = JoinAnnSeq Nothing
instance Monoid (JoinAnnSeq expr var cmd) where
mempty = JoinAnnSeq (Just emptyAnnSeq)
mappend = (<>)
type MonadGenVCs expr var = MonadWriter [Prop (expr var) Bool]
type Triplet expr var a = (Prop (expr var) Bool, Prop (expr var) Bool, a)
skipVCs
:: (HMonad expr, MonadGenVCs expr var m)
=> Triplet expr var () -> m ()
skipVCs (precond, postcond, ()) = tell [precond *-> postcond]
assignVCs
:: (HMonad expr, MonadGenVCs expr v m, VerifiableVar v)
=> Triplet expr v (Assignment expr v) -> m ()
assignVCs (precond, postcond, assignment) = do
let postcond' = subAssignment assignment postcond
tell [precond *-> postcond']
sequenceVCs
:: (HMonad expr, MonadGenVCs expr v m, VerifiableVar v)
=> (Triplet expr v cmd -> m a)
-> Triplet expr v (AnnSeq expr v cmd) -> m [a]
sequenceVCs cmdVCs (precond, postcond, annSeq) =
case annSeq of
JustAssign as -> do
tell [precond *-> chainSub postcond as]
return []
CmdAssign cmd as ->
let postcond' = chainSub postcond as
in (: []) <$> cmdVCs (precond, postcond', cmd)
Annotation l midcond r -> do
(++) <$> sequenceVCs cmdVCs (precond, midcond, l)
<*> sequenceVCs cmdVCs (midcond, postcond, r)
ifVCs
:: (HMonad expr, MonadGenVCs expr v m)
=> (Triplet expr v cmd -> m a)
-> (cond -> Prop (expr v) Bool)
-> Triplet expr v (cond, cmd, cmd) -> m (a, a)
ifVCs cmdVCs condToProp (precond, postcond, (cond, cmd1, cmd2)) = do
let condProp = condToProp cond
return (,) <*> cmdVCs ((precond *&& condProp), postcond, cmd1)
<*> cmdVCs ((precond *&& pnot condProp), postcond, cmd2)
multiIfVCs
:: (HMonad expr, Monad m)
=> (Triplet expr v cmd -> m ())
-> (cond -> Prop (expr v) Bool)
-> Triplet expr v [(Maybe cond, cmd)] -> m ()
multiIfVCs cmdVCs condToProp (precond, postcond, branches) = go precond branches
where
go precond' ((branchCond, branchCmd) : rest) =
case branchCond of
Just bc -> do
let bc' = condToProp bc
cmdVCs ((precond' *&& bc'), postcond, branchCmd)
go (precond' *&& pnot bc') rest
Nothing -> do
cmdVCs (precond', postcond, branchCmd)
go _ [] = return ()
whileVCs
:: (HMonad expr, MonadGenVCs expr v m)
=> (Triplet expr v cmd -> m ())
-> (cond -> Prop (expr v) Bool)
-> Prop (expr v) Bool
-> Triplet expr v (cond, cmd) -> m ()
whileVCs cmdVCs condToProp invariant (precond, postcond, (cond, body)) = do
let condProp = condToProp cond
cmdVCs ((invariant *&& condProp), invariant, body)
tell [precond *-> invariant, (invariant *&& pnot condProp) *-> postcond]