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@ reads a module string and returns an Exp that can be supplied to MagicHaskeller.p 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 cxt hsty) = ForallT (map (plainTV . hsNameToTHName) $ map head $ group $ sort $ varnames [] hsty) (map hsAsstToTHType cxt) (hsTypeToTHType hsty) -- This is incorrect since template-haskell-2.4*, so just forget the contexts. 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 -- The above definition should be exhaustive 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 -- Was: '(':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 -- qualifications over type names are ignored for now. 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)