diff options
Diffstat (limited to 'src/Main.hs')
-rw-r--r-- | src/Main.hs | 224 |
1 files changed, 161 insertions, 63 deletions
diff --git a/src/Main.hs b/src/Main.hs index c0e9745f..44d18f25 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -22,7 +22,7 @@ import Control.Monad ( when, liftM ) import Control.Monad.Writer ( Writer, runWriter, tell ) import Data.Char ( isSpace ) import Data.IORef ( writeIORef ) -import Data.List ( nub, (\\), foldl', sortBy, foldl1 ) +import Data.List ( nub, (\\), foldl', sortBy, foldl1, init, mapAccumL, find ) import Data.Maybe ( isJust, isNothing, maybeToList, listToMaybe ) --import Debug.Trace import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(..), OptDescr(..), ArgDescr(..) ) @@ -39,12 +39,13 @@ import Data.Maybe import Data.List ( nubBy ) import Data.FunctorM ( fmapM ) -import GHC +import qualified GHC ( init ) +import GHC hiding ( init ) import Outputable import SrcLoc import qualified Digraph as Digraph import Name -import Module ( moduleString, mkModule ) +import Module ( mkModule ) import InstEnv import Class import TypeRep @@ -54,28 +55,104 @@ import PrelNames import FastString #define FSLIT(x) (mkFastString# (x#)) import DynFlags hiding ( Option ) +import StaticFlags ( parseStaticFlags ) import Unique ( mkUnique ) import Packages ----------------------------------------------------------------------------- -- Top-level stuff -type CheckedMods = [(Module, FullyCheckedMod, FilePath)] +type CheckedMod = (Module, FullyCheckedMod, FilePath) main :: IO () main = do args <- getArgs (libDir, rest) <- getLibDir args - (session, ghcFlags, nonGHCOpts) <- startGHC libDir rest - (flags, args) <- parseHaddockOpts nonGHCOpts - handleEagerFlags flags - modules <- sortAndCheckModules session ghcFlags args - (ifaces, htmls) <- getIfacesAndHtmls flags ghcFlags + let (isGHCMode, rest') = parseModeFlag rest + (session, dynflags) <- startGHC libDir + + (dynflags', rest'') <- if isGHCMode + then parseGHCFlags_GHCMode dynflags rest' + else parseGHCFlags_HaddockMode dynflags rest' + + (flags, fileArgs) <- parseHaddockOpts rest'' + + mbPkgName <- handleEagerFlags flags + let dynflags'' = case mbPkgName of + Just name -> setPackageName name dynflags' + Nothing -> dynflags' + + setSessionDynFlags session dynflags'' + + modules <- sortAndCheckModules session dynflags' fileArgs + (ifaces, htmls) <- getIfacesAndHtmls flags dynflags' let (modss, envs) = unzip ifaces - updateHTMLXRefs htmls modss + updateHTMLXRefs htmls modss -- TODO: continue to break up the run function into parts run flags modules envs +parseModeFlag :: [String] -> (Bool, [String]) +parseModeFlag ("--ghc-flags":rest) = (True, rest) +parseModeFlag rest = (False, rest) + +parseGHCFlags_GHCMode :: DynFlags -> [String] -> IO (DynFlags, [String]) +parseGHCFlags_GHCMode dynflags args = do + (dynflags', rest) <- parseDynamicFlags dynflags args + rest' <- parseStaticFlags rest + return (dynflags', rest') + +parseGHCFlags_HaddockMode = parseGHCFlags + +parseGHCFlags :: DynFlags -> [String] -> IO (DynFlags, [String]) +parseGHCFlags dynflags args = case args of + [] -> return (dynflags, args) + ("-g":rest) -> worker rest + (('-':'-':'g':'h':'c':'-':'f':'l':'a':'g':[]):rest) -> worker rest + (x:xs) -> do + (flags, rest) <- parseGHCFlags dynflags xs + return (flags, x:rest) + where + worker rest = do + (mbFlags, rest') <- parseGHCFlag dynflags rest + case mbFlags of + Just flags -> parseGHCFlags flags rest' + Nothing -> parseGHCFlags dynflags rest' + +parseGHCFlag :: DynFlags -> [String] -> IO (Maybe DynFlags, [String]) +parseGHCFlag _ [] = die "No GHC flag supplied\n" +parseGHCFlag dynflags args = do + mbDyn <- findDynamic + case mbDyn of + Just (dynflags', rest) -> return (Just dynflags', rest) + Nothing -> do + mbStat <- findStatic + case mbStat of + Just (_, rest) -> return (Nothing, rest) + Nothing -> die ("Not a GHC flag: " ++ (head args) ++ "\n") + where + findDynamic = findFlag ( + \xs -> + (do + (fs, xs') <- parseDynamicFlags dynflags xs + if xs' /= xs then return (Just fs) else return Nothing + ) + `catch` (\_ -> return Nothing) + ) + findStatic = findFlag (\xs -> do + xs' <- parseStaticFlags xs + if xs /= xs' then return (Just ()) else return Nothing) + + findFlag p = do + xs <- (sequence . snd) (mapAccumL (f p) [] args) + case [ (x, index) | Just x <- xs | index <- [1..] ] of + ((x, index):_) -> return (Just (x, drop index args)) + _ -> return Nothing + + f :: ([String] -> IO a) -> [String] -> String -> ([String], IO a) + f parser previousArgs arg = + let args' = previousArgs ++ [arg] + in (args', parser args') + parseHaddockOpts :: [String] -> IO ([Flag], [String]) parseHaddockOpts words = case getOpt Permute (options True) words of @@ -92,23 +169,20 @@ getLibDir ("-B":dir:rest) = return (dir, rest) getLibDir (('-':'B':dir):rest) | not (null dir) = return (dir, rest) getLibDir _ = die "Missing GHC lib dir option: -B <dir>\n" --- | Initialize GHC, parse the passed in strings and set the corresponding --- GHC flags (if any). Also add the -haddock flag. Return the Session handle --- and the strings that were not GHC flags. -startGHC :: String -> [String] -> IO (Session, DynFlags, [String]) -startGHC libDir possibleOpts = do +extractGHCFlags :: [Flag] -> [String] +extractGHCFlags flags = [ flag | Flag_GHCFlag flag <- flags ] + +startGHC :: String -> IO (Session, DynFlags) +startGHC libDir = do GHC.init (Just libDir) let ghcMode = JustTypecheck session <- newSession ghcMode flags <- getSessionDynFlags session flags' <- initPackages flags - (flags'', nonOpts) <- parseDynamicFlags flags' possibleOpts - let flags''' = dopt_set flags'' Opt_Haddock - setSessionDynFlags session flags''' - return (session, flags''', nonOpts) + let flags'' = dopt_set flags' Opt_Haddock + return (session, flags'') -sortAndCheckModules :: Session -> DynFlags -> [FilePath] -> - IO [(Module, FullyCheckedMod, FilePath)] +sortAndCheckModules :: Session -> DynFlags -> [FilePath] -> IO [CheckedMod] sortAndCheckModules session flags files = defaultErrorHandler flags $ do targets <- mapM (\s -> guessTarget s Nothing) files setTargets session targets @@ -124,7 +198,7 @@ sortAndCheckModules session flags files = defaultErrorHandler flags $ do modsum <- sortedModules, modSumFile modsum `elem` files ] checkedMods <- mapM (\(mod, file) -> do - mbMod <- checkModule session mod + mbMod <- checkModule session (moduleName mod) checkedMod <- case mbMod of Just m -> return m Nothing -> die ("Failed to load module: " ++ moduleString mod) @@ -133,7 +207,7 @@ sortAndCheckModules session flags files = defaultErrorHandler flags $ do where ensureFullyChecked modules | length modules' == length modules = return modules' - | otherwise = die "Fail to check all modules properly\n" + | otherwise = die "Failed to check all modules properly\n" where modules' = [ (mod, (a,b,c,d), f) | (mod, CheckedModule a (Just b) (Just c) (Just d), f) <- modules ] @@ -179,6 +253,7 @@ data Flag | Flag_IgnoreAllExports | Flag_HideModule String | Flag_UsePackage String + | Flag_GHCFlag String deriving (Eq) options :: Bool -> [OptDescr Flag] @@ -244,32 +319,35 @@ options backwardsCompat = Option [] ["hide"] (ReqArg Flag_HideModule "MODULE") "behave as if MODULE has the hide attribute", Option [] ["use-package"] (ReqArg Flag_UsePackage "PACKAGE") - "the modules being processed depend on PACKAGE" + "the modules being processed depend on PACKAGE", + Option ['g'] ["ghc-flag"] (ReqArg Flag_GHCFlag "FLAG") + "send a flag to the Glasgow Haskell Compiler" ] handleEagerFlags flags = do whenFlag Flag_Help $ do prog <- getProgramName bye (usageInfo (usageHeader prog) (options False)) + whenFlag Flag_Version $ bye ("Haddock version " ++ projectVersion ++ ", (c) Simon Marlow 2003; port to GHC-api by David Waern 2006\n") + when ((Flag_GenIndex `elem` flags || Flag_GenContents `elem` flags) && Flag_Html `elem` flags) $ die ("-h cannot be used with --gen-index or --gen-contents") + + return (listToMaybe [str | Flag_Package str <- flags]) where whenFlag flag action = when (flag `elem` flags) action - -run :: [Flag] -> CheckedMods -> [Map Name Name] -> IO () +run :: [Flag] -> [CheckedMod] -> [Map Name Name] -> IO () run flags modules extEnvs = do let title = case [str | Flag_Heading str <- flags] of [] -> "" (t:_) -> t - package = listToMaybe [str | Flag_Package str <- flags] - maybe_source_urls = (listToMaybe [str | Flag_SourceBaseURL str <- flags] ,listToMaybe [str | Flag_SourceModuleURL str <- flags] ,listToMaybe [str | Flag_SourceEntityURL str <- flags]) @@ -316,7 +394,7 @@ run flags modules extEnvs = do prologue <- getPrologue flags let - (modMap, messages) = runWriter (pass1 modules flags package) + (modMap, messages) = runWriter (pass1 modules flags) haddockMods = catMaybes [ Map.lookup mod modMap | (mod,_,_) <- modules ] homeEnv = buildGlobalDocEnv haddockMods env = Map.unions (homeEnv:extEnvs) @@ -326,25 +404,28 @@ run flags modules extEnvs = do mapM_ putStrLn messages mapM_ putStrLn messages' - let visibleMods = [ m | m <- haddockMods'', OptHide `notElem` (hmod_options m) ] + let + visibleMods = [ m | m <- haddockMods'', OptHide `notElem` (hmod_options m) ] + packageName = (Just . packageIdString . modulePackageId . + hmod_mod . head) visibleMods when (Flag_GenIndex `elem` flags) $ do - ppHtmlIndex odir title package maybe_html_help_format + ppHtmlIndex odir title packageName maybe_html_help_format maybe_contents_url maybe_source_urls maybe_wiki_urls visibleMods copyHtmlBits odir libdir css_file when (Flag_GenContents `elem` flags && Flag_GenIndex `elem` flags) $ do - ppHtmlHelpFiles title package visibleMods odir maybe_html_help_format [] + ppHtmlHelpFiles title packageName visibleMods odir maybe_html_help_format [] when (Flag_GenContents `elem` flags) $ do - ppHtmlContents odir title package maybe_html_help_format + ppHtmlContents odir title packageName maybe_html_help_format maybe_index_url maybe_source_urls maybe_wiki_urls - visibleMods prologue + visibleMods True prologue copyHtmlBits odir libdir css_file when (Flag_Html `elem` flags) $ do - ppHtml title package visibleMods odir + ppHtml title packageName visibleMods odir prologue maybe_html_help_format maybe_source_urls maybe_wiki_urls maybe_contents_url maybe_index_url @@ -355,7 +436,7 @@ run flags modules extEnvs = do -- dump an interface if requested case dumpIface of Nothing -> return () - Just fn -> dumpInterfaces env (map hmod_mod visibleMods) fn + Just fn -> dumpInterfaces env (map hmod_mod visibleMods) fn where pprList [] = [] pprList [x] = show x @@ -383,10 +464,9 @@ type FullyCheckedMod = (ParsedSource, printEntity (DocEntity doc) = show doc printEntity (DeclEntity name) = show $ ppr name defaultUserStyle -pass1 :: [(Module, FullyCheckedMod, FilePath)] -> [Flag] -> Maybe String -> ErrMsgM ModuleMap2 -pass1 modules flags package = worker modules (Map.empty) flags +pass1 :: [CheckedMod] -> [Flag] -> ErrMsgM ModuleMap2 +pass1 modules flags = worker modules (Map.empty) flags where - worker :: [(Module, FullyCheckedMod, FilePath)] -> ModuleMap2 -> [Flag] -> ErrMsgM ModuleMap2 worker [] moduleMap _ = return moduleMap worker ((mod, checked_mod, filename):rest_modules) moduleMap flags = do @@ -405,7 +485,8 @@ pass1 modules flags package = worker modules (Map.empty) flags theseEntityNames = entityNames entities subNames = allSubnamesInGroup group localNames = theseEntityNames ++ subNames - -- guaranteed to be Just, since the module has been compiled from scratch + -- guaranteed to be Just, since the module has been compiled from + -- scratch scopeNames = fromJust $ modInfoTopLevelScope moduleInfo subMap = mk_sub_map_from_group group @@ -415,13 +496,17 @@ pass1 modules flags package = worker modules (Map.empty) flags docMap = mkDocMap group ignoreAllExports = Flag_IgnoreAllExports `elem` flags + + packageId = modulePackageId mod theseVisibleNames <- visibleNames mod moduleMap localNames scopeNames - subMap exports opts localDeclMap + subMap exports opts localDeclMap + packageId exportItems <- mkExportItems moduleMap mod exportedNames - exportedDeclMap localDeclMap subMap entities opts - exports ignoreAllExports docMap + exportedDeclMap localDeclMap subMap entities + opts exports ignoreAllExports docMap + packageId -- prune the export list to just those declarations that have -- documentation, if the 'prune' option is on. @@ -447,8 +532,7 @@ pass1 modules flags package = worker modules (Map.empty) flags hmod_exports = exportedNames, hmod_visible_exports = theseVisibleNames, hmod_exported_decl_map = exportedDeclMap, - hmod_instances = instances, - hmod_package = package + hmod_instances = instances } moduleMap' = Map.insert mod haddock_module moduleMap @@ -493,7 +577,8 @@ mkDocMap group = Map.fromList (topDeclDocs ++ classMethDocs ++ recordFieldDocs) collectDocs :: [DocEntity Name] -> [(Name, HsDoc Name)] collectDocs entities = collect Nothing DocEmpty entities -collect :: Maybe (DocEntity Name) -> HsDoc Name -> [DocEntity Name] -> [(Name, HsDoc Name)] +collect :: Maybe (DocEntity Name) -> HsDoc Name -> [DocEntity Name] -> + [(Name, HsDoc Name)] collect d doc_so_far [] = case d of Nothing -> [] @@ -592,8 +677,8 @@ getDeclFromGroup group name = _ -> Nothing where matching = [ for | for <- lfors, forName (unLoc for) == name ] - forName (ForeignExport n _ _ _) = unLoc n - forName (ForeignImport n _ _ _) = unLoc n + forName (ForeignExport n _ _) = unLoc n + forName (ForeignImport n _ _) = unLoc n parseIfaceOption :: String -> (FilePath,FilePath) parseIfaceOption s = @@ -613,9 +698,9 @@ getPrologue flags [filename] -> do str <- readFile filename case parseHaddockComment str of - Left err -> dieMsg err + Left err -> die err Right doc -> return (Just doc) - _otherwise -> dieMsg "multiple -p/--prologue options" + _otherwise -> die "multiple -p/--prologue options" -- ----------------------------------------------------------------------------- -- Phase 2 @@ -675,10 +760,11 @@ mkExportItems -> Maybe [IE Name] -> Bool -- --ignore-all-exports flag -> Map Name (HsDoc Name) + -> PackageId -> ErrMsgM [ExportItem2 Name] mkExportItems mod_map this_mod exported_names exportedDeclMap localDeclMap sub_map entities - opts maybe_exps ignore_all_exports docMap + opts maybe_exps ignore_all_exports docMap packageId | isNothing maybe_exps || ignore_all_exports || OptIgnoreExports `elem` opts = everything_local_exported | Just specs <- maybe_exps = do @@ -692,7 +778,7 @@ mkExportItems mod_map this_mod exported_names exportedDeclMap localDeclMap sub_m lookupExport (IEThingAbs t) = declWith t lookupExport (IEThingAll t) = declWith t lookupExport (IEThingWith t cs) = declWith t - lookupExport (IEModuleContents m) = fullContentsOf m + lookupExport (IEModuleContents m) = fullContentsOf (mkModule packageId m) lookupExport (IEGroup lev doc) = return [ ExportGroup2 lev "" doc ] lookupExport (IEDoc doc) = return [ ExportDoc2 doc ] lookupExport (IEDocNamed str) @@ -827,9 +913,10 @@ visibleNames :: Module -> Maybe [IE Name] -> [DocOption] -> Map Name (LHsDecl Name) + -> PackageId -> ErrMsgM [Name] -visibleNames mdl modMap localNames scope subMap maybeExps opts declMap +visibleNames mdl modMap localNames scope subMap maybeExps opts declMap packageId -- if no export list, just return all local names | Nothing <- maybeExps = return (filter hasDecl localNames) | OptIgnoreExports `elem` opts = return localNames @@ -853,18 +940,22 @@ visibleNames mdl modMap localNames scope subMap maybeExps opts declMap IEThingWith t cs -> return (t : cs) IEModuleContents m - | m == mdl -> return localNames - | otherwise -> - case Map.lookup m modMap of + | mkModule packageId m == mdl -> return localNames + | otherwise -> let m' = mkModule packageId m in + case Map.lookup m' modMap of Just mod | OptHide `elem` hmod_options mod -> return (filter (`elem` scope) (hmod_exports mod)) | otherwise -> return [] Nothing - -> tell ["Can not reexport a package module"] >> return [] - + -> tell (exportModuleMissingErr mdl m') >> return [] + _ -> return [] +exportModuleMissingErr this mdl + = ["Warning: in export list of " ++ show (moduleString this) + ++ ": module not found: " ++ show (moduleString mdl)] + -- for a given entity, find all the names it "owns" (ie. all the -- constructors and field names of a tycon, or all the methods of a -- class). @@ -1046,9 +1137,12 @@ type ErrMsgM a = Writer [ErrMsg] a getPackageFiles :: DynFlags -> IO [(String, String)] getPackageFiles dynflags = do packages <- getExplicitPackagesAnd dynflags [] - mbFiles <- mapM check packages + mbFiles <- mapM check (filter notRTS packages) return [ pair | Just pair <- mbFiles ] where + -- no better way to do this? + notRTS p = pkgName (package p) /= packageIdString rtsPackageId + check p = (do pair <- check' p return (Just pair)) `catch` (\e -> do @@ -1080,7 +1174,7 @@ getPackageFiles dynflags = do -- ----------------------------------------------------------------------------- -- The interface file format --- ehhm. this is a hack... +-- ehhm. this is a temporary hack... thisFormatVersion :: FormatVersion thisFormatVersion = mkFormatVersion 3 @@ -1155,9 +1249,13 @@ instance Binary OccName where return (mkOccName (decodeNS ns) string) instance Binary Module where - put_ bh m = put_ bh (moduleString m) - get bh = do m <- get bh; return (mkModule m) - + put_ bh m = do + put_ bh (moduleString m) + put_ bh ((packageIdString . modulePackageId) m) + get bh = do + m <- get bh + p <- get bh + return (mkModule (stringToPackageId p) (mkModuleName m)) {- thisFormatVersion :: FormatVersion thisFormatVersion = mkFormatVersion 2 |