module Language.Fixpoint.Types.Theories (
Raw
, TheorySymbol (..)
, Sem (..)
, SmtSort (..)
, sortSmtSort
, isIntSmtSort
, SymEnv (..)
, symEnv
, symEnvSort
, symEnvTheory
, insertSymEnv
, symbolAtName
, symbolAtSmtName
) where
import Data.Generics (Data)
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
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 Monoid SymEnv where
mempty = SymEnv emptySEnv emptySEnv emptySEnv emptySEnv mempty
mappend e1 e2 = SymEnv { seSort = seSort e1 `mappend` seSort e2
, seTheory = seTheory e1 `mappend` seTheory e2
, seData = seData e1 `mappend` seData e2
, seLits = seLits e1 `mappend` seLits e2
, seAppls = seAppls e1 `mappend` seAppls e2
}
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 a -> [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) }
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 a -> Sort -> SmtSort
applySmtSort = sortSmtSort False
isIntSmtSort :: SEnv a -> 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
| Data
| 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 a -> Sort -> SmtSort
sortSmtSort poly env = go
where
go (FFunc _ _) = SInt
go FInt = SInt
go FReal = SReal
go t
| t == boolSort = SBool
go (FVar i)
| poly = SVar i
| otherwise = SInt
go t = fappSmtSort poly env ct ts where (ct:ts)= unFApp t
fappSmtSort :: Bool -> SEnv a -> Sort -> [Sort] -> SmtSort
fappSmtSort poly 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
| symEnvData c env = SData c (sortSmtSort poly env <$> ts)
go _ _ = SInt
symEnvData :: (Symbolic x) => x -> SEnv a -> Bool
symEnvData = memberSEnv . symbol
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))