grisette-0.5.0.0: src/Grisette/Internal/SymPrim/AllSyms.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Module : Grisette.Internal.SymPrim.AllSyms
-- Copyright : (c) Sirui Lu 2024
-- License : BSD-3-Clause (see the LICENSE file)
--
-- Maintainer : siruilu@cs.washington.edu
-- Stability : Experimental
-- Portability : GHC only
module Grisette.Internal.SymPrim.AllSyms
( symSize,
symsSize,
SomeSym (..),
AllSyms (..),
allSymsSize,
)
where
import Control.Monad.Except (ExceptT (ExceptT))
import Control.Monad.Identity
( Identity (Identity),
IdentityT (IdentityT),
)
import Control.Monad.Trans.Maybe (MaybeT (MaybeT))
import qualified Control.Monad.Writer.Lazy as WriterLazy
import qualified Control.Monad.Writer.Strict as WriterStrict
import qualified Data.ByteString as B
import Data.Functor.Sum (Sum)
import Data.Int (Int16, Int32, Int64, Int8)
import qualified Data.Text as T
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.Generics
( Generic (Rep, from),
K1 (K1),
M1 (M1),
U1,
type (:*:) ((:*:)),
type (:+:) (L1, R1),
)
import Generics.Deriving (Default (Default, unDefault))
import Grisette.Internal.Core.Control.Exception
( AssertionError,
VerificationConditions,
)
import Grisette.Internal.SymPrim.Prim.SomeTerm
( SomeTerm (SomeTerm),
)
import Grisette.Internal.SymPrim.Prim.Term
( LinkedRep (underlyingTerm),
)
import Grisette.Internal.SymPrim.Prim.TermUtils
( someTermsSize,
termSize,
termsSize,
)
-- $setup
-- >>> import Grisette.Core
-- >>> import Grisette.SymPrim
-- >>> import Grisette.Backend
-- >>> import Data.Proxy
-- | Get the sum of the sizes of a list of symbolic terms.
-- Duplicate sub-terms are counted for only once.
--
-- >>> symsSize [1, "a" :: SymInteger, "a" + 1 :: SymInteger]
-- 3
symsSize :: forall con sym. (LinkedRep con sym) => [sym] -> Int
symsSize = termsSize . fmap (underlyingTerm @con)
{-# INLINE symsSize #-}
-- | Get the size of a symbolic term.
-- Duplicate sub-terms are counted for only once.
--
-- >>> symSize (1 :: SymInteger)
-- 1
-- >>> symSize ("a" :: SymInteger)
-- 1
-- >>> symSize ("a" + 1 :: SymInteger)
-- 3
-- >>> symSize (("a" + 1) * ("a" + 1) :: SymInteger)
-- 4
symSize :: forall con sym. (LinkedRep con sym) => sym -> Int
symSize = termSize . underlyingTerm @con
{-# INLINE symSize #-}
-- | Some symbolic value with 'LinkedRep' constraint.
data SomeSym where
SomeSym :: (LinkedRep con sym) => sym -> SomeSym
someUnderlyingTerm :: SomeSym -> SomeTerm
someUnderlyingTerm (SomeSym s) = SomeTerm $ underlyingTerm s
someSymsSize :: [SomeSym] -> Int
someSymsSize = someTermsSize . fmap someUnderlyingTerm
{-# INLINE someSymsSize #-}
-- | Extract all symbolic primitive values that are represented as SMT terms.
--
-- __Note:__ This type class can be derived for algebraic data types. You may
-- need the @DerivingVia@ and @DerivingStrategies@ extenstions.
--
-- > data X = ... deriving Generic deriving AllSyms via (Default X)
class AllSyms a where
-- | Convert a value to a list of symbolic primitive values. It should
-- prepend to an existing list of symbolic primitive values.
allSymsS :: a -> [SomeSym] -> [SomeSym]
allSymsS a l = allSyms a ++ l
-- | Specialized 'allSymsS' that prepends to an empty list.
allSyms :: a -> [SomeSym]
allSyms a = allSymsS a []
{-# MINIMAL allSymsS | allSyms #-}
-- | Get the total size of symbolic terms in a value.
-- Duplicate sub-terms are counted for only once.
--
-- >>> allSymsSize ("a" :: SymInteger, "a" + "b" :: SymInteger, ("a" + "b") * "c" :: SymInteger)
-- 5
allSymsSize :: (AllSyms a) => a -> Int
allSymsSize = someSymsSize . allSyms
class AllSyms' a where
allSymsS' :: a c -> [SomeSym] -> [SomeSym]
instance (Generic a, AllSyms' (Rep a)) => AllSyms (Default a) where
allSymsS = allSymsS' . from . unDefault
instance AllSyms' U1 where
allSymsS' _ = id
instance (AllSyms c) => AllSyms' (K1 i c) where
allSymsS' (K1 v) = allSymsS v
instance (AllSyms' a) => AllSyms' (M1 i c a) where
allSymsS' (M1 v) = allSymsS' v
instance (AllSyms' a, AllSyms' b) => AllSyms' (a :+: b) where
allSymsS' (L1 l) = allSymsS' l
allSymsS' (R1 r) = allSymsS' r
instance (AllSyms' a, AllSyms' b) => AllSyms' (a :*: b) where
allSymsS' (a :*: b) = allSymsS' a . allSymsS' b
#define CONCRETE_ALLSYMS(type) \
instance AllSyms type where \
allSymsS _ = id
#if 1
CONCRETE_ALLSYMS(Bool)
CONCRETE_ALLSYMS(Integer)
CONCRETE_ALLSYMS(Char)
CONCRETE_ALLSYMS(Int)
CONCRETE_ALLSYMS(Int8)
CONCRETE_ALLSYMS(Int16)
CONCRETE_ALLSYMS(Int32)
CONCRETE_ALLSYMS(Int64)
CONCRETE_ALLSYMS(Word)
CONCRETE_ALLSYMS(Word8)
CONCRETE_ALLSYMS(Word16)
CONCRETE_ALLSYMS(Word32)
CONCRETE_ALLSYMS(Word64)
CONCRETE_ALLSYMS(B.ByteString)
CONCRETE_ALLSYMS(T.Text)
#endif
instance AllSyms () where
allSymsS _ = id
-- Either
deriving via
(Default (Either a b))
instance
( AllSyms a,
AllSyms b
) =>
AllSyms (Either a b)
-- Maybe
deriving via (Default (Maybe a)) instance (AllSyms a) => AllSyms (Maybe a)
-- List
deriving via (Default [a]) instance (AllSyms a) => AllSyms [a]
-- (,)
deriving via
(Default (a, b))
instance
(AllSyms a, AllSyms b) =>
AllSyms (a, b)
-- (,,)
deriving via
(Default (a, b, c))
instance
( AllSyms a,
AllSyms b,
AllSyms c
) =>
AllSyms (a, b, c)
-- (,,,)
deriving via
(Default (a, b, c, d))
instance
( AllSyms a,
AllSyms b,
AllSyms c,
AllSyms d
) =>
AllSyms (a, b, c, d)
-- (,,,,)
deriving via
(Default (a, b, c, d, e))
instance
( AllSyms a,
AllSyms b,
AllSyms c,
AllSyms d,
AllSyms e
) =>
AllSyms (a, b, c, d, e)
-- (,,,,,)
deriving via
(Default (a, b, c, d, e, f))
instance
( AllSyms a,
AllSyms b,
AllSyms c,
AllSyms d,
AllSyms e,
AllSyms f
) =>
AllSyms (a, b, c, d, e, f)
-- (,,,,,,)
deriving via
(Default (a, b, c, d, e, f, g))
instance
( AllSyms a,
AllSyms b,
AllSyms c,
AllSyms d,
AllSyms e,
AllSyms f,
AllSyms g
) =>
AllSyms (a, b, c, d, e, f, g)
-- (,,,,,,,)
deriving via
(Default (a, b, c, d, e, f, g, h))
instance
( AllSyms a,
AllSyms b,
AllSyms c,
AllSyms d,
AllSyms e,
AllSyms f,
AllSyms g,
AllSyms h
) =>
AllSyms ((,,,,,,,) a b c d e f g h)
-- MaybeT
instance
(AllSyms (m (Maybe a))) =>
AllSyms (MaybeT m a)
where
allSymsS (MaybeT v) = allSymsS v
-- ExceptT
instance
(AllSyms (m (Either e a))) =>
AllSyms (ExceptT e m a)
where
allSymsS (ExceptT v) = allSymsS v
-- Sum
deriving via
(Default (Sum f g a))
instance
(AllSyms (f a), AllSyms (g a)) =>
AllSyms (Sum f g a)
-- WriterT
instance
(AllSyms (m (a, s))) =>
AllSyms (WriterLazy.WriterT s m a)
where
allSymsS (WriterLazy.WriterT v) = allSymsS v
instance
(AllSyms (m (a, s))) =>
AllSyms (WriterStrict.WriterT s m a)
where
allSymsS (WriterStrict.WriterT v) = allSymsS v
-- Identity
instance (AllSyms a) => AllSyms (Identity a) where
allSymsS (Identity a) = allSymsS a
-- IdentityT
instance (AllSyms (m a)) => AllSyms (IdentityT m a) where
allSymsS (IdentityT a) = allSymsS a
-- VerificationConditions
deriving via (Default VerificationConditions) instance AllSyms VerificationConditions
-- AssertionError
deriving via (Default AssertionError) instance AllSyms AssertionError