{-# LANGUAGE CPP #-}
module MagicHaskeller.ReadTypeRep where
import Data.Typeable
import MagicHaskeller.Types as Types
import MagicHaskeller.TyConLib
import Data.Array.IArray((!))
import qualified Data.Map(lookup)
import qualified Language.Haskell.TH as TH
#if __GLASGOW_HASKELL__ < 700
tyConName = tyConString
#endif
trToType :: TyConLib -> TypeRep -> Types.Type
trToType :: TyConLib -> TypeRep -> Type
trToType TyConLib
tcl TypeRep
tr = case TypeRep -> (TyCon, [TypeRep])
splitTyConApp TypeRep
tr of
(TyCon
tc,[TypeRep]
trs) -> (if TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
funTyCon Bool -> Bool -> Bool
|| TyCon -> String
forall a. Show a => a -> String
show TyCon
tc String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon -> String
forall a. Show a => a -> String
show TyCon
funTyCon
then TyConLib -> TypeRep -> Type
trToType TyConLib
tcl ([TypeRep] -> TypeRep
forall a. [a] -> a
head [TypeRep]
trs) Type -> Type -> Type
:-> TyConLib -> TypeRep -> Type
trToType TyConLib
tcl ([TypeRep] -> TypeRep
forall a. [a] -> a
head ([TypeRep] -> [TypeRep]
forall a. [a] -> [a]
tail [TypeRep]
trs))
else (Type -> Type -> Type) -> Type -> [Type] -> Type
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
TA (TyCon -> Type
TC (TyCon -> Type) -> TyCon -> Type
forall a b. (a -> b) -> a -> b
$ Maybe TyCon -> TyCon
forall p. Maybe p -> p
fromJust (Maybe TyCon -> TyCon) -> Maybe TyCon -> TyCon
forall a b. (a -> b) -> a -> b
$ String -> Map String TyCon -> Maybe TyCon
forall k a. Ord k => k -> Map k a -> Maybe a
Data.Map.lookup (TyCon -> String
tyConString' TyCon
tc) (TyConLib -> Map String TyCon
forall a b. (a, b) -> a
fst TyConLib
tcl)) ((TypeRep -> Type) -> [TypeRep] -> [Type]
forall a b. (a -> b) -> [a] -> [b]
map (TyConLib -> TypeRep -> Type
trToType TyConLib
tcl) [TypeRep]
trs))
where fromJust :: Maybe p -> p
fromJust (Just p
x) = p
x
fromJust Maybe p
Nothing = String -> p
forall a. HasCallStack => String -> a
error (TyCon -> String
tyConString' TyCon
tc String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" does not appear in the component library. (This is a known bug.) For now, please use a type variable instead of "String -> String -> String
forall a. [a] -> [a] -> [a]
++TyCon -> String
forall a. Show a => a -> String
show TyCon
tc
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" and use `matching :: Int -> Memo -> TH.Type -> [[TH.Exp]]'.\n(or maybe you forgot to set a component library?)")
tyConString' :: TyCon -> String
tyConString' TyCon
tc = case TyCon -> String
tyConName TyCon
tc of
str :: String
str@(Char
',':String
_) -> Char
'('Char -> String -> String
forall a. a -> [a] -> [a]
:String
strString -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
String
str -> String -> String
unqualify String
str
unqualify :: String -> String
unqualify :: String -> String
unqualify = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
'.') (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
reverse
funTyCon :: Data.Typeable.TyCon
funTyCon :: TyCon
funTyCon = TypeRep -> TyCon
typeRepTyCon ((Bool -> Bool -> Bool) -> TypeRep
forall a. Typeable a => a -> TypeRep
typeOf Bool -> Bool -> Bool
(&&))
trToTHType :: TypeRep -> TH.Type
trToTHType :: TypeRep -> Type
trToTHType TypeRep
tr = case TypeRep -> (TyCon, [TypeRep])
splitTyConApp TypeRep
tr of
(TyCon
tc,[TypeRep]
trs) -> if TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
funTyCon Bool -> Bool -> Bool
|| TyCon -> String
forall a. Show a => a -> String
show TyCon
tc String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon -> String
forall a. Show a => a -> String
show TyCon
funTyCon
then Type -> Type -> Type
TH.AppT Type
TH.ArrowT (TypeRep -> Type
trToTHType ([TypeRep] -> TypeRep
forall a. [a] -> a
head [TypeRep]
trs)) Type -> Type -> Type
`TH.AppT` TypeRep -> Type
trToTHType ([TypeRep] -> TypeRep
forall a. [a] -> a
head ([TypeRep] -> [TypeRep]
forall a. [a] -> [a]
tail [TypeRep]
trs))
else (Type -> Type -> Type) -> Type -> [Type] -> Type
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
TH.AppT (Name -> Type
TH.ConT (String -> Name
TH.mkName (TyCon -> String
tyConName TyCon
tc))) ((TypeRep -> Type) -> [TypeRep] -> [Type]
forall a b. (a -> b) -> [a] -> [b]
map TypeRep -> Type
trToTHType [TypeRep]
trs)
where tyConToName :: TyCon -> Type
tyConToName TyCon
str = case TyCon -> String
tyConName TyCon
str of String
"[]" -> Type
TH.ListT
str :: String
str@(Char
',':String
_) -> Int -> Type
TH.TupleT (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
str)
String
str -> Name -> Type
TH.ConT (Name -> Type) -> Name -> Type
forall a b. (a -> b) -> a -> b
$ String -> Name
TH.mkName String
str