--
-- (c) Susumu Katayama
--
\begin{code}
module MagicHaskeller.ReadTHType(thTypeToType, typeToTHType, showTypeName, plainTV, unPlainTV) where
import MagicHaskeller.Types as Types
import MagicHaskeller.TyConLib
import Language.Haskell.TH as TH
import Data.Array((!), inRange, bounds)
import Data.Char(ord,chr)
import Data.List(nub)
import Data.Map(lookup)
showTypeName = TH.nameBase
thTypeToType :: TyConLib -> TH.Type -> Types.Type
thTypeToType tcl t = normalize $ thTypeToType' tcl [] t
thTypeToType' tcl vs (ForallT bs [] t) = thTypeToType' tcl (vs++map tyVarBndrToName bs) t
thTypeToType' tcl _ (ForallT _ (_:_) t) = error "Type classes are not supported yet."
thTypeToType' tcl _ (TupleT n) = TC (tuple tcl n)
thTypeToType' tcl _ ListT = TC (list tcl)
thTypeToType' tcl vs (AppT (AppT ArrowT ht0) ht1) = thTypeToType' tcl vs ht0 :-> thTypeToType' tcl vs ht1
thTypeToType' tcl vs (AppT (AppT (ConT name) ht0) ht1) | nameBase name == "(->)" = thTypeToType' tcl vs ht0 :> thTypeToType' tcl vs ht1
thTypeToType' tcl vs (AppT ht0 ht1) = TA (thTypeToType' tcl vs ht0) (thTypeToType' tcl vs ht1)
thTypeToType' (fm,_) _ (ConT name) = let nstr = showTypeName name
in case Data.Map.lookup nstr fm of
Nothing ->
error $ "thTypeToType' : "++nstr++" : unknown TyCon"
Just c -> TC c
thTypeToType' _ _ ArrowT = error "Partially applied (->)."
thTypeToType' _ vs (VarT name) = TV $ case Prelude.lookup name $ zip vs [0..] of Nothing -> error "thTypeToType : unbound type variable"
Just i -> i
tyVarBndrToName (PlainTV name) = name
tyVarBndrToName (KindedTV name _) = name
typeToTHType :: TyConLib -> Types.Type -> TH.Type
typeToTHType tcl ty = (case tyvars ty of [] -> id
tvs -> TH.ForallT (map (plainTV . tvToName) $ nub tvs) [])
(typeToTHType' tcl 0 ty)
typeToTHType' (_,ar) k (TC tc) | tc >= 0 = if name == "[]" then ListT else TH.ConT (TH.mkName name)
where name = if inRange (bounds ar) k then fst ((ar ! k) !! fromIntegral tc)
else 'K':shows k ('I':show tc)
typeToTHType' tcl _ (TV tv) = TH.VarT $ tvToName tv
typeToTHType' tcl k (TA t0 t1) = TH.AppT (typeToTHType' tcl (k+1) t0) (typeToTHType' tcl 0 t1)
typeToTHType' tcl 0 (t0:->t1) = TH.AppT (TH.AppT TH.ArrowT (typeToTHType' tcl 0 t0)) (typeToTHType' tcl 0 t1)
typeToTHType' tcl 0 (t0:> t1) = TH.AppT (TH.AppT sectionedArrow (typeToTHType' tcl 0 t0)) (typeToTHType' tcl 0 t1)
#if __GLASGOW_HASKELL__<=610
plainTV = id
unPlainTV = id
#else
plainTV = PlainTV
unPlainTV (PlainTV v) = v
unPlainTV (KindedTV v _) = v
#endif
tvToName n = TH.mkName ('t':show n)
sectionedArrow = TH.ConT (mkName "GHC.Prim.(->)")
\end{code}