{-# OPTIONS -fno-warn-name-shadowing #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE NoMonoLocalBinds #-}
{-# LANGUAGE TypeFamilies #-}
module Language.Haskell.Names.Exports
( processExports
) where
import Fay.Compiler.Prelude
import Fay.Compiler.ModuleT
import Language.Haskell.Names.GlobalSymbolTable as Global
import Language.Haskell.Names.ModuleSymbols
import Language.Haskell.Names.ScopeUtils
import Language.Haskell.Names.SyntaxUtils
import Language.Haskell.Names.Types (Error (..), GName (..), ModuleNameS, NameInfo (..),
Scoped (..), Symbols (..), mkTy, mkVal, st_origName)
import Control.Monad.Writer (WriterT (WriterT), runWriterT)
import qualified Data.Map as Map
import qualified Data.Set as Set
import Language.Haskell.Exts
processExports
:: (MonadModule m, ModuleInfo m ~ Symbols, Data l, Eq l)
=> Global.Table
-> Module l
-> m (Maybe (ExportSpecList (Scoped l)), Symbols)
processExports tbl m =
case getExportSpecList m of
Nothing ->
return (Nothing, moduleSymbols tbl m)
Just exp ->
liftM (first Just) $ resolveExportSpecList tbl exp
resolveExportSpecList
:: (MonadModule m, ModuleInfo m ~ Symbols)
=> Global.Table
-> ExportSpecList l
-> m (ExportSpecList (Scoped l), Symbols)
resolveExportSpecList tbl (ExportSpecList l specs) =
liftM (first $ ExportSpecList $ none l) $
runWriterT $
mapM (WriterT . resolveExportSpec tbl) specs
resolveExportSpec
:: (MonadModule m, ModuleInfo m ~ Symbols)
=> Global.Table
-> ExportSpec l
-> m (ExportSpec (Scoped l), Symbols)
resolveExportSpec tbl exp =
case exp of
EVar l qn -> return $
case Global.lookupValue qn tbl of
Global.Error err ->
(scopeError err exp, mempty)
Global.Result i ->
let s = mkVal i
in
(EVar (Scoped (Export s) l)
(Scoped (GlobalValue i) <$> qn), s)
Global.Special {} -> error "Global.Special in export list?"
EAbs l ns qn -> return $
case Global.lookupType qn tbl of
Global.Error err ->
(scopeError err exp, mempty)
Global.Result i ->
let s = mkTy i
in
(EAbs (Scoped (Export s) l) (noScope ns)
(Scoped (GlobalType i) <$> qn), s)
Global.Special {} -> error "Global.Special in export list?"
EThingWith l (EWildcard wcl wcn) qn [] -> return $
case Global.lookupType qn tbl of
Global.Error err ->
(scopeError err exp, mempty)
Global.Result i ->
let
subs = mconcat
[ mkVal info
| info <- allValueInfos
, Just n' <- return $ sv_parent info
, n' == st_origName i ]
s = mkTy i <> subs
in
( EThingWith (Scoped (Export s) l)
(EWildcard (Scoped (Export s) wcl) wcn)
(Scoped (GlobalType i) <$> qn)
[]
, s
)
Global.Special {} -> error "Global.Special in export list?"
EThingWith _ (EWildcard _ _) _qn _cns -> error "Name resolution: CNames are not supported in wildcard exports"
EThingWith l (NoWildcard wcl) qn cns -> return $
case Global.lookupType qn tbl of
Global.Error err ->
(scopeError err exp, mempty)
Global.Result i ->
let
(cns', subs) =
resolveCNames
(Global.toSymbols tbl)
(st_origName i)
(\cn -> ENotInScope (UnQual (ann cn) (unCName cn)))
cns
s = mkTy i <> subs
in
( EThingWith (Scoped (Export s) l)
(NoWildcard (Scoped (Export s) wcl))
(Scoped (GlobalType i) <$> qn)
cns'
, s
)
Global.Special {} -> error "Global.Special in export list?"
EModuleContents _ (ModuleName _ mod) ->
let
filterByPrefix
:: Ord i
=> ModuleNameS
-> Map.Map GName (Set.Set i)
-> Set.Set i
filterByPrefix prefix m =
Set.unions
[ i | (GName { gModule = prefix' }, i) <- Map.toList m, prefix' == prefix ]
filterEntities
:: Ord i
=> Map.Map GName (Set.Set i)
-> Set.Set i
filterEntities ents =
Set.intersection
(filterByPrefix mod ents)
(filterByPrefix "" ents)
eVals = filterEntities $ Global.values tbl
eTyps = filterEntities $ Global.types tbl
s = Symbols eVals eTyps
in
return (Scoped (Export s) <$> exp, s)
where
allValueInfos =
Set.toList $ Map.foldl' Set.union Set.empty $ Global.values tbl