2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[Lexical analysis]{Lexical analysis}
6 --------------------------------------------------------
8 There's a known bug in here:
10 If an interface file ends prematurely, Lex tries to
11 do headFS of an empty FastString.
13 An example that provokes the error is
15 f _:_ _forall_ [a] <<<END OF FILE>>>
16 --------------------------------------------------------
19 {-# OPTIONS -#include "ctypes.h" #-}
26 IfaceToken(..), lexIface, IfM, thenIf, returnIf, getSrcLocIf,
33 #include "HsVersions.h"
35 import Char ( ord, isSpace )
36 import List ( isSuffixOf )
38 import IdInfo ( InlinePragInfo(..), CprInfo(..) )
39 import Name ( isLowerISO, isUpperISO )
40 import Module ( IfaceFlavour, hiFile, hiBootFile )
41 import PrelMods ( mkTupNameStr, mkUbxTupNameStr )
42 import CmdLineOpts ( opt_IgnoreIfacePragmas, opt_HiVersion, opt_NoHiCheck )
43 import Demand ( Demand(..) {- instance Read -} )
44 import UniqFM ( UniqFM, listToUFM, lookupUFM)
45 import BasicTypes ( NewOrData(..) )
46 import SrcLoc ( SrcLoc, incSrcLine, srcLocFile )
48 import Maybes ( MaybeErr(..) )
49 import ErrUtils ( Message )
57 #if __GLASGOW_HASKELL__ >= 303
63 import PrelRead ( readRational__ ) -- Glasgow non-std
66 %************************************************************************
68 \subsection{Data types}
70 %************************************************************************
72 The token data type, fairly un-interesting except from one
73 constructor, @ITidinfo@, which is used to lazily lex id info (arity,
74 strictness, unfolding etc).
76 The Idea/Observation here is that the renamer needs to scan through
77 all of an interface file before it can continue. But only a fraction
78 of the information contained in the file turns out to be useful, so
79 delaying as much as possible of the scanning and parsing of an
80 interface file Makes Sense (Heap profiles of the compiler
81 show a reduction in heap usage by at least a factor of two,
84 Hence, the interface file lexer spots when value declarations are
85 being scanned and return the @ITidinfo@ and @ITtype@ constructors
86 for the type and any other id info for that binding (unfolding, strictness
87 etc). These constructors are applied to the result of lexing these sub-chunks.
89 The lexing of the type and id info is all done lazily, of course, so
90 the scanning (and subsequent parsing) will be done *only* on the ids the
91 renamer finds out that it is interested in. The rest will just be junked.
92 Laziness, you know it makes sense :-)
96 = ITcase -- Haskell keywords
121 | ITinterface -- GHC-extension keywords
128 | ITccall (Bool,Bool,Bool) -- (is_dyn, is_casm, may_gc)
141 | ITunfold InlinePragInfo
142 | ITstrict ([Demand], Bool)
143 | ITcprinfo (CprInfo)
147 | ITdotdot -- reserved symbols
160 | ITbiglam -- GHC-extension symbols
162 | ITocurly -- special symbols
173 | ITvarid FAST_STRING -- identifiers
174 | ITconid FAST_STRING
175 | ITvarsym FAST_STRING
176 | ITconsym FAST_STRING
177 | ITqvarid (FAST_STRING,FAST_STRING,IfaceFlavour)
178 | ITqconid (FAST_STRING,FAST_STRING,IfaceFlavour)
179 | ITqvarsym (FAST_STRING,FAST_STRING,IfaceFlavour)
180 | ITqconsym (FAST_STRING,FAST_STRING,IfaceFlavour)
182 | ITpragma StringBuffer
185 | ITstring FAST_STRING
187 | ITrational Rational
189 | ITunknown String -- Used when the lexer can't make sense of it
190 | ITeof -- end of file token
191 deriving Text -- debugging
194 %************************************************************************
196 \subsection{The lexical analyser}
198 %************************************************************************
201 lexIface :: (IfaceToken -> IfM a) -> IfM a
204 -- if bufferExhausted buf then
207 -- trace ("Lexer: '"++[C# (currentChar# buf)]++"'") $
208 case currentChar# buf of
209 -- whitespace and comments, ignore.
210 ' '# -> lexIface cont (stepOn buf)
211 '\t'# -> lexIface cont (stepOn buf)
212 '\n'# -> \ loc -> lexIface cont (stepOn buf) (incSrcLine loc)
214 -- Numbers and comments
216 case lookAhead# buf 1# of
217 -- '-'# -> lex_comment cont (stepOnBy# buf 2#)
220 then lex_num cont (negate) (ord# c -# ord# '0'#) (incLexeme (incLexeme buf))
221 else lex_sym cont buf
223 '{'# -> -- look for "{-##" special iface pragma
224 case lookAhead# buf 1# of
225 '-'# -> case lookAhead# buf 2# of
226 '#'# -> case lookAhead# buf 3# of
229 = doDiscard False (stepOnBy# buf 4#) in
230 cont (ITpragma lexeme) buf'
231 _ -> lex_nested_comment (lexIface cont) buf
232 _ -> cont ITocurly (stepOn buf)
233 -- lex_nested_comment (lexIface cont) buf
234 _ -> cont ITocurly (stepOn buf)
236 -- special symbols ----------------------------------------------------
238 case prefixMatch (stepOn buf) "..)" of
239 Just buf' -> cont ITdotdot (stepOverLexeme buf')
241 case lookAhead# buf 1# of
242 '#'# -> cont IToubxparen (stepOnBy# buf 2#)
243 _ -> cont IToparen (stepOn buf)
244 ')'# -> cont ITcparen (stepOn buf)
245 '}'# -> cont ITccurly (stepOn buf)
246 '#'# -> case lookAhead# buf 1# of
247 ')'# -> cont ITcubxparen (stepOnBy# buf 2#)
248 _ -> lex_sym cont (incLexeme buf)
249 '['# -> cont ITobrack (stepOn buf)
250 ']'# -> cont ITcbrack (stepOn buf)
251 ','# -> cont ITcomma (stepOn buf)
252 ';'# -> cont ITsemi (stepOn buf)
254 -- strings/characters -------------------------------------------------
255 '\"'#{-"-} -> case untilEndOfString# (stepOn buf) of
257 -- the string literal does *not* include the dquotes
258 case lexemeToFastString buf' of
259 v -> cont (ITstring v) (stepOn (stepOverLexeme buf'))
262 -- untilEndOfChar# extends the current lexeme until
263 -- it hits a non-escaped single quote. The lexeme of the
264 -- StringBuffer returned does *not* include the closing quote,
265 -- hence we augment the lexeme and make sure to add the
266 -- starting quote, before `read'ing the string.
268 case untilEndOfChar# (stepOn buf) of
269 buf' -> case reads ('\'':lexemeToString (incLexeme buf')) of
270 [ (ch, rest)] -> cont (ITchar ch) (stepOverLexeme (incLexeme buf'))
272 -- strictness and cpr pragmas and __scc treated specially.
274 case lookAhead# buf 1# of
275 '_'# -> case lookAhead# buf 2# of
277 lex_demand cont (stepOnUntil (not . isSpace)
278 (stepOnBy# buf 3#)) -- past __S
280 lex_cpr cont (stepOnUntil (not . isSpace)
281 (stepOnBy# buf 3#)) -- past __M
283 case prefixMatch (stepOnBy# buf 3#) "cc" of
284 Just buf' -> lex_scc cont (stepOverLexeme buf')
285 Nothing -> lex_id cont buf
289 -- ``thingy'' form for casm
291 case lookAhead# buf 1# of
292 '`'# -> lex_cstring cont (stepOnBy# buf 2#) -- remove the `s and go.
293 _ -> lex_sym cont (incLexeme buf) -- add ` to lexeme and assume
294 -- scanning an id of some sort.
297 if bufferExhausted (stepOn buf) then
300 trace "lexIface: misplaced NUL?" $
301 cont (ITunknown "\NUL") (stepOn buf)
303 c | is_digit c -> lex_num cont (id) (ord# c -# ord# '0'#) (incLexeme buf)
304 | is_symbol c -> lex_sym cont buf
305 | is_upper c -> lex_con cont buf
306 | is_ident c -> lex_id cont buf
309 lex_comment cont buf =
310 -- _trace ("comment: "++[C# (currentChar# buf)]) $
311 case untilChar# buf '\n'# of {buf' -> lexIface cont (stepOverLexeme buf')}
313 -------------------------------------------------------------------------------
315 lex_nested_comment cont buf =
316 case currentChar# buf of
317 '-'# -> case lookAhead# buf 1# of
318 '}'# -> cont (stepOnBy# buf 2#)
319 _ -> lex_nested_comment cont (stepOn buf)
321 '{'# -> case lookAhead# buf 1# of
322 '-'# -> lex_nested_comment
323 (lex_nested_comment cont)
325 _ -> lex_nested_comment cont (stepOn buf)
327 _ -> lex_nested_comment cont (stepOn buf)
329 -------------------------------------------------------------------------------
331 lex_demand cont buf =
332 case read_em [] buf of { (ls,buf') ->
333 case currentChar# buf' of
334 'B'# -> cont (ITstrict (ls, True )) (stepOverLexeme (stepOn buf'))
335 _ -> cont (ITstrict (ls, False)) (stepOverLexeme buf')
338 -- code snatched from Demand.lhs
340 case currentChar# buf of
341 'L'# -> read_em (WwLazy False : acc) (stepOn buf)
342 'A'# -> read_em (WwLazy True : acc) (stepOn buf)
343 'S'# -> read_em (WwStrict : acc) (stepOn buf)
344 'P'# -> read_em (WwPrim : acc) (stepOn buf)
345 'E'# -> read_em (WwEnum : acc) (stepOn buf)
346 ')'# -> (reverse acc, stepOn buf)
347 'U'# -> do_unpack DataType True acc (stepOnBy# buf 2#)
348 'u'# -> do_unpack DataType False acc (stepOnBy# buf 2#)
349 'N'# -> do_unpack NewType True acc (stepOnBy# buf 2#)
350 'n'# -> do_unpack NewType False acc (stepOnBy# buf 2#)
351 _ -> (reverse acc, buf)
353 do_unpack new_or_data wrapper_unpacks acc buf
354 = case read_em [] buf of
355 (stuff, rest) -> read_em (WwUnpack new_or_data wrapper_unpacks stuff : acc) rest
358 case read_em [] buf of { (cpr_inf,buf') ->
359 ASSERT ( null (tail cpr_inf) )
360 cont (ITcprinfo $ head cpr_inf) (stepOverLexeme buf')
363 -- code snatched from lex_demand above
365 case currentChar# buf of
366 '-'# -> read_em (NoCPRInfo : acc) (stepOn buf)
367 '('# -> do_unpack acc (stepOn buf)
368 ')'# -> (reverse acc, stepOn buf)
369 _ -> (reverse acc, buf)
372 = case read_em [] buf of
373 (stuff, rest) -> read_em ((CPRInfo stuff) : acc) rest
377 case currentChar# buf of
378 'C'# -> cont ITsccAllCafs (stepOverLexeme (stepOn buf))
379 other -> cont ITscc buf
382 lex_num :: (IfaceToken -> IfM a) -> (Int -> Int) -> Int# -> IfM a
383 lex_num cont minus acc# buf =
384 --trace ("lex_num: "++[C# (currentChar# buf)]) $
385 case scanNumLit (I# acc#) buf of
387 case currentChar# buf' of
389 -- this case is not optimised at all, as the
390 -- presence of floating point numbers in interface
391 -- files is not that common. (ToDo)
392 case expandWhile# is_digit (incLexeme buf') of
393 buf2 -> -- points to first non digit char
394 let l = case currentChar# buf2 of
395 'e'# -> let buf3 = incLexeme buf2 in
396 case currentChar# buf3 of
397 '-'# -> expandWhile# is_digit (incLexeme buf3)
398 _ -> expandWhile# is_digit buf3
400 in let v = readRational__ (lexemeToString l) in
401 cont (ITrational v) (stepOverLexeme l)
403 _ -> cont (ITinteger (fromInt (minus acc'))) (stepOverLexeme buf')
406 lex_cstring cont buf =
407 case expandUntilMatch buf "\'\'" of
408 buf' -> cont (ITstring (lexemeToFastString (setCurrentPos# buf' (negateInt# 2#))))
409 (stepOverLexeme buf')
411 ------------------------------------------------------------------------------
414 is_ident, is_symbol, is_any, is_upper, is_digit :: Char# -> Bool
416 {-# INLINE is_ctype #-}
417 #if __GLASGOW_HASKELL__ >= 303
418 is_ctype :: Word8 -> Char# -> Bool
419 is_ctype mask = \c ->
420 (indexWord8OffAddr (``char_types'' :: Addr) (ord (C# c)) .&. mask) /= 0
422 is_ctype :: Int -> Char# -> Bool
423 is_ctype (I# mask) = \c ->
424 let (A# ctype) = ``char_types'' :: Addr
425 flag_word = int2Word# (ord# (indexCharOffAddr# ctype (ord# c)))
427 (flag_word `and#` (int2Word# mask)) `neWord#` (int2Word# 0#)
430 is_ident = is_ctype 1
431 is_symbol = is_ctype 2
433 is_space = is_ctype 8
434 is_upper = is_ctype 16
435 is_digit = is_ctype 32
437 -----------------------------------------------------------------------------
438 -- identifiers, symbols etc.
441 case expandWhile# is_ident buf of { buf1 ->
442 case expandWhile# (eqChar# '#'#) buf1 of { buf' -> -- only if GHC extns on
443 let new_buf = stepOverLexeme buf'
444 lexeme = lexemeToFastString buf'
446 case _scc_ "Lex.haskellKeyword" lookupUFM haskellKeywordsFM lexeme of {
447 Just kwd_token -> --trace ("hkeywd: "++_UNPK_(lexeme)) $
448 cont kwd_token new_buf;
450 case lookupUFM ifaceKeywordsFM lexeme of {
451 Just kwd_token -> --trace ("ifacekeywd: "++_UNPK_(lexeme)) $
452 cont kwd_token new_buf;
453 Nothing -> --trace ("id: "++_UNPK_(lexeme)) $
454 cont (mk_var_token lexeme) new_buf
458 case expandWhile# is_symbol buf of
460 | is_comment lexeme -> lex_comment cont new_buf
462 case lookupUFM haskellKeySymsFM lexeme of {
463 Just kwd_token -> --trace ("keysym: "++unpackFS lexeme) $
464 cont kwd_token new_buf ;
465 Nothing -> --trace ("sym: "++unpackFS lexeme) $
466 cont (mk_var_token lexeme) new_buf
468 where lexeme = lexemeToFastString buf'
469 new_buf = stepOverLexeme buf'
473 | otherwise = trundle 0
477 trundle n | n == len = True
478 | otherwise = indexFS fs n == '-' && trundle (n+1)
481 case expandWhile# is_ident buf of { buf1 ->
482 case expandWhile# (eqChar# '#'#) buf1 of { buf' ->
483 case currentChar# buf' of
485 '!'# -> munch hiBootFile
489 just_a_conid = --trace ("con: "++unpackFS lexeme) $
490 cont (ITconid lexeme) new_buf
491 lexeme = lexemeToFastString buf'
492 new_buf = stepOverLexeme buf'
493 munch hif = lex_qid cont lexeme hif (stepOn new_buf) just_a_conid
496 lex_qid cont mod hif buf just_a_conid =
497 case currentChar# buf of
498 '['# -> -- Special case for []
499 case lookAhead# buf 1# of
500 ']'# -> cont (ITqconid (mod,SLIT("[]"),hif)) (stepOnBy# buf 2#)
503 '('# -> -- Special case for (,,,)
504 -- This *is* necessary to deal with e.g. "instance C PrelBase.(,,)"
505 case lookAhead# buf 1# of
506 '#'# -> case lookAhead# buf 2# of
507 ','# -> lex_ubx_tuple cont mod hif (stepOnBy# buf 3#)
510 ')'# -> cont (ITqconid (mod,SLIT("()"),hif)) (stepOnBy# buf 2#)
511 ','# -> lex_tuple cont mod hif (stepOnBy# buf 2#) just_a_conid
514 '-'# -> case lookAhead# buf 1# of
515 '>'# -> cont (ITqconid (mod,SLIT("->"),hif)) (stepOnBy# buf 2#)
516 _ -> lex_id3 cont mod hif buf just_a_conid
517 _ -> lex_id3 cont mod hif buf just_a_conid
519 lex_id3 cont mod hif buf just_a_conid
521 case expandWhile# is_symbol buf of { buf' ->
523 lexeme = lexemeToFastString buf'
524 new_buf = stepOverLexeme buf'
526 case lookupUFM haskellKeySymsFM lexeme of {
527 Just kwd_token -> just_a_conid; -- avoid M.:: etc.
528 Nothing -> cont (mk_qvar_token mod hif lexeme) new_buf
532 case expandWhile# is_ident buf of { buf1 ->
536 case expandWhile# (eqChar# '#'#) buf1 of { buf' -> -- only if GHC extns on
538 lexeme = lexemeToFastString buf'
539 new_buf = stepOverLexeme buf'
541 case _scc_ "Lex.haskellKeyword" lookupUFM haskellKeywordsFM lexeme of {
542 Just kwd_token -> just_a_conid; -- avoid M.where etc.
544 case lookupUFM ifaceKeywordsFM lexeme of { -- only for iface files
545 Just kwd_token -> just_a_conid;
546 Nothing -> cont (mk_qvar_token mod hif lexeme) new_buf
548 where c = currentChar# buf
551 | is_upper f = ITconid pk_str
552 -- _[A-Z] is treated as a constructor in interface files.
553 | f `eqChar#` '_'# && not (_NULL_ tl)
554 && (case _HEAD_ tl of { C# g -> is_upper g }) = ITconid pk_str
555 | is_ident f = ITvarid pk_str
556 | f `eqChar#` ':'# = ITconsym pk_str
557 | otherwise = ITvarsym pk_str
559 (C# f) = _HEAD_ pk_str
562 mk_qvar_token m hif token =
563 case mk_var_token token of
564 ITconid n -> ITqconid (m,n,hif)
565 ITvarid n -> ITqvarid (m,n,hif)
566 ITconsym n -> ITqconsym (m,n,hif)
567 ITvarsym n -> ITqvarsym (m,n,hif)
568 _ -> ITunknown (show token)
571 ----------------------------------------------------------------------------
572 Horrible stuff for dealing with M.(,,,)
575 lex_tuple cont mod hif buf back_off =
579 case currentChar# buf of
580 ','# -> go (n+1) (stepOn buf)
581 ')'# -> cont (ITqconid (mod, snd (mkTupNameStr n),hif)) (stepOn buf)
584 lex_ubx_tuple cont mod hif buf back_off =
588 case currentChar# buf of
589 ','# -> go (n+1) (stepOn buf)
590 '#'# -> case lookAhead# buf 1# of
591 ')'# -> cont (ITqconid (mod, snd (mkUbxTupNameStr n), hif))
597 -----------------------------------------------------------------------------
601 ifaceKeywordsFM :: UniqFM IfaceToken
602 ifaceKeywordsFM = listToUFM $
603 map (\ (x,y) -> (_PK_ x,y))
604 [ ("__interface", ITinterface),
605 ("__export", ITexport),
606 ("__instimport", ITinstimport),
607 ("__forall", ITforall),
608 ("__letrec", ITletrec),
609 ("__coerce", ITcoerce),
610 ("__inline", ITinline),
611 ("__DEFAULT", ITdefaultbranch),
613 ("__integer", ITinteger_lit),
614 ("__float", ITfloat_lit),
615 ("__rational", ITrational_lit),
616 ("__addr", ITaddr_lit),
617 ("__litlit", ITlit_lit),
618 ("__string", ITstring_lit),
621 ("__P", ITspecialise),
623 ("__u", ITunfold NoInlinePragInfo),
624 ("__U", ITunfold IWantToBeINLINEd),
625 ("__UU", ITunfold IMustBeINLINEd),
626 ("__Unot", ITunfold IMustNotBeINLINEd),
627 ("__Ux", ITunfold IAmALoopBreaker),
629 ("__ccall", ITccall (False, False, False)),
630 ("__ccall_GC", ITccall (False, False, True)),
631 ("__dyn_ccall", ITccall (True, False, False)),
632 ("__dyn_ccall_GC", ITccall (True, False, True)),
633 ("__casm", ITccall (False, True, False)),
634 ("__dyn_casm", ITccall (True, True, False)),
635 ("__casm_GC", ITccall (False, True, True)),
636 ("__dyn_casm_GC", ITccall (True, True, True)),
641 haskellKeywordsFM = listToUFM $
642 map (\ (x,y) -> (_PK_ x,y))
644 ( "class", ITclass ),
646 ( "default", ITdefault ),
647 ( "deriving", ITderiving ),
651 ( "import", ITimport ),
653 ( "infix", ITinfix ),
654 ( "infixl", ITinfixl ),
655 ( "infixr", ITinfixr ),
656 ( "instance", ITinstance ),
658 ( "module", ITmodule ),
659 ( "newtype", ITnewtype ),
665 -- These three aren't Haskell keywords at all
666 -- and 'as' is often used as a variable name
668 -- ( "qualified", ITqualified ),
669 -- ( "hiding", IThiding )
673 haskellKeySymsFM = listToUFM $
674 map (\ (x,y) -> (_PK_ x,y))
690 -----------------------------------------------------------------------------
691 doDiscard rips along really fast, looking for a '#-}',
692 indicating the end of the pragma we're skipping
695 doDiscard inStr buf =
696 case currentChar# buf of
698 case lookAhead# buf 1# of { '#'# ->
699 case lookAhead# buf 2# of { '-'# ->
700 case lookAhead# buf 3# of { '}'# ->
701 (lexemeToBuffer buf, stepOverLexeme (setCurrentPos# buf 4#));
702 _ -> doDiscard inStr (incLexeme buf) };
703 _ -> doDiscard inStr (incLexeme buf) };
704 _ -> doDiscard inStr (incLexeme buf) }
707 odd_slashes buf flg i# =
708 case lookAhead# buf i# of
709 '\\'# -> odd_slashes buf (not flg) (i# -# 1#)
712 case lookAhead# buf (negateInt# 1#) of --backwards, actually
713 '\\'# -> -- escaping something..
714 if odd_slashes buf True (negateInt# 2#) then
715 -- odd number of slashes, " is escaped.
716 doDiscard inStr (incLexeme buf)
718 -- even number of slashes, \ is escaped.
719 doDiscard (not inStr) (incLexeme buf)
720 _ -> case inStr of -- forced to avoid build-up
721 True -> doDiscard False (incLexeme buf)
722 False -> doDiscard True (incLexeme buf)
723 _ -> doDiscard inStr (incLexeme buf)
727 -----------------------------------------------------------------------------
730 type IfM a = StringBuffer -- Input string
732 -> MaybeErr a {-error-}Message
734 returnIf :: a -> IfM a
735 returnIf a s l = Succeeded a
737 thenIf :: IfM a -> (a -> IfM b) -> IfM b
738 m `thenIf` k = \s l ->
740 Succeeded a -> k a s l
741 Failed err -> Failed err
743 getSrcLocIf :: IfM SrcLoc
744 getSrcLocIf s l = Succeeded l
747 happyError s l = Failed (ifaceParseErr s l)
751 Note that if the name of the file we're processing ends
752 with `hi-boot', we accept it on faith as having the right
753 version. This is done so that .hi-boot files that comes
754 with hsc don't have to be updated before every release,
755 *and* it allows us to share .hi-boot files with versions
756 of hsc that don't have .hi version checking (e.g., ghc-2.10's)
758 If the version number is 0, the checking is also turned off.
759 (needed to deal with GHC.hi only!)
761 Once we can assume we're compiling with a version of ghc that
762 supports interface file checking, we can drop the special
765 checkVersion :: Maybe Integer -> IfM ()
766 checkVersion mb@(Just v) s l
767 | (v==0) || (v == fromInt opt_HiVersion) || opt_NoHiCheck = Succeeded ()
768 | otherwise = Failed (ifaceVersionErr mb l ([]::[IfaceToken]){-Todo-})
769 checkVersion mb@Nothing s l
770 | "hi-boot" `isSuffixOf` (_UNPK_ (srcLocFile l)) = Succeeded ()
771 | otherwise = Failed (ifaceVersionErr mb l ([]::[IfaceToken]){-Todo-})
773 -----------------------------------------------------------------
775 ifaceParseErr :: StringBuffer -> SrcLoc -> Message
777 = hsep [ppr l, ptext SLIT("Interface-file parse error;"),
778 ptext SLIT("current input ="), text first_bit]
780 first_bit = lexemeToString (stepOnBy# s 100#)
782 ifaceVersionErr hi_vers l toks
783 = hsep [ppr l, ptext SLIT("Interface file version error;"),
784 ptext SLIT("Expected"), int opt_HiVersion,
785 ptext SLIT("found "), pp_version]
789 Nothing -> ptext SLIT("pre ghc-3.02 version")
790 Just v -> ptext SLIT("version") <+> integer v