{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Language.Fixpoint.Types.Theories (
Raw
, TheorySymbol (..)
, Sem (..)
, SmtSort (..)
, sortSmtSort
, isIntSmtSort
, SymEnv (..)
, symEnv
, symEnvSort
, symEnvTheory
, insertSymEnv
, insertsSymEnv
, symbolAtName
, symbolAtSmtName
) where
import Data.Generics (Data)
#if !MIN_VERSION_base(4,14,0)
import Data.Semigroup (Semigroup (..))
#endif
import Data.Typeable (Typeable)
import Data.Hashable
import GHC.Generics (Generic)
import Control.DeepSeq
import Language.Fixpoint.Types.PrettyPrint
import Language.Fixpoint.Types.Names
import Language.Fixpoint.Types.Sorts
import Language.Fixpoint.Types.Errors
import Language.Fixpoint.Types.Environments
import Text.PrettyPrint.HughesPJ.Compat
import qualified Data.List as L
import qualified Data.Text.Lazy as LT
import qualified Data.Binary as B
import qualified Data.HashMap.Strict as M
import qualified Language.Fixpoint.Misc as Misc
type Raw = LT.Text
data SymEnv = SymEnv
{ seSort :: !(SEnv Sort)
, seTheory :: !(SEnv TheorySymbol)
, seData :: !(SEnv DataDecl)
, seLits :: !(SEnv Sort)
, seAppls :: !(M.HashMap FuncSort Int)
}
deriving (Eq, Show, Data, Typeable, Generic)
type FuncSort = (SmtSort, SmtSort)
instance NFData SymEnv
instance B.Binary SymEnv
instance Semigroup SymEnv where
e1 <> e2 = SymEnv { seSort = seSort e1 <> seSort e2
, seTheory = seTheory e1 <> seTheory e2
, seData = seData e1 <> seData e2
, seLits = seLits e1 <> seLits e2
, seAppls = seAppls e1 <> seAppls e2
}
instance Monoid SymEnv where
mempty = SymEnv emptySEnv emptySEnv emptySEnv emptySEnv mempty
mappend = (<>)
symEnv :: SEnv Sort -> SEnv TheorySymbol -> [DataDecl] -> SEnv Sort -> [Sort] -> SymEnv
symEnv xEnv fEnv ds ls ts = SymEnv xEnv' fEnv dEnv ls sortMap
where
xEnv' = unionSEnv xEnv wiredInEnv
dEnv = fromListSEnv [(symbol d, d) | d <- ds]
sortMap = M.fromList (zip smts [0..])
smts = funcSorts dEnv ts
wiredInEnv :: M.HashMap Symbol Sort
wiredInEnv = M.fromList [(toIntName, mkFFunc 1 [FVar 0, FInt])]
funcSorts :: SEnv DataDecl -> [Sort] -> [FuncSort]
funcSorts dEnv ts = [ (t1, t2) | t1 <- smts, t2 <- smts]
where
smts = Misc.sortNub $ concat [ [tx t1, tx t2] | FFunc t1 t2 <- ts]
tx = applySmtSort dEnv
symEnvTheory :: Symbol -> SymEnv -> Maybe TheorySymbol
symEnvTheory x env = lookupSEnv x (seTheory env)
symEnvSort :: Symbol -> SymEnv -> Maybe Sort
symEnvSort x env = lookupSEnv x (seSort env)
insertSymEnv :: Symbol -> Sort -> SymEnv -> SymEnv
insertSymEnv x t env = env { seSort = insertSEnv x t (seSort env) }
insertsSymEnv :: SymEnv -> [(Symbol, Sort)] -> SymEnv
insertsSymEnv = L.foldl' (\env (x, s) -> insertSymEnv x s env)
symbolAtName :: (PPrint a) => Symbol -> SymEnv -> a -> Sort -> Symbol
symbolAtName mkSym env e = symbolAtSmtName mkSym env e . ffuncSort env
symbolAtSmtName :: (PPrint a) => Symbol -> SymEnv -> a -> FuncSort -> Symbol
symbolAtSmtName mkSym env e = intSymbol mkSym . funcSortIndex env e
funcSortIndex :: (PPrint a) => SymEnv -> a -> FuncSort -> Int
funcSortIndex env e z = M.lookupDefault err z (seAppls env)
where
err = panic ("Unknown func-sort: " ++ showpp z ++ " for " ++ showpp e)
ffuncSort :: SymEnv -> Sort -> FuncSort
ffuncSort env t = (tx t1, tx t2)
where
tx = applySmtSort (seData env)
(t1, t2) = args t
args (FFunc a b) = (a, b)
args _ = (FInt, FInt)
applySmtSort :: SEnv DataDecl -> Sort -> SmtSort
applySmtSort = sortSmtSort False
isIntSmtSort :: SEnv DataDecl -> Sort -> Bool
isIntSmtSort env s = SInt == applySmtSort env s
data TheorySymbol = Thy
{ tsSym :: !Symbol
, tsRaw :: !Raw
, tsSort :: !Sort
, tsInterp :: !Sem
}
deriving (Eq, Ord, Show, Data, Typeable, Generic)
instance NFData Sem
instance NFData TheorySymbol
instance B.Binary TheorySymbol
instance PPrint Sem where
pprintTidy _ = text . show
instance Fixpoint TheorySymbol where
toFix (Thy x _ t d) = text "TheorySymbol" <+> pprint (x, t) <+> parens (pprint d)
instance PPrint TheorySymbol where
pprintTidy k (Thy x _ t d) = text "TheorySymbol" <+> pprintTidy k (x, t) <+> parens (pprint d)
data Sem
= Uninterp
| Ctor
| Test
| Field
| Theory
deriving (Eq, Ord, Show, Data, Typeable, Generic)
instance B.Binary Sem
data SmtSort
= SInt
| SBool
| SReal
| SString
| SSet
| SMap
| SBitVec !Int
| SVar !Int
| SData !FTycon ![SmtSort]
deriving (Eq, Ord, Show, Data, Typeable, Generic)
instance Hashable SmtSort
instance NFData SmtSort
instance B.Binary SmtSort
sortSmtSort :: Bool -> SEnv DataDecl -> Sort -> SmtSort
sortSmtSort poly env t = go . unAbs $ t
where
m = sortAbs t
go (FFunc _ _) = SInt
go FInt = SInt
go FReal = SReal
go t
| t == boolSort = SBool
| isString t = SString
go (FVar i)
| poly, i < m = SVar i
| otherwise = SInt
go t = fappSmtSort poly m env ct ts where (ct:ts) = unFApp t
fappSmtSort :: Bool -> Int -> SEnv DataDecl -> Sort -> [Sort] -> SmtSort
fappSmtSort poly m env = go
where
go (FTC c) _
| setConName == symbol c = SSet
go (FTC c) _
| mapConName == symbol c = SMap
go (FTC bv) [FTC s]
| bitVecName == symbol bv
, Just n <- sizeBv s = SBitVec n
go s []
| isString s = SString
go (FTC c) ts
| Just n <- tyArgs c env
, let i = n - length ts = SData c ((sortSmtSort poly env . FAbs m <$> ts) ++ pad i)
go _ _ = SInt
pad i | poly = []
| otherwise = replicate i SInt
tyArgs :: (Symbolic x) => x -> SEnv DataDecl -> Maybe Int
tyArgs x env = ddVars <$> lookupSEnv (symbol x) env
instance PPrint SmtSort where
pprintTidy _ SInt = text "Int"
pprintTidy _ SBool = text "Bool"
pprintTidy _ SReal = text "Real"
pprintTidy _ SString = text "Str"
pprintTidy _ SSet = text "Set"
pprintTidy _ SMap = text "Map"
pprintTidy _ (SBitVec n) = text "BitVec" <+> int n
pprintTidy _ (SVar i) = text "@" <-> int i
pprintTidy k (SData c ts) = ppParens k (pprintTidy k c) ts
ppParens :: (PPrint d) => Tidy -> Doc -> [d] -> Doc
ppParens k d ds = parens $ Misc.intersperse (text "") (d : (pprintTidy k <$> ds))