module MagicHaskeller.ReadHsType(readHsTypeSigs) where
import Language.Haskell.TH as TH
import Language.Haskell.Syntax
import Language.Haskell.Parser
import Data.List
import MagicHaskeller.ReadTHType(plainTV)
readHsTypeSigs :: String -> TH.Exp
readHsTypeSigs str = TupE [ mkSigE hsname hsqty
| HsTypeSig _loc hsnames hsqty <- readHsDecls str
, hsname <- hsnames ]
mkSigE :: HsName -> HsQualType -> TH.Exp
mkSigE hsname hsqty = SigE (VarE $ hsNameToTHName hsname) (hsQTypeToTHType hsqty)
hsQTypeToTHType :: HsQualType -> TH.Type
hsQTypeToTHType (HsQualType [] hsty) = ForallT (map (plainTV . hsNameToTHName) $ map head $ group $ sort $ varnames [] hsty) [] (hsTypeToTHType hsty)
hsQTypeToTHType (HsQualType _cxt _hsty) = error "Contexts are not supported yet."
hsTypeToTHType (HsTyTuple hts) = foldl AppT (TupleT (length hts)) (map hsTypeToTHType hts)
hsTypeToTHType (HsTyFun ht0 ht1) = ArrowT `AppT` (hsTypeToTHType ht0) `AppT` (hsTypeToTHType ht1)
hsTypeToTHType (HsTyApp ht0 ht1) = (hsTypeToTHType ht0) `AppT` (hsTypeToTHType ht1)
hsTypeToTHType (HsTyCon hsqname) = hsQNameToTHType hsqname
hsTypeToTHType (HsTyVar hsname) = VarT $ hsNameToTHName hsname
varnames vs (HsTyTuple hts) = foldl varnames vs hts
varnames vs (HsTyFun ht0 ht1) = varnames (varnames vs ht0) ht1
varnames vs (HsTyApp ht0 ht1) = varnames (varnames vs ht0) ht1
varnames vs (HsTyCon _) = vs
varnames vs (HsTyVar hsname) = hsname:vs
hsNameToTHName = mkName . hsNameToString
hsNameToString (HsIdent str) = str
hsNameToString (HsSymbol str) = str
hsAsstToTHType :: HsAsst -> TH.Type
hsAsstToTHType (hsqname, hstypes) = foldl AppT (hsQNameToTHType hsqname) (map hsTypeToTHType hstypes)
hsQNameToTHType (UnQual hsname) = ConT $ hsNameToTHName hsname
hsQNameToTHType (Qual _ hsname) = ConT $ hsNameToTHName hsname
hsQNameToTHType (Special HsFunCon) = ArrowT
hsQNameToTHType (Special HsUnitCon) = ConT $ mkName "()"
hsQNameToTHType (Special HsListCon) = ListT
hsQNameToTHType (Special (HsTupleCon n)) = TupleT n
readHsDecls :: String -> [HsDecl]
readHsDecls src = case parseModule src of ParseOk (HsModule _loc _nam _ex _imports decls) -> decls
ParseFailed (SrcLoc _fn line column) str
-> error (str ++ " in " ++ shows line ":" ++ shows column " of\n" ++ src)