[project @ 2000-11-20 16:28:29 by simonmar]
[ghc-hetmet.git] / ghc / compiler / compMan / CompManager.lhs
index eb19468..7f0885a 100644 (file)
@@ -5,7 +5,9 @@
 
 \begin{code}
 module CompManager ( cmInit, cmLoadModule,
+#ifdef GHCI
                      cmGetExpr, cmRunExpr,
+#endif
                      CmState, emptyCmState  -- abstract
                    )
 where
@@ -15,8 +17,6 @@ where
 import CmLink
 import CmTypes
 import HscTypes
-import HscMain         ( hscExpr )
-import Interpreter     ( HValue )
 import Module          ( ModuleName, moduleName,
                          isModuleInThisPackage, moduleEnvElts,
                          moduleNameUserString )
@@ -26,21 +26,28 @@ import GetImports
 import HscTypes                ( HomeSymbolTable, HomeIfaceTable, 
                          PersistentCompilerState, ModDetails(..) )
 import Name            ( lookupNameEnv )
-import RdrName
 import Module
 import PrelNames       ( mainName )
 import HscMain         ( initPersistentCompilerState )
-import Finder          ( findModule, emptyHomeDirCache )
+import Finder
 import UniqFM          ( emptyUFM, lookupUFM, addToUFM, delListFromUFM,
                          UniqFM, listToUFM )
 import Unique          ( Uniquable )
 import Digraph         ( SCC(..), stronglyConnComp )
+import DriverPhases
 import DriverUtil      ( BarfKind(..), splitFilename3 )
-import CmdLineOpts     ( DynFlags )
 import Util
 import Outputable
 import Panic           ( panic )
 
+#ifdef GHCI
+import CmdLineOpts     ( DynFlags )
+import Interpreter     ( HValue )
+import HscMain         ( hscExpr )
+import RdrName
+import PrelGHC         ( unsafeCoerce# )
+#endif
+
 -- lang
 import Exception       ( throwDyn )
 
@@ -50,7 +57,6 @@ import Directory        ( getModificationTime, doesFileExist )
 import IO
 import List            ( nub )
 import Maybe           ( catMaybes, fromMaybe, isJust )
-import PrelGHC         ( unsafeCoerce# )
 \end{code}
 
 
@@ -59,6 +65,7 @@ cmInit :: PackageConfigInfo -> GhciMode -> IO CmState
 cmInit raw_package_info gmode
    = emptyCmState raw_package_info gmode
 
+#ifdef GHCI
 cmGetExpr :: CmState
          -> DynFlags
           -> ModuleName
@@ -83,6 +90,7 @@ cmRunExpr :: HValue -> IO ()
 cmRunExpr hval
    = do unsafeCoerce# hval :: IO ()
        -- putStrLn "done."
+#endif
 
 -- Persistent state just for CM, excluding link & compile subsystems
 data PersistentCMState
@@ -142,8 +150,10 @@ the system state at the same time.
 
 \begin{code}
 cmLoadModule :: CmState 
-             -> ModuleName
-             -> IO (CmState, Maybe ModuleName)
+             -> FilePath
+             -> IO (CmState,           -- new state
+                   Bool,               -- was successful
+                   [ModuleName])       -- list of modules loaded
 
 cmLoadModule cmstate1 rootname
    = do -- version 1's are the original, before downsweep
@@ -158,12 +168,6 @@ cmLoadModule cmstate1 rootname
         let pcii      = pci   pcms1 -- this never changes
         let ghci_mode = gmode pcms1 -- ToDo: fix!
 
-        -- During upsweep, look at new summaries to see if source has
-        -- changed.  Here's a function to pass down; it takes a new
-        -- summary.
-        let source_changed :: ModSummary -> Bool
-            source_changed = summary_indicates_source_changed mg1
-
         -- Do the downsweep to reestablish the module graph
         -- then generate version 2's by removing from HIT,HST,UI any
         -- modules in the old MG which are not in the new one.
@@ -205,7 +209,7 @@ cmLoadModule cmstate1 rootname
         let threaded2 = CmThreaded pcs1 hst2 hit2
 
         (upsweep_complete_success, threaded3, modsDone, newLis)
-           <- upsweep_mods ghci_mode ui2 reachable_from source_changed threaded2 mg2
+           <- upsweep_mods ghci_mode ui2 reachable_from threaded2 mg2
 
         let ui3 = add_to_ui ui2 newLis
         let (CmThreaded pcs3 hst3 hit3) = threaded3
@@ -234,7 +238,7 @@ cmLoadModule cmstate1 rootname
                                                           pci=pcii, gmode=ghci_mode }
                           let cmstate3 
                                  = CmState { pcms=pcms3, pcs=pcs3, pls=pls3 }
-                          return (cmstate3, Just rootname)
+                          return (cmstate3, True, map name_of_summary modsDone)
 
          else 
            -- Tricky.  We need to back out the effects of compiling any
@@ -268,43 +272,7 @@ cmLoadModule cmstate1 rootname
                                                           pci=pcii, gmode=ghci_mode }
                           let cmstate4 
                                  = CmState { pcms=pcms4, pcs=pcs3, pls=pls4 }
-                          return (cmstate4, 
-                                  -- choose rather arbitrarily who to return
-                                  if null mods_to_keep then Nothing 
-                                     else Just (last mods_to_keep_names))
-
-
--- Given a bunch of old summaries and a new summary, try and
--- find the corresponding old summary, and, if found, compare
--- its source timestamp with that of the new summary.  If in
--- doubt say True.
-summary_indicates_source_changed :: [ModSummary] -> ModSummary -> Bool
-summary_indicates_source_changed old_summaries new_summary
-   = panic "SISC"
-#if 0
-   = case [old | old <- old_summaries, 
-                 name_of_summary old == name_of_summary new_summary] of
-
-        (_:_:_) -> panic "summary_indicates_newer_source"
-                   
-        []      -> -- can't find a corresponding old summary, so
-                   -- compare source and iface dates in the new summary.
-                   trace (showSDoc (text "SISC: no old summary, new =" 
-                                    <+> pprSummaryTimes new_summary)) (
-                   case (ms_hs_date new_summary, ms_hi_date new_summary) of
-                      (Just hs_t, Just hi_t) -> hs_t > hi_t
-                      other                  -> True
-                   )
-
-        [old]   -> -- found old summary; compare source timestamps
-                   trace (showSDoc (text "SISC: old =" 
-                                    <+> pprSummaryTimes old
-                                    <+> pprSummaryTimes new_summary)) (
-                   case (ms_hs_date old, ms_hs_date new_summary) of
-                      (Just old_t, Just new_t) -> new_t > old_t
-                      other                    -> True
-                   )
-#endif
+                          return (cmstate4, False, mods_to_keep_names)
 
 
 -- Return (names of) all those in modsDone who are part of a cycle
@@ -360,7 +328,6 @@ data CmThreaded  -- stuff threaded through individual module compilations
 upsweep_mods :: GhciMode
              -> UnlinkedImage         -- old linkables
              -> (ModuleName -> [ModuleName])  -- to construct downward closures
-             -> (ModSummary -> Bool)  -- has source changed?
              -> CmThreaded            -- PCS & HST & HIT
              -> [SCC ModSummary]      -- mods to do (the worklist)
                                       -- ...... RETURNING ......
@@ -369,28 +336,27 @@ upsweep_mods :: GhciMode
                     [ModSummary],     -- mods which succeeded
                     [Linkable])       -- new linkables
 
-upsweep_mods ghci_mode oldUI reachable_from source_changed threaded 
+upsweep_mods ghci_mode oldUI reachable_from threaded 
      []
    = return (True, threaded, [], [])
 
-upsweep_mods ghci_mode oldUI reachable_from source_changed threaded 
+upsweep_mods ghci_mode oldUI reachable_from threaded 
      ((CyclicSCC ms):_)
    = do hPutStrLn stderr ("ghc: module imports form a cycle for modules:\n\t" ++
                           unwords (map (moduleNameUserString.name_of_summary) ms))
         return (False, threaded, [], [])
 
-upsweep_mods ghci_mode oldUI reachable_from source_changed threaded 
+upsweep_mods ghci_mode oldUI reachable_from threaded 
      ((AcyclicSCC mod):mods)
    = do (threaded1, maybe_linkable) 
            <- upsweep_mod ghci_mode oldUI threaded mod 
                           (reachable_from (name_of_summary mod)) 
-                          (source_changed mod)
         case maybe_linkable of
            Just linkable 
               -> -- No errors; do the rest
                  do (restOK, threaded2, modOKs, linkables) 
                        <- upsweep_mods ghci_mode oldUI reachable_from 
-                                       source_changed threaded1 mods
+                                       threaded1 mods
                     return (restOK, threaded2, mod:modOKs, linkable:linkables)
            Nothing -- we got a compilation error; give up now
               -> return (False, threaded1, [], [])
@@ -418,15 +384,24 @@ upsweep_mod :: GhciMode
             -> CmThreaded
             -> ModSummary
             -> [ModuleName]
-            -> Bool
             -> IO (CmThreaded, Maybe Linkable)
 
-upsweep_mod ghci_mode oldUI threaded1 summary1 
-            reachable_from_here source_might_have_changed
+upsweep_mod ghci_mode oldUI threaded1 summary1 reachable_from_here
    = do let mod_name = name_of_summary summary1
         let (CmThreaded pcs1 hst1 hit1) = threaded1
         let old_iface = lookupUFM hit1 (name_of_summary summary1)
 
+        -- We *have* to compile it if we're in batch mode and we can't see
+        -- a previous linkable for it on disk.
+        compilation_mandatory 
+           <- if ghci_mode /= Batch then return False 
+              else case ml_obj_file (ms_location summary1) of
+                      Nothing     -> do --putStrLn "cmcm: object?!"
+                                        return True
+                      Just obj_fn -> do --putStrLn ("cmcm: old obj " ++ obj_fn)
+                                        b <- doesFileExist obj_fn
+                                        return (not b)
+
         let maybe_oldUI_linkable = findModuleLinkable_maybe oldUI mod_name
         maybe_oldDisk_linkable
            <- case ml_obj_file (ms_location summary1) of
@@ -567,11 +542,21 @@ topological_sort include_source_imports summaries
 -- Chase downwards from the specified root set, returning summaries
 -- for all home modules encountered.  Only follow source-import
 -- links.
-downsweep :: [ModuleName] -> IO [ModSummary]
+downsweep :: [FilePath] -> IO [ModSummary]
 downsweep rootNm
-   = do rootSummaries <- mapM getSummary rootNm
+   = do rootSummaries <- mapM getRootSummary rootNm
         loop (filter (isModuleInThisPackage.ms_mod) rootSummaries)
      where
+       getRootSummary :: FilePath -> IO ModSummary
+       getRootSummary file
+          | haskellish_file file
+           = do exists <- doesFileExist file
+               if exists then summariseFile file
+                         else getSummary (mkModuleName file)
+               -- ToDo: should check import paths
+          | otherwise
+          = getSummary (mkModuleName file)
+
         getSummary :: ModuleName -> IO ModSummary
         getSummary nm
            | trace ("getSummary: "++ showSDoc (ppr nm)) True
@@ -605,6 +590,40 @@ downsweep rootNm
                  else loop (newHomeSummaries ++ homeSummaries)
 
 
+-----------------------------------------------------------------------------
+-- Summarising modules
+
+-- We have two types of summarisation:
+--
+--    * Summarise a file.  This is used for the root module passed to
+--     cmLoadModule.  The file is read, and used to determine the root
+--     module name.  The module name may differ from the filename.
+--
+--    * Summarise a module.  We are given a module name, and must provide
+--     a summary.  The finder is used to locate the file in which the module
+--     resides.
+
+summariseFile :: FilePath -> IO ModSummary
+summariseFile file
+   = do hspp_fn <- preprocess file
+        modsrc <- readFile hspp_fn
+
+        let (srcimps,imps,mod_name) = getImports modsrc
+           (path, basename, ext) = splitFilename3 file
+
+       Just (mod, location)
+          <- mkHomeModuleLocn mod_name (path ++ '/':basename) file
+          
+        maybe_src_timestamp
+           <- case ml_hs_file location of 
+                 Nothing     -> return Nothing
+                 Just src_fn -> maybe_getModificationTime src_fn
+
+        return (ModSummary mod
+                           location{ml_hspp_file=Just hspp_fn}
+                           srcimps imps
+                           maybe_src_timestamp)
+
 -- Summarise a module, and pick up source and interface timestamps.
 summarise :: Module -> ModuleLocation -> IO ModSummary
 summarise mod location
@@ -619,44 +638,24 @@ summarise mod location
                  Nothing     -> return Nothing
                  Just src_fn -> maybe_getModificationTime src_fn
 
-        -- If the module name is Main, allow it to be in a file
-        -- different from Main.hs, and mash the mod and loc 
-        -- to match.  Otherwise just moan.
-        (mashed_mod, mashed_loc)
-           <- case () of
-              () |  mod_name == moduleName mod
-                 -> return (mod, location)
-                 |  mod_name /= moduleName mod && mod_name == mkModuleName "Main"
-                 -> return (mash mod location "Main")
-                 |  otherwise
-                 -> do hPutStrLn stderr (showSDoc (
-                          text "ghc: warning: file name - module name mismatch:" <+> 
-                          ppr (moduleName mod) <+> text "vs" <+> ppr mod_name))
-                       return (mash mod location (moduleNameUserString (moduleName mod)))
-               where
-                 mash old_mod old_loc new_nm
-                    = (mkHomeModule (mkModuleName new_nm), 
-                       old_loc{ml_hi_file = maybe_swizzle_basename new_nm 
-                                                (ml_hi_file old_loc)})
-
-                 maybe_swizzle_basename new Nothing = Nothing
-                 maybe_swizzle_basename new (Just old) 
-                    = case splitFilename3 old of 
-                         (dir, name, ext) -> Just (dir ++ new ++ ext)
-
-        return (ModSummary mashed_mod 
-                           mashed_loc{ml_hspp_file=Just hspp_fn} 
-                           srcimps imps
-                           maybe_src_timestamp)
+       if mod_name == moduleName mod
+               then return ()
+               else throwDyn (OtherError 
+                       (showSDoc (text "file name does not match module name: "
+                          <+> ppr (moduleName mod) <+> text "vs" 
+                          <+> ppr mod_name)))
+
+        return (ModSummary mod location{ml_hspp_file=Just hspp_fn} 
+                               srcimps imps
+                               maybe_src_timestamp)
 
    | otherwise
    = return (ModSummary mod location [] [] Nothing)
 
-   where
-      maybe_getModificationTime :: FilePath -> IO (Maybe ClockTime)
-      maybe_getModificationTime fn
-         = (do time <- getModificationTime fn
-               return (Just time)) 
-           `catch`
-           (\err -> return Nothing)
+maybe_getModificationTime :: FilePath -> IO (Maybe ClockTime)
+maybe_getModificationTime fn
+   = (do time <- getModificationTime fn
+         return (Just time)) 
+     `catch`
+     (\err -> return Nothing)
 \end{code}