{-# LANGUAGE RecordWildCards #-}
module GhcDump.Reconstruct (reconModule) where
import Data.Foldable
import Data.Bifunctor
import Prelude hiding (readFile)
import Data.Hashable
import qualified Data.HashMap.Lazy as HM
import GhcDump.Ast
newtype BinderMap = BinderMap (HM.HashMap BinderId Binder)
instance Hashable BinderId where
hashWithSalt salt (BinderId (Unique c i)) = salt `hashWithSalt` c `hashWithSalt` i
emptyBinderMap :: BinderMap
emptyBinderMap = BinderMap mempty
insertBinder :: Binder -> BinderMap -> BinderMap
insertBinder (Bndr b) (BinderMap m) = BinderMap $ HM.insert (binderId b) (Bndr b) m
insertBinders :: [Binder] -> BinderMap -> BinderMap
insertBinders bs bm = foldl' (flip insertBinder) bm bs
getBinder :: BinderMap -> BinderId -> Binder
getBinder (BinderMap m) bid
| Just b <- HM.lookup bid m = b
| otherwise = error $ "unknown binder "++ show bid ++ ":\nin scope:\n"
++ unlines (map (\(bid',b) -> show bid' ++ "\t" ++ show b) (HM.toList m))
reconModule :: SModule -> Module
reconModule m = Module (moduleName m) (modulePhase m) binds
where
binds = map reconTopBinding $ moduleTopBindings m
bm = insertBinders (map (\(a,_,_) -> a) $ concatMap topBindings binds) emptyBinderMap
reconTopBinding :: STopBinding -> TopBinding
reconTopBinding (NonRecTopBinding b stats rhs) = NonRecTopBinding b' stats (reconExpr bm rhs)
where b' = reconBinder bm b
reconTopBinding (RecTopBinding bs) = RecTopBinding bs'
where bs' = map (\(a,stats,rhs) -> (reconBinder bm a, stats, reconExpr bm rhs)) bs
reconExpr :: BinderMap -> SExpr -> Expr
reconExpr bm (EVar var) = EVar $ getBinder bm var
reconExpr _ (EVarGlobal n) = EVarGlobal n
reconExpr _ (ELit l) = ELit l
reconExpr bm (EApp x y) = EApp (reconExpr bm x) (reconExpr bm y)
reconExpr bm (ETyLam b x) = let b' = reconBinder bm b
bm' = insertBinder b' bm
in ETyLam b' (reconExpr bm' x)
reconExpr bm (ELam b x) = let b' = reconBinder bm b
bm' = insertBinder b' bm
in ELam b' (reconExpr bm' x)
reconExpr bm (ELet bs x) = let bs' = map (bimap (reconBinder bm) (reconExpr bm')) bs
bm' = insertBinders (map fst bs') bm
in ELet bs' (reconExpr bm' x)
reconExpr bm (ECase x b alts) = let b' = reconBinder bm b
bm' = insertBinder b' bm
in ECase (reconExpr bm x) b' (map (reconAlt bm') alts)
reconExpr bm (EType t) = EType (reconType bm t)
reconExpr _ ECoercion = ECoercion
reconBinder :: BinderMap -> SBinder -> Binder
reconBinder bm (SBndr b@Binder{}) =
Bndr $ b { binderType = reconType bm $ binderType b
, binderIdInfo = reconIdInfo bm $ binderIdInfo b
}
reconBinder bm (SBndr b@TyBinder{}) =
Bndr $ b { binderKind = reconType bm $ binderKind b }
reconIdInfo :: BinderMap -> IdInfo SBinder BinderId -> IdInfo Binder Binder
reconIdInfo bm i =
i { idiUnfolding = reconUnfolding bm $ idiUnfolding i }
reconUnfolding :: BinderMap -> Unfolding SBinder BinderId -> Unfolding Binder Binder
reconUnfolding _ NoUnfolding = NoUnfolding
reconUnfolding _ BootUnfolding = BootUnfolding
reconUnfolding _ (OtherCon alts) = OtherCon alts
reconUnfolding _ DFunUnfolding = DFunUnfolding
reconUnfolding bm CoreUnfolding{..} = CoreUnfolding { unfTemplate = reconExpr bm unfTemplate
, .. }
reconAlt :: BinderMap -> SAlt -> Alt
reconAlt bm0 (Alt con bs rhs) =
let (bm', bs') = doBinders bm0 [] bs
in Alt con bs' (reconExpr bm' rhs)
where
doBinders bm acc [] = (bm, reverse acc)
doBinders bm acc (b:rest) = doBinders bm' (b':acc) rest
where
b' = reconBinder bm b
bm' = insertBinder b' bm
reconType :: BinderMap -> SType -> Type
reconType bm (VarTy v) = VarTy $ getBinder bm v
reconType bm (FunTy x y) = FunTy (reconType bm x) (reconType bm y)
reconType bm (TyConApp tc tys) = TyConApp tc (map (reconType bm) tys)
reconType bm (AppTy x y) = AppTy (reconType bm x) (reconType bm y)
reconType bm (ForAllTy b x) = let b' = reconBinder bm b
bm' = insertBinder b' bm
in ForAllTy b' (reconType bm' x)
reconType _ LitTy = LitTy
reconType _ CoercionTy = CoercionTy