[project @ 1996-04-07 15:41:24 by partain]
[ghc-hetmet.git] / ghc / compiler / rename / RnUtils.lhs
index 1d4e45b..f79e7c4 100644 (file)
 #include "HsVersions.h"
 
 module RnUtils (
-       mkGlobalNameFun, mkNameFun,
-       GlobalNameMapper(..),  GlobalNameMappers(..),
-       PreludeNameMapper(..), PreludeNameMappers(..),
-
-       dupNamesErr -- used in various places
+       RnEnv(..), QualNames(..),
+       UnqualNames(..), ScopeStack(..),
+       emptyRnEnv, extendGlobalRnEnv, extendLocalRnEnv,
+       lookupRnEnv, lookupTcRnEnv,
+
+       unknownNameErr,
+       badClassOpErr,
+       qualNameErr,
+       dupNamesErr,
+       shadowedNameWarn,
+       multipleOccWarn,
+
+       -- ToDo: nuke/move? WDP 96/04/05
+       GlobalNameMapper(..),  GlobalNameMappers(..)
     ) where
 
-import Ubiq{-uitous-}
+import Ubiq
 
-import Bag             ( bagToList, Bag )
-import FiniteMap       ( lookupFM, listToFM )
-import Name            ( Name{-instances-} )
-import Outputable      ( pprNonOp )
+import Bag             ( Bag, emptyBag, snocBag, unionBags )
+import ErrUtils                ( addShortErrLocLine, addErrLoc )
+import FiniteMap       ( FiniteMap, emptyFM, isEmptyFM,
+                         lookupFM, addListToFM, addToFM )
+import Maybes          ( maybeToBool )
+import Name            ( RdrName(..), isQual )
+import Outputable      ( pprNonOp, getLocalName )
 import PprStyle                ( PprStyle(..) )
 import Pretty
-import ProtoName       ( ProtoName(..) )
-import Util            ( cmpPString, removeDups, pprPanic, panic )
-\end{code}
+import RnHsSyn         ( RnName )
+import Util            ( assertPanic )
 
-\begin{code}
-type GlobalNameMapper  = ProtoName -> Maybe Name
+type GlobalNameMapper  = RnName -> Maybe Name
 type GlobalNameMappers = (GlobalNameMapper, GlobalNameMapper)
-
-type PreludeNameMapper = FAST_STRING -> Maybe Name
-type PreludeNameMappers = (PreludeNameMapper,          -- Values
-                       PreludeNameMapper               -- Types and classes
-                      )
 \end{code}
 
-\begin{code}
-mkGlobalNameFun :: FAST_STRING         -- The module name
-               -> PreludeNameMapper    -- The prelude things
-               -> [(ProtoName, Name)]  -- The local and imported things
-               -> GlobalNameMapper     -- The global name function
+*********************************************************
+*                                                      *
+\subsection{RnEnv: renaming environment}
+*                                                      *
+*********************************************************
 
-mkGlobalNameFun this_module prel_nf alist
-  = the_fun
-  where
-    the_fun (Prel n)     = Just n
-    the_fun (Unk s)      = case (unk_fun s) of
-                             Just n  -> Just n
-                             Nothing -> prel_nf s
-    the_fun (Imp m d _ _) = imp_fun (d, m) -- NB: module-name 2nd!
-
-    -- Things in the domain of the prelude function shouldn't be put
-    -- in the unk_fun; because the prel_nf will catch them.
-    -- This can arise if, for example, an interface gives a signature
-    -- for a prelude thing.
-    --
-    -- Neither should they be in the domain of the imp_fun, because
-    -- prelude things will have been converted to Prel x rather than
-    -- Imp p q r s.
-    --
-    -- So we strip out prelude things from the alist; this is not just
-    -- desirable, it's essential because get_orig and get_local don't handle
-    -- prelude things.
-
-    non_prel_alist = filter non_prel alist
-
-    non_prel (Prel _, _) = False
-    non_prel other       = True
-
-    -- unk_fun looks up local names (just strings),
-    -- imp_fun looks up original names: (string,string) pairs
-    unk_fun = lookupFM (listToFM [(get_local pn,n) | (pn,n) <- non_prel_alist])
-    imp_fun = lookupFM (listToFM [(get_orig  pn,n) | (pn,n) <- non_prel_alist])
-
-               -- the lists *are* sorted by *some* ordering (by local
-               -- names), but not generally, and not in some way we
-               -- are going to rely on.
-
-    get_local :: ProtoName -> FAST_STRING
-    get_local (Unk s)       = s
-    get_local (Imp _ _ _ l) = l
-    get_local (Prel n)     = pprPanic "get_local: " (ppr PprShowAll n)
-
-    get_orig :: ProtoName -> (FAST_STRING, FAST_STRING) -- **NB**! module-name 2nd!
-    get_orig (Unk s)       = (s, this_module)
-    get_orig (Imp m d _ _) = (d, m)
-    get_orig (Prel n)      = pprPanic "get_orig: " (ppr PprShowAll n)
+Seperate FiniteMaps are kept for lookup up Qual names,
+Unqual names and Local names.
+
+\begin{code}
+type RnEnv = ((QualNames, UnqualNames, QualNames, UnqualNames), ScopeStack)
+
+type QualNames    = FiniteMap (FAST_STRING,Module) RnName
+type UnqualNames  = FiniteMap FAST_STRING RnName
+type ScopeStack   = FiniteMap FAST_STRING RnName
+
+emptyRnEnv       :: RnEnv
+extendGlobalRnEnv :: RnEnv -> [(RdrName,RnName)] -> [(RdrName,RnName)]
+                 -> (RnEnv, Bag (RdrName, RnName, RnName))
+extendLocalRnEnv  :: Bool -> RnEnv -> [RnName] -> (RnEnv, [RnName])
+lookupRnEnv      :: RnEnv -> RdrName -> Maybe RnName
+lookupTcRnEnv    :: RnEnv -> RdrName -> Maybe RnName
 \end{code}
 
+If the @RdrName@ is a @Qual@, @lookupValue@ looks it up in the global
+value QualNames.  If it is @Unqual@, it looks it up first in the
+ScopeStack, and if it isn't found there, then in the global
+vaule Unqual Names.
 
-@mkNameFun@ builds a function from @ProtoName@s to things, where a
-``thing'' is either a @ProtoName@ (in the case of values), or a
-@(ProtoName, ProtoName -> ProtoName)@ pair in the case of types and
-classes.  It takes:
+@lookupTcRnEnv@ looks up tycons/classes in the alternative global
+name space.
 
-\begin{itemize}
-\item  The name of the interface
-\item  A bag of new string-to-thing bindings to add,
+@extendGlobalRnEnv@ adds global names to the RnEnv. It takes seperate
+value and tycon/class name lists. It returns any duplicate names
+seperatle.
 
-\item  An extractor function, to get a @ProtoName@ out of a thing,
-       for use in error messages.
-\end{itemize}
-The function it returns only expects to see @Unk@ things.
+@extendRnEnv@ adds new local names to the ScopeStack in an RnEnv.
+It optionally reports any shadowed names.
 
-@mkNameFun@ checks for clashes in the domain of the new bindings.
+\begin{code}
+emptyRnEnv
+  = ((emptyFM, emptyFM, emptyFM, emptyFM), emptyFM)
 
-ToDo: it should check for clashes with the prelude bindings too.
 
-\begin{code}
-mkNameFun :: Bag (FAST_STRING, thing)      -- Value bindings
-         -> (FAST_STRING -> Maybe thing,   -- The function to use
-             [[(FAST_STRING,thing)]])      -- Duplicates, if any
-
-mkNameFun the_bag
-  = case (removeDups cmp (bagToList the_bag)) of { (no_dup_list, dups) ->
-    case (lookupFM (listToFM no_dup_list))    of { the_fun ->
-    (the_fun, dups) }}
+extendGlobalRnEnv ((qual, unqual, tc_qual, tc_unqual), stack) val_list tc_list
+  = ASSERT(isEmptyFM stack)
+    (((qual', unqual', tc_qual, tc_unqual), stack), tc_dups `unionBags` dups)
   where
-    cmp :: (FAST_STRING, a) -> (FAST_STRING, a) -> TAG_
+    (qual', unqual', dups)          = extend_global qual unqual val_list
+    (tc_qual', tc_unqual', tc_dups) = extend_global tc_qual tc_unqual tc_list
+
+    extend_global qual unqual rdr_list = (qual', unqual', dups)
+      where
+       (qual_list, unqual_list) = partition (isQual.fst) rdr_list
+       qual_in   = map mk_qual qual_list
+       unqual_in = map mk_unqual unqual_list
+       mk_qual   (Qual m s, rn) = ((s,m), rn)
+       mk_unqual (Unqual s, rn) = (s, rn)
+
+       (qual', qual_dups)     = do_dups qual_in qual emptyBag (\ (s,m) -> Qual m s)
+       (unqual', unqual_dups) = do_dups unqual_in unqual emptyBag Unqual
 
-    cmp (s1,_) (s2,_) = _CMP_STRING_ s1 s2
+       dups = unqual_dups `unionBags` qual_dups
+
+       do_dups [] fm dups to_rdr = (fm, dups)
+       do_dups ((k,v):rest) fm dups to_rdr
+          = case lookupFM fm k of
+             Nothing  -> do_dups rest (addToFM fm k v) dups to_rdr
+             Just cur -> do_dups rest fm (dups `snocBag` (to_rdr k, cur, v)) to_rdr
+
+
+extendLocalRnEnv report_shadows (global, stack) new_local
+  = ((global, new_stack), dups)
+  where
+    (new_stack, dups) = extend new_local stack
+
+    extend names stack
+      = if report_shadows then
+           do_shadows names stack []
+       else
+           (addListToFM stack [ (getLocalName n, n) | n <- names], []) 
+
+    do_shadows [] stack dups = (stack, dups)
+    do_shadows (name:names) stack dups
+      = do_shadows names (addToFM stack str name) ext_dups
+      where
+       str = getLocalName name
+       ext_dups = if maybeToBool (lookupFM stack str)
+                  then name:dups
+                  else dups
+
+
+lookupRnEnv ((qual, unqual, _, _), stack) rdr
+  = case rdr of 
+      Unqual str   -> lookup stack str (lookup unqual str Nothing)
+      Qual mod str -> lookup qual (str,mod) Nothing
+  where
+    lookup fm thing do_on_fail
+      = case lookupFM fm thing of
+           found@(Just name) -> found
+           Nothing           -> do_on_fail
+
+lookupTcRnEnv ((_, _, tc_qual, tc_unqual), _) rdr
+  = case rdr of 
+      Unqual str   -> lookupFM tc_unqual str
+      Qual mod str -> lookupFM tc_qual (str,mod)
 \end{code}
 
+*********************************************************
+*                                                      *
+\subsection{Errors used in RnMonad}
+*                                                      *
+*********************************************************
+
 \begin{code}
-dupNamesErr descriptor ((first_pname,locn1) : dup_things) sty
-  = ppAboves (first_item : map dup_item dup_things)
+unknownNameErr descriptor name locn
+  = addShortErrLocLine locn ( \ sty ->
+    ppBesides [ppStr "undefined ", ppStr descriptor, ppStr ": ", pprNonOp sty name] )
+
+badClassOpErr clas op locn
+  = addErrLoc locn "" ( \ sty ->
+    ppBesides [ppChar '`', pprNonOp sty op, ppStr "' is not an operation of class `",
+             ppr sty clas, ppStr "'"] )
+
+qualNameErr descriptor (name,locn)
+  = addShortErrLocLine locn ( \ sty ->
+    ppBesides [ppStr "invalid use of qualified ", ppStr descriptor, ppStr ": ", pprNonOp sty name ] )
+
+dupNamesErr descriptor ((name1,locn1) : dup_things) sty
+  = ppAboves (item1 : map dup_item dup_things)
   where
-    first_item
+    item1
       = ppBesides [ ppr PprForUser locn1,
            ppStr ": multiple declarations of a ", ppStr descriptor, ppStr ": ",
-           pprNonOp sty first_pname ]
+           pprNonOp sty name1 ]
 
-    dup_item (pname, locn)
+    dup_item (name, locn)
       = ppBesides [ ppr PprForUser locn,
-           ppStr ": here was another declaration of `", pprNonOp sty pname, ppStr "'" ]
+           ppStr ": here was another declaration of `", pprNonOp sty name, ppStr "'" ]
+
+shadowedNameWarn locn shadow
+  = addShortErrLocLine locn ( \ sty ->
+    ppBesides [ppStr "more than one value with the same name (shadowing): ", ppr sty shadow] )
+
+multipleOccWarn (name, occs) sty
+  = ppBesides [ppStr "multiple names used to refer to `", ppr sty name, ppStr "': ",
+              ppInterleave ppComma (map (ppr sty) occs)]
 \end{code}
+