summaryrefslogtreecommitdiff
path: root/compiler/GHC/Parser/Lexer.x
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Parser/Lexer.x')
-rw-r--r--compiler/GHC/Parser/Lexer.x247
1 files changed, 103 insertions, 144 deletions
diff --git a/compiler/GHC/Parser/Lexer.x b/compiler/GHC/Parser/Lexer.x
index b3d83b2408..90ee473c5d 100644
--- a/compiler/GHC/Parser/Lexer.x
+++ b/compiler/GHC/Parser/Lexer.x
@@ -53,8 +53,6 @@ module GHC.Parser.Lexer (
ParserOpts(..), mkParserOpts,
PState (..), initParserState, initPragState,
P(..), ParseResult(..),
- appendWarning,
- appendError,
allocateComments,
MonadP(..),
getRealSrcLoc, getPState, withHomeUnitId,
@@ -70,6 +68,7 @@ module GHC.Parser.Lexer (
addAnnsAt,
commentToAnnotation,
HdkComment(..),
+ warnopt,
) where
import GHC.Prelude
@@ -104,8 +103,6 @@ import GHC.Types.Unique.FM
import GHC.Data.Maybe
import GHC.Data.OrdList
import GHC.Utils.Misc ( readRational, readHexRational )
-import GHC.Utils.Error
-import GHC.Driver.Session as DynFlags
import GHC.Types.SrcLoc
import GHC.Unit
@@ -117,6 +114,8 @@ import GHC.Hs.Doc
import GHC.Parser.CharClass
import GHC.Parser.Annotation
+import GHC.Driver.Flags
+import GHC.Parser.Errors
}
-- -----------------------------------------------------------------------------
@@ -357,7 +356,7 @@ $tab { warnTab }
}
<0,option_prags> {
- "{-#" { warnThen Opt_WarnUnrecognisedPragmas (text "Unrecognised pragma")
+ "{-#" { warnThen Opt_WarnUnrecognisedPragmas WarnUnrecognisedPragma
(nested_comment lexToken) }
}
@@ -1086,7 +1085,7 @@ failLinePrag1 :: Action
failLinePrag1 span _buf _len = do
b <- getBit InNestedCommentBit
if b then return (L span ITcomment_line_prag)
- else lexError "lexical error in pragma"
+ else lexError LexErrorInPragma
-- See Note [Nested comment line pragmas]
popLinePrag1 :: Action
@@ -1107,7 +1106,7 @@ hopefully_open_brace span buf len
Layout prev_off _ : _ -> prev_off < offset
_ -> True
if isOK then pop_and open_brace span buf len
- else addFatalError (mkSrcSpanPs span) (text "Missing block")
+ else addFatalError $ Error ErrMissingBlock [] (mkSrcSpanPs span)
pop_and :: Action -> Action
pop_and act span buf len = do _ <- popLexState
@@ -1486,7 +1485,7 @@ docCommentEnd input commentAcc docType buf span = do
commentEnd lexToken input commentAcc finalizeComment buf span
errBrace :: AlexInput -> RealSrcSpan -> P a
-errBrace (AI end _) span = failLocMsgP (realSrcSpanStart span) (psRealLoc end) "unterminated `{-'"
+errBrace (AI end _) span = failLocMsgP (realSrcSpanStart span) (psRealLoc end) (Error (ErrLexer LexUnterminatedComment LexErrKind_EOF) [])
open_brace, close_brace :: Action
open_brace span _str _len = do
@@ -1545,8 +1544,7 @@ varid span buf len =
lambdaCase <- getBit LambdaCaseBit
unless lambdaCase $ do
pState <- getPState
- addError (mkSrcSpanPs (last_loc pState)) $ text
- "Illegal lambda-case (use LambdaCase)"
+ addError $ Error ErrLambdaCase [] (mkSrcSpanPs (last_loc pState))
return ITlcase
_ -> return ITcase
maybe_layout keyword
@@ -1595,9 +1593,8 @@ varsym_prefix = sym $ \exts s ->
-- See Note [Whitespace-sensitive operator parsing]
varsym_suffix :: Action
varsym_suffix = sym $ \_ s ->
- if | s == fsLit "@"
- -> failMsgP "Suffix occurrence of @. For an as-pattern, remove the leading whitespace."
- | otherwise -> return (ITvarsym s)
+ if | s == fsLit "@" -> failMsgP (Error ErrSuffixAT [])
+ | otherwise -> return (ITvarsym s)
-- See Note [Whitespace-sensitive operator parsing]
varsym_tight_infix :: Action
@@ -1649,8 +1646,7 @@ tok_integral itint transint transbuf translen (radix,char_to_int) span buf len =
let src = lexemeToString buf len
when ((not numericUnderscores) && ('_' `elem` src)) $ do
pState <- getPState
- addError (mkSrcSpanPs (last_loc pState)) $ text
- "Use NumericUnderscores to allow underscores in integer literals"
+ addError $ Error (ErrNumUnderscores NumUnderscore_Integral) [] (mkSrcSpanPs (last_loc pState))
return $ L span $ itint (SourceText src)
$! transint $ parseUnsignedInteger
(offsetBytes transbuf buf) (subtract translen len) radix char_to_int
@@ -1691,8 +1687,7 @@ tok_frac drop f span buf len = do
let src = lexemeToString buf (len-drop)
when ((not numericUnderscores) && ('_' `elem` src)) $ do
pState <- getPState
- addError (mkSrcSpanPs (last_loc pState)) $ text
- "Use NumericUnderscores to allow underscores in floating literals"
+ addError $ Error (ErrNumUnderscores NumUnderscore_Float) [] (mkSrcSpanPs (last_loc pState))
return (L span $! (f $! src))
tok_float, tok_primfloat, tok_primdouble :: String -> Token
@@ -1862,7 +1857,7 @@ lex_string_prag mkTok span _buf _len
= case alexGetChar i of
Just (c,i') | c == x -> isString i' xs
_other -> False
- err (AI end _) = failLocMsgP (realSrcSpanStart (psRealSpan span)) (psRealLoc end) "unterminated options pragma"
+ err (AI end _) = failLocMsgP (realSrcSpanStart (psRealSpan span)) (psRealLoc end) (Error (ErrLexer LexUnterminatedOptions LexErrKind_EOF) [])
-- -----------------------------------------------------------------------------
@@ -1900,8 +1895,8 @@ lex_string s = do
setInput i
when (any (> '\xFF') s') $ do
pState <- getPState
- addError (mkSrcSpanPs (last_loc pState)) $ text
- "primitive string literal must contain only characters <= \'\\xFF\'"
+ let err = Error ErrPrimStringInvalidChar [] (mkSrcSpanPs (last_loc pState))
+ addError err
return (ITprimstring (SourceText s') (unsafeMkByteString s'))
_other ->
return (ITstring (SourceText s') (mkFastString s'))
@@ -2057,7 +2052,7 @@ readNum2 is_digit base conv i = do
Just (c,input') | is_digit c -> do
let i' = i*base + conv c
if i' > 0x10ffff
- then setInput input >> lexError "numeric escape sequence out of range"
+ then setInput input >> lexError LexNumEscapeRange
else read i' input'
_other -> do
setInput input; return (chr i)
@@ -2106,12 +2101,12 @@ silly_escape_chars = [
-- a correct location to the user, but also so we can detect UTF-8 decoding
-- errors if they occur.
lit_error :: AlexInput -> P a
-lit_error i = do setInput i; lexError "lexical error in string/character literal"
+lit_error i = do setInput i; lexError LexStringCharLit
getCharOrFail :: AlexInput -> P Char
getCharOrFail i = do
case alexGetChar' i of
- Nothing -> lexError "unexpected end-of-file in string/character literal"
+ Nothing -> lexError LexStringCharLitEOF
Just (c,i) -> do setInput i; return c
-- -----------------------------------------------------------------------------
@@ -2162,7 +2157,8 @@ lex_quasiquote start s = do
quasiquote_error :: RealSrcLoc -> P a
quasiquote_error start = do
(AI end buf) <- getInput
- reportLexError start (psRealLoc end) buf "unterminated quasiquotation"
+ reportLexError start (psRealLoc end) buf
+ (\k -> Error (ErrLexer LexUnterminatedQQ k) [])
-- -----------------------------------------------------------------------------
-- Warnings
@@ -2172,9 +2168,9 @@ warnTab srcspan _buf _len = do
addTabWarning (psRealSpan srcspan)
lexToken
-warnThen :: WarningFlag -> SDoc -> Action -> Action
-warnThen option warning action srcspan buf len = do
- addWarning option (RealSrcSpan (psRealSpan srcspan) Nothing) warning
+warnThen :: WarningFlag -> (SrcSpan -> Warning) -> Action -> Action
+warnThen flag warning action srcspan buf len = do
+ addWarning flag (warning (RealSrcSpan (psRealSpan srcspan) Nothing))
action srcspan buf len
-- -----------------------------------------------------------------------------
@@ -2234,11 +2230,10 @@ data HdkComment
data PState = PState {
buffer :: StringBuffer,
options :: ParserOpts,
- -- This needs to take DynFlags as an argument until
- -- we have a fix for #10143
- messages :: DynFlags -> Messages,
+ warnings :: Bag Warning,
+ errors :: Bag Error,
tab_first :: Maybe RealSrcSpan, -- pos of first tab warning in the file
- tab_count :: !Int, -- number of tab warnings in the file
+ tab_count :: !Word, -- number of tab warnings in the file
last_tk :: Maybe Token,
last_loc :: PsSpan, -- pos of previous token
last_len :: !Int, -- len of previous token
@@ -2316,14 +2311,14 @@ thenP :: P a -> (a -> P b) -> P b
POk s1 a -> (unP (k a)) s1
PFailed s1 -> PFailed s1
-failMsgP :: String -> P a
-failMsgP msg = do
+failMsgP :: (SrcSpan -> Error) -> P a
+failMsgP f = do
pState <- getPState
- addFatalError (mkSrcSpanPs (last_loc pState)) (text msg)
+ addFatalError (f (mkSrcSpanPs (last_loc pState)))
-failLocMsgP :: RealSrcLoc -> RealSrcLoc -> String -> P a
-failLocMsgP loc1 loc2 str =
- addFatalError (RealSrcSpan (mkRealSrcSpan loc1 loc2) Nothing) (text str)
+failLocMsgP :: RealSrcLoc -> RealSrcLoc -> (SrcSpan -> Error) -> P a
+failLocMsgP loc1 loc2 f =
+ addFatalError (f (RealSrcSpan (mkRealSrcSpan loc1 loc2) Nothing))
getPState :: P PState
getPState = P $ \s -> POk s s
@@ -2370,7 +2365,7 @@ setLastTk tk = P $ \s -> POk s { last_tk = Just tk } ()
getLastTk :: P (Maybe Token)
getLastTk = P $ \s@(PState { last_tk = last_tk }) -> POk s last_tk
-data AlexInput = AI PsLoc StringBuffer
+data AlexInput = AI !PsLoc !StringBuffer
{-
Note [Unicode in Alex]
@@ -2732,7 +2727,8 @@ initParserState options buf loc =
PState {
buffer = buf,
options = options,
- messages = const emptyMessages,
+ errors = emptyBag,
+ warnings = emptyBag,
tab_first = Nothing,
tab_count = 0,
last_tk = Nothing,
@@ -2778,59 +2774,40 @@ class Monad m => MonadP m where
-- to the accumulator and parsing continues. This allows GHC to report
-- more than one parse error per file.
--
- addError :: SrcSpan -> SDoc -> m ()
+ addError :: Error -> m ()
+
-- | Add a warning to the accumulator.
-- Use 'getMessages' to get the accumulated warnings.
- addWarning :: WarningFlag -> SrcSpan -> SDoc -> m ()
+ addWarning :: WarningFlag -> Warning -> m ()
+
-- | Add a fatal error. This will be the last error reported by the parser, and
-- the parser will not produce any result, ending in a 'PFailed' state.
- addFatalError :: SrcSpan -> SDoc -> m a
+ addFatalError :: Error -> m a
+
-- | Check if a given flag is currently set in the bitmap.
getBit :: ExtBits -> m Bool
+
-- | Given a location and a list of AddAnn, apply them all to the location.
addAnnotation :: SrcSpan -- SrcSpan of enclosing AST construct
-> AnnKeywordId -- The first two parameters are the key
-> SrcSpan -- The location of the keyword itself
-> m ()
-appendError
- :: SrcSpan
- -> SDoc
- -> (DynFlags -> Messages)
- -> (DynFlags -> Messages)
-appendError srcspan msg m =
- \d ->
- let (ws, es) = m d
- errormsg = mkErrMsg d srcspan alwaysQualify msg
- es' = es `snocBag` errormsg
- in (ws, es')
-
-appendWarning
- :: ParserOpts
- -> WarningFlag
- -> SrcSpan
- -> SDoc
- -> (DynFlags -> Messages)
- -> (DynFlags -> Messages)
-appendWarning o option srcspan warning m =
- \d ->
- let (ws, es) = m d
- warning' = makeIntoWarning (Reason option) $
- mkWarnMsg d srcspan alwaysQualify warning
- ws' = if warnopt option o then ws `snocBag` warning' else ws
- in (ws', es)
-
instance MonadP P where
- addError srcspan msg
- = P $ \s@PState{messages=m} ->
- POk s{messages=appendError srcspan msg m} ()
- addWarning option srcspan warning
- = P $ \s@PState{messages=m, options=o} ->
- POk s{messages=appendWarning o option srcspan warning m} ()
- addFatalError span msg =
- addError span msg >> P PFailed
+ addError err
+ = P $ \s -> POk s { errors = err `consBag` errors s} ()
+
+ addWarning option w
+ = P $ \s -> if warnopt option (options s)
+ then POk (s { warnings = w `consBag` warnings s }) ()
+ else POk s ()
+
+ addFatalError err =
+ addError err >> P PFailed
+
getBit ext = P $ \s -> let b = ext `xtest` pExtsBitmap (options s)
in b `seq` POk s b
+
addAnnotation (RealSrcSpan l _) a (RealSrcSpan v _) = do
addAnnotationOnly l a v
allocateCommentsP l
@@ -2849,32 +2826,23 @@ addTabWarning srcspan
else s
in POk s' ()
-mkTabWarning :: PState -> DynFlags -> Maybe ErrMsg
-mkTabWarning PState{tab_first=tf, tab_count=tc} d =
- let middle = if tc == 1
- then text ""
- else text ", and in" <+> speakNOf (tc - 1) (text "further location")
- message = text "Tab character found here"
- <> middle
- <> text "."
- $+$ text "Please use spaces instead."
- in fmap (\s -> makeIntoWarning (Reason Opt_WarnTabs) $
- mkWarnMsg d (RealSrcSpan s Nothing) alwaysQualify message) tf
-
-- | Get a bag of the errors that have been accumulated so far.
-- Does not take -Werror into account.
-getErrorMessages :: PState -> DynFlags -> ErrorMessages
-getErrorMessages PState{messages=m} d =
- let (_, es) = m d in es
+getErrorMessages :: PState -> Bag Error
+getErrorMessages p = errors p
-- | Get the warnings and errors accumulated so far.
-- Does not take -Werror into account.
-getMessages :: PState -> DynFlags -> Messages
-getMessages p@PState{messages=m} d =
- let (ws, es) = m d
- tabwarning = mkTabWarning p d
- ws' = maybe ws (`consBag` ws) tabwarning
- in (ws', es)
+getMessages :: PState -> (Bag Warning, Bag Error)
+getMessages p =
+ let ws = warnings p
+ -- we add the tabulation warning on the fly because
+ -- we count the number of occurences of tab characters
+ ws' = case tab_first p of
+ Nothing -> ws
+ Just tf -> WarnTab (RealSrcSpan tf Nothing) (tab_count p)
+ `consBag` ws
+ in (ws', errors p)
getContext :: P [LayoutContext]
getContext = P $ \s@PState{context=ctx} -> POk s ctx
@@ -2889,7 +2857,7 @@ popContext = P $ \ s@(PState{ buffer = buf, options = o, context = ctx,
(_:tl) ->
POk s{ context = tl } ()
[] ->
- unP (addFatalError (mkSrcSpanPs last_loc) (srcParseErr o buf len)) s
+ unP (addFatalError $ srcParseErr o buf len (mkSrcSpanPs last_loc)) s
-- Push a new layout context at the indentation of the last token read.
pushCurrentContext :: GenSemic -> P ()
@@ -2919,29 +2887,27 @@ srcParseErr
:: ParserOpts
-> StringBuffer -- current buffer (placed just after the last token)
-> Int -- length of the previous token
- -> MsgDoc
-srcParseErr options buf len
- = if null token
- then text "parse error (possibly incorrect indentation or mismatched brackets)"
- else text "parse error on input" <+> quotes (text token)
- $$ ppWhen (not th_enabled && token == "$") -- #7396
- (text "Perhaps you intended to use TemplateHaskell")
- $$ ppWhen (token == "<-")
- (if mdoInLast100
- then text "Perhaps you intended to use RecursiveDo"
- else text "Perhaps this statement should be within a 'do' block?")
- $$ ppWhen (token == "=" && doInLast100) -- #15849
- (text "Perhaps you need a 'let' in a 'do' block?"
- $$ text "e.g. 'let x = 5' instead of 'x = 5'")
- $$ ppWhen (not ps_enabled && pattern == "pattern ") -- #12429
- (text "Perhaps you intended to use PatternSynonyms")
- where token = lexemeToString (offsetBytes (-len) buf) len
- pattern = decodePrevNChars 8 buf
- last100 = decodePrevNChars 100 buf
- doInLast100 = "do" `isInfixOf` last100
- mdoInLast100 = "mdo" `isInfixOf` last100
- th_enabled = ThQuotesBit `xtest` pExtsBitmap options
- ps_enabled = PatternSynonymsBit `xtest` pExtsBitmap options
+ -> SrcSpan
+ -> Error
+srcParseErr options buf len loc = Error (ErrParse token) suggests loc
+ where
+ token = lexemeToString (offsetBytes (-len) buf) len
+ pattern = decodePrevNChars 8 buf
+ last100 = decodePrevNChars 100 buf
+ doInLast100 = "do" `isInfixOf` last100
+ mdoInLast100 = "mdo" `isInfixOf` last100
+ th_enabled = ThQuotesBit `xtest` pExtsBitmap options
+ ps_enabled = PatternSynonymsBit `xtest` pExtsBitmap options
+
+ sug c s = if c then Just s else Nothing
+ sug_th = sug (not th_enabled && token == "$") SuggestTH -- #7396
+ sug_rdo = sug (token == "<-" && mdoInLast100) SuggestRecursiveDo
+ sug_do = sug (token == "<-" && not mdoInLast100) SuggestDo
+ sug_let = sug (token == "=" && doInLast100) SuggestLetInDo -- #15849
+ sug_pat = sug (not ps_enabled && pattern == "pattern ") SuggestPatternSynonyms -- #12429
+ suggests
+ | null token = []
+ | otherwise = catMaybes [sug_th, sug_rdo, sug_do, sug_let, sug_pat]
-- Report a parse failure, giving the span of the previous token as
-- the location of the error. This is the entry point for errors
@@ -2949,15 +2915,16 @@ srcParseErr options buf len
srcParseFail :: P a
srcParseFail = P $ \s@PState{ buffer = buf, options = o, last_len = len,
last_loc = last_loc } ->
- unP (addFatalError (mkSrcSpanPs last_loc) (srcParseErr o buf len)) s
+ unP (addFatalError $ srcParseErr o buf len (mkSrcSpanPs last_loc)) s
-- A lexical error is reported at a particular position in the source file,
-- not over a token range.
-lexError :: String -> P a
-lexError str = do
+lexError :: LexErr -> P a
+lexError e = do
loc <- getRealSrcLoc
(AI end buf) <- getInput
- reportLexError loc (psRealLoc end) buf str
+ reportLexError loc (psRealLoc end) buf
+ (\k -> Error (ErrLexer e k) [])
-- -----------------------------------------------------------------------------
-- This is the top-level function: called from the parser each time a
@@ -3073,9 +3040,7 @@ alternativeLayoutRuleToken t
(ITwhere, ALRLayout _ col : ls, _)
| newLine && thisCol == col && transitional ->
do addWarning Opt_WarnAlternativeLayoutRuleTransitional
- (mkSrcSpanPs thisLoc)
- (transitionalAlternativeLayoutWarning
- "`where' clause at the same depth as implicit layout block")
+ $ WarnTransitionalLayout (mkSrcSpanPs thisLoc) TransLayout_Where
setALRContext ls
setNextToken t
-- Note that we use lastLoc, as we may need to close
@@ -3085,9 +3050,7 @@ alternativeLayoutRuleToken t
(ITvbar, ALRLayout _ col : ls, _)
| newLine && thisCol == col && transitional ->
do addWarning Opt_WarnAlternativeLayoutRuleTransitional
- (mkSrcSpanPs thisLoc)
- (transitionalAlternativeLayoutWarning
- "`|' at the same depth as implicit layout block")
+ $ WarnTransitionalLayout (mkSrcSpanPs thisLoc) TransLayout_Pipe
setALRContext ls
setNextToken t
-- Note that we use lastLoc, as we may need to close
@@ -3154,11 +3117,6 @@ alternativeLayoutRuleToken t
-- the other ITwhere case omitted; general case below covers it
(_, _, _) -> return t
-transitionalAlternativeLayoutWarning :: String -> SDoc
-transitionalAlternativeLayoutWarning msg
- = text "transitional layout will not be accepted in the future:"
- $$ text msg
-
isALRopen :: Token -> Bool
isALRopen ITcase = True
isALRopen ITif = True
@@ -3213,7 +3171,8 @@ lexToken = do
setLastToken span 0
return (L span ITeof)
AlexError (AI loc2 buf) ->
- reportLexError (psRealLoc loc1) (psRealLoc loc2) buf "lexical error"
+ reportLexError (psRealLoc loc1) (psRealLoc loc2) buf
+ (\k -> Error (ErrLexer LexError k) [])
AlexSkip inp2 _ -> do
setInput inp2
lexToken
@@ -3227,14 +3186,14 @@ lexToken = do
unless (isComment lt') (setLastTk lt')
return lt
-reportLexError :: RealSrcLoc -> RealSrcLoc -> StringBuffer -> [Char] -> P a
-reportLexError loc1 loc2 buf str
- | atEnd buf = failLocMsgP loc1 loc2 (str ++ " at end of input")
+reportLexError :: RealSrcLoc -> RealSrcLoc -> StringBuffer -> (LexErrKind -> SrcSpan -> Error) -> P a
+reportLexError loc1 loc2 buf f
+ | atEnd buf = failLocMsgP loc1 loc2 (f LexErrKind_EOF)
| otherwise =
let c = fst (nextChar buf)
in if c == '\0' -- decoding errors are mapped to '\0', see utf8DecodeChar#
- then failLocMsgP loc2 loc2 (str ++ " (UTF-8 decoding error)")
- else failLocMsgP loc1 loc2 (str ++ " at character " ++ show c)
+ then failLocMsgP loc2 loc2 (f LexErrKind_UTF8)
+ else failLocMsgP loc1 loc2 (f (LexErrKind_Char c))
lexTokenStream :: ParserOpts -> StringBuffer -> RealSrcLoc -> ParseResult [Located Token]
lexTokenStream opts buf loc = unP go initState{ options = opts' }
@@ -3309,7 +3268,7 @@ twoWordPrags = Map.fromList [
dispatch_pragmas :: Map String Action -> Action
dispatch_pragmas prags span buf len = case Map.lookup (clean_pragma (lexemeToString buf len)) prags of
Just found -> found span buf len
- Nothing -> lexError "unknown pragma"
+ Nothing -> lexError LexUnknownPragma
known_pragma :: Map String Action -> AlexAccPred ExtsBitmap
known_pragma prags _ (AI _ startbuf) _ (AI _ curbuf)