module OccName (
-- The NameSpace type; abstact
NameSpace, tcName, clsName, tcClsName, dataName, varName,
- tvName, nameSpaceString,
+ tvName, srcDataName, nameSpaceString,
-- The OccName type
OccName, -- Abstract, instance of Outputable
pprOccName,
- mkOccFS, mkSysOcc, mkSysOccFS, mkFCallOcc, mkKindOccFS,
+ -- The OccEnv type
+ OccEnv, emptyOccEnv, unitOccEnv, extendOccEnv,
+ lookupOccEnv, mkOccEnv, extendOccEnvList, elemOccEnv,
+ occEnvElts, foldOccEnv, plusOccEnv, plusOccEnv_C, extendOccEnv_C,
+
+
+ -- The OccSet type
+ OccSet, emptyOccSet, unitOccSet, mkOccSet, extendOccSet, extendOccSetList,
+ unionOccSets, unionManyOccSets, minusOccSet, elemOccSet, occSetElts,
+ foldOccSet, isEmptyOccSet, intersectOccSet, intersectsOccSet,
+
+ mkOccName, mkOccFS, mkSysOcc, mkSysOccFS, mkFCallOcc, mkKindOccFS,
mkVarOcc, mkVarOccEncoded,
mkSuperDictSelOcc, mkDFunOcc, mkForeignExportOcc,
mkDictOcc, mkIPOcc, mkWorkerOcc, mkMethodOcc, mkDefaultMethodOcc,
mkDerivedTyConOcc, mkClassTyConOcc, mkClassDataConOcc, mkSpecOcc,
- mkGenOcc1, mkGenOcc2, mkLocalOcc,
+ mkGenOcc1, mkGenOcc2, mkLocalOcc, mkDataTOcc, mkDataCOcc,
+ mkDataConWrapperOcc, mkDataConWorkerOcc,
- isTvOcc, isTcOcc, isDataOcc, isDataSymOcc, isSymOcc, isValOcc,
+ isVarOcc, isTvOcc, isTcOcc, isDataOcc, isDataSymOcc, isSymOcc, isValOcc,
reportIfUnused,
- occNameFS, occNameString, occNameUserString, occNameSpace, occNameFlavour,
+ occNameFS, occNameString, occNameUserString, occNameSpace,
+ occNameFlavour, briefOccNameFlavour,
setOccNameSpace,
+ mkTupleOcc, isTupleOcc_maybe,
+
-- Tidying up
TidyOccEnv, emptyTidyOccEnv, tidyOccName, initTidyOccEnv,
import Char ( isDigit, isUpper, isLower, isAlphaNum, ord, chr, digitToInt )
import Util ( thenCmp )
-import Unique ( Unique )
-import FiniteMap ( FiniteMap, emptyFM, lookupFM, addToFM, elemFM )
+import Unique ( Unique, mkUnique, Uniquable(..) )
+import BasicTypes ( Boxity(..), Arity )
+import UniqFM
+import UniqSet
import FastString
import Outputable
import Binary
%************************************************************************
\begin{code}
-data NameSpace = VarName -- Variables
- | DataName -- Data constructors
+data NameSpace = VarName -- Variables, including "source" data constructors
+ | DataName -- "Real" data constructors
| TvName -- Type variables
| TcClsName -- Type constructors and classes; Haskell has them
-- in the same name space for now.
deriving( Eq, Ord )
{-! derive: Binary !-}
+-- Note [Data Constructors]
+-- see also: Note [Data Constructor Naming] in DataCon.lhs
+--
+-- "Source" data constructors are the data constructors mentioned
+-- in Haskell source code
+--
+-- "Real" data constructors are the data constructors of the
+-- representation type, which may not be the same as the source
+-- type
+
+-- Example:
+-- data T = T !(Int,Int)
+--
+-- The source datacon has type (Int,Int) -> T
+-- The real datacon has type Int -> Int -> T
+-- GHC chooses a representation based on the strictness etc.
+
+
-- Though type constructors and classes are in the same name space now,
-- the NameSpace type is abstract, so we can easily separate them later
tcName = TcClsName -- Type constructors
clsName = TcClsName -- Classes
tcClsName = TcClsName -- Not sure which!
-dataName = DataName
-tvName = TvName
-varName = VarName
+dataName = DataName
+srcDataName = DataName -- Haskell-source data constructors should be
+ -- in the Data name space
+tvName = TvName
+varName = VarName
nameSpaceString :: NameSpace -> String
nameSpaceString DataName = "Data constructor"
ppr = pprOccName
pprOccName :: OccName -> SDoc
-pprOccName (OccName sp occ) = pprEncodedFS occ
+pprOccName (OccName sp occ)
+ = getPprStyle $ \ sty ->
+ pprEncodedFS occ <> if debugStyle sty then
+ braces (text (briefNameSpaceFlavour sp))
+ else empty
\end{code}
%* *
\subsection{Construction}
%* *
-%************************************************************************
+%*****p*******************************************************************
*Sys* things do no encoding; the caller should ensure that the thing is
already encoded
mkOccFS :: NameSpace -> UserFS -> OccName
mkOccFS occ_sp fs = mkSysOccFS occ_sp (encodeFS fs)
+mkOccName :: NameSpace -> String -> OccName
+mkOccName ns s = mkSysOcc ns (encode s)
+
mkVarOcc :: UserFS -> OccName
mkVarOcc fs = mkSysOccFS varName (encodeFS fs)
%************************************************************************
%* *
+ Environments
+%* *
+%************************************************************************
+
+OccEnvs are used mainly for the envts in ModIfaces.
+
+They are efficient, because FastStrings have unique Int# keys. We assume
+this key is less than 2^24, so we can make a Unique using
+ mkUnique ns key :: Unique
+where 'ns' is a Char reprsenting the name space. This in turn makes it
+easy to build an OccEnv.
+
+\begin{code}
+instance Uniquable OccName where
+ getUnique (OccName ns fs)
+ = mkUnique char (I# (uniqueOfFS fs))
+ where -- See notes above about this getUnique function
+ char = case ns of
+ VarName -> 'i'
+ DataName -> 'd'
+ TvName -> 'v'
+ TcClsName -> 't'
+
+type OccEnv a = UniqFM a
+
+emptyOccEnv :: OccEnv a
+unitOccEnv :: OccName -> a -> OccEnv a
+extendOccEnv :: OccEnv a -> OccName -> a -> OccEnv a
+extendOccEnvList :: OccEnv a -> [(OccName, a)] -> OccEnv a
+lookupOccEnv :: OccEnv a -> OccName -> Maybe a
+mkOccEnv :: [(OccName,a)] -> OccEnv a
+elemOccEnv :: OccName -> OccEnv a -> Bool
+foldOccEnv :: (a -> b -> b) -> b -> OccEnv a -> b
+occEnvElts :: OccEnv a -> [a]
+extendOccEnv_C :: (a->a->a) -> OccEnv a -> OccName -> a -> OccEnv a
+plusOccEnv :: OccEnv a -> OccEnv a -> OccEnv a
+plusOccEnv_C :: (a->a->a) -> OccEnv a -> OccEnv a -> OccEnv a
+
+emptyOccEnv = emptyUFM
+unitOccEnv = unitUFM
+extendOccEnv = addToUFM
+extendOccEnvList = addListToUFM
+lookupOccEnv = lookupUFM
+mkOccEnv = listToUFM
+elemOccEnv = elemUFM
+foldOccEnv = foldUFM
+occEnvElts = eltsUFM
+plusOccEnv = plusUFM
+plusOccEnv_C = plusUFM_C
+extendOccEnv_C = addToUFM_C
+
+
+type OccSet = UniqFM OccName
+
+emptyOccSet :: OccSet
+unitOccSet :: OccName -> OccSet
+mkOccSet :: [OccName] -> OccSet
+extendOccSet :: OccSet -> OccName -> OccSet
+extendOccSetList :: OccSet -> [OccName] -> OccSet
+unionOccSets :: OccSet -> OccSet -> OccSet
+unionManyOccSets :: [OccSet] -> OccSet
+minusOccSet :: OccSet -> OccSet -> OccSet
+elemOccSet :: OccName -> OccSet -> Bool
+occSetElts :: OccSet -> [OccName]
+foldOccSet :: (OccName -> b -> b) -> b -> OccSet -> b
+isEmptyOccSet :: OccSet -> Bool
+intersectOccSet :: OccSet -> OccSet -> OccSet
+intersectsOccSet :: OccSet -> OccSet -> Bool
+
+emptyOccSet = emptyUniqSet
+unitOccSet = unitUniqSet
+mkOccSet = mkUniqSet
+extendOccSet = addOneToUniqSet
+extendOccSetList = addListToUniqSet
+unionOccSets = unionUniqSets
+unionManyOccSets = unionManyUniqSets
+minusOccSet = minusUniqSet
+elemOccSet = elementOfUniqSet
+occSetElts = uniqSetToList
+foldOccSet = foldUniqSet
+isEmptyOccSet = isEmptyUniqSet
+intersectOccSet = intersectUniqSets
+intersectsOccSet s1 s2 = not (isEmptyOccSet (s1 `intersectOccSet` s2))
+\end{code}
+
+
+%************************************************************************
+%* *
\subsection{Predicates and taking them apart}
%* *
%************************************************************************
occNameSpace :: OccName -> NameSpace
occNameSpace (OccName sp _) = sp
-setOccNameSpace :: OccName -> NameSpace -> OccName
-setOccNameSpace (OccName _ occ) sp = OccName sp occ
+setOccNameSpace :: NameSpace -> OccName -> OccName
+setOccNameSpace sp (OccName _ occ) = OccName sp occ
-- occNameFlavour is used only to generate good error messages
-occNameFlavour :: OccName -> String
-occNameFlavour (OccName sp _) = nameSpaceString sp
+occNameFlavour :: OccName -> SDoc
+occNameFlavour (OccName DataName _) = ptext SLIT("data constructor")
+occNameFlavour (OccName TvName _) = ptext SLIT("type variable")
+occNameFlavour (OccName TcClsName _) = ptext SLIT("type constructor or class")
+occNameFlavour (OccName VarName s) = empty
+
+-- briefOccNameFlavour is used in debug-printing of names
+briefOccNameFlavour :: OccName -> String
+briefOccNameFlavour (OccName sp _) = briefNameSpaceFlavour sp
+
+briefNameSpaceFlavour DataName = "d"
+briefNameSpaceFlavour VarName = "v"
+briefNameSpaceFlavour TvName = "tv"
+briefNameSpaceFlavour TcClsName = "tc"
\end{code}
\begin{code}
-isTvOcc, isDataSymOcc, isSymOcc, isTcOcc :: OccName -> Bool
+isVarOcc, isTvOcc, isDataSymOcc, isSymOcc, isTcOcc :: OccName -> Bool
+
+isVarOcc (OccName VarName _) = True
+isVarOcc other = False
isTvOcc (OccName TvName _) = True
isTvOcc other = False
-- Data constructor operator (starts with ':', or '[]')
-- Pretty inefficient!
isDataSymOcc (OccName DataName s) = isLexConSym (decodeFS s)
+isDataSymOcc (OccName VarName s) = isLexConSym (decodeFS s)
isDataSymOcc other = False
isDataOcc (OccName DataName _) = True
+isDataOcc (OccName VarName s) = isLexCon (decodeFS s)
isDataOcc other = False
-- Any operator (data constructor or variable)
-- Pretty inefficient!
isSymOcc (OccName DataName s) = isLexConSym (decodeFS s)
isSymOcc (OccName VarName s) = isLexSym (decodeFS s)
+isSymOcc other = False
\end{code}
:: OccName -> OccName
-- These derived variables have a prefix that no Haskell value could have
+mkDataConWrapperOcc = mk_simple_deriv varName "$W"
mkWorkerOcc = mk_simple_deriv varName "$w"
mkDefaultMethodOcc = mk_simple_deriv varName "$dm"
mkDerivedTyConOcc = mk_simple_deriv tcName ":" -- The : prefix makes sure it classifies
mkClassTyConOcc = mk_simple_deriv tcName ":T" -- as a tycon/datacon
-mkClassDataConOcc = mk_simple_deriv dataName ":D" --
+mkClassDataConOcc = mk_simple_deriv dataName ":D" -- We go straight to the "real" data con
+ -- for datacons from classes
mkDictOcc = mk_simple_deriv varName "$d"
mkIPOcc = mk_simple_deriv varName "$i"
mkSpecOcc = mk_simple_deriv varName "$s"
mkForeignExportOcc = mk_simple_deriv varName "$f"
-mkGenOcc1 = mk_simple_deriv varName "$gfrom" -- Generics
-mkGenOcc2 = mk_simple_deriv varName "$gto" -- Generics
+
+-- Generic derivable classes
+mkGenOcc1 = mk_simple_deriv varName "$gfrom"
+mkGenOcc2 = mk_simple_deriv varName "$gto"
+
+-- data T = MkT ... deriving( Data ) needs defintions for
+-- $tT :: Data.Generics.Basics.DataType
+-- $cMkT :: Data.Generics.Basics.Constr
+mkDataTOcc = mk_simple_deriv varName "$t"
+mkDataCOcc = mk_simple_deriv varName "$c"
+
mk_simple_deriv sp px occ = mk_deriv sp px (occNameString occ)
+
+
+-- Data constructor workers are made by setting the name space
+-- of the data constructor OccName (which should be a DataName)
+-- to DataName
+mkDataConWorkerOcc datacon_occ = setOccNameSpace varName datacon_occ
\end{code}
\begin{code}
tack on the '1', if necessary.
\begin{code}
-type TidyOccEnv = FiniteMap FastString Int -- The in-scope OccNames
-emptyTidyOccEnv = emptyFM
+type TidyOccEnv = OccEnv Int -- The in-scope OccNames
+ -- Range gives a plausible starting point for new guesses
+
+emptyTidyOccEnv = emptyOccEnv
initTidyOccEnv :: [OccName] -> TidyOccEnv -- Initialise with names to avoid!
-initTidyOccEnv = foldl (\env (OccName _ fs) -> addToFM env fs 1) emptyTidyOccEnv
+initTidyOccEnv = foldl (\env occ -> extendOccEnv env occ 1) emptyTidyOccEnv
tidyOccName :: TidyOccEnv -> OccName -> (TidyOccEnv, OccName)
tidyOccName in_scope occ@(OccName occ_sp fs)
- | not (fs `elemFM` in_scope)
- = (addToFM in_scope fs 1, occ) -- First occurrence
-
- | otherwise -- Already occurs
- = go in_scope (unpackFS fs)
- where
-
- go in_scope str = case lookupFM in_scope pk_str of
- Just n -> go (addToFM in_scope pk_str (n+1)) (str ++ show n)
- -- Need to go round again, just in case "t3" (say)
- -- clashes with a "t3" that's already in scope
-
- Nothing -> (addToFM in_scope pk_str 1, mkSysOccFS occ_sp pk_str)
- -- str is now unique
- where
- pk_str = mkFastString str
+ = case lookupOccEnv in_scope occ of
+ Nothing -> -- Not already used: make it used
+ (extendOccEnv in_scope occ 1, occ)
+
+ Just n -> -- Already used: make a new guess,
+ -- change the guess base, and try again
+ tidyOccName (extendOccEnv in_scope occ (n+1))
+ (mkSysOcc occ_sp (unpackFS fs ++ show n))
\end{code}
go [] = []
go (c:cs) = encode_ch c ++ go cs
-maybe_tuple "(# #)" = Just("Z1H")
-maybe_tuple ('(' : '#' : cs) = case count_commas (0::Int) cs of
- (n, '#' : ')' : cs) -> Just ('Z' : shows (n+1) "H")
- other -> Nothing
-maybe_tuple "()" = Just("Z0T")
-maybe_tuple ('(' : cs) = case count_commas (0::Int) cs of
- (n, ')' : cs) -> Just ('Z' : shows (n+1) "T")
- other -> Nothing
-maybe_tuple other = Nothing
-
-count_commas :: Int -> String -> (Int, String)
-count_commas n (',' : cs) = count_commas (n+1) cs
-count_commas n cs = (n,cs)
-
encodeFS :: UserFS -> EncodedFS
encodeFS fast_str | all unencodedChar str = fast_str
| otherwise = mkFastString (encode str)
decode :: EncodedString -> UserString
decode [] = []
-decode ('Z' : rest) = decode_escape rest
-decode ('z' : rest) = decode_escape rest
+decode ('Z' : d : rest) | isDigit d = decode_tuple d rest
+ | otherwise = decode_upper d : decode rest
+decode ('z' : d : rest) | isDigit d = decode_num_esc d rest
+ | otherwise = decode_lower d : decode rest
decode (c : rest) = c : decode rest
-decode_escape :: EncodedString -> UserString
-
-decode_escape ('L' : rest) = '(' : decode rest
-decode_escape ('R' : rest) = ')' : decode rest
-decode_escape ('M' : rest) = '[' : decode rest
-decode_escape ('N' : rest) = ']' : decode rest
-decode_escape ('C' : rest) = ':' : decode rest
-decode_escape ('Z' : rest) = 'Z' : decode rest
-
-decode_escape ('z' : rest) = 'z' : decode rest
-decode_escape ('a' : rest) = '&' : decode rest
-decode_escape ('b' : rest) = '|' : decode rest
-decode_escape ('c' : rest) = '^' : decode rest
-decode_escape ('d' : rest) = '$' : decode rest
-decode_escape ('e' : rest) = '=' : decode rest
-decode_escape ('g' : rest) = '>' : decode rest
-decode_escape ('h' : rest) = '#' : decode rest
-decode_escape ('i' : rest) = '.' : decode rest
-decode_escape ('l' : rest) = '<' : decode rest
-decode_escape ('m' : rest) = '-' : decode rest
-decode_escape ('n' : rest) = '!' : decode rest
-decode_escape ('p' : rest) = '+' : decode rest
-decode_escape ('q' : rest) = '\'' : decode rest
-decode_escape ('r' : rest) = '\\' : decode rest
-decode_escape ('s' : rest) = '/' : decode rest
-decode_escape ('t' : rest) = '*' : decode rest
-decode_escape ('u' : rest) = '_' : decode rest
-decode_escape ('v' : rest) = '%' : decode rest
-
--- Tuples are coded as Z23T
+decode_upper, decode_lower :: Char -> Char
+
+decode_upper 'L' = '('
+decode_upper 'R' = ')'
+decode_upper 'M' = '['
+decode_upper 'N' = ']'
+decode_upper 'C' = ':'
+decode_upper 'Z' = 'Z'
+decode_upper ch = pprTrace "decode_upper" (char ch) ch
+
+decode_lower 'z' = 'z'
+decode_lower 'a' = '&'
+decode_lower 'b' = '|'
+decode_lower 'c' = '^'
+decode_lower 'd' = '$'
+decode_lower 'e' = '='
+decode_lower 'g' = '>'
+decode_lower 'h' = '#'
+decode_lower 'i' = '.'
+decode_lower 'l' = '<'
+decode_lower 'm' = '-'
+decode_lower 'n' = '!'
+decode_lower 'p' = '+'
+decode_lower 'q' = '\''
+decode_lower 'r' = '\\'
+decode_lower 's' = '/'
+decode_lower 't' = '*'
+decode_lower 'u' = '_'
+decode_lower 'v' = '%'
+decode_lower ch = pprTrace "decode_lower" (char ch) ch
+
-- Characters not having a specific code are coded as z224U
-decode_escape (c : rest)
- | isDigit c = go (digitToInt c) rest
+decode_num_esc d rest
+ = go (digitToInt d) rest
where
go n (c : rest) | isDigit c = go (10*n + digitToInt c) rest
- go 0 ('T' : rest) = "()" ++ (decode rest)
- go n ('T' : rest) = '(' : replicate (n-1) ',' ++ ')' : decode rest
- go 1 ('H' : rest) = "(# #)" ++ (decode rest)
- go n ('H' : rest) = '(' : '#' : replicate (n-1) ',' ++ '#' : ')' : decode rest
go n ('U' : rest) = chr n : decode rest
- go n other = pprPanic "decode_escape" (ppr n <+> text (c:rest))
+ go n other = pprPanic "decode_num_esc" (ppr n <+> text other)
-decode_escape (c : rest) = pprTrace "decode_escape" (char c) (decode rest)
-decode_escape [] = pprTrace "decode_escape" (text "empty") ""
+decode_tuple :: Char -> EncodedString -> UserString
+decode_tuple d rest
+ = go (digitToInt d) rest
+ where
+ -- NB. recurse back to decode after decoding the tuple, because
+ -- the tuple might be embedded in a longer name.
+ go n (c : rest) | isDigit c = go (10*n + digitToInt c) rest
+ go 0 ('T':rest) = "()" ++ decode rest
+ go n ('T':rest) = '(' : replicate (n-1) ',' ++ ")" ++ decode rest
+ go 1 ('H':rest) = "(# #)" ++ decode rest
+ go n ('H':rest) = '(' : '#' : replicate (n-1) ',' ++ "#)" ++ decode rest
+ go n other = pprPanic "decode_tuple" (ppr n <+> text other)
\end{code}
%************************************************************************
%* *
+ Stuff for dealing with tuples
+%* *
+%************************************************************************
+
+Tuples are encoded as
+ Z3T or Z3H
+for 3-tuples or unboxed 3-tuples respectively. No other encoding starts
+ Z<digit>
+
+* "(# #)" is the tycon for an unboxed 1-tuple (not 0-tuple)
+ There are no unboxed 0-tuples.
+
+* "()" is the tycon for a boxed 0-tuple.
+ There are no boxed 1-tuples.
+
+
+\begin{code}
+maybe_tuple :: UserString -> Maybe EncodedString
+
+maybe_tuple "(# #)" = Just("Z1H")
+maybe_tuple ('(' : '#' : cs) = case count_commas (0::Int) cs of
+ (n, '#' : ')' : cs) -> Just ('Z' : shows (n+1) "H")
+ other -> Nothing
+maybe_tuple "()" = Just("Z0T")
+maybe_tuple ('(' : cs) = case count_commas (0::Int) cs of
+ (n, ')' : cs) -> Just ('Z' : shows (n+1) "T")
+ other -> Nothing
+maybe_tuple other = Nothing
+
+count_commas :: Int -> String -> (Int, String)
+count_commas n (',' : cs) = count_commas (n+1) cs
+count_commas n cs = (n,cs)
+\end{code}
+
+\begin{code}
+mkTupleOcc :: NameSpace -> Boxity -> Arity -> OccName
+mkTupleOcc ns bx ar
+ = OccName ns (mkFastString ('Z' : (show ar ++ bx_char)))
+ where
+ bx_char = case bx of
+ Boxed -> "T"
+ Unboxed -> "H"
+
+isTupleOcc_maybe :: OccName -> Maybe (NameSpace, Boxity, Arity)
+-- Tuples are special, because there are so many of them!
+isTupleOcc_maybe (OccName ns fs)
+ = case unpackFS fs of
+ ('Z':d:rest) | isDigit d -> Just (decode_tup (digitToInt d) rest)
+ other -> Nothing
+ where
+ decode_tup n "H" = (ns, Unboxed, n)
+ decode_tup n "T" = (ns, Boxed, n)
+ decode_tup n (d:rest) = decode_tup (n*10 + digitToInt d) rest
+\end{code}
+
+%************************************************************************
+%* *
\subsection{Lexical categories}
%* *
%************************************************************************
isLowerISO (C# c#) = c# `geChar#` '\xdf'# && c# `leChar#` '\xff'# && c# `neChar#` '\xf7'#
--0xdf <= oc && oc <= 0xff && oc /= 0xf7 where oc = ord c
\end{code}
+
+%************************************************************************
+%* *
+ Binary instance
+ Here rather than BinIface because OccName is abstract
+%* *
+%************************************************************************
+
\begin{code}
-{-* Generated by DrIFT-v1.0 : Look, but Don't Touch. *-}
instance Binary NameSpace where
put_ bh VarName = do
putByte bh 0
aa <- get bh
ab <- get bh
return (OccName aa ab)
-
--- Imported from other files :-
-
\end{code}