{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Grisette.Internal.Internal.Decl.Unified.EvalMode
( EvalModeBase,
EvalModeInteger,
EvalModeBV,
EvalModeFP,
EvalModeAlgReal,
EvalModeAll,
MonadEvalModeAll,
genEvalMode,
)
where
import Data.List (nub)
import Data.Maybe (mapMaybe)
import Grisette.Internal.Core.Data.Class.TryMerge (TryMerge)
import Grisette.Internal.Internal.Decl.Unified.BVFPConversion
( AllUnifiedBVFPConversion,
)
import Grisette.Internal.Internal.Decl.Unified.FPFPConversion
( AllUnifiedFPFPConversion,
)
import Grisette.Internal.Internal.Decl.Unified.UnifiedBV (AllUnifiedBV)
import Grisette.Internal.Internal.Decl.Unified.UnifiedBool
( UnifiedBool (GetBool),
)
import Grisette.Internal.Internal.Decl.Unified.UnifiedFP (AllUnifiedFP)
import Grisette.Internal.Unified.BVBVConversion (AllUnifiedBVBVConversion)
import Grisette.Internal.Unified.BaseMonad (BaseMonad)
import Grisette.Internal.Unified.Class.UnifiedSimpleMergeable (UnifiedBranching)
import Grisette.Internal.Unified.EvalModeTag (EvalModeTag (C, S))
import Grisette.Internal.Unified.Theories
( TheoryToUnify (UAlgReal, UFP, UFun, UIntN, UInteger, UWordN),
isUFun,
)
import Grisette.Internal.Unified.UnifiedAlgReal (UnifiedAlgReal)
import Grisette.Internal.Unified.UnifiedData (AllUnifiedData)
import Grisette.Internal.Unified.UnifiedFun
( genUnifiedFunInstance,
unifiedFunInstanceName,
)
import Grisette.Internal.Unified.UnifiedInteger (UnifiedInteger)
import Grisette.Internal.Unified.UnifiedPrim (UnifiedBasicPrim)
import Grisette.Internal.Unified.Util (DecideEvalMode)
import Language.Haskell.TH
( DecsQ,
Type (AppT, ArrowT, ConT, StarT, VarT),
appT,
classD,
conT,
instanceD,
kindedTV,
mkName,
newName,
promotedT,
tySynD,
varT,
)
class
( DecideEvalMode mode,
UnifiedBool mode,
UnifiedBasicPrim mode (GetBool mode),
Monad (BaseMonad mode),
TryMerge (BaseMonad mode),
UnifiedBranching mode (BaseMonad mode),
AllUnifiedData mode
) =>
EvalModeBase mode
class (AllUnifiedBV mode, AllUnifiedBVBVConversion mode) => EvalModeBV mode
type EvalModeInteger = UnifiedInteger
class
( AllUnifiedFP mode,
AllUnifiedFPFPConversion mode,
AllUnifiedBVFPConversion mode
) =>
EvalModeFP mode
type EvalModeAlgReal = UnifiedAlgReal
class
( EvalModeBase mode,
EvalModeInteger mode,
EvalModeAlgReal mode,
EvalModeBV mode,
EvalModeFP mode
) =>
EvalModeAll mode
type MonadEvalModeAll mode m =
( EvalModeAll mode,
Monad m,
TryMerge m,
UnifiedBranching mode m
)
genEvalMode :: String -> [TheoryToUnify] -> DecsQ
genEvalMode :: String -> [TheoryToUnify] -> DecsQ
genEvalMode String
nm [TheoryToUnify]
theories = do
modeName <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"mode"
let modeType = Name -> Type
VarT Name
modeName
baseConstraint <- [t|EvalModeBase $(return modeType)|]
basicConstraints <- concat <$> traverse (nonFuncConstraint modeType) nonFuncs
funcInstances <- concat <$> traverse (genUnifiedFunInstance nm) funcs
let instanceNames = (String
"All" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String)
-> ([TheoryToUnify] -> String) -> [TheoryToUnify] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [TheoryToUnify] -> String
unifiedFunInstanceName String
nm ([TheoryToUnify] -> String) -> [[TheoryToUnify]] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [[TheoryToUnify]]
funcs
funcConstraints <- traverse (genFunConstraint (return modeType)) instanceNames
r <-
classD
(return $ baseConstraint : basicConstraints ++ funcConstraints)
(mkName nm)
[kindedTV modeName (ConT ''EvalModeTag)]
[]
[]
rc <- instanceD (return []) (appT (conT $ mkName nm) (promotedT 'C)) []
rs <- instanceD (return []) (appT (conT $ mkName nm) (promotedT 'S)) []
m <- newName "m"
let mType = Name -> Q Type
forall (m :: * -> *). Quote m => Name -> m Type
varT Name
m
monad <-
tySynD
(mkName $ "Monad" ++ nm)
[ kindedTV modeName (ConT ''EvalModeTag),
kindedTV m (AppT (AppT ArrowT StarT) StarT)
]
[t|
( $(appT (conT $ mkName nm) (return modeType)),
Monad $mType,
TryMerge $mType,
UnifiedBranching $(return modeType) $mType
)
|]
return $ funcInstances ++ [r, rc, rs, monad]
where
nonFuncs :: [TheoryToUnify]
nonFuncs =
[TheoryToUnify] -> [TheoryToUnify]
forall a. Eq a => [a] -> [a]
nub ([TheoryToUnify] -> [TheoryToUnify])
-> [TheoryToUnify] -> [TheoryToUnify]
forall a b. (a -> b) -> a -> b
$
(\TheoryToUnify
x -> if TheoryToUnify
x TheoryToUnify -> TheoryToUnify -> Bool
forall a. Eq a => a -> a -> Bool
== TheoryToUnify
UIntN then TheoryToUnify
UWordN else TheoryToUnify
x)
(TheoryToUnify -> TheoryToUnify)
-> [TheoryToUnify] -> [TheoryToUnify]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TheoryToUnify -> Bool) -> [TheoryToUnify] -> [TheoryToUnify]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (TheoryToUnify -> Bool) -> TheoryToUnify -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TheoryToUnify -> Bool
isUFun) ([TheoryToUnify]
theories [TheoryToUnify] -> [TheoryToUnify] -> [TheoryToUnify]
forall a. [a] -> [a] -> [a]
++ [[TheoryToUnify]] -> [TheoryToUnify]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[TheoryToUnify]]
funcs)
funcs :: [[TheoryToUnify]]
funcs =
[[TheoryToUnify]] -> [[TheoryToUnify]]
forall a. Eq a => [a] -> [a]
nub ([[TheoryToUnify]] -> [[TheoryToUnify]])
-> [[TheoryToUnify]] -> [[TheoryToUnify]]
forall a b. (a -> b) -> a -> b
$
(TheoryToUnify -> Maybe [TheoryToUnify])
-> [TheoryToUnify] -> [[TheoryToUnify]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe
( \case
UFun [TheoryToUnify]
x -> [TheoryToUnify] -> Maybe [TheoryToUnify]
forall a. a -> Maybe a
Just [TheoryToUnify]
x
TheoryToUnify
_ -> Maybe [TheoryToUnify]
forall a. Maybe a
Nothing
)
[TheoryToUnify]
theories
nonFuncConstraint :: Type -> TheoryToUnify -> f [Type]
nonFuncConstraint Type
mode TheoryToUnify
UInteger =
(Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
: []) (Type -> [Type]) -> f Type -> f [Type]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [t|EvalModeInteger $(Type -> f Type
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
mode)|]
nonFuncConstraint Type
mode TheoryToUnify
UAlgReal =
(Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
: []) (Type -> [Type]) -> f Type -> f [Type]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [t|EvalModeAlgReal $(Type -> f Type
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
mode)|]
nonFuncConstraint Type
mode TheoryToUnify
UWordN =
(Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
: []) (Type -> [Type]) -> f Type -> f [Type]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [t|EvalModeBV $(Type -> f Type
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
mode)|]
nonFuncConstraint Type
mode TheoryToUnify
UFP = (Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
: []) (Type -> [Type]) -> f Type -> f [Type]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [t|EvalModeFP $(Type -> f Type
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return Type
mode)|]
nonFuncConstraint Type
_ TheoryToUnify
_ = [Type] -> f [Type]
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return []
genFunConstraint :: m Type -> String -> m Type
genFunConstraint m Type
mode String
name = m Type -> m Type -> m Type
forall (m :: * -> *). Quote m => m Type -> m Type -> m Type
appT (Name -> m Type
forall (m :: * -> *). Quote m => Name -> m Type
conT (String -> Name
mkName String
name)) m Type
mode