[project @ 2004-10-25 09:23:08 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / HscMain.lhs
index 4de831c..953791a 100644 (file)
@@ -6,9 +6,12 @@
 
 \begin{code}
 module HscMain ( 
-       HscResult(..), hscMain, newHscEnv
+       HscResult(..),
+       hscMain, newHscEnv, hscCmmFile, 
+       hscBufferCheck, hscFileCheck,
 #ifdef GHCI
-       , hscStmt, hscTcExpr, hscThing, 
+       , hscStmt, hscTcExpr, hscKcType
+       , hscGetInfo, GetInfoResult
        , compileExpr
 #endif
        ) where
@@ -16,33 +19,38 @@ module HscMain (
 #include "HsVersions.h"
 
 #ifdef GHCI
-import HsSyn           ( Stmt(..) )
-import TcHsSyn         ( TypecheckedHsExpr )
-import IfaceSyn                ( IfaceDecl )
+import HsSyn           ( Stmt(..), LStmt, LHsExpr, LHsType )
+import IfaceSyn                ( IfaceDecl, IfaceInst )
 import CodeOutput      ( outputForeignStubs )
 import ByteCodeGen     ( byteCodeGen, coreExprToBCOs )
 import Linker          ( HValue, linkExpr )
 import TidyPgm         ( tidyCoreExpr )
 import CorePrep                ( corePrepExpr )
 import Flattening      ( flattenExpr )
-import TcRnDriver      ( tcRnStmt, tcRnExpr, tcRnThing ) 
-import RdrHsSyn                ( RdrNameStmt )
-import RdrName         ( GlobalRdrEnv )
+import TcRnDriver      ( tcRnStmt, tcRnExpr, tcRnGetInfo, tcRnType ) 
+import RdrName         ( rdrNameOcc )
+import OccName         ( occNameUserString )
 import Type            ( Type )
 import PrelNames       ( iNTERACTIVE )
 import StringBuffer    ( stringToStringBuffer )
-import SrcLoc          ( noSrcLoc )
-import Name            ( Name )
+import Kind            ( Kind )
+import Var             ( Id )
 import CoreLint                ( lintUnfolding )
 import DsMeta          ( templateHaskellNames )
 import BasicTypes      ( Fixity )
+import SrcLoc          ( SrcLoc, noSrcLoc )
 #endif
 
+import RdrName         ( RdrName )
+import HsSyn           ( HsModule )
+import SrcLoc          ( Located(..) )
 import StringBuffer    ( hGetStringBuffer )
 import Parser
-import Lexer           ( P(..), ParseResult(..), mkPState, showPFailed )
+import Lexer           ( P(..), ParseResult(..), mkPState )
 import SrcLoc          ( mkSrcLoc )
-import TcRnDriver      ( tcRnModule, tcRnExtCore, tcRnIface )
+import TcRnDriver      ( tcRnModule, tcRnExtCore )
+import TcRnTypes       ( TcGblEnv )
+import TcIface         ( typecheckIface )
 import IfaceEnv                ( initNameCache )
 import LoadIface       ( ifaceStats, initExternalPackageState )
 import PrelInfo                ( wiredInThings, basicKnownKeyNames )
@@ -57,11 +65,12 @@ import CoreToStg    ( coreToStg )
 import Name            ( Name, NamedThing(..) )
 import SimplStg                ( stg2stg )
 import CodeGen         ( codeGen )
+import CmmParse                ( parseCmmFile )
 import CodeOutput      ( codeOutput )
 
 import CmdLineOpts
-import DriverPhases     ( isExtCore_file )
-import ErrUtils                ( dumpIfSet, dumpIfSet_dyn, showPass )
+import DriverPhases     ( isExtCoreFilename )
+import ErrUtils
 import UniqSupply      ( mkSplitUniqSupply )
 
 import Outputable
@@ -73,6 +82,8 @@ import ParserCoreUtils
 import Module          ( Module, ModLocation(..), showModMsg )
 import FastString
 import Maybes          ( expectJust )
+import StringBuffer    ( StringBuffer )
+import Bag             ( unitBag, emptyBag )
 
 import Monad           ( when )
 import Maybe           ( isJust, fromJust )
@@ -119,7 +130,10 @@ knownKeyNames = map getName wiredInThings
 \begin{code}
 data HscResult
    -- Compilation failed
-   = HscFail     
+   = HscFail
+
+   -- In IDE mode: we just do the static/dynamic checks
+   | HscChecked (Located (HsModule RdrName)) (Maybe TcGblEnv)
 
    -- Concluded that it wasn't necessary
    | HscNoRecomp ModDetails             -- new details (HomeSymbolTable additions)
@@ -133,11 +147,16 @@ data HscResult
                 Bool                   -- stub_c exists
                 (Maybe CompiledByteCode)
 
+
+-- What to do when we have compiler error or warning messages
+type MessageAction = Messages -> IO ()
+
        -- no errors or warnings; the individual passes
        -- (parse/rename/typecheck) print messages themselves
 
 hscMain
   :: HscEnv
+  -> MessageAction             -- what to do with errors/warnings
   -> Module
   -> ModLocation               -- location info
   -> Bool                      -- True <=> source unchanged
@@ -145,7 +164,7 @@ hscMain
   -> Maybe ModIface            -- old interface, if available
   -> IO HscResult
 
-hscMain hsc_env mod location 
+hscMain hsc_env msg_act mod location 
        source_unchanged have_object maybe_old_iface
  = do {
       (recomp_reqd, maybe_checked_iface) <- 
@@ -158,18 +177,18 @@ hscMain hsc_env mod location
           what_next | recomp_reqd || no_old_iface = hscRecomp 
                     | otherwise                   = hscNoRecomp
 
-      ; what_next hsc_env have_object 
+      ; what_next hsc_env msg_act have_object 
                  mod location maybe_checked_iface
       }
 
 
 -- hscNoRecomp definitely expects to have the old interface available
-hscNoRecomp hsc_env have_object 
+hscNoRecomp hsc_env msg_act have_object 
            mod location (Just old_iface)
- | hsc_mode hsc_env == OneShot
+ | isOneShot (hsc_mode hsc_env)
  = do {
-      when (verbosity (hsc_dflags hsc_env) > 0) $
-         hPutStrLn stderr "compilation IS NOT required";
+      compilationProgressMsg (hsc_dflags hsc_env) $
+       "compilation IS NOT required";
       dumpIfaceStats hsc_env ;
 
       let { bomb = panic "hscNoRecomp:OneShot" };
@@ -177,35 +196,35 @@ hscNoRecomp hsc_env have_object
       }
  | otherwise
  = do {
-      when (verbosity (hsc_dflags hsc_env) >= 1) $
-               hPutStrLn stderr ("Skipping  " ++ 
-                       showModMsg have_object mod location);
+      compilationProgressMsg (hsc_dflags hsc_env) $
+       ("Skipping  " ++ showModMsg have_object mod location);
 
       new_details <- _scc_ "tcRnIface"
-                    tcRnIface hsc_env old_iface ;
+                    typecheckIface hsc_env old_iface ;
       dumpIfaceStats hsc_env ;
 
       return (HscNoRecomp new_details old_iface)
       }
 
-hscRecomp hsc_env have_object 
+hscRecomp hsc_env msg_act have_object 
          mod location maybe_checked_iface
  = do  {
          -- what target are we shooting for?
-       ; let one_shot  = hsc_mode hsc_env == OneShot
+       ; let one_shot  = isOneShot (hsc_mode hsc_env)
        ; let dflags    = hsc_dflags hsc_env
        ; let toInterp  = dopt_HscLang dflags == HscInterpreted
        ; let toCore    = isJust (ml_hs_file location) &&
-                         isExtCore_file (fromJust (ml_hs_file location))
+                         isExtCoreFilename (fromJust (ml_hs_file location))
 
-       ; when (not one_shot && verbosity dflags >= 1) $
-               hPutStrLn stderr ("Compiling " ++ 
-                       showModMsg (not toInterp) mod location);
+       ; when (not one_shot) $
+               compilationProgressMsg dflags $
+                 ("Compiling " ++ showModMsg (not toInterp) mod location);
                        
+       ; let hspp_file = expectJust "hscFrontEnd:hspp" (ml_hspp_file location)
        ; front_res <- if toCore then 
-                         hscCoreFrontEnd hsc_env location
+                         hscCoreFrontEnd hsc_env msg_act hspp_file
                       else 
-                         hscFrontEnd hsc_env location
+                         hscFileFrontEnd hsc_env msg_act hspp_file
 
        ; case front_res of
            Left flure -> return flure;
@@ -309,20 +328,21 @@ hscRecomp hsc_env have_object
                            maybe_bcos)
         }}
 
-hscCoreFrontEnd hsc_env location = do {
+hscCoreFrontEnd hsc_env msg_act hspp_file = do {
            -------------------
            -- PARSE
            -------------------
-       ; inp <- readFile (expectJust "hscCoreFrontEnd:hspp" (ml_hspp_file location))
+       ; inp <- readFile hspp_file
        ; case parseCore inp 1 of
-           FailP s        -> hPutStrLn stderr s >> return (Left HscFail);
+           FailP s        -> putMsg s{-ToDo: wrong-} >> return (Left HscFail)
            OkP rdr_module -> do {
     
            -------------------
            -- RENAME and TYPECHECK
            -------------------
-       ; maybe_tc_result <- _scc_ "TypeCheck" 
+       ; (tc_msgs, maybe_tc_result) <- _scc_ "TypeCheck" 
                              tcRnExtCore hsc_env rdr_module
+       ; msg_act tc_msgs
        ; case maybe_tc_result of {
             Nothing       -> return (Left  HscFail);
             Just mod_guts -> return (Right mod_guts)
@@ -330,22 +350,24 @@ hscCoreFrontEnd hsc_env location = do {
        }}}
         
 
-hscFrontEnd hsc_env location = do {
+hscFileFrontEnd hsc_env msg_act hspp_file = do {
            -------------------
            -- PARSE
            -------------------
-       ; maybe_parsed <- myParseModule (hsc_dflags hsc_env) 
-                             (expectJust "hscFrontEnd:hspp" (ml_hspp_file location))
+       ; maybe_parsed <- myParseModule (hsc_dflags hsc_env)  hspp_file
 
        ; case maybe_parsed of {
-            Nothing -> return (Left HscFail);
-            Just rdr_module -> do {
-    
+            Left err -> do { msg_act (unitBag err, emptyBag) ;
+                           ; return (Left HscFail) ;
+                           };
+            Right rdr_module -> do {
+
            -------------------
            -- RENAME and TYPECHECK
            -------------------
-       ; maybe_tc_result <- _scc_ "Typecheck-Rename" 
+       ; (tc_msgs, maybe_tc_result) <- _scc_ "Typecheck-Rename" 
                                        tcRnModule hsc_env rdr_module
+       ; msg_act tc_msgs
        ; case maybe_tc_result of {
             Nothing -> return (Left HscFail);
             Just tc_result -> do {
@@ -353,14 +375,54 @@ hscFrontEnd hsc_env location = do {
            -------------------
            -- DESUGAR
            -------------------
-       ; maybe_ds_result <- _scc_ "DeSugar" 
+       ; (warns, maybe_ds_result) <- _scc_ "DeSugar" 
                             deSugar hsc_env tc_result
+       ; msg_act (warns, emptyBag)
        ; case maybe_ds_result of
            Nothing        -> return (Left HscFail);
            Just ds_result -> return (Right ds_result);
        }}}}}
 
 
+hscFileCheck hsc_env msg_act hspp_file = do {
+           -------------------
+           -- PARSE
+           -------------------
+       ; maybe_parsed <- myParseModule (hsc_dflags hsc_env)  hspp_file
+
+       ; case maybe_parsed of {
+            Left err -> do { msg_act (unitBag err, emptyBag) ;
+                           ; return HscFail ;
+                           };
+            Right rdr_module -> hscBufferTypecheck hsc_env rdr_module msg_act
+       }}
+
+
+-- Perform static/dynamic checks on the source code in a StringBuffer
+-- This is a temporary solution: it'll read in interface files lazily, whereas
+-- we probably want to use the compilation manager to load in all the modules
+-- in a project.
+hscBufferCheck :: HscEnv -> StringBuffer -> MessageAction -> IO HscResult
+hscBufferCheck hsc_env buffer msg_act = do
+       let loc  = mkSrcLoc (mkFastString "*edit*") 1 0
+        showPass (hsc_dflags hsc_env) "Parser"
+       case unP parseModule (mkPState buffer loc (hsc_dflags hsc_env)) of
+               PFailed span err -> do
+                  msg_act (emptyBag, unitBag (mkPlainErrMsg span err))
+                  return HscFail
+               POk _ rdr_module -> do
+                  hscBufferTypecheck hsc_env rdr_module msg_act
+
+hscBufferTypecheck hsc_env rdr_module msg_act = do
+       (tc_msgs, maybe_tc_result) <- _scc_ "Typecheck-Rename" 
+                                       tcRnModule hsc_env rdr_module
+       msg_act tc_msgs
+       case maybe_tc_result of
+           Nothing  -> return (HscChecked rdr_module Nothing)
+                               -- space leak on rdr_module!
+           Just r -> return (HscChecked rdr_module (Just r))
+
+
 hscBackEnd dflags 
     ModGuts{  -- This is the last use of the ModGuts in a compilation.
              -- From now on, we just use the bits we need.
@@ -414,6 +476,18 @@ hscBackEnd dflags
    }
 
 
+hscCmmFile :: DynFlags -> FilePath -> IO Bool
+hscCmmFile dflags filename = do
+  maybe_cmm <- parseCmmFile dflags filename
+  case maybe_cmm of
+    Nothing -> return False
+    Just cmm -> do
+       codeOutput dflags no_mod NoStubs noDependencies [cmm]
+       return True
+  where
+       no_mod = panic "hscCmmFile: no_mod"
+
+
 myParseModule dflags src_filename
  = do --------------------------  Parser  ----------------
       showPass dflags "Parser"
@@ -424,8 +498,7 @@ myParseModule dflags src_filename
 
       case unP parseModule (mkPState buf loc dflags) of {
 
-       PFailed l1 l2 err -> do { hPutStrLn stderr (showSDoc (showPFailed l1 l2 err));
-                                 return Nothing };
+       PFailed span err -> return (Left (mkPlainErrMsg span err));
 
        POk _ rdr_module -> do {
 
@@ -434,7 +507,7 @@ myParseModule dflags src_filename
       dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"
                           (ppSourceStats False rdr_module) ;
       
-      return (Just rdr_module)
+      return (Right rdr_module)
        -- ToDo: free the string buffer later.
       }}
 
@@ -494,8 +567,9 @@ hscStmt             -- Compile a stmt all the way to an HValue, but don't run it
 hscStmt hsc_env icontext stmt
   = do { maybe_stmt <- hscParseStmt (hsc_dflags hsc_env) stmt
        ; case maybe_stmt of {
-            Nothing -> return Nothing ;
-            Just parsed_stmt -> do {
+            Nothing      -> return Nothing ;   -- Parse error
+            Just Nothing -> return Nothing ;   -- Empty line
+            Just (Just parsed_stmt) -> do {    -- The real stuff
 
                -- Rename and typecheck it
          maybe_tc_result
@@ -523,16 +597,45 @@ hscTcExpr -- Typecheck an expression (but don't run it)
 hscTcExpr hsc_env icontext expr
   = do { maybe_stmt <- hscParseStmt (hsc_dflags hsc_env) expr
        ; case maybe_stmt of {
-            Just (ExprStmt expr _ _) 
+            Nothing      -> return Nothing ;   -- Parse error
+            Just (Just (L _ (ExprStmt expr _)))
                        -> tcRnExpr hsc_env icontext expr ;
-            Just other -> do { hPutStrLn stderr ("not an expression: `" ++ expr ++ "'") ;
+            Just other -> do { errorMsg ("not an expression: `" ++ expr ++ "'") ;
+                               return Nothing } ;
+            } }
+
+hscKcType      -- Find the kind of a type
+  :: HscEnv
+  -> InteractiveContext                -- Context for compiling
+  -> String                    -- The type
+  -> IO (Maybe Kind)
+
+hscKcType hsc_env icontext str
+  = do { maybe_type <- hscParseType (hsc_dflags hsc_env) str
+       ; case maybe_type of {
+            Just ty    -> tcRnType hsc_env icontext ty ;
+            Just other -> do { errorMsg ("not an type: `" ++ str ++ "'") ;
                                return Nothing } ;
             Nothing    -> return Nothing } }
 \end{code}
 
 \begin{code}
-hscParseStmt :: DynFlags -> String -> IO (Maybe RdrNameStmt)
-hscParseStmt dflags str
+hscParseStmt :: DynFlags -> String -> IO (Maybe (Maybe (LStmt RdrName)))
+hscParseStmt = hscParseThing parseStmt
+
+hscParseType :: DynFlags -> String -> IO (Maybe (LHsType RdrName))
+hscParseType = hscParseThing parseType
+
+hscParseIdentifier :: DynFlags -> String -> IO (Maybe (Located RdrName))
+hscParseIdentifier = hscParseThing parseIdentifier
+
+hscParseThing :: Outputable thing
+             => Lexer.P thing
+             -> DynFlags -> String
+             -> IO (Maybe thing)
+       -- Nothing => Parse error (message already printed)
+       -- Just x  => success
+hscParseThing parser dflags str
  = do showPass dflags "Parser"
       _scc_ "Parser"  do
 
@@ -540,20 +643,17 @@ hscParseStmt dflags str
 
       let loc  = mkSrcLoc FSLIT("<interactive>") 1 0
 
-      case unP parseStmt (mkPState buf loc dflags) of {
+      case unP parser (mkPState buf loc dflags) of {
 
-       PFailed l1 l2 err -> do { hPutStrLn stderr (showSDoc (showPFailed l1 l2 err));  
-                                  return Nothing };
+       PFailed span err -> do { printError span err;
+                                 return Nothing };
 
-       -- no stmt: the line consisted of just space or comments
-       POk _ Nothing -> return Nothing;
-
-       POk _ (Just rdr_stmt) -> do {
+       POk _ thing -> do {
 
       --ToDo: can't free the string buffer until we've finished this
       -- compilation sweep and all the identifiers have gone away.
-      dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr rdr_stmt);
-      return (Just rdr_stmt)
+      dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr thing);
+      return (Just thing)
       }}
 #endif
 \end{code}
@@ -566,35 +666,30 @@ hscParseStmt dflags str
 
 \begin{code}
 #ifdef GHCI
-hscThing -- like hscStmt, but deals with a single identifier
+type GetInfoResult = (String, (IfaceDecl, Fixity, SrcLoc, [(IfaceInst,SrcLoc)]))
+
+hscGetInfo -- like hscStmt, but deals with a single identifier
   :: HscEnv
   -> InteractiveContext                -- Context for compiling
   -> String                    -- The identifier
-  -> IO [(IfaceDecl, Fixity)]
+  -> IO [GetInfoResult]
 
-hscThing hsc_env ic str
-   = do maybe_rdr_name <- myParseIdentifier (hsc_dflags hsc_env) str
+hscGetInfo hsc_env ic str
+   = do maybe_rdr_name <- hscParseIdentifier (hsc_dflags hsc_env) str
        case maybe_rdr_name of {
          Nothing -> return [];
-         Just rdr_name -> do
+         Just (L _ rdr_name) -> do
+
+       maybe_tc_result <- tcRnGetInfo hsc_env ic rdr_name
 
-       maybe_tc_result <- tcRnThing hsc_env ic rdr_name
+       let     -- str' is the the naked occurrence name
+               -- after stripping off qualification and parens (+)
+          str' = occNameUserString (rdrNameOcc rdr_name)
 
        case maybe_tc_result of {
             Nothing     -> return [] ;
-            Just things -> return things
+            Just things -> return [(str', t) | t <- things]
        }}
-
-myParseIdentifier dflags str
-  = do buf <- stringToStringBuffer str
-       let loc  = mkSrcLoc FSLIT("<interactive>") 1 0
-       case unP parseIdentifier (mkPState buf loc dflags) of
-
-         PFailed l1 l2 err -> do { hPutStrLn stderr (showSDoc (showPFailed l1 l2 err));
-                                    return Nothing }
-
-         POk _ rdr_name -> return (Just rdr_name)
 #endif
 \end{code}
 
@@ -608,7 +703,7 @@ myParseIdentifier dflags str
 #ifdef GHCI
 compileExpr :: HscEnv 
            -> Module -> GlobalRdrEnv -> TypeEnv
-           -> TypecheckedHsExpr
+           -> LHsExpr Id
            -> IO HValue
 
 compileExpr hsc_env this_mod rdr_env type_env tc_expr