diff --git a/compiler/GHC/Parser.y b/compiler/GHC/Parser.y index 2257f55603fbdf525abd7056ab12234825917191..6750ee526132536366e036e96a188544c1ce7276 100644 --- a/compiler/GHC/Parser.y +++ b/compiler/GHC/Parser.y @@ -3943,9 +3943,40 @@ literal :: { Located (HsLit GhcPs) } ----------------------------------------------------------------------------- -- Layout +{- Note [Layout and error] +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The Haskell 2010 report (Section 10.3, Note 5) dictates the use of the error +token in `close`. To recall why that is necessary, consider + + f x = case x of + True -> False + where y = x+1 + +The virtual pass L inserts vocurly, semi, vccurly to return a laid-out +token stream. It must insert a vccurly before `where` to close the layout +block introduced by `of`. +But there is no good way to do so other than L becoming aware of the grammar! +Thus, L is specified to detect the ensuing parse error (implemented via +happy's `error` token) and then insert the vccurly. +Thus in effect, L is distributed between Lexer.x and Parser.y. + +There are a bunch of other, less "tricky" examples: + + let x = x {- vccurly -} in x -- could just track bracketing of + -- let..in on layout stack to fix + (case x of + True -> False {- vccurly -}) -- ditto for surrounding delimiters such as () + + data T = T;{- vccurly -} -- Need insert vccurly at EOF + +Many of these are not that hard to fix, but still tedious and prone to break +when the grammar changes; but the `of`/`where` example is especially gnarly, +because it demonstrates a grammatical interaction between two lexically +unrelated tokens. +-} close :: { () } : vccurly { () } -- context popped in lexer. - | error {% popContext } + | error {% popContext } -- See Note [Layout and error] ----------------------------------------------------------------------------- -- Miscellaneous (mostly renamings)