{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
module Language.Fixpoint.Horn.Info (
hornFInfo
) where
import qualified Data.HashMap.Strict as M
import qualified Data.List as L
import qualified Data.Tuple as Tuple
import qualified Data.Maybe as Mb
import Data.Either (partitionEithers)
import GHC.Generics (Generic)
import qualified Language.Fixpoint.Misc as Misc
import qualified Language.Fixpoint.Types as F
import qualified Language.Fixpoint.Horn.Types as H
hornFInfo :: H.Query a -> F.FInfo a
hornFInfo q = mempty
{ F.cm = cs
, F.bs = be2
, F.ebinds = ebs
, F.ws = kvEnvWfCs kve
, F.quals = H.qQuals q
, F.gLits = F.fromMapSEnv $ H.qCon q
, F.dLits = F.fromMapSEnv $ H.qDis q
}
where
be0 = F.emptyBindEnv
(be1, kve) = hornWfs be0 (H.qVars q)
(be2, ebs, cs) = hornSubCs be1 kve hCst
hCst = H.qCstr q
hornSubCs :: F.BindEnv -> KVEnv a -> H.Cstr a
-> (F.BindEnv, [F.BindId], M.HashMap F.SubcId (F.SubC a))
hornSubCs be kve c = (be', ebs, M.fromList (F.addIds cs))
where
(be', ebs, cs) = goS kve F.emptyIBindEnv lhs0 be c
lhs0 = bindSortedReft kve H.dummyBind
goS :: KVEnv a -> F.IBindEnv -> F.SortedReft -> F.BindEnv -> H.Cstr a
-> (F.BindEnv, [F.BindId], [F.SubC a])
goS kve env lhs be c = (be', mEbs, subcs)
where
(be', ecs) = goS' kve env lhs be c
(mEbs, subcs) = partitionEithers ecs
goS' :: KVEnv a -> F.IBindEnv -> F.SortedReft -> F.BindEnv -> H.Cstr a
-> (F.BindEnv, [Either F.BindId (F.SubC a)])
goS' kve env lhs be (H.Head p l) = (be, [Right subc])
where
subc = F.mkSubC env lhs rhs Nothing [] l
rhs = updSortedReft kve lhs p
goS' kve env lhs be (H.CAnd cs) = (be', concat subcss)
where
(be', subcss) = L.mapAccumL (goS' kve env lhs) be cs
goS' kve env _ be (H.All b c) = (be'', subcs)
where
(be'', subcs) = goS' kve env' bSR be' c
(bId, be') = F.insertBindEnv (H.bSym b) bSR be
bSR = bindSortedReft kve b
env' = F.insertsIBindEnv [bId] env
goS' kve env _ be (H.Any b c) = (be'', Left bId : subcs)
where
(be'', subcs) = goS' kve env' bSR be' c
(bId, be') = F.insertBindEnv (H.bSym b) bSR be
bSR = bindSortedReft kve b
env' = F.insertsIBindEnv [bId] env
bindSortedReft :: KVEnv a -> H.Bind -> F.SortedReft
bindSortedReft kve (H.Bind x t p) = F.RR t (F.Reft (x, predExpr kve p))
updSortedReft :: KVEnv a -> F.SortedReft -> H.Pred -> F.SortedReft
updSortedReft kve (F.RR s (F.Reft (v, _))) p = F.RR s (F.Reft (v, predExpr kve p))
predExpr :: KVEnv a -> H.Pred -> F.Expr
predExpr kve = go
where
go (H.Reft e ) = e
go (H.Var k ys) = kvApp kve k ys
go (H.PAnd ps) = F.PAnd (go <$> ps)
kvApp :: KVEnv a -> F.Symbol -> [F.Symbol] -> F.Expr
kvApp kve k ys = F.PKVar (F.KV k) su
where
su = F.mkSubst (zip params (F.eVar <$> ys))
params = Mb.fromMaybe err1 $ kvParams <$> M.lookup k kve
err1 = F.panic ("Unknown Horn variable: " ++ F.showpp k)
hornWfs :: F.BindEnv -> [H.Var a] -> (F.BindEnv, KVEnv a)
hornWfs be vars = (be', kve)
where
kve = M.fromList [ (kname i, i) | i <- is ]
(be', is) = L.mapAccumL kvInfo be vars
kname = H.hvName . kvVar
kvInfo :: F.BindEnv -> H.Var a -> (F.BindEnv, KVInfo a)
kvInfo be k = (be', KVInfo k (fst <$> xts) wfc)
where
wfc = F.WfC wenv wrft (H.hvMeta k)
wenv = F.fromListIBindEnv ids
wrft = (x, t, F.KV (H.hvName k))
(be', ids) = L.mapAccumL insertBE be xts'
((x,t), xts') = Misc.safeUncons "Horn var with no args" xts
xts = [ (hvarArg k i, t) | (t, i) <- zip (H.hvArgs k) [0..] ]
insertBE :: F.BindEnv -> (F.Symbol, F.Sort) -> (F.BindEnv, F.BindId)
insertBE be (x, t) = Tuple.swap $ F.insertBindEnv x (F.trueSortedReft t) be
type KVEnv a = M.HashMap F.Symbol (KVInfo a)
data KVInfo a = KVInfo
{ kvVar :: !(H.Var a)
, kvParams :: ![F.Symbol]
, kvWfC :: !(F.WfC a)
}
deriving (Generic, Functor)
kvEnvWfCs :: KVEnv a -> M.HashMap F.KVar (F.WfC a)
kvEnvWfCs kve = M.fromList [ (F.KV k, kvWfC info) | (k, info) <- M.toList kve ]
hvarArg :: H.Var a -> Int -> F.Symbol
hvarArg k i = F.intSymbol (F.suffixSymbol hvarPrefix (H.hvName k)) i
hvarPrefix :: F.Symbol
hvarPrefix = F.symbol "nnf_arg"