summaryrefslogtreecommitdiff
path: root/ghc/compiler
diff options
context:
space:
mode:
authorsimonpj <unknown>1996-12-19 18:36:20 +0000
committersimonpj <unknown>1996-12-19 18:36:20 +0000
commitbb521c6bba76f19474f12195b990b29eda66a4e8 (patch)
treefecb11771c7d9f25634e6bd5857c991686707b8d /ghc/compiler
parentc3e7e772db4fbc7171de7b7e98d578ab9cff167c (diff)
downloadhaskell-bb521c6bba76f19474f12195b990b29eda66a4e8.tar.gz
[project @ 1996-12-19 18:35:23 by simonpj]
Adding and removing files
Diffstat (limited to 'ghc/compiler')
-rw-r--r--ghc/compiler/basicTypes/Demand.lhs124
-rw-r--r--ghc/compiler/main/Constants.lhs186
-rw-r--r--ghc/compiler/prelude/StdIdInfo.lhs282
-rw-r--r--ghc/compiler/reader/Lex.lhs372
-rw-r--r--ghc/compiler/utils/SpecLoop.lhi67
5 files changed, 1031 insertions, 0 deletions
diff --git a/ghc/compiler/basicTypes/Demand.lhs b/ghc/compiler/basicTypes/Demand.lhs
new file mode 100644
index 0000000000..21c22d4606
--- /dev/null
+++ b/ghc/compiler/basicTypes/Demand.lhs
@@ -0,0 +1,124 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+%
+\section[Demand]{@Demand@: the amount of demand on a value}
+
+\begin{code}
+#include "HsVersions.h"
+
+module Demand where
+
+import PprStyle ( PprStyle )
+import Outputable
+import Pretty ( SYN_IE(Pretty), PrettyRep, ppStr )
+import Util ( panic )
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{The @Demand@ data type}
+%* *
+%************************************************************************
+
+\begin{code}
+data Demand
+ = WwLazy -- Argument is lazy as far as we know
+ MaybeAbsent -- (does not imply worker's existence [etc]).
+ -- If MaybeAbsent == True, then it is
+ -- *definitely* lazy. (NB: Absence implies
+ -- a worker...)
+
+ | WwStrict -- Argument is strict but that's all we know
+ -- (does not imply worker's existence or any
+ -- calling-convention magic)
+
+ | WwUnpack -- Argument is strict & a single-constructor
+ [Demand] -- type; its constituent parts (whose StrictInfos
+ -- are in the list) should be passed
+ -- as arguments to the worker.
+
+ | WwPrim -- Argument is of primitive type, therefore
+ -- strict; doesn't imply existence of a worker;
+ -- argument should be passed as is to worker.
+
+ | WwEnum -- Argument is strict & an enumeration type;
+ -- an Int# representing the tag (start counting
+ -- at zero) should be passed to the worker.
+ deriving (Eq, Ord)
+ -- we need Eq/Ord to cross-chk update infos in interfaces
+
+type MaybeAbsent = Bool -- True <=> not even used
+
+-- versions that don't worry about Absence:
+wwLazy = WwLazy False
+wwStrict = WwStrict
+wwUnpack xs = WwUnpack xs
+wwPrim = WwPrim
+wwEnum = WwEnum
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Functions over @Demand@}
+%* *
+%************************************************************************
+
+\begin{code}
+isStrict :: Demand -> Bool
+
+isStrict WwStrict = True
+isStrict (WwUnpack _) = True
+isStrict WwPrim = True
+isStrict WwEnum = True
+isStrict _ = False
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Instances}
+%* *
+%************************************************************************
+
+\begin{code}
+#ifdef REALLY_HASKELL_1_3
+instance Read Demand where
+#else
+instance Text Demand where
+#endif
+ readList str = read_em [{-acc-}] str
+ where
+ read_em acc ('L' : xs) = read_em (WwLazy False : acc) xs
+ read_em acc ('A' : xs) = read_em (WwLazy True : acc) xs
+ read_em acc ('S' : xs) = read_em (WwStrict : acc) xs
+ read_em acc ('P' : xs) = read_em (WwPrim : acc) xs
+ read_em acc ('E' : xs) = read_em (WwEnum : acc) xs
+
+ read_em acc (')' : xs) = [(reverse acc, xs)]
+ read_em acc ( 'U' : '(' : xs)
+ = case (read_em [] xs) of
+ [(stuff, rest)] -> read_em (WwUnpack stuff : acc) rest
+ _ -> panic ("Text.Demand:"++str++"::"++xs)
+
+ read_em acc rest = [(reverse acc, rest)]
+
+#ifdef REALLY_HASKELL_1_3
+instance Show Demand where
+#endif
+ showList wrap_args rest = foldr show1 rest wrap_args
+ where
+ show1 (WwLazy False) rest = 'L' : rest
+ show1 (WwLazy True) rest = 'A' : rest
+ show1 WwStrict rest = 'S' : rest
+ show1 WwPrim rest = 'P' : rest
+ show1 WwEnum rest = 'E' : rest
+ show1 (WwUnpack args) rest = "U(" ++ showList args (')' : rest)
+
+instance Outputable Demand where
+ ppr sty si = ppStr (showList [si] "")
+\end{code}
+
+
+
diff --git a/ghc/compiler/main/Constants.lhs b/ghc/compiler/main/Constants.lhs
new file mode 100644
index 0000000000..aaafe10d2b
--- /dev/null
+++ b/ghc/compiler/main/Constants.lhs
@@ -0,0 +1,186 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
+%
+\section[Constants]{Info about this compilation}
+
+!!!!! THIS CODE MUST AGREE WITH SMinterface.h !!!!!!
+
+*** This SHOULD BE the only module that is CPP'd with "stgdefs.h" stuff.
+
+\begin{code}
+#include "HsVersions.h"
+
+module Constants (
+ uNFOLDING_USE_THRESHOLD,
+ uNFOLDING_CREATION_THRESHOLD,
+-- uNFOLDING_OVERRIDE_THRESHOLD,
+ iNTERFACE_UNFOLD_THRESHOLD,
+ lIBERATE_CASE_THRESHOLD,
+ uNFOLDING_CHEAP_OP_COST,
+ uNFOLDING_DEAR_OP_COST,
+ uNFOLDING_NOREP_LIT_COST,
+ uNFOLDING_CON_DISCOUNT_WEIGHT,
+
+ mAX_SPEC_ALL_PTRS,
+ mAX_SPEC_ALL_NONPTRS,
+ mAX_SPEC_MIXED_FIELDS,
+ mAX_SPEC_SELECTEE_SIZE,
+
+ tARGET_MIN_INT, tARGET_MAX_INT,
+
+ mIN_UPD_SIZE,
+ mIN_SIZE_NonUpdHeapObject,
+ mIN_SIZE_NonUpdStaticHeapObject,
+
+ mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
+
+ sTD_UF_SIZE, cON_UF_SIZE,
+ sCC_STD_UF_SIZE, sCC_CON_UF_SIZE,
+ uF_RET,
+ uF_SUB,
+ uF_SUA,
+ uF_UPDATEE,
+ uF_COST_CENTRE,
+
+ mAX_Vanilla_REG,
+ mAX_Float_REG,
+ mAX_Double_REG,
+
+ mIN_BIG_TUPLE_SIZE,
+
+ mIN_MP_INT_SIZE,
+ mP_STRUCT_SIZE,
+
+ oTHER_TAG, iND_TAG, -- semi-tagging stuff
+
+ lIVENESS_R1,
+ lIVENESS_R2,
+ lIVENESS_R3,
+ lIVENESS_R4,
+ lIVENESS_R5,
+ lIVENESS_R6,
+ lIVENESS_R7,
+ lIVENESS_R8,
+
+ mAX_INTLIKE, mIN_INTLIKE,
+
+
+ spARelToInt,
+ spBRelToInt
+ ) where
+
+-- This magical #include brings in all the everybody-knows-these magic
+-- constants unfortunately, we need to be *explicit* about which one
+-- we want; if we just hope a -I... will get the right one, we could
+-- be in trouble.
+
+#include "../../includes/GhcConstants.h"
+
+CHK_Ubiq() -- debugging consistency check
+
+import Util
+\end{code}
+
+All pretty arbitrary:
+\begin{code}
+uNFOLDING_USE_THRESHOLD = ( 3 :: Int)
+uNFOLDING_CREATION_THRESHOLD = (30 :: Int)
+iNTERFACE_UNFOLD_THRESHOLD = (30 :: Int)
+lIBERATE_CASE_THRESHOLD = (10 :: Int)
+-- uNFOLDING_OVERRIDE_THRESHOLD = ( 8 :: Int)
+
+uNFOLDING_CHEAP_OP_COST = ( 1 :: Int)
+uNFOLDING_DEAR_OP_COST = ( 4 :: Int)
+uNFOLDING_NOREP_LIT_COST = ( 4 :: Int)
+uNFOLDING_CON_DISCOUNT_WEIGHT = ( 1 :: Int)
+\end{code}
+
+\begin{code}
+mAX_SPEC_ALL_PTRS = (MAX_SPEC_ALL_PTRS :: Int)
+mAX_SPEC_ALL_NONPTRS = (MAX_SPEC_ALL_NONPTRS :: Int)
+mAX_SPEC_MIXED_FIELDS = (MAX_SPEC_OTHER_SIZE :: Int)
+mAX_SPEC_SELECTEE_SIZE = (MAX_SPEC_SELECTEE_SIZE :: Int)
+
+-- closure sizes: these do NOT include the header
+mIN_UPD_SIZE = (MIN_UPD_SIZE::Int)
+mIN_SIZE_NonUpdHeapObject = (MIN_NONUPD_SIZE::Int)
+mIN_SIZE_NonUpdStaticHeapObject = (0::Int)
+\end{code}
+
+A completely random number:
+\begin{code}
+mIN_BIG_TUPLE_SIZE = (16::Int)
+\end{code}
+
+Sizes of gmp objects:
+\begin{code}
+mIN_MP_INT_SIZE = (MIN_MP_INT_SIZE :: Int)
+mP_STRUCT_SIZE = (MP_STRUCT_SIZE :: Int)
+\end{code}
+
+\begin{code}
+tARGET_MIN_INT, tARGET_MAX_INT :: Integer
+tARGET_MIN_INT = -536870912
+tARGET_MAX_INT = 536870912
+\end{code}
+
+Constants for semi-tagging; the tags associated with the data
+constructors will start at 0 and go up.
+\begin{code}
+oTHER_TAG = (INFO_OTHER_TAG :: Integer) -- (-1) unevaluated, probably
+iND_TAG = (INFO_IND_TAG :: Integer) -- (-2) NOT USED, REALLY
+\end{code}
+
+Stuff for liveness masks:
+\begin{code}
+lIVENESS_R1 = (LIVENESS_R1 :: Int)
+lIVENESS_R2 = (LIVENESS_R2 :: Int)
+lIVENESS_R3 = (LIVENESS_R3 :: Int)
+lIVENESS_R4 = (LIVENESS_R4 :: Int)
+lIVENESS_R5 = (LIVENESS_R5 :: Int)
+lIVENESS_R6 = (LIVENESS_R6 :: Int)
+lIVENESS_R7 = (LIVENESS_R7 :: Int)
+lIVENESS_R8 = (LIVENESS_R8 :: Int)
+\end{code}
+
+\begin{code}
+mIN_INTLIKE, mAX_INTLIKE :: Integer -- Only used to compare with (MachInt Integer)
+mIN_INTLIKE = MIN_INTLIKE
+mAX_INTLIKE = MAX_INTLIKE
+\end{code}
+
+\begin{code}
+-- THESE ARE DIRECTION SENSITIVE!
+spARelToInt :: Int{-VirtualSpAOffset-} -> Int{-VirtualSpAOffset-} -> Int
+spBRelToInt :: Int{-VirtualSpBOffset-} -> Int{-VirtualSpBOffset-} -> Int
+
+spARelToInt spA off = spA - off -- equiv to: AREL(spA - off)
+spBRelToInt spB off = off - spB -- equiv to: BREL(spB - off)
+\end{code}
+
+A section of code-generator-related MAGIC CONSTANTS.
+\begin{code}
+mAX_FAMILY_SIZE_FOR_VEC_RETURNS = (MAX_VECTORED_RTN::Int) -- pretty arbitrary
+-- If you change this, you may need to change runtimes/standard/Update.lhc
+
+-- The update frame sizes
+sTD_UF_SIZE = (NOSCC_STD_UF_SIZE::Int)
+cON_UF_SIZE = (NOSCC_CON_UF_SIZE::Int)
+
+-- Same again, with profiling
+sCC_STD_UF_SIZE = (SCC_STD_UF_SIZE::Int)
+sCC_CON_UF_SIZE = (SCC_CON_UF_SIZE::Int)
+
+-- Offsets in an update frame. They don't change with profiling!
+uF_RET = (UF_RET::Int)
+uF_SUB = (UF_SUB::Int)
+uF_SUA = (UF_SUA::Int)
+uF_UPDATEE = (UF_UPDATEE::Int)
+uF_COST_CENTRE = (UF_COST_CENTRE::Int)
+\end{code}
+
+\begin{code}
+mAX_Vanilla_REG = (MAX_VANILLA_REG :: Int)
+mAX_Float_REG = (MAX_FLOAT_REG :: Int)
+mAX_Double_REG = (MAX_DOUBLE_REG :: Int)
+\end{code}
diff --git a/ghc/compiler/prelude/StdIdInfo.lhs b/ghc/compiler/prelude/StdIdInfo.lhs
new file mode 100644
index 0000000000..a13fa83b56
--- /dev/null
+++ b/ghc/compiler/prelude/StdIdInfo.lhs
@@ -0,0 +1,282 @@
+%
+% (c) The AQUA Project, Glasgow University, 1994-1996
+%
+\section[StdIdInfo]{Standard unfoldings}
+
+This module contains definitions for the IdInfo for things that
+have a standard form, namely:
+
+ * data constructors
+ * record selectors
+ * method and superclass selectors
+ * primitive operations
+
+\begin{code}
+#include "HsVersions.h"
+
+module StdIdInfo (
+ addStandardIdInfo
+ ) where
+
+IMP_Ubiq()
+
+import Type
+import CoreSyn
+import Literal
+import CoreUnfold ( mkUnfolding )
+import TysWiredIn ( tupleCon )
+import Id ( GenId, mkTemplateLocals, idType,
+ dataConStrictMarks, dataConFieldLabels, dataConArgTys,
+ recordSelectorFieldLabel, dataConSig,
+ StrictnessMark(..),
+ isDataCon, isMethodSelId_maybe, isSuperDictSelId_maybe,
+ isRecordSelector, isPrimitiveId_maybe,
+ addIdUnfolding, addIdArity
+ )
+import IdInfo ( ArityInfo, exactArity )
+import Class ( GenClass, GenClassOp, classSig, classOpLocalType )
+import TyCon ( isNewTyCon )
+import FieldLabel ( FieldLabel )
+import PrelVals ( pAT_ERROR_ID )
+import Maybes
+import PprStyle ( PprStyle(..) )
+import Pretty
+import Util ( assertPanic, pprTrace,
+ assoc
+ )
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Data constructors}
+%* *
+%************************************************************************
+
+We're going to build a constructor that looks like:
+
+ data (Data a, C b) => T a b = T1 !a !Int b
+
+ T1 = /\ a b ->
+ \d1::Data a, d2::C b ->
+ \p q r -> case p of { p ->
+ case q of { q ->
+ Con T1 [a,b] [p,q,r]}}
+
+Notice that
+
+* d2 is thrown away --- a context in a data decl is used to make sure
+ one *could* construct dictionaries at the site the constructor
+ is used, but the dictionary isn't actually used.
+
+* We have to check that we can construct Data dictionaries for
+ the types a and Int. Once we've done that we can throw d1 away too.
+
+* We use (case p of ...) to evaluate p, rather than "seq" because
+ all that matters is that the arguments are evaluated. "seq" is
+ very careful to preserve evaluation order, which we don't need
+ to be here.
+
+\begin{code}
+addStandardIdInfo :: Id -> Id
+
+addStandardIdInfo con_id
+
+ | isDataCon con_id
+ = con_id `addIdUnfolding` unfolding
+ `addIdArity` exactArity (length locals)
+ where
+ unfolding = mkUnfolding True {- Always inline constructors -} con_rhs
+
+ (tyvars,theta,arg_tys,tycon) = dataConSig con_id
+ dict_tys = [mkDictTy clas ty | (clas,ty) <- theta]
+ n_dicts = length dict_tys
+ result_ty = applyTyCon tycon (mkTyVarTys tyvars)
+
+ locals = mkTemplateLocals (dict_tys ++ arg_tys)
+ data_args = drop n_dicts locals
+ (data_arg1:_) = data_args -- Used for newtype only
+ strict_marks = dataConStrictMarks con_id
+ strict_args = [arg | (arg,MarkedStrict) <- data_args `zip` strict_marks]
+ -- NB: we can't call mkTemplateLocals twice, because it
+ -- always starts from the same unique.
+
+ con_app | isNewTyCon tycon
+ = ASSERT( length arg_tys == 1)
+ Coerce (CoerceIn con_id) result_ty (Var data_arg1)
+ | otherwise
+ = Con con_id (map TyArg (mkTyVarTys tyvars) ++ map VarArg data_args)
+
+ con_rhs = mkTyLam tyvars $
+ mkValLam locals $
+ foldr mk_case con_app strict_args
+
+ mk_case arg body | isUnboxedType (idType arg)
+ = body -- "!" on unboxed arg does nothing
+ | otherwise
+ = Case (Var arg) (AlgAlts [] (BindDefault arg body))
+ -- This case shadows "arg" but that's fine
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Record selectors}
+%* *
+%************************************************************************
+
+We're going to build a record selector that looks like this:
+
+ data T a b c = T1 { ..., op :: a, ...}
+ | T2 { ..., op :: a, ...}
+ | T3
+
+ sel = /\ a b c -> \ d -> case d of
+ T1 ... x ... -> x
+ T2 ... x ... -> x
+ other -> error "..."
+
+\begin{code}
+addStandardIdInfo sel_id
+ | isRecordSelector sel_id
+ = ASSERT( null theta )
+ sel_id `addIdUnfolding` unfolding
+ `addIdArity` exactArity 1
+ -- ToDo: consider adding further IdInfo
+ where
+ unfolding = mkUnfolding False {- Don't inline every selector -} sel_rhs
+
+ (tyvars, theta, tau) = splitSigmaTy (idType sel_id)
+ field_lbl = recordSelectorFieldLabel sel_id
+ (data_ty,rhs_ty) = expectJust "StdIdInfoRec" (getFunTy_maybe tau)
+ -- tau is of form (T a b c -> field-type)
+ (tycon, _, data_cons) = getAppDataTyCon data_ty
+ tyvar_tys = mkTyVarTys tyvars
+
+ [data_id] = mkTemplateLocals [data_ty]
+ sel_rhs = mkTyLam tyvars $
+ mkValLam [data_id] $
+ Case (Var data_id) (AlgAlts (catMaybes (map mk_maybe_alt data_cons))
+ (BindDefault data_id error_expr))
+ mk_maybe_alt data_con
+ = case maybe_the_arg_id of
+ Nothing -> Nothing
+ Just the_arg_id -> Just (data_con, arg_ids, Var the_arg_id)
+ where
+ arg_ids = mkTemplateLocals (dataConArgTys data_con tyvar_tys)
+ -- The first one will shadow data_id, but who cares
+ field_lbls = dataConFieldLabels data_con
+ maybe_the_arg_id = assocMaybe (field_lbls `zip` arg_ids) field_lbl
+
+ error_expr = mkApp (Var pAT_ERROR_ID) [] [rhs_ty] [LitArg msg_lit]
+ full_msg = ppShow 80 (ppSep [ppStr "No match in record selector", ppr PprForUser sel_id])
+ msg_lit = NoRepStr (_PK_ full_msg)
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Super selectors}
+%* *
+%************************************************************************
+
+\begin{code}
+addStandardIdInfo sel_id
+ | maybeToBool maybe_sc_sel_id
+ = sel_id `addIdUnfolding` unfolding
+ -- The always-inline thing means we don't need any other IdInfo
+ where
+ maybe_sc_sel_id = isSuperDictSelId_maybe sel_id
+ Just (cls, the_sc) = maybe_sc_sel_id
+
+ unfolding = mkUnfolding True {- Always inline selectors -} rhs
+ rhs = mk_dict_selector [tyvar] dict_id arg_ids the_arg_id
+
+ (tyvar, scs, ops) = classSig cls
+ tyvar_ty = mkTyVarTy tyvar
+ [dict_id] = mkTemplateLocals [mkDictTy cls tyvar_ty]
+ arg_ids = mkTemplateLocals ([mkDictTy sc tyvar_ty | sc <- scs] ++
+ map classOpLocalType ops)
+ the_arg_id = assoc "StdIdInfoSC" (scs `zip` arg_ids) the_sc
+
+addStandardIdInfo sel_id
+ | maybeToBool maybe_meth_sel_id
+ = sel_id `addIdUnfolding` unfolding
+ -- The always-inline thing means we don't need any other IdInfo
+ where
+ maybe_meth_sel_id = isMethodSelId_maybe sel_id
+ Just (cls, the_op) = maybe_meth_sel_id
+
+ unfolding = mkUnfolding True {- Always inline selectors -} rhs
+ rhs = mk_dict_selector [tyvar] dict_id arg_ids the_arg_id
+
+ (tyvar, scs, ops) = classSig cls
+ n_scs = length scs
+ tyvar_ty = mkTyVarTy tyvar
+ [dict_id] = mkTemplateLocals [mkDictTy cls tyvar_ty]
+ arg_ids = mkTemplateLocals ([mkDictTy sc tyvar_ty | sc <- scs] ++
+ map classOpLocalType ops)
+
+ the_arg_id = assoc "StdIdInfoMeth" (ops `zip` (drop n_scs arg_ids)) the_op
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Primitive operations
+%* *
+%************************************************************************
+
+
+\begin{code}
+addStandardIdInfo prim_id
+ | maybeToBool maybe_prim_id
+ = prim_id `addIdUnfolding` unfolding
+ where
+ maybe_prim_id = isPrimitiveId_maybe prim_id
+ Just prim_op = maybe_prim_id
+
+ unfolding = mkUnfolding True {- Always inline PrimOps -} rhs
+
+ (tyvars, tau) = splitForAllTy (idType prim_id)
+ (arg_tys, _) = splitFunTy tau
+
+ args = mkTemplateLocals arg_tys
+ rhs = mkLam tyvars args $
+ Prim prim_op
+ ([TyArg (mkTyVarTy tv) | tv <- tyvars] ++
+ [VarArg v | v <- args])
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Catch-all}
+%* *
+%************************************************************************
+
+\begin{code}
+addStandardIdInfo id
+ = pprTrace "addStandardIdInfo missing:" (ppr PprDebug id) id
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Dictionary selector help function
+%* *
+%************************************************************************
+
+Selecting a field for a dictionary. If there is just one field, then
+there's nothing to do.
+
+\begin{code}
+mk_dict_selector tyvars dict_id [arg_id] the_arg_id
+ = mkLam tyvars [dict_id] (Var dict_id)
+
+mk_dict_selector tyvars dict_id arg_ids the_arg_id
+ = mkLam tyvars [dict_id] $
+ Case (Var dict_id) (AlgAlts [(tup_con, arg_ids, Var the_arg_id)] NoDefault)
+ where
+ tup_con = tupleCon (length arg_ids)
+\end{code}
diff --git a/ghc/compiler/reader/Lex.lhs b/ghc/compiler/reader/Lex.lhs
new file mode 100644
index 0000000000..a353f79eca
--- /dev/null
+++ b/ghc/compiler/reader/Lex.lhs
@@ -0,0 +1,372 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+%
+\section[Lexical analysis]{Lexical analysis}
+
+\begin{code}
+#include "HsVersions.h"
+
+module Lex (
+
+ isLexCon, isLexVar, isLexId, isLexSym,
+ isLexConId, isLexConSym, isLexVarId, isLexVarSym,
+ mkTupNameStr,
+
+ -- Monad for parser
+ IfaceToken(..), lexIface, SYN_IE(IfM), thenIf, returnIf, happyError
+
+ ) where
+
+
+IMPORT_1_3(Char(isDigit, isAlpha, isAlphanum, isUpper))
+
+import Demand ( Demand {- instance Read -} )
+import FiniteMap ( FiniteMap, listToFM, lookupFM )
+import Maybes ( Maybe(..), MaybeErr(..) )
+import Pretty
+import CharSeq ( CSeq )
+import ErrUtils ( Error(..) )
+import Outputable ( Outputable(..) )
+import PprStyle ( PprStyle(..) )
+import Util ( nOfThem, panic )
+
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Lexical categories}
+%* *
+%************************************************************************
+
+These functions test strings to see if they fit the lexical categories
+defined in the Haskell report. Normally applied as in e.g. @isCon
+(getLocalName foo)@.
+
+\begin{code}
+isLexCon, isLexVar, isLexId, isLexSym, isLexConId, isLexConSym,
+ isLexVarId, isLexVarSym :: FAST_STRING -> Bool
+
+isLexCon cs = isLexConId cs || isLexConSym cs
+isLexVar cs = isLexVarId cs || isLexVarSym cs
+
+isLexId cs = isLexConId cs || isLexVarId cs
+isLexSym cs = isLexConSym cs || isLexVarSym cs
+
+-------------
+
+isLexConId cs
+ | _NULL_ cs = False
+ | cs == SLIT("[]") = True
+ | c == '(' = True -- (), (,), (,,), ...
+ | otherwise = isUpper c || isUpperISO c
+ where
+ c = _HEAD_ cs
+
+isLexVarId cs
+ | _NULL_ cs = False
+ | otherwise = isLower c || isLowerISO c
+ where
+ c = _HEAD_ cs
+
+isLexConSym cs
+ | _NULL_ cs = False
+ | otherwise = c == ':'
+ || cs == SLIT("->")
+ where
+ c = _HEAD_ cs
+
+isLexVarSym cs
+ | _NULL_ cs = False
+ | otherwise = isSymbolASCII c
+ || isSymbolISO c
+ where
+ c = _HEAD_ cs
+
+-------------
+isSymbolASCII c = c `elem` "!#$%&*+./<=>?@\\^|~-"
+isSymbolISO c = ord c `elem` (0xd7 : 0xf7 : [0xa1 .. 0xbf])
+isUpperISO c = 0xc0 <= oc && oc <= 0xde && oc /= 0xd7 where oc = ord c
+isLowerISO c = 0xdf <= oc && oc <= 0xff && oc /= 0xf7 where oc = ord c
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Tuple strings -- ugh!}
+%* *
+%************************************************************************
+
+\begin{code}
+mkTupNameStr 0 = SLIT("()")
+mkTupNameStr 1 = panic "Name.mkTupNameStr: 1 ???"
+mkTupNameStr 2 = _PK_ "(,)" -- not strictly necessary
+mkTupNameStr 3 = _PK_ "(,,)" -- ditto
+mkTupNameStr 4 = _PK_ "(,,,)" -- ditto
+mkTupNameStr n = _PK_ ("(" ++ nOfThem (n-1) ',' ++ ")")
+\end{code}
+
+
+
+%************************************************************************
+%* *
+\subsection{Data types}
+%* *
+%************************************************************************
+
+\begin{code}
+data IfaceToken
+ = ITinterface -- keywords
+ | ITusages
+ | ITversions
+ | ITexports
+ | ITinstance_modules
+ | ITinstances
+ | ITfixities
+ | ITdeclarations
+ | ITpragmas
+ | ITdata
+ | ITtype
+ | ITnewtype
+ | ITderiving
+ | ITclass
+ | ITwhere
+ | ITinstance
+ | ITinfixl
+ | ITinfixr
+ | ITinfix
+ | ITforall
+ | ITbang -- magic symbols
+ | ITvbar
+ | ITdcolon
+ | ITcomma
+ | ITdarrow
+ | ITdotdot
+ | ITequal
+ | ITocurly
+ | ITdccurly
+ | ITdocurly
+ | ITobrack
+ | IToparen
+ | ITrarrow
+ | ITccurly
+ | ITcbrack
+ | ITcparen
+ | ITsemi
+ | ITinteger Integer -- numbers and names
+ | ITvarid FAST_STRING
+ | ITconid FAST_STRING
+ | ITvarsym FAST_STRING
+ | ITconsym FAST_STRING
+ | ITqvarid (FAST_STRING,FAST_STRING)
+ | ITqconid (FAST_STRING,FAST_STRING)
+ | ITqvarsym (FAST_STRING,FAST_STRING)
+ | ITqconsym (FAST_STRING,FAST_STRING)
+
+ -- Stuff for reading unfoldings
+ | ITarity | ITstrict | ITunfold
+ | ITdemand [Demand] | ITbottom
+ | ITlam | ITbiglam | ITcase | ITlet | ITletrec | ITin | ITof
+ | ITcoerce_in | ITcoerce_out
+ | ITchar Char | ITstring FAST_STRING
+ deriving Text -- debugging
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{The lexical analyser}
+%* *
+%************************************************************************
+
+\begin{code}
+lexIface :: String -> [IfaceToken]
+
+lexIface input
+ = _scc_ "Lexer"
+ case input of
+ [] -> []
+
+ -- whitespace and comments
+ ' ' : cs -> lexIface cs
+ '\t' : cs -> lexIface cs
+ '\n' : cs -> lexIface cs
+ '-' : '-' : cs -> lex_comment cs
+
+-- Leave out nested comments for now; danger of finding { and - juxtaposed by mistake?
+-- '{' : '-' : cs -> lex_nested_comment 1{-one seen-} cs
+
+ '(' : '.' : '.' : ')' : cs -> ITdotdot : lexIface cs
+ '{' : cs -> ITocurly : lexIface cs
+ '}' : cs -> ITccurly : lexIface cs
+ '(' : ',' : cs -> lex_tuple Nothing cs
+ '(' : ')' : cs -> ITconid SLIT("()") : lexIface cs
+ '(' : cs -> IToparen : lexIface cs
+ ')' : cs -> ITcparen : lexIface cs
+ '[' : ']' : cs -> ITconid SLIT("[]") : lexIface cs
+ '[' : cs -> ITobrack : lexIface cs
+ ']' : cs -> ITcbrack : lexIface cs
+ ',' : cs -> ITcomma : lexIface cs
+ ':' : ':' : cs -> ITdcolon : lexIface cs
+ ';' : cs -> ITsemi : lexIface cs
+ '\"' : cs -> case read input of
+ ((str, rest) : _) -> ITstring (_PK_ (str::String)) : lexIface rest
+ '\'' : cs -> case read input of
+ ((ch, rest) : _) -> ITchar ch : lexIface rest
+
+ '_' : 'S' : '_' : cs -> ITstrict : lex_demand cs
+ '_' : cs -> lex_keyword cs
+
+ c : cs | isDigit c -> lex_num input
+ | otherwise -> lex_id input
+
+ other -> error ("lexing:"++other)
+ where
+ lex_comment str
+ = case (span ((/=) '\n') str) of { (junk, rest) ->
+ lexIface rest }
+
+ ------------------
+ lex_demand (c:cs) | isSpace c = lex_demand cs
+ | otherwise = case readList (c:cs) of
+ ((demand,rest) : _) -> ITdemand demand : lexIface rest
+ -----------
+ lex_num str
+ = case (span isDigit str) of { (num, rest) ->
+ ITinteger (read num) : lexIface rest }
+
+ ------------
+ lex_keyword str
+ = case (span is_kwd_mod_char str) of { (kw, rest) ->
+ case (lookupFM ifaceKeywordsFM kw) of
+ Nothing -> panic ("lex_keyword:"++str)
+ Just xx -> xx : lexIface rest
+ }
+
+ is_kwd_mod_char '_' = True
+ is_kwd_mod_char c = isAlphanum c
+
+ -----------
+ lex_tuple module_dot orig_cs = go 2 orig_cs
+ where
+ go n (',':cs) = go (n+1) cs
+ go n (')':cs) = end_lex_id module_dot (ITconid (mkTupNameStr n)) cs
+ go n other = panic ("lex_tuple" ++ orig_cs)
+
+ -- NB: ':' isn't valid inside an identifier, only at the start.
+ -- otherwise we get confused by a::t!
+ is_id_char c = isAlphanum c || c `elem` "_'!#$%&*+./<=>?@\\^|-~" -- ToDo: add ISOgraphic
+
+ lex_id cs = go [] cs
+ where
+ go xs (f :cs) | is_kwd_mod_char f = go (f : xs) cs
+ go xs ('.':cs) | not (null xs) = lex_id2 (Just (_PK_ (reverse xs))) [] cs
+ go xs cs = lex_id2 Nothing xs cs
+
+ -- Dealt with the Module.part
+ lex_id2 module_dot [] ('[': ']': cs) = end_lex_id module_dot (ITconid SLIT("[]")) cs
+ lex_id2 module_dot [] ('(': ')': cs) = end_lex_id module_dot (ITconid SLIT("()")) cs
+ lex_id2 module_dot [] ('(': ',': cs) = lex_tuple module_dot cs
+ lex_id2 module_dot [] (':' : cs) = lex_id3 module_dot [':'] cs
+ lex_id2 module_dot xs cs = lex_id3 module_dot xs cs
+
+ -- Dealt with [], (), : special cases
+ lex_id3 module_dot xs (f:cs) | is_id_char f = lex_id3 module_dot (f : xs) cs
+
+ lex_id3 Nothing xs rest = case lookupFM haskellKeywordsFM rxs of
+ Just kwd_token -> kwd_token : lexIface rest
+ other -> (mk_var_token rxs) : lexIface rest
+ where
+ rxs = reverse xs
+
+ lex_id3 (Just m) xs rest = end_lex_id (Just m) (mk_var_token (reverse xs)) rest
+
+ mk_var_token xs@(f:_) | isUpper f || isUpperISO f = ITconid n
+ | f == ':' = ITconsym n
+ | isAlpha f = ITvarid n
+ | otherwise = ITvarsym n
+ where
+ n = _PK_ xs
+
+ end_lex_id (Just m) (ITconid n) cs = ITqconid (m,n) : lexIface cs
+ end_lex_id (Just m) (ITvarid n) cs = ITqvarid (m,n) : lexIface cs
+ end_lex_id (Just m) (ITconsym n) cs = ITqconsym (m,n): lexIface cs
+ end_lex_id (Just m) (ITvarsym n) cs = ITqvarsym (m,n): lexIface cs
+ end_lex_id (Just m) ITbang cs = ITqvarsym (m,SLIT("!")) : lexIface cs
+ end_lex_id (Just m) token cs = panic ("end_lex_id:" ++ show token)
+ end_lex_id Nothing token cs = token : lexIface cs
+
+ ------------
+ ifaceKeywordsFM :: FiniteMap String IfaceToken
+ ifaceKeywordsFM = listToFM [
+ ("interface_", ITinterface)
+ ,("usages_", ITusages)
+ ,("versions_", ITversions)
+ ,("exports_", ITexports)
+ ,("instance_modules_", ITinstance_modules)
+ ,("instances_", ITinstances)
+ ,("fixities_", ITfixities)
+ ,("declarations_", ITdeclarations)
+ ,("pragmas_", ITpragmas)
+ ,("forall_", ITforall)
+ ,("U_", ITunfold)
+ ,("A_", ITarity)
+ ,("coerce_in_", ITcoerce_in)
+ ,("coerce_out_", ITcoerce_out)
+ ,("A_", ITarity)
+ ,("A_", ITarity)
+ ,("!_", ITbottom)
+
+ ]
+
+ haskellKeywordsFM = listToFM [
+ ("data", ITdata)
+ ,("type", ITtype)
+ ,("newtype", ITnewtype)
+ ,("class", ITclass)
+ ,("where", ITwhere)
+ ,("instance", ITinstance)
+ ,("infixl", ITinfixl)
+ ,("infixr", ITinfixr)
+ ,("infix", ITinfix)
+ ,("case", ITcase)
+ ,("of", ITof)
+ ,("in", ITin)
+ ,("let", ITlet)
+ ,("letrec", ITletrec)
+ ,("deriving", ITderiving)
+
+ ,("->", ITrarrow)
+ ,("\\", ITlam)
+ ,("/\\", ITbiglam)
+ ,("|", ITvbar)
+ ,("!", ITbang)
+ ,("=>", ITdarrow)
+ ,("=", ITequal)
+ ]
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Other utility functions
+%* *
+%************************************************************************
+
+\begin{code}
+type IfM a = MaybeErr a Error
+
+returnIf :: a -> IfM a
+thenIf :: IfM a -> (a -> IfM b) -> IfM b
+happyError :: Int -> [IfaceToken] -> IfM a
+
+returnIf a = Succeeded a
+
+thenIf (Succeeded a) k = k a
+thenIf (Failed err) _ = Failed err
+
+happyError ln toks = Failed (ifaceParseErr ln toks)
+
+-----------------------------------------------------------------
+
+ifaceParseErr ln toks sty
+ = ppCat [ppPStr SLIT("Interface-file parse error: line"), ppInt ln, ppStr "toks=", ppStr (show (take 10 toks))]
+\end{code}
diff --git a/ghc/compiler/utils/SpecLoop.lhi b/ghc/compiler/utils/SpecLoop.lhi
new file mode 100644
index 0000000000..74e3f2cb7b
--- /dev/null
+++ b/ghc/compiler/utils/SpecLoop.lhi
@@ -0,0 +1,67 @@
+This loop-breaking module is used solely to braek the loops caused by
+SPECIALIZE pragmas.
+
+\begin{code}
+interface SpecLoop where
+
+import RdrHsSyn ( RdrName )
+import Name ( Name, OrigName, OccName )
+import TyVar ( GenTyVar )
+import TyCon ( TyCon )
+import Class ( GenClass, GenClassOp )
+import Id ( GenId )
+import Unique ( Unique )
+import UniqFM ( Uniquable(..) )
+import MachRegs ( Reg )
+import CLabel ( CLabel )
+
+data RdrName
+data GenClass a b
+data GenClassOp a
+data GenId a -- NB: fails the optimisation criterion
+data GenTyVar a -- NB: fails the optimisation criterion
+data Name
+data OrigName
+data OccName
+data TyCon
+data Unique
+data Reg
+data CLabel
+
+
+class Uniquable a where
+ uniqueOf :: a -> Unique
+
+-- SPECIALIZing in FiniteMap
+instance Eq Reg
+instance Eq CLabel
+instance Eq OccName
+instance Eq RdrName
+instance Eq OrigName
+instance Eq (GenId a)
+instance Eq TyCon
+instance Eq (GenClass a b)
+instance Eq Unique
+instance Eq Name
+
+instance Ord Reg
+instance Ord CLabel
+instance Ord OccName
+instance Ord RdrName
+instance Ord OrigName
+instance Ord (GenId a)
+instance Ord TyCon
+instance Ord (GenClass a b)
+instance Ord Unique
+instance Ord Name
+
+-- SPECIALIZing in UniqFM, UniqSet
+instance Uniquable OrigName
+instance Uniquable (GenId a)
+instance Uniquable TyCon
+instance Uniquable (GenClass a b)
+instance Uniquable Unique
+instance Uniquable Name
+
+-- SPECIALIZing in Name
+\end{code}