Alan Zimmerman pushed to branch wip/az/ghc-cpp at Glasgow Haskell Compiler / GHC
Commits:
-
1c9b5d4a
by Alan Zimmerman at 2025-06-21T15:40:56+01:00
-
2c673901
by Alan Zimmerman at 2025-06-21T16:41:35+01:00
6 changed files:
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PreProcess.hs
- compiler/GHC/Parser/PreProcess/Macro.hs
- compiler/GHC/Parser/PreProcess/State.hs
- testsuite/tests/ghc-cpp/GhcCpp02.stderr
- utils/check-cpp/PreProcess.hs
Changes:
... | ... | @@ -59,7 +59,6 @@ module GHC.Parser.Lexer ( |
59 | 59 | Token(..), lexer, lexerDbg,
|
60 | 60 | ParserOpts(..), mkParserOpts,
|
61 | 61 | PState (..), initParserState, initPragState,
|
62 | - PSavedAlrState(..), getAlrState, setAlrState,
|
|
63 | 62 | startSkipping, stopSkipping,
|
64 | 63 | P(..), ParseResult(POk, PFailed),
|
65 | 64 | allocateComments, allocatePriorComments, allocateFinalComments,
|
... | ... | @@ -273,7 +272,6 @@ $tab { warnTab } |
273 | 272 | -- set.
|
274 | 273 | |
275 | 274 | "{-" / { isNormalComment } { nested_comment }
|
276 | --- "/*" / { ifExtension GhcCppBit } { cpp_comment }
|
|
277 | 275 | |
278 | 276 | -- Single-line comments are a bit tricky. Haskell 98 says that two or
|
279 | 277 | -- more dashes followed by a symbol should be parsed as a varsym, so we
|
... | ... | @@ -1351,6 +1349,7 @@ hopefully_open_brace :: Action p |
1351 | 1349 | hopefully_open_brace span buf len buf2
|
1352 | 1350 | = do relaxed <- getBit RelaxedLayoutBit
|
1353 | 1351 | ctx <- getContext
|
1352 | + -- See Note [GHC_CPP saved offset]
|
|
1354 | 1353 | offset <- getOffset
|
1355 | 1354 | let
|
1356 | 1355 | isOK = relaxed ||
|
... | ... | @@ -1592,15 +1591,6 @@ nested_doc_comment span buf _len _buf2 = {-# SCC "nested_doc_comment" #-} withLe |
1592 | 1591 | dropTrailingDec "-}" = ""
|
1593 | 1592 | dropTrailingDec (x:xs) = x:dropTrailingDec xs
|
1594 | 1593 | |
1595 | -cpp_comment :: Action p
|
|
1596 | -cpp_comment span buf len _buf2 = {-# SCC "cpp_comment" #-} do
|
|
1597 | - l <- getLastLocIncludingComments
|
|
1598 | - let endComment input (L _ comment) = commentEnd lexToken input (Nothing, ITblockComment comment l) buf span
|
|
1599 | - input <- getInput
|
|
1600 | - -- Include decorator in comment
|
|
1601 | - let start_decorator = reverse $ lexemeToString buf len
|
|
1602 | - cpp_comment_logic endComment start_decorator input span
|
|
1603 | - |
|
1604 | 1594 | {-# INLINE nested_comment_logic #-}
|
1605 | 1595 | -- | Includes the trailing '-}' decorators
|
1606 | 1596 | -- drop the last two elements with the callback if you don't want them to be included
|
... | ... | @@ -1635,31 +1625,6 @@ nested_comment_logic endComment commentAcc input span = go commentAcc (1::Int) i |
1635 | 1625 | Just (_,_) -> go ('\n':commentAcc) n input
|
1636 | 1626 | Just (c,input) -> go (c:commentAcc) n input
|
1637 | 1627 | |
1638 | -{-# INLINE cpp_comment_logic #-}
|
|
1639 | --- | Includes the trailing '*/' decorators
|
|
1640 | --- drop the last two elements with the callback if you don't want them to be included
|
|
1641 | -cpp_comment_logic
|
|
1642 | - :: (AlexInput -> Located String -> P p (PsLocated Token)) -- ^ Continuation that gets the rest of the input and the lexed comment
|
|
1643 | - -> String -- ^ starting value for accumulator (reversed) - When we want to include a decorator '/*' in the comment
|
|
1644 | - -> AlexInput
|
|
1645 | - -> PsSpan
|
|
1646 | - -> P p (PsLocated Token)
|
|
1647 | -cpp_comment_logic endComment commentAcc input span = go commentAcc (1::Int) input
|
|
1648 | - where
|
|
1649 | - go commentAcc 0 input@(AI end_loc _) = do
|
|
1650 | - let comment = reverse commentAcc
|
|
1651 | - cspan = mkSrcSpanPs $ mkPsSpan (psSpanStart span) end_loc
|
|
1652 | - lcomment = L cspan comment
|
|
1653 | - endComment input lcomment
|
|
1654 | - go commentAcc n input = case alexGetChar' input of
|
|
1655 | - Nothing -> errBrace input (psRealSpan span)
|
|
1656 | - Just ('*',input) -> case alexGetChar' input of
|
|
1657 | - Nothing -> errBrace input (psRealSpan span)
|
|
1658 | - Just ('/',input) -> go ('/':'*':commentAcc) (n-1) input -- '/'
|
|
1659 | - Just (_,_) -> go ('*':commentAcc) n input
|
|
1660 | - Just (c,input) -> go (c:commentAcc) n input
|
|
1661 | - |
|
1662 | - |
|
1663 | 1628 | ghcCppSet :: P p Bool
|
1664 | 1629 | ghcCppSet = do
|
1665 | 1630 | exts <- getExts
|
... | ... | @@ -1775,9 +1740,12 @@ linePrag span buf len buf2 = do |
1775 | 1740 | usePosPrags <- getBit UsePosPragsBit
|
1776 | 1741 | if usePosPrags
|
1777 | 1742 | then begin line_prag2 span buf len buf2
|
1778 | - -- else let !src = lexemeToFastString buf len
|
|
1779 | - -- in return (L span (ITline_prag (SourceText src)))
|
|
1780 | - else nested_comment span buf len buf2
|
|
1743 | + else do
|
|
1744 | + useGhcCpp <- getBit GhcCppBit
|
|
1745 | + if useGhcCpp
|
|
1746 | + then nested_comment span buf len buf2
|
|
1747 | + else let !src = lexemeToFastString buf len
|
|
1748 | + in return (L span (ITline_prag (SourceText src)))
|
|
1781 | 1749 | |
1782 | 1750 | -- When 'UsePosPragsBit' is not set, it is expected that we emit a token instead
|
1783 | 1751 | -- of updating the position in 'PState'
|
... | ... | @@ -2166,6 +2134,7 @@ do_bol span _str _len _buf2 = do |
2166 | 2134 | -- See Note [Nested comment line pragmas]
|
2167 | 2135 | b <- getBit InNestedCommentBit
|
2168 | 2136 | if b then return (L span ITcomment_line_prag) else do
|
2137 | + -- See Note [GHC_CPP saved offset]
|
|
2169 | 2138 | resetOffset
|
2170 | 2139 | (pos, gen_semic) <- getOffside
|
2171 | 2140 | case pos of
|
... | ... | @@ -2216,6 +2185,7 @@ maybe_layout t = do -- If the alternative layout rule is enabled then |
2216 | 2185 | new_layout_context :: Bool -> Bool -> Token -> Action p
|
2217 | 2186 | new_layout_context strict gen_semic tok span _buf len _buf2 = do
|
2218 | 2187 | _ <- popLexState
|
2188 | + -- See Note [GHC_CPP saved offset]
|
|
2219 | 2189 | current_col <- getOffset
|
2220 | 2190 | let offset = current_col - len
|
2221 | 2191 | ctx <- getContext
|
... | ... | @@ -2670,6 +2640,7 @@ data PState a = PState { |
2670 | 2640 | pp :: !a,
|
2671 | 2641 | -- If a CPP directive occurs in the layout context, we need to
|
2672 | 2642 | -- store the prior column so any alr processing can continue.
|
2643 | + -- See Note [GHC_CPP saved offset]
|
|
2673 | 2644 | pp_last_col :: !(Maybe Int)
|
2674 | 2645 | }
|
2675 | 2646 | -- last_loc and last_len are used when generating error messages,
|
... | ... | @@ -2684,32 +2655,6 @@ data PState a = PState { |
2684 | 2655 | -- of the action, it is the *current* token. Do I understand
|
2685 | 2656 | -- correctly?
|
2686 | 2657 | |
2687 | -data PSavedAlrState = PSavedAlrState {
|
|
2688 | - -- s_warnings :: Messages PsMessage,
|
|
2689 | - -- s_errors :: Messages PsMessage,
|
|
2690 | - s_lex_state :: [Int],
|
|
2691 | - s_context :: [LayoutContext],
|
|
2692 | - s_alr_pending_implicit_tokens :: [PsLocated Token],
|
|
2693 | - s_alr_next_token :: Maybe (PsLocated Token),
|
|
2694 | - s_alr_last_loc :: PsSpan,
|
|
2695 | - s_alr_context :: [ALRContext],
|
|
2696 | - s_alr_expecting_ocurly :: Maybe ALRLayout,
|
|
2697 | - s_alr_justClosedExplicitLetBlock :: Bool,
|
|
2698 | - s_last_col :: Int
|
|
2699 | - }
|
|
2700 | - |
|
2701 | - |
|
2702 | --- -- | Use for emulating (limited) CPP preprocessing in GHC.
|
|
2703 | --- -- TODO: move this into PreProcess, and make a param on PState
|
|
2704 | --- data PpState = PpState {
|
|
2705 | --- pp_defines :: !(Map String [String]),
|
|
2706 | --- pp_continuation :: ![Located Token],
|
|
2707 | --- -- pp_context :: ![PpContext],
|
|
2708 | --- pp_context :: ![Token], -- What preprocessor directive we are currently processing
|
|
2709 | --- pp_accepting :: !Bool
|
|
2710 | --- }
|
|
2711 | --- deriving (Show)
|
|
2712 | - |
|
2713 | 2658 | data PpContext = PpContextIf [Located Token]
|
2714 | 2659 | deriving (Show)
|
2715 | 2660 | |
... | ... | @@ -2825,7 +2770,7 @@ getLastBufCur = P $ \s@(PState { last_buf_cur = last_buf_cur }) -> POk s last_bu |
2825 | 2770 | getLastLen :: P p Int
|
2826 | 2771 | getLastLen = P $ \s@(PState { last_len = last_len }) -> POk s last_len
|
2827 | 2772 | |
2828 | --- see Note [TBD]
|
|
2773 | +-- See Note [GHC_CPP saved offset]
|
|
2829 | 2774 | getOffset :: P p Int
|
2830 | 2775 | getOffset = P $ \s@(PState { pp_last_col = last_col,
|
2831 | 2776 | loc = l}) ->
|
... | ... | @@ -2835,74 +2780,55 @@ getOffset = P $ \s@(PState { pp_last_col = last_col, |
2835 | 2780 | -- (fromMaybe (srcLocCol (psRealLoc l)) last_col)
|
2836 | 2781 | in POk s { pp_last_col = Nothing} offset
|
2837 | 2782 | |
2783 | +-- See Note [GHC_CPP saved offset]
|
|
2838 | 2784 | resetOffset :: P p ()
|
2839 | 2785 | resetOffset = P $ \s -> POk s { pp_last_col = Nothing} ()
|
2840 | 2786 | |
2787 | +{- Note [GHC_CPP saved offset]
|
|
2788 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2789 | + |
|
2790 | +The layout processing machinery examines the offset of the previous
|
|
2791 | +line when doing its calculations.
|
|
2792 | + |
|
2793 | +When GHC_CPP is used, a set of CPP directives may ignore some number
|
|
2794 | +of preceding lines, each of which has a different offset.
|
|
2795 | + |
|
2796 | +We deal with this as follows
|
|
2797 | + |
|
2798 | +- When we start skipping lines due to CPP we store the offset of the
|
|
2799 | + line before the CPP directive
|
|
2800 | +- We explicitly ask for the offset using `getOffset` when doing layout
|
|
2801 | + calculations
|
|
2802 | +- If there is a stored offset, we use that instead of the prior line
|
|
2803 | + offset
|
|
2804 | + |
|
2805 | +-}
|
|
2806 | + |
|
2841 | 2807 | startSkipping :: P p ()
|
2842 | 2808 | startSkipping = do
|
2843 | 2809 | pushLexState skipping
|
2844 | 2810 | -- pushLexState (trace ("startSkipping:" ++ show skipping) skipping)
|
2845 | 2811 | |
2846 | -stopSkipping :: P p Int
|
|
2812 | +stopSkipping :: P p ()
|
|
2847 | 2813 | stopSkipping = do
|
2848 | - -- popLexState
|
|
2849 | - ret <- popLexState
|
|
2814 | + _ <- popLexState
|
|
2850 | 2815 | -- We just processed a CPP directive, which included a trailing newline.
|
2851 | 2816 | -- To properly sync up, we now need to ensure that `do_bol` processing occurs.
|
2852 | - -- But this call does not emit a token.
|
|
2853 | - -- Maybe it should be an argument to lexToken instead?
|
|
2854 | - -- Alternatively, push the input location to the previous char.
|
|
2855 | - AI ps buf <- getInput
|
|
2856 | - last_buf_cur <- getLastBufCur
|
|
2857 | - last_loc <- getLastLoc
|
|
2817 | + -- But this call does not emit a token, so we instead
|
|
2818 | + -- change the input location to the previous char, the newline
|
|
2819 | + AI _ps buf <- getInput
|
|
2858 | 2820 | last_tk <- getLastTk
|
2859 | 2821 | case last_tk of
|
2860 | 2822 | Strict.Just (L l _) -> do
|
2861 | 2823 | let ps' = PsLoc (realSrcSpanEnd (psRealSpan l)) (bufSpanEnd (psBufSpan l))
|
2862 | 2824 | let cur' = (cur buf) - 1
|
2863 | - -- let cur' = trace ("stopSkipping:(cur',ps'):" ++ show (cur'',ps')) cur''
|
|
2864 | 2825 | setInput (AI ps' (buf { cur = cur'}))
|
2865 | 2826 | _ -> return ()
|
2866 | - -- return $ trace ("stopSkipping: (ps, cur buf, last_loc, last_buf_cur, last_tk):" ++ show (ps, cur buf, last_loc, last_buf_cur, last_tk)) ret
|
|
2867 | - return ret
|
|
2868 | 2827 | |
2869 | 2828 | -- old <- popLexState
|
2870 | 2829 | -- return (trace ("stopSkipping:" ++ show old) old)
|
2871 | 2830 | |
2872 | 2831 | |
2873 | -getAlrState :: P p PSavedAlrState
|
|
2874 | -getAlrState = P $ \s@(PState {loc=l}) -> POk s
|
|
2875 | - PSavedAlrState {
|
|
2876 | - -- s_warnings = warnings s,
|
|
2877 | - -- s_errors = errors s,
|
|
2878 | - -- s_lex_state = lex_state s,
|
|
2879 | - s_lex_state = lex_state s,
|
|
2880 | - s_context = context s,
|
|
2881 | - s_alr_pending_implicit_tokens = alr_pending_implicit_tokens s,
|
|
2882 | - s_alr_next_token = alr_next_token s,
|
|
2883 | - s_alr_last_loc = alr_last_loc s,
|
|
2884 | - s_alr_context = alr_context s,
|
|
2885 | - s_alr_expecting_ocurly = alr_expecting_ocurly s,
|
|
2886 | - s_alr_justClosedExplicitLetBlock = alr_justClosedExplicitLetBlock s,
|
|
2887 | - s_last_col = srcLocCol (psRealLoc l)
|
|
2888 | - }
|
|
2889 | - |
|
2890 | -setAlrState :: PSavedAlrState -> P p ()
|
|
2891 | -setAlrState ss = P $ \s -> POk s {
|
|
2892 | - -- errors = s_errors ss,
|
|
2893 | - -- warnings = s_warnings ss,
|
|
2894 | - lex_state = s_lex_state ss,
|
|
2895 | - context = s_context ss,
|
|
2896 | - alr_pending_implicit_tokens = s_alr_pending_implicit_tokens ss,
|
|
2897 | - alr_next_token = s_alr_next_token ss,
|
|
2898 | - alr_last_loc = s_alr_last_loc ss,
|
|
2899 | - alr_context = s_alr_context ss,
|
|
2900 | - alr_expecting_ocurly = s_alr_expecting_ocurly ss,
|
|
2901 | - alr_justClosedExplicitLetBlock = s_alr_justClosedExplicitLetBlock ss,
|
|
2902 | - pp_last_col = Just (s_last_col ss)
|
|
2903 | - } ()
|
|
2904 | - |
|
2905 | - |
|
2906 | 2832 | |
2907 | 2833 | {-# INLINE alexGetChar' #-}
|
2908 | 2834 | -- This version does not squash unicode characters, it is used when
|
... | ... | @@ -3199,6 +3125,7 @@ disableHaddock opts = upd_bitmap (xunset HaddockBit) |
3199 | 3125 | where
|
3200 | 3126 | upd_bitmap f = opts { pExtsBitmap = f (pExtsBitmap opts) }
|
3201 | 3127 | |
3128 | +-- TODO:AZ check which of these are actually needed,
|
|
3202 | 3129 | enableGhcCpp :: ParserOpts -> ParserOpts
|
3203 | 3130 | enableGhcCpp = enableExtBit GhcCppBit
|
3204 | 3131 | |
... | ... | @@ -3881,8 +3808,6 @@ warn_unknown_prag prags span buf len buf2 = do |
3881 | 3808 | %************************************************************************
|
3882 | 3809 | -}
|
3883 | 3810 | |
3884 | --- TODO:AZ: we should have only mkParensEpToks. Delete mkParensEpAnn, mkParensLocs
|
|
3885 | - |
|
3886 | 3811 | -- |Given a 'RealSrcSpan' that surrounds a 'HsPar' or 'HsParTy', generate
|
3887 | 3812 | -- 'EpToken' values for the opening and closing bordering on the start
|
3888 | 3813 | -- and end of the span
|
... | ... | @@ -14,8 +14,8 @@ module GHC.Parser.PreProcess ( |
14 | 14 | ) where
|
15 | 15 | |
16 | 16 | import Data.List (intercalate, sortBy)
|
17 | -import Data.Maybe (fromMaybe, listToMaybe)
|
|
18 | 17 | import Data.Map qualified as Map
|
18 | +import Data.Maybe (fromMaybe, listToMaybe)
|
|
19 | 19 | import Debug.Trace (trace)
|
20 | 20 | import GHC.Data.FastString
|
21 | 21 | import GHC.Data.Strict qualified as Strict
|
... | ... | @@ -23,6 +23,7 @@ import GHC.Data.StringBuffer |
23 | 23 | import GHC.Driver.DynFlags (DynFlags, xopt)
|
24 | 24 | import GHC.LanguageExtensions qualified as LangExt
|
25 | 25 | import GHC.Parser.Errors.Ppr ()
|
26 | +import GHC.Parser.Errors.Types (PsMessage (PsErrGhcCpp))
|
|
26 | 27 | import GHC.Parser.Lexer (P (..), PState (..), ParseResult (..), Token (..))
|
27 | 28 | import GHC.Parser.Lexer qualified as Lexer
|
28 | 29 | import GHC.Parser.PreProcess.Macro
|
... | ... | @@ -34,7 +35,6 @@ import GHC.Types.SrcLoc |
34 | 35 | import GHC.Utils.Error
|
35 | 36 | import GHC.Utils.Outputable (text)
|
36 | 37 | import GHC.Utils.Panic.Plain (panic)
|
37 | -import GHC.Parser.Errors.Types (PsMessage(PsErrGhcCpp))
|
|
38 | 38 | |
39 | 39 | -- ---------------------------------------------------------------------
|
40 | 40 | |
... | ... | @@ -42,9 +42,10 @@ dumpGhcCpp :: DynFlags -> PState PpState -> SDoc |
42 | 42 | dumpGhcCpp dflags pst = output
|
43 | 43 | where
|
44 | 44 | ghc_cpp_enabled = xopt LangExt.GhcCpp dflags
|
45 | - output = if ghc_cpp_enabled
|
|
46 | - then text $ sepa ++ defines ++ sepa ++ final ++ sepa
|
|
47 | - else text "GHC_CPP not enabled"
|
|
45 | + output =
|
|
46 | + if ghc_cpp_enabled
|
|
47 | + then text $ sepa ++ defines ++ sepa ++ final ++ sepa
|
|
48 | + else text "GHC_CPP not enabled"
|
|
48 | 49 | -- Note: pst is the state /before/ the parser runs, so we can use it to lex.
|
49 | 50 | (pst_final, bare_toks) = lexAll pst
|
50 | 51 | comments = reverse (Lexer.comment_q pst_final)
|
... | ... | @@ -76,6 +77,7 @@ renderCombinedToks toks = showCppTokenStream toks |
76 | 77 | -- ---------------------------------------------------------------------
|
77 | 78 | -- addSourceToTokens copied here to unbreak an import loop.
|
78 | 79 | -- It should probably move somewhere else
|
80 | +-- TODO: We should be able to do away with this once #26095 is done
|
|
79 | 81 | |
80 | 82 | {- | Given a source location and a StringBuffer corresponding to this
|
81 | 83 | location, return a rich token stream with the source associated to the
|
... | ... | @@ -105,7 +107,8 @@ addSourceToTokens loc0 buf0 (t@(L sp _) : ts) = |
105 | 107 | |
106 | 108 | -- ---------------------------------------------------------------------
|
107 | 109 | |
108 | --- Tweaked from showRichTokenStream
|
|
110 | +-- Tweaked from showRichTokenStream, to add markers per line if it is
|
|
111 | +-- currently active or not
|
|
109 | 112 | showCppTokenStream :: [(Located Token, String)] -> String
|
110 | 113 | showCppTokenStream ts0 = go startLoc ts0 ""
|
111 | 114 | where
|
... | ... | @@ -196,7 +199,7 @@ ppLexer queueComments cont = |
196 | 199 | ppLexer queueComments cont
|
197 | 200 | in
|
198 | 201 | case tk of
|
199 | - -- case (trace ("M.ppLexer:tk=" ++ show (unLoc tk)) tk) of
|
|
202 | + -- case (trace ("M.ppLexer:tk=" ++ show (unLoc tk)) tk) of
|
|
200 | 203 | L _ ITeof -> do
|
201 | 204 | mInp <- popIncludeLoc
|
202 | 205 | case mInp of
|
... | ... | @@ -219,13 +222,11 @@ ppLexer queueComments cont = |
219 | 222 | case mdump of
|
220 | 223 | Just dump ->
|
221 | 224 | -- We have a dump of the state, put it into an ignored token
|
225 | + -- AZ: TODO: is this actually useful?
|
|
222 | 226 | contIgnoreTok (L l (ITcpp continuation (appendFS s (fsLit dump)) sp))
|
223 | 227 | Nothing -> contIgnoreTok tk
|
224 | 228 | else contInner tk
|
225 | 229 | L _ (ITcppIgnored _ _) -> contIgnoreTok tk
|
226 | - L _ (ITline_prag _) -> do
|
|
227 | - setInLinePragma True
|
|
228 | - contIgnoreTok tk
|
|
229 | 230 | _ -> do
|
230 | 231 | state <- getCppState
|
231 | 232 | inLinePragma <- getInLinePragma
|
... | ... | @@ -253,7 +254,7 @@ processCppToks fs = do |
253 | 254 | -- Combine any prior continuation tokens
|
254 | 255 | cs <- popContinuation
|
255 | 256 | let loc = combineLocs fs (fromMaybe fs (listToMaybe cs))
|
256 | - processCpp loc (concat $ reverse $ map get (fs:cs))
|
|
257 | + processCpp loc (concat $ reverse $ map get (fs : cs))
|
|
257 | 258 | |
258 | 259 | processCpp :: SrcSpan -> String -> PP (Maybe String)
|
259 | 260 | processCpp loc s = do
|
... | ... | @@ -262,13 +263,11 @@ processCpp loc s = do |
262 | 263 | then return (Just "\ndumped state\n")
|
263 | 264 | else do
|
264 | 265 | case directive of
|
265 | - Left err -> Lexer.addError $ mkPlainErrorMsgEnvelope loc $ PsErrGhcCpp (text err)
|
|
266 | + Left err -> Lexer.addError $ mkPlainErrorMsgEnvelope loc $ PsErrGhcCpp (text err)
|
|
266 | 267 | Right (CppInclude filename) -> do
|
267 | 268 | ppInclude filename
|
268 | - Right (CppDefine name args def) -> do
|
|
269 | - ppDefine (MacroName name args) def
|
|
270 | - Right (CppUndef name) -> do
|
|
271 | - ppUndef name
|
|
269 | + Right (CppDefine name args def) -> ppDefine (MacroName name args) def
|
|
270 | + Right (CppUndef name) -> ppUndef name
|
|
272 | 271 | Right (CppIf cond) -> do
|
273 | 272 | val <- cppCond loc cond
|
274 | 273 | ar <- pushAccepting val
|
... | ... | @@ -37,12 +37,15 @@ import Data.Map qualified as Map |
37 | 37 | import Data.Maybe
|
38 | 38 | |
39 | 39 | import Data.Semigroup qualified as S
|
40 | +import GHC.Driver.Errors.Types (PsMessage)
|
|
41 | +import GHC.Parser.Lexer qualified as Lexer
|
|
40 | 42 | import GHC.Parser.PreProcess.Eval
|
41 | 43 | import GHC.Parser.PreProcess.ParsePP
|
42 | 44 | import GHC.Parser.PreProcess.Parser qualified as Parser
|
43 | 45 | import GHC.Parser.PreProcess.ParserM
|
44 | 46 | import GHC.Parser.PreProcess.State
|
45 | 47 | import GHC.Prelude
|
48 | +import GHC.Types.Error (MsgEnvelope)
|
|
46 | 49 | import GHC.Types.SrcLoc
|
47 | 50 | import GHC.Utils.Outputable
|
48 | 51 | import GHC.Utils.Panic (panic)
|
... | ... | @@ -54,58 +57,84 @@ cppCond :: SrcSpan -> String -> PP Bool |
54 | 57 | cppCond loc str = do
|
55 | 58 | s <- getPpState
|
56 | 59 | expanded <- expand loc (pp_defines s) str
|
57 | - v <- case Parser.parseExpr expanded of
|
|
60 | + case expanded of
|
|
58 | 61 | Left err -> do
|
59 | - addGhcCPPError
|
|
60 | - loc
|
|
61 | - ( hang
|
|
62 | - (text "Error evaluating CPP condition:")
|
|
63 | - 2
|
|
64 | - (text err <+> text "of" $+$ text expanded)
|
|
65 | - )
|
|
66 | - return 0
|
|
67 | - Right tree -> return (eval tree)
|
|
68 | - return (toBool v)
|
|
62 | + Lexer.addError err
|
|
63 | + return False
|
|
64 | + Right expanded -> do
|
|
65 | + v <- case Parser.parseExpr expanded of
|
|
66 | + Left err -> do
|
|
67 | + let detail =
|
|
68 | + if str == expanded || expanded == ""
|
|
69 | + then
|
|
70 | + [ text str
|
|
71 | + ]
|
|
72 | + else
|
|
73 | + [ text expanded
|
|
74 | + , text "expanded from:"
|
|
75 | + , text str
|
|
76 | + ]
|
|
77 | + addGhcCPPError
|
|
78 | + loc
|
|
79 | + ( hang
|
|
80 | + (text "Error evaluating CPP condition:")
|
|
81 | + 2
|
|
82 | + ( text err
|
|
83 | + <+> text "of"
|
|
84 | + $+$ vcat detail
|
|
85 | + )
|
|
86 | + )
|
|
87 | + return 0
|
|
88 | + Right tree -> return (eval tree)
|
|
89 | + return (toBool v)
|
|
69 | 90 | |
70 | 91 | -- ---------------------------------------------------------------------
|
71 | 92 | |
72 | -expand :: SrcSpan -> MacroDefines -> String -> PP String
|
|
93 | +expand :: SrcSpan -> MacroDefines -> String -> PP (Either (MsgEnvelope PsMessage) String)
|
|
73 | 94 | expand loc s str = do
|
74 | - toks <- case cppLex False str of
|
|
95 | + case cppLex False str of
|
|
75 | 96 | Left err -> do
|
76 | - addGhcCPPError
|
|
77 | - loc
|
|
78 | - ( hang
|
|
79 | - (text "Error evaluating CPP condition:")
|
|
80 | - 2
|
|
81 | - (text err <+> text "of" $+$ text str)
|
|
97 | + return
|
|
98 | + ( Left $
|
|
99 | + mkGhcCPPError
|
|
100 | + loc
|
|
101 | + ( hang
|
|
102 | + (text "Error evaluating CPP condition:")
|
|
103 | + 2
|
|
104 | + (text err <+> text "of" $+$ text str)
|
|
105 | + )
|
|
82 | 106 | )
|
83 | - return []
|
|
84 | - Right tks -> return tks
|
|
85 | - expandedToks <- expandToks loc maxExpansions s toks
|
|
86 | - return $ combineToks $ map t_str expandedToks
|
|
107 | + Right tks -> do
|
|
108 | + expandedToks <- expandToks loc maxExpansions s tks
|
|
109 | + case expandedToks of
|
|
110 | + Left err -> return (Left err)
|
|
111 | + Right toks -> return $ Right $ combineToks $ map t_str toks
|
|
87 | 112 | |
88 | 113 | maxExpansions :: Int
|
89 | 114 | maxExpansions = 15
|
90 | 115 | |
91 | -expandToks :: SrcSpan -> Int -> MacroDefines -> [Token] -> PP [Token]
|
|
116 | +expandToks :: SrcSpan -> Int -> MacroDefines -> [Token] -> PP (Either (MsgEnvelope PsMessage) [Token])
|
|
92 | 117 | expandToks loc 0 _ ts = do
|
93 | - addGhcCPPError
|
|
94 | - loc
|
|
95 | - ( hang
|
|
96 | - (text "CPP macro expansion limit hit:")
|
|
97 | - 2
|
|
98 | - (text (combineToks $ map t_str ts))
|
|
99 | - )
|
|
100 | - return ts
|
|
118 | + return $
|
|
119 | + Left $
|
|
120 | + mkGhcCPPError
|
|
121 | + loc
|
|
122 | + ( hang
|
|
123 | + (text "CPP macro expansion limit hit:")
|
|
124 | + 2
|
|
125 | + (text (combineToks $ map t_str ts))
|
|
126 | + )
|
|
101 | 127 | expandToks loc cnt s ts = do
|
102 | - (!expansionDone, !r) <- doExpandToks loc False s ts
|
|
103 | - if expansionDone
|
|
104 | - then expandToks loc (cnt - 1) s r
|
|
105 | - else return r
|
|
106 | - |
|
107 | -doExpandToks :: SrcSpan -> Bool -> MacroDefines -> [Token] -> PP (Bool, [Token])
|
|
108 | -doExpandToks _loc ed _ [] = return (ed, [])
|
|
128 | + expansion <- doExpandToks loc False s ts
|
|
129 | + case expansion of
|
|
130 | + Left err -> return (Left err)
|
|
131 | + Right (!expansionDone, !r) ->
|
|
132 | + if expansionDone
|
|
133 | + then expandToks loc (cnt - 1) s r
|
|
134 | + else return (Right r)
|
|
135 | + |
|
136 | +doExpandToks :: SrcSpan -> Bool -> MacroDefines -> [Token] -> PP (Either (MsgEnvelope PsMessage) (Bool, [Token]))
|
|
137 | +doExpandToks _loc ed _ [] = return $ Right (ed, [])
|
|
109 | 138 | doExpandToks loc ed s (TIdentifierLParen n : ts) =
|
110 | 139 | -- TIdentifierLParen has no meaning here (only in a #define), so
|
111 | 140 | -- restore it to its constituent tokens
|
... | ... | @@ -116,30 +145,32 @@ doExpandToks loc _ s (TIdentifier "defined" : ts) = do |
116 | 145 | case expandedArgs of
|
117 | 146 | (Just [[TIdentifier macro_name]], rest0) ->
|
118 | 147 | case Map.lookup macro_name s of
|
119 | - Nothing -> return (True, TInteger "0" : rest0)
|
|
120 | - Just _ -> return (True, TInteger "1" : rest0)
|
|
148 | + Nothing -> return $ Right (True, TInteger "0" : rest0)
|
|
149 | + Just _ -> return $ Right (True, TInteger "1" : rest0)
|
|
121 | 150 | (Nothing, TIdentifier macro_name : ts0) ->
|
122 | 151 | case Map.lookup macro_name s of
|
123 | - Nothing -> return (True, TInteger "0" : ts0)
|
|
124 | - Just _ -> return (True, TInteger "1" : ts0)
|
|
152 | + Nothing -> return $ Right (True, TInteger "0" : ts0)
|
|
153 | + Just _ -> return $ Right (True, TInteger "1" : ts0)
|
|
125 | 154 | (Nothing, _) -> do
|
126 | - addGhcCPPError
|
|
127 | - loc
|
|
128 | - ( hang
|
|
129 | - (text "CPP defined: expected an identifier, got:")
|
|
130 | - 2
|
|
131 | - (text (concatMap t_str ts))
|
|
132 | - )
|
|
133 | - return (False, [])
|
|
155 | + return $
|
|
156 | + Left $
|
|
157 | + mkGhcCPPError
|
|
158 | + loc
|
|
159 | + ( hang
|
|
160 | + (text "CPP defined: expected an identifier, got:")
|
|
161 | + 2
|
|
162 | + (text (concatMap t_str ts))
|
|
163 | + )
|
|
134 | 164 | (Just args, _) -> do
|
135 | - addGhcCPPError
|
|
136 | - loc
|
|
137 | - ( hang
|
|
138 | - (text "CPP defined: expected a single arg, got:")
|
|
139 | - 2
|
|
140 | - (text (intercalate "," (map (concatMap t_str) args)))
|
|
141 | - )
|
|
142 | - return (False, [])
|
|
165 | + return $
|
|
166 | + Left $
|
|
167 | + mkGhcCPPError
|
|
168 | + loc
|
|
169 | + ( hang
|
|
170 | + (text "CPP defined: expected a single arg, got:")
|
|
171 | + 2
|
|
172 | + (text (intercalate "," (map (concatMap t_str) args)))
|
|
173 | + )
|
|
143 | 174 | doExpandToks loc ed s (TIdentifier n : ts) = do
|
144 | 175 | (args, rest0) <- getExpandArgs loc ts
|
145 | 176 | let
|
... | ... | @@ -152,11 +183,15 @@ doExpandToks loc ed s (TIdentifier n : ts) = do |
152 | 183 | (ed0, r, rest1) = case m_args of
|
153 | 184 | Nothing -> (True, rhs, ts)
|
154 | 185 | Just _ -> (True, replace_args args m_args rhs, rest0)
|
155 | - (ed'', rest) <- doExpandToks loc ed' s ts'
|
|
156 | - return (ed'', expanded ++ rest)
|
|
186 | + expansion <- doExpandToks loc ed' s ts'
|
|
187 | + case expansion of
|
|
188 | + Left err -> return $ Left err
|
|
189 | + Right (ed'', rest) -> return $ Right (ed'', expanded ++ rest)
|
|
157 | 190 | doExpandToks loc ed s (t : ts) = do
|
158 | - (ed', r) <- doExpandToks loc ed s ts
|
|
159 | - return (ed', t : r)
|
|
191 | + expansion <- doExpandToks loc ed s ts
|
|
192 | + case expansion of
|
|
193 | + Left err -> return (Left err)
|
|
194 | + Right (ed', r) -> return $ Right (ed', t : r)
|
|
160 | 195 | |
161 | 196 | {-
|
162 | 197 | Note: ['defined' unary operator]
|
... | ... | @@ -32,6 +32,7 @@ module GHC.Parser.PreProcess.State ( |
32 | 32 | ghcCppEnabled,
|
33 | 33 | setInLinePragma,
|
34 | 34 | getInLinePragma,
|
35 | + mkGhcCPPError,
|
|
35 | 36 | addGhcCPPError,
|
36 | 37 | ) where
|
37 | 38 | |
... | ... | @@ -71,7 +72,6 @@ initPpState = |
71 | 72 | , pp_continuation = []
|
72 | 73 | , pp_defines = Map.empty
|
73 | 74 | , pp_scope = (PpScope True PpNoGroup) :| []
|
74 | - , pp_alr_state = Nothing
|
|
75 | 75 | , pp_in_line_pragma = False
|
76 | 76 | }
|
77 | 77 | |
... | ... | @@ -81,7 +81,6 @@ data PpState = PpState |
81 | 81 | , pp_continuation :: ![Located Lexer.Token]
|
82 | 82 | , pp_defines :: !MacroDefines
|
83 | 83 | , pp_scope :: !(NonEmpty PpScope)
|
84 | - , pp_alr_state :: Maybe Lexer.PSavedAlrState
|
|
85 | 84 | , pp_in_line_pragma :: !Bool
|
86 | 85 | }
|
87 | 86 | |
... | ... | @@ -416,6 +415,8 @@ insertMacroDef (MacroName name args) def md = |
416 | 415 | |
417 | 416 | -- ---------------------------------------------------------------------
|
418 | 417 | |
418 | +mkGhcCPPError :: SrcSpan -> SDoc -> MsgEnvelope PsMessage
|
|
419 | +mkGhcCPPError loc err = mkPlainErrorMsgEnvelope loc $ PsErrGhcCpp err
|
|
420 | + |
|
419 | 421 | addGhcCPPError :: SrcSpan -> SDoc -> P p ()
|
420 | -addGhcCPPError loc err =
|
|
421 | - Lexer.addError $ mkPlainErrorMsgEnvelope loc $ PsErrGhcCpp err |
|
422 | +addGhcCPPError loc err = Lexer.addError $ mkGhcCPPError loc err |
... | ... | @@ -6,28 +6,15 @@ GhcCpp02.hs:12:1: error: [GHC-93098] |
6 | 6 | Error evaluating CPP condition:
|
7 | 7 | Parse error at line 1, column 23 of
|
8 | 8 | 2 + NONEXISTENT_MACRO ( 4 )
|
9 | - |
|
10 | -GhcCpp02.hs:17:1: error: [GHC-93098]
|
|
11 | - Error evaluating CPP condition:
|
|
12 | - Parse error at line 1, column 4 of
|
|
13 | - FOO( 3 )
|
|
9 | + expanded from:
|
|
10 | + EXISTENT_MACRO( 4 )
|
|
14 | 11 | |
15 | 12 | GhcCpp02.hs:17:1: error: [GHC-93098]
|
16 | 13 | CPP macro expansion limit hit: FOO( 3 )
|
17 | 14 | |
18 | -GhcCpp02.hs:21:1: error: [GHC-93098]
|
|
19 | - Error evaluating CPP condition:
|
|
20 | - Parse error at line 1, column 0 of
|
|
21 | -
|
|
22 | - |
|
23 | 15 | GhcCpp02.hs:21:1: error: [GHC-93098]
|
24 | 16 | CPP defined: expected an identifier, got: 34
|
25 | 17 | |
26 | -GhcCpp02.hs:24:1: error: [GHC-93098]
|
|
27 | - Error evaluating CPP condition:
|
|
28 | - Parse error at line 1, column 0 of
|
|
29 | -
|
|
30 | - |
|
31 | 18 | GhcCpp02.hs:24:1: error: [GHC-93098]
|
32 | 19 | CPP defined: expected a single arg, got: A,B
|
33 | 20 |
... | ... | @@ -329,15 +329,8 @@ processCpp loc s = do |
329 | 329 | acceptStateChange :: AcceptingResult -> PP ()
|
330 | 330 | acceptStateChange ArNoChange = return ()
|
331 | 331 | acceptStateChange ArNowIgnoring = do
|
332 | - -- alr <- Lexer.getAlrState
|
|
333 | - -- s <- getPpState
|
|
334 | - -- let s = trace ("acceptStateChange:ArNowIgnoring") s'
|
|
335 | - -- setPpState (s { pp_alr_state = Just alr})
|
|
336 | 332 | Lexer.startSkipping
|
337 | 333 | acceptStateChange ArNowAccepting = do
|
338 | - -- s <- getPpState
|
|
339 | - -- let s = trace ("acceptStateChange:ArNowAccepting") s'
|
|
340 | - -- mapM_ Lexer.setAlrState (pp_alr_state s)
|
|
341 | 334 | _ <- Lexer.stopSkipping
|
342 | 335 | return ()
|
343 | 336 |