@@ -68,6 +68,9 @@ export default grammar({
6868 // A parenthesised operator is either a binder name `(:|) = ..` or a
6969 // parenthesised atom (in a bare expression or an argument).
7070 [ $ . paren_operator , $ . _atom ] ,
71+ [ $ . paren_operator , $ . _operator_atom ] ,
72+ // A leading `/` opens a lambda or a prefix division. See `_operator_atom`.
73+ [ $ . _operator_atom , $ . lambda ] ,
7174 // A binding's trailing `;` (the -ddump-late-cc layout terminator) collides
7275 // with the `;` that separates bindings inside a `let { b1; b2 }`. GLR keeps
7376 // whichever completes: the separator reading inside a let, the terminator
@@ -91,6 +94,8 @@ export default grammar({
9194 optional ( $ . _item_sep ) ,
9295 sepBy ( $ . _item_sep , $ . _group ) ,
9396 optional ( $ . _item_sep ) ,
97+ optional ( $ . rules_block ) ,
98+ optional ( $ . _item_sep ) ,
9499 repeat ( $ . _later_section ) ,
95100 optional ( $ . trailing_sections ) ,
96101 optional ( $ . _item_sep ) ,
@@ -105,8 +110,15 @@ export default grammar({
105110 optional ( $ . _item_sep ) ,
106111 sepBy ( $ . _item_sep , $ . _group ) ,
107112 optional ( $ . _item_sep ) ,
113+ optional ( $ . rules_block ) ,
114+ optional ( $ . _item_sep ) ,
108115 ) ,
109116
117+ // GHC appends the local-rules block to the emitting pass's own dump_doc
118+ // (GHC.Core.Lint pp_rules), so it tails that section and the next `====`
119+ // banner still opens the next one.
120+ rules_block : ( $ ) => seq ( $ . dash_header , repeat ( $ . _soup ) ) ,
121+
110122 // Simplifier-iteration dumps print a counts preamble whose `---- .. ----` lines lex as
111123 // comments, so only the `Total ticks: N` line needs a rule.
112124 simplifier_stats : ( $ ) => token ( / T o t a l t i c k s : [ ^ \n ] * / ) ,
@@ -150,7 +162,7 @@ export default grammar({
150162 choice (
151163 $ . variable ,
152164 $ . constructor ,
153- $ . operator ,
165+ $ . _operator_atom ,
154166 $ . con_operator ,
155167 $ . operator_name ,
156168 $ . special_con ,
@@ -160,12 +172,12 @@ export default grammar({
160172 $ . foreign_call ,
161173 ) ,
162174
163- // Header-delimited sections after the Tidy Core: `==== .. ====` banners and `---- ..
164- // ----` markers (e.g. `------ Local rules for imported ids --------`, bannerless
165- // rules). Coarse balanced soup per section, stopping at the next header (which
166- // out-lexes a soup token by longest match).
167- trailing_sections : ( $ ) =>
168- repeat1 ( seq ( choice ( $ . banner , $ . dash_header ) , repeat ( $ . _soup ) ) ) ,
175+ // Banner-led sections after the Tidy Core whose body is not Core, such as
176+ // `==== Tidy Core rules ====` and CorePrep tails. Soup runs to the next
177+ // header, which out-lexes a soup token by longest match.
178+ //
179+ // A dash header never opens a section, see `rules_block`.
180+ trailing_sections : ( $ ) => repeat1 ( seq ( $ . banner , repeat ( $ . _soup ) ) ) ,
169181
170182 // ------ Local rules for imported ids -------- (4+ dashes both ends, so it
171183 // out-precedences the `--` line comment).
@@ -299,11 +311,21 @@ export default grammar({
299311 seq ( $ . _soup_token , optional ( seq ( $ . _dcolon , $ . _type ) ) ) ,
300312 ) ,
301313
314+ // A lone `/` lexes as the lambda head, because an anonymous string beats the
315+ // `operator` regex. Spelling the token out as an operator too recovers Core's
316+ // prefix division, `(/ @Double $fFractionalDouble x y)`.
317+ //
318+ // Both readings then complete, since an unparenthesised `->` also lexes as an
319+ // `operator`. The negative dynamic precedence hands that tie to the lambda.
320+ // Where no `->` follows, the lambda derivation has already died.
321+ _operator_atom : ( $ ) =>
322+ choice ( $ . operator , prec . dynamic ( - 1 , alias ( "/" , $ . operator ) ) ) ,
323+
302324 _atom : ( $ ) =>
303325 choice (
304326 $ . variable ,
305327 $ . constructor ,
306- $ . operator ,
328+ $ . _operator_atom ,
307329 $ . con_operator ,
308330 $ . operator_name ,
309331 $ . literal ,
@@ -395,9 +417,16 @@ export default grammar({
395417 type_arg : ( $ ) => seq ( "@" , $ . _type_atom ) ,
396418 coercion_arg : ( $ ) => seq ( "@~" , $ . coercion ) ,
397419
398- // GHC prints the lambda head as `\`. Some newer dumps render it `/`.
420+ // GHC prints the head as `\`, or `λ` under -fprint-unicode-syntax
421+ // (Outputable.lambda). The `/` is the testsuite normaliser's, which rewrites
422+ // `\` before comparing .stderr. See `_operator_atom` for what it costs.
399423 lambda : ( $ ) =>
400- seq ( choice ( "\\" , "/" ) , repeat1 ( $ . _binder ) , choice ( "->" , "→" ) , $ . _expr ) ,
424+ seq (
425+ choice ( "\\" , "λ" , "/" ) ,
426+ repeat1 ( $ . _binder ) ,
427+ choice ( "->" , "→" ) ,
428+ $ . _expr ,
429+ ) ,
401430
402431 // The join target is a variable, or `(v :: t)` under -dppr-debug.
403432 jump : ( $ ) => seq ( "jump" , $ . _atom , repeat ( $ . _arg ) ) ,
0 commit comments