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 |