{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ViewPatterns #-}
module Cryptol.Symbolic
( ProverCommand(..)
, QueryType(..)
, SatNum(..)
, ProverResult(..)
, ProverStats
, CounterExampleType(..)
, FinType(..)
, finType
, unFinType
, predArgTypes
) where
import Data.IORef(IORef)
import qualified Cryptol.Eval.Concrete as Concrete
import Cryptol.TypeCheck.AST
import Cryptol.Eval.Type (TValue(..), evalType)
import Cryptol.Utils.Ident (Ident)
import Cryptol.Utils.RecordMap
import Cryptol.Utils.PP
import Prelude ()
import Prelude.Compat
import Data.Time (NominalDiffTime)
type SatResult = [(Type, Expr, Concrete.Value)]
data SatNum = AllSat | SomeSat Int
deriving (Show)
data QueryType = SatQuery SatNum | ProveQuery | SafetyQuery
deriving (Show)
data ProverCommand = ProverCommand {
pcQueryType :: QueryType
, pcProverName :: String
, pcVerbose :: Bool
, pcValidate :: Bool
, pcProverStats :: !(IORef ProverStats)
, pcExtraDecls :: [DeclGroup]
, pcSmtFile :: Maybe FilePath
, pcExpr :: Expr
, pcSchema :: Schema
, pcIgnoreSafety :: Bool
}
type ProverStats = NominalDiffTime
data CounterExampleType = SafetyViolation | PredicateFalsified
data ProverResult = AllSatResult [SatResult]
| ThmResult [Type]
| CounterExample CounterExampleType SatResult
| EmptyResult
| ProverError String
predArgTypes :: QueryType -> Schema -> Either String [FinType]
predArgTypes qtype schema@(Forall ts ps ty)
| null ts && null ps =
case go <$> (evalType mempty ty) of
Right (Just fts) -> Right fts
_ | SafetyQuery <- qtype -> Left $ "Expected finite result type:\n" ++ show (pp schema)
| otherwise -> Left $ "Not a valid predicate type:\n" ++ show (pp schema)
| otherwise = Left $ "Not a monomorphic type:\n" ++ show (pp schema)
where
go :: TValue -> Maybe [FinType]
go TVBit = Just []
go (TVFun ty1 ty2) = (:) <$> finType ty1 <*> go ty2
go tv
| Just _ <- finType tv
, SafetyQuery <- qtype
= Just []
| otherwise
= Nothing
data FinType
= FTBit
| FTInteger
| FTIntMod Integer
| FTRational
| FTFloat Integer Integer
| FTSeq Int FinType
| FTTuple [FinType]
| FTRecord (RecordMap Ident FinType)
numType :: Integer -> Maybe Int
numType n
| 0 <= n && n <= toInteger (maxBound :: Int) = Just (fromInteger n)
| otherwise = Nothing
finType :: TValue -> Maybe FinType
finType ty =
case ty of
TVBit -> Just FTBit
TVInteger -> Just FTInteger
TVIntMod n -> Just (FTIntMod n)
TVRational -> Just FTRational
TVFloat e p -> Just (FTFloat e p)
TVSeq n t -> FTSeq <$> numType n <*> finType t
TVTuple ts -> FTTuple <$> traverse finType ts
TVRec fields -> FTRecord <$> traverse finType fields
TVAbstract {} -> Nothing
_ -> Nothing
unFinType :: FinType -> Type
unFinType fty =
case fty of
FTBit -> tBit
FTInteger -> tInteger
FTIntMod n -> tIntMod (tNum n)
FTRational -> tRational
FTFloat e p -> tFloat (tNum e) (tNum p)
FTSeq l ety -> tSeq (tNum l) (unFinType ety)
FTTuple ftys -> tTuple (unFinType <$> ftys)
FTRecord fs -> tRec (unFinType <$> fs)