module Djinn.GHC (djinn) where
import Control.Monad (forM)
import Data.Set (Set, insert, union, unions, empty, toList)
import qualified Djinn.HTypes as D
import qualified Djinn.LJT as D
import qualified DataCon as G
import qualified GHC as G
import qualified Name as G
import qualified TyCon as G
import qualified Type as G
data NoExtraInfo = NoExtraInfo
type HEnvironment1 a = [(D.HSymbol, ([D.HSymbol], D.HType, a))]
type HEnvironment = HEnvironment1 NoExtraInfo
getConTs :: G.Type -> Set G.Name
getConTs t | Just (_, i) <- G.splitForAllTy_maybe t = getConTs i
getConTs t | Just (c, ts) <- G.splitTyConApp_maybe t =
let args = unions $ map getConTs ts
in if G.isTupleTyCon c then args else insert (G.getName c) args
getConTs t | Just (t1,t2) <- G.splitAppTy_maybe t = getConTs t1 `union` getConTs t2
getConTs _ = empty
hType :: G.Type -> D.HType
hType t | Just (_, i) <- G.splitForAllTy_maybe t = hType i
hType t | Just (t1,t2) <- G.splitFunTy_maybe t = D.HTArrow (hType t1) (hType t2)
hType t | Just (c, ts) <- G.splitTyConApp_maybe t =
let args = map hType ts
in if G.isTupleTyCon c
then D.HTTuple args
else createHTApp (G.getOccString c) (reverse args)
where createHTApp n [] = D.HTCon n
createHTApp n (x:xs) = D.HTApp (createHTApp n xs) x
hType t | Just (t1,t2) <- G.splitAppTy_maybe t = D.HTApp (hType t1) (hType t2)
hType t | Just var <- G.getTyVar_maybe t = D.HTVar (toHSymbol var)
hType _ = error "Unimplemented"
environment :: G.GhcMonad m => G.Type -> m HEnvironment
environment = fmap concat . mapM environment1 . toList . getConTs
environment1 :: G.GhcMonad m => G.Name -> m HEnvironment
environment1 name = do
thing <- G.lookupGlobalName name
case thing of
Just (G.ATyCon tycon) | G.isAlgTyCon tycon -> do
let tyconName = toHSymbol $ G.tyConName tycon
varsH = map toHSymbol $ G.tyConTyVars tycon
Just datacons = G.tyConDataCons_maybe tycon
dtypes <- forM datacons $ \dcon -> do
let dconN = toHSymbol $ G.dataConName dcon
(_,_,dconT,_) = G.dataConSig dcon
dconE <- mapM environment dconT
return ((dconN, map hType dconT), dconE)
let dtypesT = map fst dtypes
dtypesE = concatMap snd dtypes
return $ (tyconName, (varsH, D.HTUnion dtypesT, NoExtraInfo)) : concat dtypesE
Just (G.ATyCon tycon) | G.isSynTyCon tycon -> do
let tyconName = toHSymbol $ G.tyConName tycon
Just (vars, defn) = G.synTyConDefn_maybe tycon
varsH = map toHSymbol vars
htype = hType defn
defnEnv <- environment defn
return $ (tyconName, (varsH, htype, NoExtraInfo)) : defnEnv
_ -> return []
toHSymbol :: G.NamedThing a => a -> D.HSymbol
toHSymbol = G.getOccString
djinn :: G.GhcMonad m => Bool -> G.Type -> m [String]
djinn multi ty = do
env <- environment ty
let form = D.hTypeToFormula env (hType ty)
prfs = D.prove multi [] form
return $ map show prfs