{-# LANGUAGE CPP #-} module GhcDump.Convert where import Data.Bifunctor import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Literal (Literal(..)) #if MIN_VERSION_ghc(8,6,0) import qualified Literal #endif import Var (Var) import qualified Var import Id (isFCallId) import Module (ModuleName, moduleNameFS, moduleName) import Unique (Unique, getUnique, unpkUnique) import Name (getOccName, occNameFS, OccName, getName, nameModule_maybe) import qualified IdInfo import qualified BasicTypes as OccInfo (OccInfo(..), isStrongLoopBreaker) #if MIN_VERSION_ghc(8,0,0) import qualified CoreStats #else import qualified CoreUtils as CoreStats #endif import qualified CoreSyn import CoreSyn (Expr(..), CoreExpr, Bind(..), CoreAlt, CoreBind, AltCon(..)) import HscTypes (ModGuts(..)) import FastString (FastString) import qualified FastString #if MIN_VERSION_ghc(8,2,0) import TyCoRep as Type (Type(..)) #elif MIN_VERSION_ghc(8,0,0) import TyCoRep as Type (Type(..), TyBinder(..)) #else import TypeRep as Type (Type(..)) #endif #if !(MIN_VERSION_ghc(8,2,0)) import Type (splitFunTy_maybe) #endif import TyCon (TyCon, tyConUnique) import Outputable (ppr, showSDoc, SDoc) import DynFlags (unsafeGlobalDynFlags) import GhcDump.Ast as Ast cvtSDoc :: SDoc -> T.Text cvtSDoc = T.pack . showSDoc unsafeGlobalDynFlags fastStringToText :: FastString -> T.Text fastStringToText = TE.decodeUtf8 #if MIN_VERSION_ghc(8,10,0) . FastString.bytesFS #else . FastString.fastStringToByteString #endif occNameToText :: OccName -> T.Text occNameToText = fastStringToText . occNameFS cvtUnique :: Unique.Unique -> Ast.Unique cvtUnique u = let (a,b) = unpkUnique u in Ast.Unique a b cvtVar :: Var -> BinderId cvtVar = BinderId . cvtUnique . Var.varUnique cvtBinder :: Var -> SBinder cvtBinder v | Var.isId v = SBndr $ Binder { binderName = occNameToText $ getOccName v , binderId = cvtVar v , binderIdInfo = cvtIdInfo $ Var.idInfo v , binderIdDetails = cvtIdDetails $ Var.idDetails v , binderType = cvtType $ Var.varType v } | otherwise = SBndr $ TyBinder { binderName = occNameToText $ getOccName v , binderId = cvtVar v , binderKind = cvtType $ Var.varType v } cvtIdInfo :: IdInfo.IdInfo -> Ast.IdInfo SBinder BinderId cvtIdInfo i = IdInfo { idiArity = IdInfo.arityInfo i , idiIsOneShot = IdInfo.oneShotInfo i == IdInfo.OneShotLam , idiUnfolding = cvtUnfolding $ IdInfo.unfoldingInfo i , idiInlinePragma = cvtSDoc $ ppr $ IdInfo.inlinePragInfo i , idiOccInfo = case IdInfo.occInfo i of #if MIN_VERSION_ghc(8,2,0) OccInfo.ManyOccs{} -> OccManyOccs #else OccInfo.NoOccInfo -> OccManyOccs #endif OccInfo.IAmDead -> OccDead OccInfo.OneOcc{} -> OccOneOcc oi@OccInfo.IAmALoopBreaker{} -> OccLoopBreaker (OccInfo.isStrongLoopBreaker oi) , idiStrictnessSig = cvtSDoc $ ppr $ IdInfo.strictnessInfo i , idiDemandSig = cvtSDoc $ ppr $ IdInfo.demandInfo i , idiCallArity = IdInfo.callArityInfo i } cvtUnfolding :: CoreSyn.Unfolding -> Ast.Unfolding SBinder BinderId cvtUnfolding CoreSyn.NoUnfolding = Ast.NoUnfolding #if MIN_VERSION_ghc(8,2,0) cvtUnfolding CoreSyn.BootUnfolding = Ast.BootUnfolding #endif cvtUnfolding (CoreSyn.OtherCon cons) = Ast.OtherCon (map cvtAltCon cons) cvtUnfolding (CoreSyn.DFunUnfolding{}) = Ast.DFunUnfolding cvtUnfolding u@(CoreSyn.CoreUnfolding{}) = Ast.CoreUnfolding { unfTemplate = cvtExpr $ CoreSyn.uf_tmpl u , unfIsValue = CoreSyn.uf_is_value u , unfIsConLike = CoreSyn.uf_is_conlike u , unfIsWorkFree = CoreSyn.uf_is_work_free u , unfGuidance = cvtSDoc $ ppr $ CoreSyn.uf_guidance u } cvtIdDetails :: IdInfo.IdDetails -> Ast.IdDetails cvtIdDetails d = case d of IdInfo.VanillaId -> Ast.VanillaId IdInfo.RecSelId{} -> Ast.RecSelId IdInfo.DataConWorkId{} -> Ast.DataConWorkId IdInfo.DataConWrapId{} -> Ast.DataConWrapId IdInfo.ClassOpId{} -> Ast.ClassOpId IdInfo.PrimOpId{} -> Ast.PrimOpId IdInfo.FCallId{} -> error "This shouldn't happen" IdInfo.TickBoxOpId{} -> Ast.TickBoxOpId IdInfo.DFunId{} -> Ast.DFunId #if MIN_VERSION_ghc(8,0,0) IdInfo.CoVarId{} -> Ast.CoVarId #endif #if MIN_VERSION_ghc(8,2,0) IdInfo.JoinId n -> Ast.JoinId n #endif cvtCoreStats :: CoreStats.CoreStats -> Ast.CoreStats cvtCoreStats stats = Ast.CoreStats { csTerms = CoreStats.cs_tm stats , csTypes = CoreStats.cs_ty stats , csCoercions = CoreStats.cs_co stats #if MIN_VERSION_ghc(8,2,0) , csValBinds = CoreStats.cs_vb stats , csJoinBinds = CoreStats.cs_jb stats #else , csValBinds = 0 , csJoinBinds = 0 #endif } exprStats :: CoreExpr -> CoreStats.CoreStats #if MIN_VERSION_ghc(8,0,0) exprStats = CoreStats.exprStats #else -- exprStats wasn't exported in 7.10 exprStats _ = CoreStats.CS 0 0 0 #endif cvtTopBind :: CoreBind -> STopBinding cvtTopBind (NonRec b e) = NonRecTopBinding (cvtBinder b) (cvtCoreStats $ exprStats e) (cvtExpr e) cvtTopBind (Rec bs) = RecTopBinding $ map to bs where to (b, e) = (cvtBinder b, cvtCoreStats $ exprStats e, cvtExpr e) cvtExpr :: CoreExpr -> Ast.SExpr cvtExpr expr = case expr of Var x -- foreign calls are local but have no binding site. -- TODO: use hasNoBinding here. | isFCallId x -> EVarGlobal ForeignCall | Just m <- nameModule_maybe $ getName x -> EVarGlobal $ ExternalName (cvtModuleName $ Module.moduleName m) (occNameToText $ getOccName x) (cvtUnique $ getUnique x) | otherwise -> EVar (cvtVar x) Lit l -> ELit (cvtLit l) App x y -> EApp (cvtExpr x) (cvtExpr y) Lam x e | Var.isTyVar x -> ETyLam (cvtBinder x) (cvtExpr e) | otherwise -> ELam (cvtBinder x) (cvtExpr e) Let (NonRec b e) body -> ELet [(cvtBinder b, cvtExpr e)] (cvtExpr body) Let (Rec bs) body -> ELet (map (bimap cvtBinder cvtExpr) bs) (cvtExpr body) Case e x _ as -> ECase (cvtExpr e) (cvtBinder x) (map cvtAlt as) Cast x _ -> cvtExpr x Tick _ e -> cvtExpr e Type t -> EType $ cvtType t Coercion _ -> ECoercion cvtAlt :: CoreAlt -> Ast.SAlt cvtAlt (con, bs, e) = Alt (cvtAltCon con) (map cvtBinder bs) (cvtExpr e) cvtAltCon :: CoreSyn.AltCon -> Ast.AltCon cvtAltCon (DataAlt altcon) = Ast.AltDataCon $ occNameToText $ getOccName altcon cvtAltCon (LitAlt l) = Ast.AltLit $ cvtLit l cvtAltCon DEFAULT = Ast.AltDefault cvtLit :: Literal -> Ast.Lit cvtLit l = case l of #if MIN_VERSION_ghc(8,8,0) Literal.LitChar x -> Ast.MachChar x Literal.LitString x -> Ast.MachStr x Literal.LitNullAddr -> Ast.MachNullAddr Literal.LitFloat x -> Ast.MachFloat x Literal.LitDouble x -> Ast.MachDouble x Literal.LitLabel x _ _ -> Ast.MachLabel $ fastStringToText x Literal.LitRubbish -> Ast.LitRubbish #else Literal.MachChar x -> Ast.MachChar x Literal.MachStr x -> Ast.MachStr x Literal.MachNullAddr -> Ast.MachNullAddr Literal.MachFloat x -> Ast.MachFloat x Literal.MachDouble x -> Ast.MachDouble x Literal.MachLabel x _ _ -> Ast.MachLabel $ fastStringToText x #endif #if MIN_VERSION_ghc(8,6,0) Literal.LitNumber numty n _ -> case numty of Literal.LitNumInt -> Ast.MachInt n Literal.LitNumInt64 -> Ast.MachInt64 n Literal.LitNumWord -> Ast.MachWord n Literal.LitNumWord64 -> Ast.MachWord64 n Literal.LitNumInteger -> Ast.LitInteger n Literal.LitNumNatural -> Ast.LitNatural n #else Literal.MachInt x -> Ast.MachInt x Literal.MachInt64 x -> Ast.MachInt64 x Literal.MachWord x -> Ast.MachWord x Literal.MachWord64 x -> Ast.MachWord64 x Literal.LitInteger x _ -> Ast.LitInteger x #endif cvtModule :: String -> ModGuts -> Ast.SModule cvtModule phase guts = Ast.Module name (T.pack phase) (map cvtTopBind $ mg_binds guts) where name = cvtModuleName $ Module.moduleName $ mg_module guts cvtModuleName :: Module.ModuleName -> Ast.ModuleName cvtModuleName = Ast.ModuleName . fastStringToText . moduleNameFS cvtType :: Type.Type -> Ast.SType #if MIN_VERSION_ghc(8,10,0) cvtType (Type.FunTy _flag a b) = Ast.FunTy (cvtType a) (cvtType b) #elif MIN_VERSION_ghc(8,2,0) cvtType (Type.FunTy a b) = Ast.FunTy (cvtType a) (cvtType b) #else cvtType t | Just (a,b) <- splitFunTy_maybe t = Ast.FunTy (cvtType a) (cvtType b) #endif cvtType (Type.TyVarTy v) = Ast.VarTy (cvtVar v) cvtType (Type.AppTy a b) = Ast.AppTy (cvtType a) (cvtType b) cvtType (Type.TyConApp tc tys) = Ast.TyConApp (cvtTyCon tc) (map cvtType tys) #if MIN_VERSION_ghc(8,8,0) cvtType (Type.ForAllTy (Var.Bndr b _) t) = Ast.ForAllTy (cvtBinder b) (cvtType t) #elif MIN_VERSION_ghc(8,2,0) cvtType (Type.ForAllTy (Var.TvBndr b _) t) = Ast.ForAllTy (cvtBinder b) (cvtType t) #elif MIN_VERSION_ghc(8,0,0) cvtType (Type.ForAllTy (Named b _) t) = Ast.ForAllTy (cvtBinder b) (cvtType t) cvtType (Type.ForAllTy (Anon _) t) = cvtType t #else cvtType (Type.ForAllTy b t) = Ast.ForAllTy (cvtBinder b) (cvtType t) #endif cvtType (Type.LitTy _) = Ast.LitTy #if MIN_VERSION_ghc(8,0,0) cvtType (Type.CastTy t _) = cvtType t cvtType (Type.CoercionTy _) = Ast.CoercionTy #endif cvtTyCon :: TyCon.TyCon -> Ast.TyCon cvtTyCon tc = TyCon (occNameToText $ getOccName tc) (cvtUnique $ tyConUnique tc)