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