[project @ 2001-07-23 23:08:41 by sof]
[ghc-hetmet.git] / ghc / compiler / parser / Lex.lhs
index 6c69738..fba97ed 100644 (file)
@@ -27,7 +27,7 @@ module Lex (
        StringBuffer,
 
        P, thenP, thenP_, returnP, mapP, failP, failMsgP,
-       getSrcLocP, getSrcFile,
+       getSrcLocP, setSrcLocP, getSrcFile,
        layoutOn, layoutOff, pushContext, popContext
     ) where
 
@@ -39,9 +39,11 @@ import List             ( isSuffixOf )
 import IdInfo          ( InlinePragInfo(..) )
 import PrelNames       ( mkTupNameStr )
 import CmdLineOpts     ( opt_HiVersion, opt_NoHiCheck )
-import Demand          ( Demand(..) {- instance Read -} )
+import ForeignCall     ( Safety(..) )
+import NewDemand       ( StrictSig(..), Demand(..), Keepity(..), 
+                         DmdResult(..), Deferredness(..), mkTopDmdType )
 import UniqFM           ( listToUFM, lookupUFM )
-import BasicTypes      ( NewOrData(..), Boxity(..) )
+import BasicTypes      ( Boxity(..) )
 import SrcLoc          ( SrcLoc, incSrcLine, srcLocFile, srcLocLine,
                          replaceSrcLine, mkSrcLoc )
 
@@ -52,7 +54,7 @@ import FastString
 import StringBuffer
 import GlaExts
 import Ctype
-import Char            ( ord )
+import Char            ( chr, ord )
 import PrelRead        ( readRational__ ) -- Glasgow non-std
 \end{code}
 
@@ -110,7 +112,7 @@ data Token
   | ITthen
   | ITtype
   | ITwhere
-  | ITscc
+  | ITscc                      -- ToDo: remove (we use {-# SCC "..." #-} now)
 
   | ITforall                   -- GHC extension keywords
   | ITforeign
@@ -121,6 +123,7 @@ data Token
   | ITwith
   | ITstdcallconv
   | ITccallconv
+  | ITdotnet
 
   | ITinterface                        -- interface keywords
   | IT__export
@@ -130,7 +133,7 @@ data Token
   | ITcoerce
   | ITinlineMe
   | ITinlineCall
-  | ITccall (Bool,Bool,Bool)   -- (is_dyn, is_casm, may_gc)
+  | ITccall (Bool,Bool,Safety) -- (is_dyn, is_casm, may_gc)
   | ITdefaultbranch
   | ITbottom
   | ITinteger_lit 
@@ -150,7 +153,7 @@ data Token
   | ITspecialise
   | ITnocaf
   | ITunfold InlinePragInfo
-  | ITstrict ([Demand], Bool)
+  | ITstrict StrictSig
   | ITrules
   | ITcprinfo
   | ITdeprecated
@@ -164,6 +167,7 @@ data Token
   | ITrules_prag
   | ITdeprecated_prag
   | ITline_prag
+  | ITscc_prag
   | ITclose_prag
 
   | ITdotdot                   -- reserved symbols
@@ -243,6 +247,7 @@ pragmaKeywordsFM = listToUFM $
        ( "LINE",       ITline_prag ),
        ( "RULES",      ITrules_prag ),
        ( "RULEZ",      ITrules_prag ), -- american spelling :-)
+       ( "SCC",        ITscc_prag ),
        ( "DEPRECATED", ITdeprecated_prag )
        ]
 
@@ -273,9 +278,26 @@ haskellKeywordsFM = listToUFM $
        ( "then",       ITthen ),     
        ( "type",       ITtype ),     
        ( "where",      ITwhere ),
-       ( "_scc_",      ITscc )
+       ( "_scc_",      ITscc )         -- ToDo: remove
      ]
 
+isSpecial :: Token -> Bool
+-- If we see M.x, where x is a keyword, but
+-- is special, we treat is as just plain M.x, 
+-- not as a keyword.
+isSpecial ITas         = True
+isSpecial IThiding     = True
+isSpecial ITqualified  = True
+isSpecial ITforall     = True
+isSpecial ITexport     = True
+isSpecial ITlabel      = True
+isSpecial ITdynamic    = True
+isSpecial ITunsafe     = True
+isSpecial ITwith       = True
+isSpecial ITccallconv   = True
+isSpecial ITstdcallconv = True
+isSpecial _             = False
+
 -- IMPORTANT: Keep this in synch with ParseIface.y's var_fs production! (SUP)
 ghcExtensionKeywordsFM = listToUFM $
        map (\ (x,y) -> (_PK_ x,y))
@@ -288,10 +310,11 @@ ghcExtensionKeywordsFM = listToUFM $
        ( "with",       ITwith ),
        ( "stdcall",    ITstdcallconv),
        ( "ccall",      ITccallconv),
-        ("_ccall_",    ITccall (False, False, False)),
-        ("_ccall_GC_", ITccall (False, False, True)),
-        ("_casm_",     ITccall (False, True,  False)),
-        ("_casm_GC_",  ITccall (False, True,  True)),
+       ( "dotnet",     ITdotnet),
+        ("_ccall_",    ITccall (False, False, PlayRisky)),
+        ("_ccall_GC_", ITccall (False, False, PlaySafe)),
+        ("_casm_",     ITccall (False, True,  PlayRisky)),
+        ("_casm_GC_",  ITccall (False, True,  PlaySafe)),
 
        -- interface keywords
         ("__interface",                ITinterface),
@@ -325,14 +348,14 @@ ghcExtensionKeywordsFM = listToUFM $
         ("__D",                        ITdeprecated),
         ("__U",                        ITunfold NoInlinePragInfo),
        
-        ("__ccall",            ITccall (False, False, False)),
-        ("__ccall_GC",         ITccall (False, False, True)),
-        ("__dyn_ccall",                ITccall (True,  False, False)),
-        ("__dyn_ccall_GC",     ITccall (True,  False, True)),
-        ("__casm",             ITccall (False, True,  False)),
-        ("__dyn_casm",         ITccall (True,  True,  False)),
-        ("__casm_GC",          ITccall (False, True,  True)),
-        ("__dyn_casm_GC",      ITccall (True,  True,  True)),
+        ("__ccall",            ITccall (False, False, PlayRisky)),
+        ("__ccall_GC",         ITccall (False, False, PlaySafe)),
+        ("__dyn_ccall",                ITccall (True,  False, PlayRisky)),
+        ("__dyn_ccall_GC",     ITccall (True,  False, PlaySafe)),
+        ("__casm",             ITccall (False, True,  PlayRisky)),
+        ("__dyn_casm",         ITccall (True,  True,  PlayRisky)),
+        ("__casm_GC",          ITccall (False, True,  PlaySafe)),
+        ("__dyn_casm_GC",      ITccall (True,  True,  PlaySafe)),
 
         ("/\\",                        ITbiglam)
      ]
@@ -429,7 +452,11 @@ lexer cont buf s@(PState{
 
                -- special GHC extension: we grok cpp-style #line pragmas
            '#'# | lexemeIndex buf ==# bol ->   -- the '#' must be in column 0
-               line_prag next_line (stepOn buf) s'
+               case expandWhile# is_space (stepOn buf) of { buf1 ->
+               if is_digit (currentChar# buf1) 
+                       then line_prag next_line buf1 s'
+                       else is_a_token
+               }
                where
                next_line buf = lexer cont (stepOnUntilChar# buf '\n'#)
 
@@ -570,7 +597,7 @@ lexToken cont glaexts buf =
                    '#'# -> case lookAhead# buf 3# of
                                '#'# -> 
                                   let (lexeme, buf') 
-                                         = doDiscard False (stepOnBy# (stepOverLexeme buf) 4#) in
+                                         = doDiscard 0# (stepOnBy# (stepOverLexeme buf) 4#) in
                                             cont (ITpragma lexeme) buf'
                                _ -> lex_prag cont (setCurrentPos# buf 3#)
                    _    -> cont ITocurly (incLexeme buf) 
@@ -645,11 +672,12 @@ lex_prag cont buf
 lex_string cont glaexts s buf
   = case currentChar# buf of
        '"'#{-"-} -> 
-          let buf' = incLexeme buf; s' = mkFastStringInt (reverse s) in
-          case currentChar# buf' of
+          let buf' = incLexeme buf
+               s' = mkFastStringNarrow (map chr (reverse s)) 
+           in case currentChar# buf' of
                '#'# | flag glaexts -> if all (<= 0xFF) s
                     then cont (ITprimstring s') (incLexeme buf')
-                    else lexError "primitive string literal must contain only characters <= '\xFF'" buf'
+                    else lexError "primitive string literal must contain only characters <= \'\\xFF\'" buf'
                _                   -> cont (ITstring s') buf'
 
        -- ignore \& in a string, deal with string gaps
@@ -719,7 +747,7 @@ lex_escape cont buf
                            [] -> charError buf'
 
 after_charnum cont i buf
-  = if i >= 0 && i <= 0x7FFFFFFF
+  = if i >= 0 && i <= 0x10FFFF
        then cont (fromInteger i) buf
        else charError buf
 
@@ -791,29 +819,38 @@ silly_escape_chars = [
 lex_demand cont buf = 
  case read_em [] buf of { (ls,buf') -> 
  case currentChar# buf' of
-   'B'# -> cont (ITstrict (ls, True )) (incLexeme buf')
-   _    -> cont (ITstrict (ls, False)) buf'
+   'X'# -> cont (ITstrict (StrictSig (mkTopDmdType ls BotRes))) (incLexeme buf')
+   'M'# -> cont (ITstrict (StrictSig (mkTopDmdType ls RetCPR))) (incLexeme buf')
+   _    -> cont (ITstrict (StrictSig (mkTopDmdType ls TopRes))) buf'
  }
  where
    -- code snatched from Demand.lhs
   read_em acc buf = 
    case currentChar# buf of
-    'L'# -> read_em (WwLazy False : acc) (stepOn buf)
-    'A'# -> read_em (WwLazy True  : acc) (stepOn buf)
-    'S'# -> read_em (WwStrict     : acc) (stepOn buf)
-    'P'# -> read_em (WwPrim       : acc) (stepOn buf)
-    'E'# -> read_em (WwEnum       : acc) (stepOn buf)
+    'L'# -> read_em (Lazy : acc) (stepOn buf)
+    'A'# -> read_em (Abs : acc) (stepOn buf)
+    'V'# -> read_em (Eval : acc) (stepOn buf)
+    'X'# -> read_em (Err : acc) (stepOn buf)
+    'B'# -> read_em (Bot : acc) (stepOn buf)
     ')'# -> (reverse acc, stepOn buf)
-    'U'# -> do_unpack DataType True  acc (stepOnBy# buf 2#)
-    'u'# -> do_unpack DataType False acc (stepOnBy# buf 2#)
-    'N'# -> do_unpack NewType True  acc (stepOnBy# buf 2#)
-    'n'# -> do_unpack NewType False acc (stepOnBy# buf 2#)
+    'C'# -> do_call acc (stepOnBy# buf 2#)
+    'U'# -> do_unpack1 Drop Now acc (stepOnBy# buf 1#)
+    'S'# -> do_unpack1 Keep Now acc (stepOnBy# buf 1#)
     _    -> (reverse acc, buf)
 
-  do_unpack new_or_data wrapper_unpacks acc buf
-   = case read_em [] buf of
-      (stuff, rest) -> read_em (WwUnpack new_or_data wrapper_unpacks stuff : acc) rest
+  do_unpack1 keepity defer acc buf
+    = case currentChar# buf of
+       '*'# -> do_unpack1 keepity Defer acc (stepOnBy# buf 1#)
+       '('# -> do_unpack2 keepity defer acc (stepOnBy# buf 1#)
+       _    -> read_em (Seq keepity defer [] : acc) buf
+
+  do_unpack2 keepity defer acc buf
+    = case read_em [] buf of
+        (stuff, rest) -> read_em (Seq keepity defer stuff : acc) rest
 
+  do_call acc buf
+    = case read_em [] buf of
+        ([dmd], rest) -> read_em (Call dmd : acc) rest
 
 ------------------
 lex_scc cont buf =
@@ -925,23 +962,36 @@ lex_sym cont buf =
        where lexeme = lexemeToFastString buf'
 
 
-lex_con cont glaexts buf = 
- -- trace ("con: "{-++unpackFS lexeme-}) $
- case expandWhile# is_ident buf          of { buf1 ->
- case slurp_trailing_hashes buf1 glaexts of { buf' ->
+-- lex_con recursively collects components of a qualified identifer.
+-- The argument buf is the StringBuffer representing the lexeme
+-- identified so far, where the next character is upper-case.
 
- case currentChar# buf' of
-     '.'# -> munch
+lex_con cont glaexts buf =
+ -- trace ("con: "{-++unpackFS lexeme-}) $
+ let empty_buf = stepOverLexeme buf in
+ case expandWhile# is_ident empty_buf    of { buf1 ->
+ case slurp_trailing_hashes buf1 glaexts of { con_buf ->
+
+ let all_buf = mergeLexemes buf con_buf
+     
+     con_lexeme = lexemeToFastString con_buf
+     mod_lexeme = lexemeToFastString (decLexeme buf)
+     all_lexeme = lexemeToFastString all_buf
+
+     just_a_conid
+       | emptyLexeme buf = cont (ITconid con_lexeme)               all_buf
+       | otherwise       = cont (ITqconid (mod_lexeme,con_lexeme)) all_buf
+ in
+
+ case currentChar# all_buf of
+     '.'# -> maybe_qualified cont glaexts all_lexeme 
+               (incLexeme all_buf) just_a_conid
      _    -> just_a_conid
-   where
-    just_a_conid = cont (ITconid lexeme) buf'
-    lexeme = lexemeToFastString buf'
-    munch = lex_qid cont glaexts lexeme (incLexeme buf') just_a_conid
- }}
-
-lex_qid cont glaexts mod buf just_a_conid =
- -- trace ("quid: "{-++unpackFS lexeme-}) $
+  }}
+
+
+maybe_qualified cont glaexts mod buf just_a_conid =
+ -- trace ("qid: "{-++unpackFS lexeme-}) $
  case currentChar# buf of
   '['# ->      -- Special case for []
     case lookAhead# buf 1# of
@@ -962,9 +1012,14 @@ lex_qid cont glaexts mod buf just_a_conid =
   '-'# -> case lookAhead# buf 1# of
             '>'# -> cont (ITqconid (mod,SLIT("(->)"))) (setCurrentPos# buf 2#)
             _    -> lex_id3 cont glaexts mod buf just_a_conid
+
   _    -> lex_id3 cont glaexts mod buf just_a_conid
 
+
 lex_id3 cont glaexts mod buf just_a_conid
+  | is_upper (currentChar# buf) =
+     lex_con cont glaexts buf
+
   | is_symbol (currentChar# buf) =
      let 
        start_new_lexeme = stepOverLexeme buf
@@ -993,17 +1048,18 @@ lex_id3 cont glaexts mod buf just_a_conid
      case slurp_trailing_hashes buf1 glaexts of { buf' ->
 
      let
-      lexeme  = lexemeToFastString buf'
-      new_buf = mergeLexemes buf buf'
+      lexeme     = lexemeToFastString buf'
+      new_buf     = mergeLexemes buf buf'
       is_a_qvarid = cont (mk_qvar_token mod lexeme) new_buf
      in
      case _scc_ "Lex.haskellKeyword" lookupUFM haskellKeywordsFM lexeme of {
-           Just kwd_token -> just_a_conid; -- avoid M.where etc.
-           Nothing        -> is_a_qvarid
-       -- TODO: special ids (as, qualified, hiding) shouldn't be
-       -- recognised as keywords here.  ie.  M.as is a qualified varid.
-     }}}
+           Nothing          -> is_a_qvarid ;
 
+           Just kwd_token | isSpecial kwd_token   -- special ids (as, qualified, hiding) shouldn't be
+                          -> is_a_qvarid          --  recognised as keywords here.
+                          | otherwise
+                          -> just_a_conid         -- avoid M.where etc.
+     }}}
 
 slurp_trailing_hashes buf glaexts
   | flag glaexts = expandWhile# (`eqChar#` '#'#) buf
@@ -1056,13 +1112,13 @@ lex_ubx_tuple cont mod buf back_off =
 \end{code}
 
 -----------------------------------------------------------------------------
-doDiscard rips along really fast, looking for a '#-}', 
+doDiscard rips along really fast, looking for a '##-}', 
 indicating the end of the pragma we're skipping
 
 \begin{code}
 doDiscard inStr buf =
  case currentChar# buf of
-   '#'# | not inStr ->
+   '#'# | inStr ==# 0# ->
        case lookAhead# buf 1# of { '#'# -> 
        case lookAhead# buf 2# of { '-'# ->
        case lookAhead# buf 3# of { '}'# -> 
@@ -1070,24 +1126,32 @@ doDiscard inStr buf =
        _    -> doDiscard inStr (incLexeme buf) };
         _    -> doDiscard inStr (incLexeme buf) };
         _    -> doDiscard inStr (incLexeme buf) }
+
    '"'# ->
        let
         odd_slashes buf flg i# =
           case lookAhead# buf i# of
           '\\'# -> odd_slashes buf (not flg) (i# -# 1#)
           _     -> flg
+
+       not_inStr = if inStr ==# 0# then 1# else 0#
        in
        case lookAhead# buf (negateInt# 1#) of --backwards, actually
         '\\'# -> -- escaping something..
-          if odd_slashes buf True (negateInt# 2#) then
-              -- odd number of slashes, " is escaped.
-             doDiscard inStr (incLexeme buf)
-          else
-              -- even number of slashes, \ is escaped.
-             doDiscard (not inStr) (incLexeme buf)
-         _ -> case inStr of -- forced to avoid build-up
-              True  -> doDiscard False (incLexeme buf)
-               False -> doDiscard True  (incLexeme buf)
+          if odd_slashes buf True (negateInt# 2#) 
+               then  -- odd number of slashes, " is escaped.
+                     doDiscard inStr (incLexeme buf)
+               else  -- even number of slashes, \ is escaped.
+                     doDiscard not_inStr (incLexeme buf)
+         _ -> doDiscard not_inStr (incLexeme buf)
+
+   '\''# | inStr ==# 0# ->
+       case lookAhead# buf 1# of { '"'# ->
+       case lookAhead# buf 2# of { '\''# ->
+          doDiscard inStr (setCurrentPos# buf 3#);
+       _ -> doDiscard inStr (incLexeme buf) };
+       _ -> doDiscard inStr (incLexeme buf) }
+
    _ -> doDiscard inStr (incLexeme buf)
 
 \end{code}
@@ -1147,12 +1211,16 @@ lexError str buf s@PState{ loc = loc }
 getSrcLocP :: P SrcLoc
 getSrcLocP buf s@(PState{ loc = loc }) = POk s loc
 
+-- use a temporary SrcLoc for the duration of the argument
+setSrcLocP :: SrcLoc -> P a -> P a
+setSrcLocP new_loc p buf s = 
+  case p buf s{ loc=new_loc } of
+      POk _ a   -> POk s a
+      PFailed e -> PFailed e
+  
 getSrcFile :: P FAST_STRING
 getSrcFile buf s@(PState{ loc = loc }) = POk s (srcLocFile loc)
 
-getContext :: P [LayoutContext]
-getContext buf s@(PState{ context = ctx }) = POk s ctx
-
 pushContext :: LayoutContext -> P ()
 pushContext ctxt buf s@(PState{ context = ctx }) = POk s{context = ctxt:ctx} ()