grisette-0.13.0.1: test/Grisette/Unified/EvalModeTest.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# HLINT ignore "Unused LANGUAGE pragma" #-}
{-# HLINT ignore "Use fewer imports" #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
module Grisette.Unified.EvalModeTest (evalModeTest) where
#if !MIN_VERSION_base(4,16,0)
import Grisette.Unified
( SafeUnifiedBV,
SafeUnifiedBVFPConversion,
SafeUnifiedSomeBV,
UnifiedBV,
UnifiedData,
UnifiedBVBVConversion,
UnifiedBVFPConversion,
UnifiedFPFPConversion
)
#endif
import Control.Exception (ArithException (DivideByZero))
import Control.Monad.Error.Class (MonadError)
import Control.Monad.Except (ExceptT (ExceptT))
import Control.Monad.Identity (Identity (Identity))
import GHC.Generics (Generic)
import GHC.TypeLits (KnownNat, type (<=))
import Grisette
( AsKey (AsKey),
BV (bv),
BitCast (bitCast),
Default (Default),
Function ((#)),
IEEEFPConstants (fpNaN),
IEEEFPConvertible (toFP),
IEEEFPRoundingMode (rne),
IntN,
Mergeable,
MonadTryMerge,
SomeBVException,
SymBool,
SymFP,
SymIntN,
SymInteger,
ToSym (toSym),
Union,
WordN,
bitCastOrCanonical,
mrgReturn,
type (=->) (TabularFun),
)
import qualified Grisette
import Grisette.Internal.Core.Data.Class.LogicalOp (LogicalOp ((.&&)))
import Grisette.Internal.SymPrim.FP (NotRepresentableFPError (NaNError))
import Grisette.Internal.SymPrim.SomeBV (SomeIntN, SomeSymIntN, ssymBV)
import Grisette.TestUtil.SymbolicAssertion ((.@?=))
import Grisette.Unified
( EvalModeBV,
EvalModeBase,
EvalModeFP,
EvalModeInteger,
EvalModeTag (C, S),
GetBool,
GetData,
GetFP,
GetFPRoundingMode,
GetIntN,
GetInteger,
GetSomeIntN,
GetWordN,
TheoryToUnify (UFun, UIntN, UWordN),
UnifiedBranching,
UnifiedFun (GetFun),
extractData,
genEvalMode,
mrgIte,
safeBitCast,
safeDiv,
symFromIntegral,
symIte,
(.<),
(.==),
)
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit ((@?=))
fbool ::
forall mode. (EvalModeBase mode) => GetBool mode -> GetBool mode -> GetBool mode
fbool l r =
mrgIte
(l .== r :: GetBool mode)
(l .< r)
(symIte (l .&& r) l r)
finteger ::
forall mode.
(EvalModeBase mode, EvalModeInteger mode) =>
GetInteger mode ->
GetInteger mode ->
GetInteger mode
finteger l r =
mrgIte
(l .== r :: GetBool mode)
(l + r)
(symIte (l .< r :: GetBool mode) l r)
#if MIN_VERSION_base(4,16,0)
type BVConstraint mode m n =
( EvalModeBase mode,
EvalModeBV mode,
MonadError ArithException m,
UnifiedBranching mode m,
MonadTryMerge m,
KnownNat n,
1 <= n
)
#else
type BVConstraint mode m n =
( EvalModeBase mode,
EvalModeBV mode,
MonadError ArithException m,
UnifiedBranching mode m,
MonadTryMerge m,
SafeUnifiedBV mode n m
)
#endif
fbv ::
forall mode n m.
(BVConstraint mode m n) =>
GetIntN mode n ->
GetIntN mode n ->
m (GetIntN mode n)
fbv l r = do
v <- safeDiv @mode l r
mrgReturn $
mrgIte @mode
(l .== r)
(v + r)
(symIte @mode (l .< r) l r)
#if MIN_VERSION_base(4,16,0)
type BVConstraint' mode m n =
( EvalModeBase mode,
EvalModeBV mode,
MonadTryMerge m,
UnifiedBranching mode m,
KnownNat n,
1 <= n
)
#else
type BVConstraint' mode m n =
( EvalModeBase mode,
EvalModeBV mode,
MonadTryMerge m,
UnifiedBranching mode m,
SafeUnifiedBV mode n (ExceptT ArithException m)
)
#endif
fbv' ::
forall mode n m.
(BVConstraint' mode m n) =>
GetIntN mode n ->
GetIntN mode n ->
ExceptT ArithException m (GetIntN mode n)
fbv' l r = do
v <- safeDiv @mode l r
mrgReturn $
mrgIte @mode
(l .== r)
(v + r)
(symIte @mode (l .< r) l r)
#if MIN_VERSION_base(4,16,0)
type SomeBVConstraint mode m =
( EvalModeBase mode,
EvalModeBV mode,
UnifiedBranching mode m,
MonadTryMerge m,
MonadError (Either SomeBVException ArithException) m
)
#else
type SomeBVConstraint mode m =
( EvalModeBase mode,
EvalModeBV mode,
UnifiedBranching mode m,
MonadTryMerge m,
MonadError (Either SomeBVException ArithException) m,
SafeUnifiedSomeBV mode m
)
#endif
fsomebv ::
forall mode m.
(SomeBVConstraint mode m) =>
GetSomeIntN mode ->
GetSomeIntN mode ->
m (GetSomeIntN mode)
fsomebv l r = do
v <- safeDiv @mode l r
mrgReturn $
symIte @mode
(l .== r)
(v + r)
(symIte @mode (l .< r) l r)
#if MIN_VERSION_base(4,16,0)
type SomeBVConstraint' mode m =
(EvalModeBase mode, EvalModeBV mode, MonadTryMerge m, UnifiedBranching mode m)
#else
type SomeBVConstraint' mode m =
( EvalModeBase mode,
EvalModeBV mode,
MonadTryMerge m,
UnifiedBranching mode m,
SafeUnifiedSomeBV mode (ExceptT (Either SomeBVException ArithException) m)
)
#endif
fsomebv' ::
forall mode m.
(SomeBVConstraint' mode m) =>
GetSomeIntN mode ->
GetSomeIntN mode ->
ExceptT (Either SomeBVException ArithException) m (GetSomeIntN mode)
fsomebv' l r = do
v <- safeDiv @mode l r
mrgReturn $
symIte @mode
(l .== r)
(v + r)
(symIte @mode (l .< r) l r)
data A mode = A (GetIntN mode 8) | AT (GetData mode (A mode))
deriving (Generic)
#if MIN_VERSION_base(4,16,0)
type DataConstraint mode = (EvalModeBase mode, EvalModeBV mode)
#else
type DataConstraint mode =
( EvalModeBase mode,
EvalModeBV mode,
UnifiedData mode (A mode),
UnifiedBV mode 8,
Mergeable (GetData mode (A mode))
)
#endif
deriving via
(Default (A mode))
instance
(DataConstraint mode) =>
(Mergeable (A mode))
#if MIN_VERSION_base(4,16,0)
type FDataConstraint mode m =
( EvalModeBase mode,
EvalModeBV mode,
UnifiedBranching mode m,
MonadError ArithException m
)
#else
type FDataConstraint mode m =
( EvalModeBase mode,
EvalModeBV mode,
MonadError ArithException m,
UnifiedBranching mode m,
UnifiedData mode (A mode),
SafeUnifiedBV mode 8 m,
Mergeable (GetData mode (A mode))
)
#endif
fdata ::
forall mode m.
(FDataConstraint mode m) =>
GetData mode (A mode) ->
m (GetIntN mode 8)
fdata d = do
a <- extractData d
case a of
A v -> safeDiv @mode v (v - 1)
AT v -> fdata v
#if MIN_VERSION_base(4,16,0)
type BVToFPConstraint mode = (EvalModeFP mode)
#else
type BVToFPConstraint mode =
(EvalModeFP mode, BitCast (GetIntN mode 8) (GetFP mode 4 4))
#endif
bvToFPBitCast ::
forall mode.
(BVToFPConstraint mode) =>
GetIntN mode 8 ->
GetFP mode 4 4
bvToFPBitCast = bitCast
#if MIN_VERSION_base(4,16,0)
type FPToBVConstraint mode = (EvalModeFP mode)
#else
type FPToBVConstraint mode =
(EvalModeFP mode, UnifiedBVFPConversion mode 8 4 4)
#endif
fpToBVBitCast ::
forall mode.
(FPToBVConstraint mode) =>
GetFP mode 4 4 ->
GetIntN mode 8
fpToBVBitCast = bitCastOrCanonical
#if MIN_VERSION_base(4,16,0)
type SafeFPToBVConstraint mode m =
( EvalModeFP mode,
UnifiedBranching mode m,
MonadError NotRepresentableFPError m
)
#else
type SafeFPToBVConstraint mode m =
( EvalModeFP mode,
UnifiedBranching mode m,
MonadError NotRepresentableFPError m,
SafeUnifiedBVFPConversion mode 8 4 4 m
)
#endif
safeFPToBVBitCast ::
forall mode m.
(SafeFPToBVConstraint mode m) =>
GetFP mode 4 4 ->
m (GetIntN mode 8)
safeFPToBVBitCast = safeBitCast @mode
#if MIN_VERSION_base(4,16,0)
type FPToFPConstraint mode = (EvalModeFP mode)
#else
type FPToFPConstraint mode =
( EvalModeFP mode,
UnifiedFPFPConversion mode 4 4 3 5
)
#endif
fpToFPConvert ::
forall mode.
(FPToFPConstraint mode) =>
GetFPRoundingMode mode ->
GetFP mode 4 4 ->
GetFP mode 3 5
fpToFPConvert = toFP
#if MIN_VERSION_base(4,16,0)
type BVToBVConstraint mode = (EvalModeBase mode, EvalModeBV mode)
#else
type BVToBVConstraint mode =
( EvalModeBase mode,
EvalModeBV mode,
UnifiedBVBVConversion mode 4 4
)
#endif
bvToBVFromIntegral ::
forall mode.
(BVToBVConstraint mode) =>
GetIntN mode 4 ->
GetWordN mode 4
bvToBVFromIntegral = symFromIntegral @mode
genEvalMode "EvalMode" [UFun [UIntN, UWordN]]
#if MIN_VERSION_base(4,16,0)
type EvalModeUFunConstraint mode n m =
( EvalMode mode,
KnownNat n,
1 <= n,
KnownNat m,
1 <= m
)
#else
type EvalModeUFunConstraint mode n m =
( EvalMode mode,
KnownNat n,
1 <= n,
KnownNat m,
1 <= m,
EvalModeFunUIntNUWordN mode n m
)
#endif
ufuncTest0 ::
forall mode n m.
(EvalModeUFunConstraint mode n m) =>
GetFun mode (GetIntN mode n) (GetWordN mode m) ->
GetIntN mode n ->
GetWordN mode m
ufuncTest0 f = (f #)
ufunc0 ::
forall mode n m.
(EvalModeUFunConstraint mode n m) =>
GetFun mode (GetIntN mode n) (GetWordN mode m)
ufunc0 = toSym (TabularFun [(1, 0)] 2 :: IntN n =-> WordN m)
ufuncTest :: forall mode. (EvalMode mode) => GetIntN mode 8 -> GetWordN mode 8
ufuncTest = ufuncTest0 ufunc0
#if MIN_VERSION_base(4,16,0)
type EvalModeBVConstraint mode m n =
( MonadEvalMode mode m,
MonadError ArithException m,
KnownNat n,
1 <= n
)
#else
type EvalModeBVConstraint mode m n =
( MonadEvalMode mode m,
MonadError ArithException m,
MonadTryMerge m,
SafeUnifiedBV mode n m
)
#endif
fbvEvalMode ::
forall mode n m.
(EvalModeBVConstraint mode m n) =>
GetIntN mode n ->
GetIntN mode n ->
m (GetIntN mode n)
fbvEvalMode l r = do
v <- safeDiv @mode l r
mrgReturn $
mrgIte @mode
(l .== r)
(v + r)
(symIte @mode (l .< r) l r)
evalModeTest :: Test
evalModeTest =
testGroup
"EvalMode"
[ testGroup
"GetBool"
[ testCase "C" $ fbool True False @?= False,
testCase "S" $ do
let l = "l" :: SymBool
let r = "r" :: SymBool
fbool l r
.@?= Grisette.mrgIte
(l Grisette..== r)
(l Grisette..< r)
(Grisette.symIte (l Grisette..&& r) l r)
],
testGroup
"GetInteger"
[ testCase "C" $ finteger (1 :: Integer) 2 @?= 1,
testCase "S" $ do
let l = "l" :: SymInteger
let r = "r" :: SymInteger
finteger l r
.@?= Grisette.mrgIte
(l Grisette..== r)
(l + r)
(Grisette.symIte (l Grisette..< r) l r)
],
testGroup
"GetIntN"
[ testCase "C" $ do
fbv (1 :: IntN 8) 2 @?= Right 1
fbv' (1 :: IntN 8) 2 @?= ExceptT (Identity (Right 1))
fbvEvalMode (1 :: IntN 8) 2 @?= ExceptT (Identity (Right 1)),
testCase "S" $ do
let l = "l" :: SymIntN 8
let r = "r" :: SymIntN 8
let expected = do
v <- Grisette.safeDiv l r
mrgReturn $
Grisette.symIte
(l Grisette..== r)
(v + r)
(Grisette.symIte (l Grisette..< r) l r) ::
ExceptT
ArithException
Union
(SymIntN 8)
fbv l r .@?= expected
fbv' l r .@?= expected
fbvEvalMode l r .@?= expected
],
testGroup
"GetSomeIntN"
[ testCase "C" $ do
fsomebv (bv 8 1 :: SomeIntN) (bv 8 2) @?= Right (bv 8 1)
fsomebv' (bv 8 1 :: SomeIntN) (bv 8 2)
@?= ExceptT (Identity (Right (bv 8 1))),
testCase "S" $ do
let l = ssymBV 8 "l" :: SomeSymIntN
let r = ssymBV 8 "r" :: SomeSymIntN
let expected = do
v <- Grisette.safeDiv l r
mrgReturn $
Grisette.symIte
(l Grisette..== r)
(v + r)
(Grisette.symIte (l Grisette..< r) l r) ::
ExceptT
(Either SomeBVException ArithException)
Union
SomeSymIntN
fsomebv l r .@?= expected
fsomebv' l r .@?= expected
],
testGroup
"GetData"
[ testCase "C" $ do
fdata @'C (Identity $ A 2) @?= Right 2
fdata @'C (Identity $ A 1) @?= Left DivideByZero,
testCase "S" $ do
let a = "a" :: SymIntN 8
fdata (mrgReturn $ A a)
.@?= ( Grisette.safeDiv a (a - 1) ::
ExceptT ArithException Union (SymIntN 8)
)
],
testGroup
"Conversion"
[ testGroup
"FP/BV"
[ testCase "C" $ do
bvToFPBitCast @'C 0x22 @?= 0.15625
fpToBVBitCast @'C 0.15625 @?= 0x22
fpToBVBitCast @'C fpNaN @?= 0x7c
safeFPToBVBitCast @'C 0.15625 @?= Right 0x22
safeFPToBVBitCast @'C fpNaN @?= Left NaNError,
testCase "S" $ do
bvToFPBitCast @'S 0x22 .@?= 0.15625
let a = "a" :: SymIntN 8
AsKey (bvToFPBitCast @'S a) @?= bitCast a
fpToBVBitCast @'S 0.15625 .@?= 0x22
AsKey (fpToBVBitCast @'S fpNaN) @?= 0x7c
let b = "b" :: SymFP 4 4
AsKey (fpToBVBitCast @'S b) @?= bitCastOrCanonical b
safeFPToBVBitCast @'S b
.@?= ( Grisette.safeBitCast b ::
ExceptT NotRepresentableFPError Union (SymIntN 8)
)
],
testGroup
"FP/FP"
[ testCase "C" $ do
fpToFPConvert @'C rne 1 @?= 1,
testCase "S" $ do
fpToFPConvert @'S rne 1 .@?= 1
],
testGroup
"BV/BV"
[ testCase "C" $ do
bvToBVFromIntegral @'C 0xa @?= 0xa,
testCase "S" $ do
bvToBVFromIntegral @'S 0xa .@?= 0xa
]
],
testGroup
"GetFun"
[ testCase "C" $ do
ufuncTest @'C 1 @?= 0
ufuncTest @'C 2 @?= 2,
testCase "S" $ do
let a = "a"
ufuncTest @'S a .@?= symIte (a Grisette..== 1) 0 2
]
]