module Modules(computeInsOuts,inscope) where import Relations import NamesEntities import ModSysAST import Maybe (isNothing) import Sets mEntSpec :: (Ord j,ToSimple j) => Bool -> -- is it a hiding import? Rel j Entity -> -- the original relation EntSpec j -- the specification -> Rel j Entity -- the subset satisfying the specification mEntSpec isHiding rel (Ent x subspec) = unionRels [mSpec, mSub] where mSpec = restrictRng consider (restrictDom (== x) rel) allSubs = owns `unionMapSet` rng mSpec subs = restrictRng (`elementOf` allSubs) rel mSub = case subspec of Nothing -> emptyRel Just AllSubs -> subs Just (Subs xs) -> restrictDom ((`elem` xs) . toSimple) subs consider | isHiding && isNothing subspec = const True | otherwise = not . isCon exports :: Module -> Rel QName Entity -> Rel Name Entity exports mod inscp = case modExpList mod of Nothing -> modDefines mod Just es -> getQualified `mapDom` unionRels exps where exps = mExpListEntry inscp `map` es mExpListEntry :: Rel QName Entity -> ExpListEntry -> Rel QName Entity mExpListEntry inscp (EntExp it) = mEntSpec False inscp it mExpListEntry inscp (ModuleExp m) = (qual m `mapDom` unqs) `intersectRel` qs where (qs,unqs) = partitionDom isQual inscp inscope :: Module -> (ModName -> Rel Name Entity) -> Rel QName Entity inscope m expsOf = unionRels [imports, locals] where defEnts = modDefines m locals = unionRels [mkUnqual `mapDom` defEnts, mkQual (modName m) `mapDom` defEnts] imports = unionRels $ map (mImp expsOf) (modImports m) mImp :: (ModName -> Rel Name Entity) -> Import -> Rel QName Entity mImp expsOf imp | impQualified imp = qs | otherwise = unionRels [unqs, qs] where qs = mkQual (impAs imp) `mapDom` incoming unqs = mkUnqual `mapDom` incoming listed = unionRels $ map (mEntSpec isHiding exps) (impList imp) incoming | isHiding = exps `minusRel` listed | otherwise = listed isHiding = impHiding imp exps = expsOf (impSource imp) computeInsOuts :: (ModName -> Rel Name Entity) -> [Module] -> [(Rel QName Entity, Rel Name Entity)] computeInsOuts otherExps mods = inscps `zip` exps where inscps = computeIs exps exps = lfpAfter nextExps $ replicate (length mods) emptyRel nextExps = computeEs . computeIs computeEs is = zipWith exports mods is computeIs es = map (`inscope` toFun es) mods toFun es m = maybe (otherExps m) (es !!) (lookup m mod_ixs) mod_ixs = map modName mods `zip` [0..] lfpAfter f x = if fx == x then fx else lfpAfter f fx where fx = f x