@dekobon/tree-sitter-groovy 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.js CHANGED
@@ -1,19 +1,24 @@
1
1
  /**
2
2
  * @file Apache Groovy grammar for tree-sitter
3
3
  * @author Elijah Zupancic <elijah@zupancic.name>
4
- * @license MIT
4
+ * @license Apache-2.0 OR MIT
5
5
  *
6
6
  * The authoritative design document for this grammar is
7
7
  * SPECIFICATION.md at the repository root. Every rule below maps to
8
8
  * a section there. Read the spec before making non-trivial changes.
9
9
  *
10
- * The external scanner (src/scanner.c) handles four context-sensitive
10
+ * The external scanner (src/scanner.c) handles the context-sensitive
11
11
  * lexing situations that pure grammar rules cannot disambiguate:
12
12
  * - Slashy-string-start vs. division
13
- * - Automatic-semicolon (newline-as-terminator)
14
- * - Labelled-statement colon
15
- * - Block-comment / Groovydoc single-token emit
16
- * See SPECIFICATION.md §6.
13
+ * - Line / block / Groovydoc comment single-token emit
14
+ * - The contextual `record` keyword, emitted only before a record
15
+ * header so the word stays an identifier everywhere else
16
+ * - Three decisions that depend on what shares a line: the key of
17
+ * a named argument in a parenthesis-free call, a subscript `[`,
18
+ * and the `)` of a cast
19
+ * - The `!in` operator, which depends on the character after it
20
+ * Inside a string body it emits nothing. See SPECIFICATION.md §6 and
21
+ * the `externals` list below.
17
22
  */
18
23
 
19
24
  /// <reference types="tree-sitter-cli/dsl" />
@@ -54,11 +59,50 @@ const PREC = {
54
59
  };
55
60
  /* eslint-enable no-multi-spaces */
56
61
 
62
+ /*
63
+ * Identifier characters, after GroovyLexer.g4 `JavaLetter` and
64
+ * `JavaLetterOrDigit`: Java's `Character.isJavaIdentifierStart` and
65
+ * `isJavaIdentifierPart` without the identifier-ignorable characters.
66
+ * In Unicode general categories that is L, Nl, Sc and Pc to start a
67
+ * name, and Nd, Mn and Mc as well to continue it. `$` is in Sc and
68
+ * `_` is in Pc.
69
+ */
70
+ const ID_START = String.raw`\p{L}\p{Nl}\p{Sc}\p{Pc}`;
71
+ const ID_PART = ID_START + String.raw`\p{Nd}\p{Mn}\p{Mc}`;
72
+
73
+ /**
74
+ * The source of an identifier pattern, in Rust regex syntax.
75
+ *
76
+ * The ASCII characters are spelled out and come first, so that the
77
+ * lexer has a state that loops on them with plain comparisons. The
78
+ * Unicode classes compile to a binary search over several hundred
79
+ * ranges; written as one class, every character of every ASCII name
80
+ * went through that search, which made the lexer about 2.5 times
81
+ * slower per identifier character.
82
+ *
83
+ * @param {boolean} dollar Whether `$` is an identifier character. It
84
+ * is not in a GString `$name` path (GroovyLexer.g4
85
+ * `IdentifierInGString`).
86
+ * @returns {string} The pattern source.
87
+ */
88
+ function identifierPattern(dollar) {
89
+ const asciiStart = dollar ? 'A-Za-z_$' : 'A-Za-z_';
90
+ const asciiPart = asciiStart + '0-9';
91
+ const otherStart = String.raw`[${ID_START}--[\x00-\x7F]]`;
92
+ const otherPart = String.raw`[${ID_PART}--[\x00-\x7F]]`;
93
+ const anyPart = `[${asciiPart}${otherPart}]`;
94
+ return `(?:[${asciiStart}][${asciiPart}]*(?:${otherPart}${anyPart}*)?|${otherStart}${anyPart}*)`;
95
+ }
96
+
57
97
  /**
58
98
  * GString body segment choice shared between `"..."` and `"""..."""`.
59
99
  * The text rule differs (single-quoted bans newlines, triple-quoted
60
100
  * allows them) but every other alternative is identical.
61
101
  *
102
+ * `_string_body` is never emitted. Listing it here makes it valid
103
+ * wherever a body segment may start, which is how the external scanner
104
+ * learns that it is inside a string (SPECIFICATION.md §6.10).
105
+ *
62
106
  * @param {GrammarSymbols<string>} $ Grammar reference symbols.
63
107
  * @param {RuleOrLiteral} textRule The flavour-specific literal-text rule.
64
108
  * @returns {ChoiceRule} The shared body-segment choice.
@@ -69,25 +113,145 @@ function gstringPart($, textRule) {
69
113
  $.gstring_dollar_interpolation,
70
114
  $.gstring_brace_interpolation,
71
115
  alias($._gstring_literal_dollar, $.string_fragment),
116
+ $._string_body,
117
+ );
118
+ }
119
+
120
+ /**
121
+ * The members of a type body, listed once. `enum_body` repeats the
122
+ * list for the member directly after a trailing comma, where a plain
123
+ * constructor is not allowed (see `enum_declaration`), and the two
124
+ * lists must not drift apart.
125
+ *
126
+ * @param {GrammarSymbols<string>} $ Grammar reference symbols.
127
+ * @param {RuleOrLiteral | null} constructor The constructor rule for
128
+ * this position, or null where a constructor cannot appear.
129
+ * @returns {RuleOrLiteral[]} The member rules, in a fixed order.
130
+ */
131
+ function classMembers($, constructor) {
132
+ return [
133
+ $.method_declaration,
134
+ $.field_declaration,
135
+ ...(constructor ? [constructor] : []),
136
+ $.static_initializer,
137
+ $.enum_declaration,
138
+ $.class_declaration,
139
+ $.interface_declaration,
140
+ $.trait_declaration,
141
+ $.record_declaration,
142
+ $.annotation_type_declaration,
143
+ ];
144
+ }
145
+
146
+ /**
147
+ * A constructor. The enum position directly after a trailing comma
148
+ * requires an access modifier (see `enum_declaration`); everywhere
149
+ * else any modifiers are optional.
150
+ *
151
+ * @param {GrammarSymbols<string>} $ Grammar reference symbols.
152
+ * @param {RuleOrLiteral} modifiers The modifier list for this position.
153
+ * @returns {PrecRightRule} The constructor rule body.
154
+ */
155
+ function constructorDeclaration($, modifiers) {
156
+ return prec.right(3, seq(
157
+ repeat($.annotation),
158
+ modifiers,
159
+ field('name', $.identifier),
160
+ field('parameters', $.formal_parameters),
161
+ optional($.throws_clause),
162
+ field('body', $.block),
163
+ ));
164
+ }
165
+
166
+ /**
167
+ * A method parameter or a closure parameter. Apache's `closure` takes
168
+ * the `formalParameterList` of a method, so the two have one shape:
169
+ * annotations, `final`, then `def`, `var` or a type (a `varargs_type`
170
+ * included), the name, and a default value.
171
+ *
172
+ * Apache's `variableModifiersOpt` is wider: annotations and modifiers
173
+ * in any order, `def` or `var` together with a type, and `...` with no
174
+ * type. Those are not accepted (divergence 14).
175
+ *
176
+ * @param {GrammarSymbols<string>} $ Grammar reference symbols.
177
+ * @returns {ChoiceRule} The parameter rule body.
178
+ */
179
+ function parameter($) {
180
+ const defaultValue = optional(seq('=', field('default', $._expression)));
181
+ return choice(
182
+ seq(
183
+ repeat($.annotation),
184
+ optional('final'),
185
+ choice(
186
+ seq(
187
+ optional(choice('def', 'var', field('type', choice($._type, $.varargs_type)))),
188
+ field('name', $.identifier),
189
+ ),
190
+ // `var` is a contextual keyword and a valid name: `def f(var)`.
191
+ // With no name after it, it is the name.
192
+ field('name', alias('var', $.identifier)),
193
+ ),
194
+ defaultValue,
195
+ ),
196
+ // `_` is a literal directly after an annotation where a statement
197
+ // can start (see `_placeholder_declarator`), and an annotated
198
+ // closure parameter starts there too: `{ @A _ -> }`, or with `_`
199
+ // as the type, `{ @A _ x -> }`. Anywhere else in a parameter `_`
200
+ // is an ordinary identifier.
201
+ seq(
202
+ repeat1($.annotation),
203
+ choice(
204
+ field('name', alias('_', $.identifier)),
205
+ seq(
206
+ field('type', alias('_', $.type_identifier)),
207
+ field('name', $.identifier),
208
+ ),
209
+ ),
210
+ defaultValue,
211
+ ),
72
212
  );
73
213
  }
74
214
 
75
215
  module.exports = grammar({
76
216
  name: 'groovy',
77
217
 
78
- // Placeholder for the real implementation. SPECIFICATION.md §3-§7
79
- // is the contract this rule set will fulfil.
218
+ // Keywords are extracted from this token. A keyword is lexed as
219
+ // such only in a state where it has a parse action, or where it is
220
+ // reserved (`reserved` below); anywhere else the same text is an
221
+ // `identifier`. Several comments in this file depend on that.
80
222
  word: $ => $.identifier,
81
223
 
224
+ // §5.2 — `new` is a hard keyword. Keyword extraction alone still
225
+ // lexes it as `identifier` wherever the keyword has no action,
226
+ // which let `def f = (Foo) new T()` after another member split
227
+ // into a field `= (Foo)` and a method `T()` returning `new`. The
228
+ // empty `property` set keeps `foo.new` (Apache `namePart`) valid;
229
+ // `_property_name` also names methods, so `new` is not reserved
230
+ // where a method name may follow (`def new`, `int new`).
231
+ reserved: {
232
+ global: _ => ['new'],
233
+ property: _ => [],
234
+ },
235
+
82
236
  extras: $ => [
83
237
  /\s/,
238
+ // §5.10 — a line escape, `\` at the end of a line. Groovy's lexer
239
+ // skips it as it skips spaces and tabs.
240
+ /\\\r?\n/,
84
241
  $.line_comment,
85
242
  $.block_comment,
86
243
  $.groovydoc_comment,
87
244
  ],
88
245
 
89
246
  // Externals listed here must have a matching branch in
90
- // `src/scanner.c` AND be referenced by at least one rule below.
247
+ // `src/scanner.c` AND be referenced by at least one rule below
248
+ // (`_command_named_key` and `_subscript_open` included). There are
249
+ // two exceptions. No rule references `_error_sentinel`: it exists so
250
+ // the scanner can detect error recovery, when tree-sitter marks
251
+ // every external valid. It is kept last here and in the scanner's
252
+ // `TokenType` enum, and the two orders must match. The scanner never
253
+ // emits `_string_body`: a string body references it so that the
254
+ // scanner can tell it is inside one.
91
255
  // Tokens the spec §6 proposes as external scanner branches but
92
256
  // that this grammar implements in-grammar (GString interpolation
93
257
  // via regex tokens, slashy body via in-grammar `_slashy_text`,
@@ -102,10 +266,40 @@ module.exports = grammar({
102
266
  $.line_comment,
103
267
  $.block_comment,
104
268
  $.groovydoc_comment,
269
+ $._record_keyword,
270
+ // §5.5 — empty token before the `name:` key of a named argument in
271
+ // a parenthesis-free call. Scanner-side so the newline before a Spock
272
+ // label (`result` then `where:`) is not swallowed, and so
273
+ // `Type name =` stays a declaration.
274
+ $._command_named_key,
275
+ // §5.10 — `[` on the same line as the token before it (spaces, tabs and
276
+ // line escapes allowed). A `[` after a newline isn't one and can only
277
+ // start a list or map literal: a statement, not a subscript of the line
278
+ // above.
279
+ $._subscript_open,
280
+ // §6.11 — a `)` with something after it on the same line. A cast
281
+ // that closes with it outranks a parenthesized expression; a cast
282
+ // whose operand is on a later line ranks below one, so `x = (a)`
283
+ // followed by `foo()` is two statements.
284
+ $._cast_close,
285
+ // §6.12 — the `!in` operator, which needs whitespace or an opening
286
+ // bracket after it. The scanner reads that character and leaves it.
287
+ $._not_in,
288
+ // §6.10 — never emitted: valid only between the quotes of a string
289
+ // whose body is lexed in pieces. Comments are extras, so the parser
290
+ // offers them there too; the scanner must emit nothing, or `//` and
291
+ // `/*` at a piece boundary become comments.
292
+ $._string_body,
293
+ // Never referenced by a rule: valid only during error recovery, when
294
+ // the scanner must not emit context-sensitive tokens.
295
+ $._error_sentinel,
105
296
  ],
106
297
 
107
298
  conflicts: $ => [
108
- // See SPECIFICATION.md §7. Populated as rules accumulate.
299
+ // `final def x` / `final x = 1` in a block vs. a modified member at top level.
300
+ [$._modifier, $.local_variable_declaration],
301
+ // This array is the authoritative list; SPECIFICATION.md §7 is
302
+ // the list predicted before the grammar existed.
109
303
  // (list_literal vs map_literal — tree-sitter resolves without
110
304
  // an explicit conflict because `:` after the first element
111
305
  // always disambiguates within one token of lookahead.)
@@ -164,6 +358,39 @@ module.exports = grammar({
164
358
  // tree-sitter report it unnecessary. Regenerate without it to
165
359
  // confirm that still holds.
166
360
  [$.formal_parameter, $._expression],
361
+ // §4 — after an enum's trailing comma, `private` may open a
362
+ // constructor (`private E() { }`) or any other member.
363
+ [$._modifier, $._modified_constructor_declaration],
364
+ // §5.8 — a closure's parameter list and a closure body that opens
365
+ // with a declaration share their first tokens, and so does a
366
+ // block, whose `{` may also open a closure. The `->` decides, or
367
+ // the first token that only one reading accepts.
368
+ //
369
+ // `{ final x -> }` vs. a body opening with a final local (#56) or
370
+ // with a modified declaration; all three stay alive at `final`.
371
+ [$._modifier, $.local_variable_declaration, $.closure_parameter],
372
+ // `{ String a = 'x', b -> }` vs. `{ String a = 'x', b = 'y' }`, and
373
+ // `{ def a, b -> }` vs. `{ def a, b }`. These two fork at every
374
+ // `,` of a declaration that opens a closure or block, and both
375
+ // stacks run to the end of the list: 15% to 60% more work for a
376
+ // list of two to eight names, about twice for a long one. A list
377
+ // of one name does not fork.
378
+ [$._initialized_declarator, $.closure_parameter],
379
+ [$.variable_declarator, $.closure_parameter],
380
+ // `{ @A _ x -> }`, a parameter of type `_`, vs. `{ @A _` as the
381
+ // declaration of the placeholder followed by a statement `x`.
382
+ [$._placeholder_declarator, $.closure_parameter],
383
+ // An untyped default, `{ a = 1 -> }` vs. `{ a = 1 }`, needs no
384
+ // entry: see `expression_statement`.
385
+ //
386
+ // Two things keep these forks from changing a valid parse, and a
387
+ // new rule must keep both. `closure_parameter` carries no dynamic
388
+ // precedence, so a reading that survives to the `->` wins by being
389
+ // the only one left. And `->` appears nowhere at the top level of
390
+ // a closure body: only in `closure_parameters` and in the arrow
391
+ // forms of `switch`. On invalid input the parameter reading can
392
+ // win, because a missing `->` is a cheaper repair than an ERROR:
393
+ // `{ x = 1, y }` recovers as two parameters.
167
394
  ],
168
395
 
169
396
  rules: {
@@ -198,6 +425,7 @@ module.exports = grammar({
198
425
  $.assert_statement,
199
426
  $.yield_statement,
200
427
  $.try_statement,
428
+ $.synchronized_statement,
201
429
  $.class_declaration,
202
430
  $.trait_declaration,
203
431
  $.interface_declaration,
@@ -217,18 +445,51 @@ module.exports = grammar({
217
445
  // §5.5 — command_chain is the parenthesis-free method-call
218
446
  // form (`println 'hello'`, `events 'a', 'b', 'c'`). v1 is
219
447
  // intentionally conservative: receiver is a bare identifier
220
- // and arguments are restricted to literal-shaped expressions
221
- // and closures (no risk of mis-parsing `foo bar` as a command
222
- // call on a bare identifier). Multi-argument lists are supported
223
- // (comma-separated literal arguments per Gradle / Jenkins DSL
224
- // idioms). Chained `foo bar baz` and complex argument shapes
225
- // land later. Closes a subset of murtaza64 #5.
448
+ // and the first argument is restricted to literal-shaped
449
+ // expressions, closures and named arguments (no risk of
450
+ // mis-parsing `foo bar` as a command call on a bare identifier).
451
+ // After a comma an argument is a named argument or any
452
+ // expression: Apache's `argumentListElement` without spread
453
+ // arguments (`foo 'a', *args` is an ERROR). Chained
454
+ // `foo bar baz` lands later. Closes a subset of murtaza64 #5.
226
455
  command_chain: $ => prec(2, seq(
227
456
  field('receiver', $.identifier),
228
- field('argument', $._command_argument),
229
- repeat(seq(',', field('argument', $._command_argument))),
457
+ field('argument', choice($._command_argument, alias($._command_named_argument, $.named_argument))),
458
+ repeat(seq(',', field('argument', choice(
459
+ alias($._command_named_argument, $.named_argument),
460
+ alias($._command_continued_named_argument, $.named_argument),
461
+ $._expression,
462
+ )))),
230
463
  )),
231
464
 
465
+ // §5.5 item 3 — named arguments in a parenthesis-free call:
466
+ // `exclude group: 'a', module: 'b'`, `archiveArtifacts artifacts: 'x'`,
467
+ // GORM's `name blank: false, size: 1..100`. `_command_named_key`
468
+ // is an empty token that the external scanner emits before a name
469
+ // only when `:` follows it on the same line, so `Type name = …` and
470
+ // a bare statement followed by a Spock label on the next line are
471
+ // unaffected. The name itself is an ordinary `identifier`. A
472
+ // keyword is a valid key (Apache `namedArgLabel`): it has no
473
+ // action after the empty token, so it lexes as an identifier, and
474
+ // the empty `property` set does the same for the reserved `new`.
475
+ _command_named_argument: $ => seq(
476
+ $._command_named_key,
477
+ field('key', reserved('property', $.identifier)),
478
+ ':',
479
+ field('value', $._expression),
480
+ ),
481
+
482
+ // After a comma a newline cannot end the statement, so a key on a
483
+ // continuation line (`sh script: 'make',` then `returnStdout: true`)
484
+ // needs no scanner token. Same-line keys normally come from the
485
+ // scanner; `case` and `default`, which the scanner rejects, reach
486
+ // this rule on the same line too (`foo 'a', default: 1`).
487
+ _command_continued_named_argument: $ => seq(
488
+ field('key', $.identifier),
489
+ ':',
490
+ field('value', $._expression),
491
+ ),
492
+
232
493
  _command_argument: $ => choice(
233
494
  $.string_literal,
234
495
  $.number_literal,
@@ -243,17 +504,18 @@ module.exports = grammar({
243
504
  // labeled_statement and expression_statement alive after
244
505
  // `identifier`; the `:` decides. A scanner-token form
245
506
  // (`_label_colon`) was attempted but interacted with
246
- // not-yet-implemented named-argument command chains
247
- // (`archiveArtifacts artifacts: 'x'`); see divergence #5.
507
+ // named-argument command chains (`archiveArtifacts artifacts: 'x'`),
508
+ // which now have their key decided by `_command_named_key`
509
+ // instead; see the §6.5 row in `docs/divergences-from-spec.md`.
248
510
  labeled_statement: $ => prec(1, seq(
249
511
  field('label', $.identifier),
250
512
  ':',
251
513
  field('statement', $._statement),
252
514
  )),
253
515
 
254
- // §4 — block of statements, used in control-flow bodies and
255
- // (eventually) method bodies. Shares `{ ... }` syntax with
256
- // closure (§5.8). A `prec(1, …)` keeps block preferred at use
516
+ // §4 — block of statements: control-flow, method and constructor
517
+ // bodies, static / instance initializers. Shares `{ ... }` syntax
518
+ // with closure (§5.8). A `prec(1, …)` keeps block preferred at use
257
519
  // sites where both `block` and a closure-bearing `_statement`
258
520
  // are valid alternatives (e.g. the body slot of `if` / `while`).
259
521
  block: $ => prec(1, seq(
@@ -370,8 +632,7 @@ module.exports = grammar({
370
632
  // §4 — try / catch / finally. At least one of catch/finally is
371
633
  // required per Java/Groovy semantics; the grammar relaxes that
372
634
  // to allow a bare `try { … }` and lets downstream tooling
373
- // surface the error if needed. Try-with-resources lands later
374
- // with local variable declarations.
635
+ // surface the error if needed.
375
636
  try_statement: $ => seq(
376
637
  'try',
377
638
  optional(field('resources', $.resource_specification)),
@@ -380,6 +641,16 @@ module.exports = grammar({
380
641
  optional($.finally_clause),
381
642
  ),
382
643
 
644
+ // §4 — `synchronized (lock) { … }` (Apache `#synchronizedStmtAlt`).
645
+ // The body must be a block.
646
+ synchronized_statement: $ => seq(
647
+ 'synchronized',
648
+ '(',
649
+ field('lock', $._expression),
650
+ ')',
651
+ field('body', $.block),
652
+ ),
653
+
383
654
  // §4 — `try (Foo f = expr; Bar b = expr) { … }`. Resources
384
655
  // are typed or `def`-style declarators with required `=`
385
656
  // initializer (per Java-style try-with-resources). Multiple
@@ -393,8 +664,15 @@ module.exports = grammar({
393
664
  ),
394
665
 
395
666
  resource: $ => seq(
396
- optional(field('type', $._type)),
397
- field('name', $.identifier),
667
+ optional('final'),
668
+ choice(
669
+ seq(
670
+ optional(choice('def', 'var', field('type', $._type))),
671
+ field('name', $.identifier),
672
+ ),
673
+ // `var` alone is the name: `try (var = open())`.
674
+ field('name', alias('var', $.identifier)),
675
+ ),
398
676
  '=',
399
677
  field('value', $._expression),
400
678
  ),
@@ -412,8 +690,15 @@ module.exports = grammar({
412
690
  // murtaza64 #39. The type itself is optional — Groovy allows a
413
691
  // bare `catch (e) { … }`, implicitly typed as Exception.
414
692
  catch_formal_parameter: $ => seq(
415
- optional(field('type', choice($._type, $.multi_type))),
416
- field('name', $.identifier),
693
+ optional('final'),
694
+ choice(
695
+ seq(
696
+ optional(choice('def', 'var', field('type', choice($._type, $.multi_type)))),
697
+ field('name', $.identifier),
698
+ ),
699
+ // `var` alone is the name: `catch (var)`.
700
+ field('name', alias('var', $.identifier)),
701
+ ),
417
702
  ),
418
703
 
419
704
  multi_type: $ => seq(
@@ -455,6 +740,7 @@ module.exports = grammar({
455
740
  field('name', $.identifier),
456
741
  optional(field('type_parameters', $.type_parameters)),
457
742
  optional($.extends_interfaces),
743
+ optional($.super_interfaces),
458
744
  optional($.permits_clause),
459
745
  field('body', $.class_body),
460
746
  ),
@@ -501,17 +787,17 @@ module.exports = grammar({
501
787
  repeat(seq(',', $._type)),
502
788
  ),
503
789
 
504
- // §4 — trait / interface extend multiple interfaces (no
505
- // `implements` keyword in that position).
790
+ // §4 — trait / interface list their super-interfaces with `extends`.
506
791
  extends_interfaces: $ => seq(
507
792
  'extends',
508
793
  $._type,
509
794
  repeat(seq(',', $._type)),
510
795
  ),
511
796
 
512
- // §4 — Java-style modifiers. Each one is a hard reserved
513
- // keyword (§5.2) so the `word: $.identifier` directive keeps
514
- // them from accidentally being treated as identifiers.
797
+ // §4 — Java-style modifiers. Each one is a hard reserved keyword
798
+ // in Groovy (§5.2). Here it is a keyword only where a modifier can
799
+ // stand; anywhere else the word lexes as an identifier, and input
800
+ // such as `foo(private)` parses with no ERROR (#93).
515
801
  _modifier: _ => choice(
516
802
  'public',
517
803
  'private',
@@ -545,30 +831,46 @@ module.exports = grammar({
545
831
  field('body', $.class_body),
546
832
  ),
547
833
 
548
- // §4 — `{ method* }` for v1. Field declarations, static
549
- // initialisers, and inner classes land later.
834
+ // §4 — member list shared by class / interface / trait / record /
835
+ // `@interface` bodies and the anonymous inner class body of
836
+ // `object_creation_expression`.
550
837
  // The body accepts `;` as an empty member / terminator the same
551
838
  // way statement lists do (§5.10): a field or abstract method is
552
839
  // commonly written `int x = 1;` / `void f();`, and a stray `;` is
553
840
  // a no-op member. `;` is anonymous, so it never appears in the AST.
841
+ //
842
+ // A bare `block` is an instance initializer. It sits in the member
843
+ // repeat — here and in the four identical repeats of `enum_body` —
844
+ // rather than in `_class_member`, because `enum_body` also places
845
+ // a lone `_class_member` directly after its constants. A block in
846
+ // that slot is an LR conflict on `A() {` (constructor, or constant
847
+ // plus initializer) and, once that is resolved, silently accepts
848
+ // `A { }` (a constant with an anonymous class body, unsupported)
849
+ // as constant-plus-initializer.
554
850
  class_body: $ => seq(
555
851
  '{',
556
- repeat(choice($._class_member, ';')),
852
+ repeat(choice($._class_member, $.block, ';')),
557
853
  '}',
558
854
  ),
559
855
 
560
- // A nested enum (`static enum EventType { … }` inside a domain
561
- // class) is common enough in real Groovy that leaving it out
562
- // silently misparses `enum` as a field_declaration's type name.
563
- // Nested class/interface/trait land separately (bigger surface,
564
- // own conflict set) — out of scope here.
565
- _class_member: $ => choice(
566
- $.method_declaration,
567
- $.field_declaration,
568
- $.constructor_declaration,
569
- $.static_initializer,
570
- $.enum_declaration,
571
- ),
856
+ // Nested type declarations are members, as in Apache's
857
+ // `memberDeclaration`. Each kind must be listed: a declaration
858
+ // keyword with no action at member start lexes as an identifier,
859
+ // so `class Inner { … }` would silently parse as a field `Inner`
860
+ // of type `class` followed by an instance initializer block, and
861
+ // a nested `record R(int x) { }` as a method `R` returning
862
+ // `record`. The record keyword comes from the scanner (§6.7), so
863
+ // listing it here does not reserve `record` as a member name.
864
+ //
865
+ // The price: `trait` and `sealed` are keywords wherever a member
866
+ // can start, as they already are where a statement can. A member
867
+ // cannot open with one of them as a plain identifier, with or
868
+ // without modifiers (`static trait = 1`, `sealed() { }`), nor use
869
+ // one as the name after `modifier(s) Type`, because `private Foo`
870
+ // is already a complete field (`private boolean sealed` is an
871
+ // ERROR; `boolean sealed` is not). See divergence 12. No
872
+ // `conflicts` entry is needed.
873
+ _class_member: $ => choice(...classMembers($, $.constructor_declaration)),
572
874
 
573
875
  // §4 — constructors share the method_declaration shape but have
574
876
  // no return type and the name matches the enclosing class. We
@@ -577,13 +879,16 @@ module.exports = grammar({
577
879
  // tell constructors apart from methods. `prec(3, …)` wins over
578
880
  // both field and method when the identifier is followed by `(`
579
881
  // and no return type precedes it.
580
- constructor_declaration: $ => prec.right(3, seq(
581
- repeat($.annotation),
582
- repeat($._modifier),
583
- field('name', $.identifier),
584
- field('parameters', $.formal_parameters),
585
- optional($.throws_clause),
586
- field('body', $.block),
882
+ constructor_declaration: $ => constructorDeclaration($, repeat($._modifier)),
883
+
884
+ // The constructor form for the member directly after an enum's
885
+ // trailing comma (see `enum_declaration`). Only access modifiers
886
+ // qualify: `static f() { }` there is a method. The weight is above
887
+ // a method with a body, which matches the same text through its
888
+ // modifier-only form.
889
+ _modified_constructor_declaration: $ => prec.dynamic(4, constructorDeclaration(
890
+ $,
891
+ repeat1(choice('public', 'private', 'protected')),
587
892
  )),
588
893
 
589
894
  // §4 — `static { … }` class-body initializer block. Runs once
@@ -607,38 +912,74 @@ module.exports = grammar({
607
912
  // would collide with a plain expression_statement.
608
913
  field_declaration: $ => choice(
609
914
  // Prefer the typed field when both parses succeed, rather than
610
- // splitting `private final int v\n C() {}` after `int`.
611
- prec.dynamic(1, seq(
915
+ // splitting `private final int v\n C() {}` after `int`. The
916
+ // weight is above a method body's: the split reading holds a
917
+ // method (`v C() {}`), which would otherwise tie.
918
+ prec.dynamic(4, seq(
612
919
  repeat($.annotation),
613
920
  repeat($._modifier),
614
921
  choice('def', field('type', $._type)),
615
922
  $.variable_declarator,
616
923
  repeat(seq(',', $.variable_declarator)),
617
924
  )),
618
- seq(
925
+ // The negative weight settles the split that the typed weight
926
+ // cannot. `private final int v` followed by `public A() { }` is
927
+ // also `private final int`, a field `v public` and a constructor
928
+ // `A() { }`: a keyword is an identifier wherever it has no
929
+ // action. Both readings hold one typed field, so they tied, and
930
+ // a comment between the two members made the split win.
931
+ prec.dynamic(-1, seq(
619
932
  repeat($.annotation),
620
933
  repeat1($._modifier),
621
934
  $.variable_declarator,
622
935
  repeat(seq(',', $.variable_declarator)),
623
- ),
936
+ )),
624
937
  ),
625
938
 
626
- // §4 — `def name(params) body`. Typed return type (`String foo()
627
- // { … }`) lands once we can disambiguate from local variable
628
- // declaration. Modifiers and throws clause similarly defer.
629
- // prec(1) wins over local_variable_declaration when `(` follows
630
- // the name, so `def f() { … }` at script-top-level parses as a
631
- // method rather than a `def f` variable followed by `(…) { … }`.
632
- method_declaration: $ => prec.right(2, seq(
633
- repeat($.annotation),
634
- repeat($._modifier),
635
- optional(field('type_parameters', $.method_type_parameters)),
636
- choice('def', field('return_type', $._type)),
637
- field('name', $._property_name),
638
- field('parameters', $.formal_parameters),
639
- optional($.throws_clause),
640
- optional(field('body', $.block)),
641
- )),
939
+ // §4 — `def name(params) body`, or a return type in place of
940
+ // `def`, with modifiers and a throws clause. The static precedence
941
+ // wins over local_variable_declaration when `(` follows the name,
942
+ // so `def f() { … }` at script-top-level parses as a method
943
+ // rather than a `def f` variable followed by `(…) { … }`.
944
+ // Modifiers alone (no `def`, no return type) also introduce a
945
+ // method outside a class body: `final f() { }`. In a class body
946
+ // that shape stays a constructor_declaration.
947
+ //
948
+ // A method with a body carries a dynamic precedence because its
949
+ // tokens also parse as statements: `String f() { }` as the
950
+ // expression `String` followed by the call `f() { }`, and
951
+ // `def f(a) { }` as a variable `f` followed by the cast
952
+ // `(a) { }`. Without a weight, a comment before the method made
953
+ // the split win. The weight is above the blank final local's
954
+ // (`final Type name`, see local_variable_declaration):
955
+ // `final String f(a) { }` is also that local followed by the cast
956
+ // `(a) { }`.
957
+ //
958
+ // A method without a body carries a negative one. Its tokens are
959
+ // also `x` followed by the call `foo()`, and outside a class body
960
+ // only that reading is valid Groovy: a script method needs a
961
+ // body. In a class body nothing competes, so abstract and
962
+ // interface methods are unaffected.
963
+ method_declaration: $ => {
964
+ const signature = seq(
965
+ repeat($.annotation),
966
+ choice(
967
+ seq(
968
+ repeat($._modifier),
969
+ optional(field('type_parameters', $.method_type_parameters)),
970
+ choice('def', field('return_type', $._type)),
971
+ ),
972
+ repeat1($._modifier),
973
+ ),
974
+ field('name', $._property_name),
975
+ field('parameters', $.formal_parameters),
976
+ optional($.throws_clause),
977
+ );
978
+ return prec.right(2, choice(
979
+ prec.dynamic(-1, signature),
980
+ prec.dynamic(3, seq(signature, field('body', $.block))),
981
+ ));
982
+ },
642
983
 
643
984
  // §4 / §5.14 — method-level generic type parameters
644
985
  // (`<T> T identity(T x) { x }`). Distinct from `type_parameters`
@@ -672,13 +1013,11 @@ module.exports = grammar({
672
1013
  // `@PathVariable`, `@RequestBody`, JPA's `@Param`, … — ubiquitous
673
1014
  // on framework-facing methods), optional type, optional varargs
674
1015
  // marker (`Type... name`), and optional default value
675
- // (`name = expr`).
676
- formal_parameter: $ => seq(
677
- repeat($.annotation),
678
- optional(field('type', choice($._type, $.varargs_type))),
679
- field('name', $.identifier),
680
- optional(seq('=', field('default', $._expression))),
681
- ),
1016
+ // (`name = expr`). `final` is the only modifier accepted here.
1017
+ // `def` and `var` stand in place of the type and are keywords, so
1018
+ // `def f(def a)` has no `type`. The shape is `parameter()`, shared
1019
+ // with `closure_parameter`.
1020
+ formal_parameter: $ => parameter($),
682
1021
 
683
1022
  varargs_type: $ => seq($._type, '...'),
684
1023
 
@@ -691,17 +1030,51 @@ module.exports = grammar({
691
1030
  // members follow after `;`, `,;`, or nothing at all — Groovy's
692
1031
  // own parser treats the newline as the separator (GROOVY-7773,
693
1032
  // GROOVY-9306), and newlines are extras here, so the member
694
- // simply follows the last constant. `A,` directly before a
695
- // member is rejected, as in Groovy. With no constants the body
696
- // is an ordinary member list. The member list is spelled three
697
- // times rather than shared with `class_body` through a hidden
698
- // rule: a new rule renumbers the aux symbols and ~100 symbol ids,
699
- // which a patch release must not do.
1033
+ // simply follows the last constant. With no constants the body
1034
+ // is an ordinary member list.
1035
+ //
1036
+ // Groovy up to 4.x also accepts a member directly after a trailing
1037
+ // `,` (`A, B,\n private int x`): GroovyParser.g4 on those branches
1038
+ // has `enumConstants (nls COMMA)? sep?` before the member list.
1039
+ // Groovy 5 requires a `;`. Without this alternative the modifier
1040
+ // had no action after the `,`, lexed as an identifier, and became
1041
+ // a constant named `private` with no ERROR.
1042
+ //
1043
+ // The alternative is narrower than Groovy, which takes any member
1044
+ // there (divergence 13). `prec(1)` on `enum_constant` keeps a bare
1045
+ // identifier after the `,` a constant, so the member has to start
1046
+ // with something that cannot be one: a modifier, `def`, a
1047
+ // declaration keyword, or an annotation followed by one of those.
1048
+ // `A,\n String x` is an ERROR, and so is an instance initializer.
1049
+ // A constructor needs an access modifier. `B(x) { … }` after a
1050
+ // `,`, with or without annotations, reads as a constant with an
1051
+ // anonymous class body (unsupported, so an ERROR). With an access
1052
+ // modifier it cannot be a constant, and with no constructor form
1053
+ // here `private B(x) { }` parsed, with no ERROR, as a method named
1054
+ // `B`: the modifier-only form of `method_declaration` took it.
1055
+ // Other modifiers do not make a constructor, so `static f() { }`
1056
+ // is a method.
1057
+ //
1058
+ // An instance initializer (`block`) is accepted wherever the
1059
+ // member list repeats — after `;`, after a first member, or with
1060
+ // no constants — but not directly after a constant. Newlines are
1061
+ // extras, so `A\n{ … }` (in the .g4 a constant, then an
1062
+ // initializer) cannot be told from `A { … }` (a constant with an
1063
+ // anonymous class body, unsupported); both stay errors.
1064
+ //
1065
+ // The four member repeats are spelled out, and must stay
1066
+ // identical to the one in `class_body`, so that the generator
1067
+ // folds all five into one aux symbol (`aux_sym_class_body_repeat1`).
1068
+ // A differing copy, or a hidden rule that is not inlined, adds a
1069
+ // symbol and renumbers every id after it — the alias kinds
1070
+ // `named_argument`, `quoted_identifier` and `type_identifier`
1071
+ // included — which a patch release must not do.
700
1072
  enum_declaration: $ => seq(
701
1073
  repeat($.annotation),
702
1074
  repeat($._modifier),
703
1075
  'enum',
704
1076
  field('name', $.identifier),
1077
+ optional($.super_interfaces),
705
1078
  field('body', $.enum_body),
706
1079
  ),
707
1080
 
@@ -713,11 +1086,19 @@ module.exports = grammar({
713
1086
  repeat(seq(',', $.enum_constant)),
714
1087
  optional(choice(
715
1088
  ',',
716
- seq(optional(','), ';', repeat(choice($._class_member, ';'))),
717
- seq($._class_member, repeat(choice($._class_member, ';'))),
1089
+ seq(optional(','), ';', repeat(choice($._class_member, $.block, ';'))),
1090
+ seq($._class_member, repeat(choice($._class_member, $.block, ';'))),
1091
+ seq(
1092
+ ',',
1093
+ choice(...classMembers(
1094
+ $,
1095
+ alias($._modified_constructor_declaration, $.constructor_declaration),
1096
+ )),
1097
+ repeat(choice($._class_member, $.block, ';')),
1098
+ ),
718
1099
  )),
719
1100
  ),
720
- repeat(choice($._class_member, ';')),
1101
+ repeat(choice($._class_member, $.block, ';')),
721
1102
  ),
722
1103
  '}',
723
1104
  ),
@@ -733,22 +1114,63 @@ module.exports = grammar({
733
1114
  // with an `[enum_constant, _type]` conflict: both yield the same
734
1115
  // tree on every valid shape, but the GLR form silently accepts
735
1116
  // `A\n B` (constants missing their comma, which Groovy rejects) as
736
- // a field `A B`, where this form reports the ERROR.
737
- enum_constant: $ => prec(1, seq(
738
- field('name', $.identifier),
739
- optional(field('arguments', $.argument_list)),
740
- )),
1117
+ // a field `A B`, where this form reports the ERROR. Annotations
1118
+ // share the prefix with an annotated member; the same precedence
1119
+ // decides after them, so `@Foo A\n int x` is a constant and a
1120
+ // field.
1121
+ enum_constant: $ => choice(
1122
+ prec(1, seq(
1123
+ repeat($.annotation),
1124
+ field('name', $.identifier),
1125
+ optional(field('arguments', $.argument_list)),
1126
+ )),
1127
+ // `sealed` and `trait` are keywords wherever a member can start
1128
+ // (divergence 12): at the first constant and, since #89, after
1129
+ // every `,`. A constant may still have either name, so the
1130
+ // keyword is accepted as one. The negative precedence gives way
1131
+ // to a declaration when one follows: `sealed class`, `trait T {`.
1132
+ prec(-1, seq(
1133
+ repeat($.annotation),
1134
+ field('name', alias(choice('sealed', 'trait'), $.identifier)),
1135
+ optional(field('arguments', $.argument_list)),
1136
+ )),
1137
+ ),
741
1138
 
742
- // §4 — record (Groovy 4+). `record Name(Type a, Type b) [{ body }]`.
743
- // `record` is a contextual keyword — tree-sitter's word: directive
744
- // keeps `record` usable as a plain identifier elsewhere.
745
- record_declaration: $ => prec.right(seq(
1139
+ // §4 — record (Groovy 4+), after Apache's `classDeclaration`:
1140
+ // `[modifiers] record Name[<T>](Type a, Type b) [implements I] [{ body }]`.
1141
+ // Records cannot `extends`, and the body is optional here where
1142
+ // Groovy requires it.
1143
+ // §5.2 / §6.7 — `record` is a contextual keyword. The keyword
1144
+ // comes from the external scanner, which emits it only when a
1145
+ // name follows on the same line and `(` or `<` after that; in
1146
+ // every other position the word lexes as `identifier`. A grammar literal
1147
+ // cannot do this: keyword extraction yields the keyword wherever
1148
+ // it has an action, which made `record.key()` at statement start,
1149
+ // and `private Record record` once record_declaration became a
1150
+ // class member, errors. The alias keeps the anonymous `record`
1151
+ // node that the queries capture.
1152
+ //
1153
+ // The dynamic precedence settles a GLR tie the scanner creates.
1154
+ // After `private Record`, the `[variable_declarator, _type]`
1155
+ // conflict forks on the next word: `record` is the field's name
1156
+ // in one branch and a type in the other. When a record header
1157
+ // follows on the next line, the first branch lexes its `record`
1158
+ // as the keyword and the second as that field's name, and both
1159
+ // survive (`private Record` / `record record` / constructor
1160
+ // `Inner(int x) { }` is a valid member list). Without a weight,
1161
+ // which tree wins depends on tree shape, and a comment between
1162
+ // the two lines flipped it. Favouring the record declaration is
1163
+ // right whenever both parse.
1164
+ record_declaration: $ => prec.dynamic(1, prec.right(seq(
746
1165
  repeat($.annotation),
747
- 'record',
1166
+ repeat($._modifier),
1167
+ alias($._record_keyword, 'record'),
748
1168
  field('name', $.identifier),
1169
+ optional(field('type_parameters', $.type_parameters)),
749
1170
  field('components', $.record_components),
1171
+ optional($.super_interfaces),
750
1172
  optional(field('body', $.class_body)),
751
- )),
1173
+ ))),
752
1174
 
753
1175
  record_components: $ => seq(
754
1176
  '(',
@@ -767,6 +1189,7 @@ module.exports = grammar({
767
1189
  // §4 — package and import. Trailing `;` is optional in Groovy;
768
1190
  // we accept both forms by not requiring it.
769
1191
  package_declaration: $ => seq(
1192
+ repeat($.annotation),
770
1193
  'package',
771
1194
  field('name', $.qualified_name),
772
1195
  ),
@@ -777,6 +1200,7 @@ module.exports = grammar({
777
1200
  // imports only appear in this position, so the lexer-wide
778
1201
  // longest-match is safe.
779
1202
  import_declaration: $ => seq(
1203
+ repeat($.annotation),
780
1204
  'import',
781
1205
  optional('static'),
782
1206
  field('name', $.qualified_name),
@@ -795,19 +1219,80 @@ module.exports = grammar({
795
1219
  // would conflict with method_invocation `Type(x)` and is
796
1220
  // disallowed in v1. Multiple declarators per statement
797
1221
  // (`def a = 1, b = 2`) are supported in all three forms.
1222
+ // `final` is the only modifier accepted here.
1223
+ // `final x = 1` with no type or `def` is the modifier-only form;
1224
+ // the variable is dynamically typed, as with `def`. `final` also
1225
+ // allows the typed form without an initializer (`final String
1226
+ // name`, a blank final), with a single declarator.
1227
+ //
1228
+ // The typed forms carry a dynamic precedence because their tokens
1229
+ // also parse another way: `String s = 'a'` as the expression
1230
+ // `String` followed by `s = 'a'`, and `final String s = 'a'` as
1231
+ // the modifier-only `final String` followed by `s = 'a'`. Without
1232
+ // a weight, which tree wins depends on tree shape, and a comment
1233
+ // before the declaration flipped it. The blank form ranks above
1234
+ // the initialized one, or `final String name` followed by
1235
+ // `name = 'a'` would tie with `final String` followed by
1236
+ // `name name = 'a'`.
1237
+ //
1238
+ // Newlines do not end a declaration, so these read wrongly with
1239
+ // no ERROR node:
1240
+ // - `final x` followed by a line that starts with an identifier
1241
+ // reads `x` as the type and that identifier as the name. `y = 2`
1242
+ // becomes `final x y = 2`, the same resolution modifier-only
1243
+ // fields get (`static x` then `y = 1`), and `String s = 'a'`
1244
+ // becomes `final x String` followed by `s = 'a'`.
1245
+ // - `final String name` followed by a line reading `foo() { }` is
1246
+ // `final String` followed by the method `name foo() { }`. A
1247
+ // method with a body outranks the blank form, so that
1248
+ // `final String f(a) { }` stays a method (see method_declaration).
1249
+ // - A bare `x` followed by a line reading `y = 1` is the typed
1250
+ // declaration `x y = 1`.
1251
+ //
1252
+ // Annotations may come first on every form (Apache
1253
+ // `variableModifier`): `@Field def x = 1` in a script,
1254
+ // `@SuppressWarnings('unchecked') List<String> xs = []` in a body.
798
1255
  local_variable_declaration: $ => prec.right(choice(
799
1256
  seq(
1257
+ repeat($.annotation),
1258
+ optional('final'),
800
1259
  choice('def', 'var'),
801
1260
  $.variable_declarator,
802
1261
  repeat(seq(',', $.variable_declarator)),
803
1262
  ),
804
- seq(
1263
+ prec.dynamic(1, seq(
1264
+ repeat($.annotation),
1265
+ optional('final'),
805
1266
  field('type', $._type),
806
1267
  $._initialized_declarator,
807
1268
  repeat(seq(',', $._initialized_declarator)),
1269
+ )),
1270
+ seq(
1271
+ repeat($.annotation),
1272
+ 'final',
1273
+ $.variable_declarator,
1274
+ repeat(seq(',', $.variable_declarator)),
808
1275
  ),
1276
+ prec.dynamic(2, seq(
1277
+ repeat($.annotation),
1278
+ 'final',
1279
+ field('type', $._type),
1280
+ field('name', $.identifier),
1281
+ )),
1282
+ prec.dynamic(2, seq(
1283
+ repeat1($.annotation),
1284
+ alias($._placeholder_declarator, $.variable_declarator),
1285
+ )),
809
1286
  )),
810
1287
 
1288
+ // `@Library('shared') _`, the Jenkins idiom: an annotation needs a
1289
+ // declaration to stand on, and `_` is the name used for it. Apache
1290
+ // takes any name there (`variableModifiers variableDeclarators`).
1291
+ // Only `_` is accepted here, as a literal: with any identifier,
1292
+ // `@A x` followed by `y = 1` on the next line would also be a typed
1293
+ // local `x y = 1`, and nothing but the line break tells them apart.
1294
+ _placeholder_declarator: $ => field('name', alias('_', $.identifier)),
1295
+
811
1296
  _initialized_declarator: $ => seq(
812
1297
  field('name', $.identifier),
813
1298
  '=',
@@ -862,6 +1347,7 @@ module.exports = grammar({
862
1347
  for_in_statement: $ => seq(
863
1348
  'for',
864
1349
  '(',
1350
+ optional('final'),
865
1351
  optional(choice('def', field('type', $._type))),
866
1352
  field('variable', $.identifier),
867
1353
  choice('in', ':'),
@@ -870,7 +1356,29 @@ module.exports = grammar({
870
1356
  field('body', choice($.block, $._statement)),
871
1357
  ),
872
1358
 
873
- expression_statement: $ => $._expression,
1359
+ // A statement that is `name = value` keeps the name unreduced.
1360
+ // A closure can open with the same tokens as a parameter with a
1361
+ // default (`{ a = 1 -> a }`), and so can an `if` / `while` / `for`
1362
+ // block, because its `{` may also open a closure. With `name`
1363
+ // already reduced to an expression, the two readings needed a
1364
+ // fork that ran to the end of the value: 14% to 32% more work for
1365
+ // `ext { version = '1.0' }` or `if (c) { a = 1 }`, and twice the
1366
+ // work for a long value. Here both readings shift the `=` and one
1367
+ // stack parses the value; the token after it decides.
1368
+ //
1369
+ // The form is limited to the start of a statement. Inside an
1370
+ // expression it would take `b = 1` out of `a + b = 1`, which the
1371
+ // operator precedence reads as `(a + b) = 1`.
1372
+ expression_statement: $ => choice(
1373
+ $._expression,
1374
+ alias($._statement_assignment, $.assignment_expression),
1375
+ ),
1376
+
1377
+ _statement_assignment: $ => prec.right(PREC.ASSIGN, seq(
1378
+ field('left', $.identifier),
1379
+ field('operator', '='),
1380
+ field('right', $._expression),
1381
+ )),
874
1382
 
875
1383
  // §3.2 PRIMARY — minimal alternative set for now. Every primary
876
1384
  // expression form from §3.2 / §5 will land in this choice over
@@ -1001,21 +1509,18 @@ module.exports = grammar({
1001
1509
  optional($._dotted_type_tail),
1002
1510
  )),
1003
1511
 
1004
- // §3.2 — `x in xs` and `x !in xs`. RELATIONAL level. Both
1512
+ // §3.2 / §3.2.2 — `x in xs` and `x !in xs`. RELATIONAL level. Both
1005
1513
  // operators share one node kind; the `operator` field
1006
- // distinguishes them. `!in` is wrapped in `token(prec(1, …))`
1007
- // so it lexes as a single token despite the embedded space
1008
- // requirement implied by §3.2.2's trailing-context rule —
1009
- // Apache's `NOT_IN` predicate is approximated by requiring at
1010
- // least one trailing whitespace, `[`, `(`, or `{` after `!in`.
1011
- // §3.2 / §3.2.2 — `x in xs` and `x !in xs`. `!in` is a single
1012
- // token whose match requires a trailing whitespace / bracket
1013
- // character (Apache `NOT_IN` predicate) so `a !inXs` does not
1014
- // mis-tokenise as `!in` followed by `Xs`.
1514
+ // distinguishes them. `!in` is an operator only before whitespace
1515
+ // or `[`, `(`, `{` (Apache's `NOT_IN` predicate), so that
1516
+ // `a !inXs` is not `!in` followed by `Xs`. The external scanner
1517
+ // makes that check (§6.12) and leaves the character where it is.
1518
+ // As a regex the token had to include it, which made
1519
+ // `a !in[1, 2]` an ERROR: the `[` was part of the operator.
1015
1520
  membership_expression: $ => {
1016
1521
  const ops = [
1017
1522
  'in',
1018
- token(prec(1, seq('!in', /[ \t\r\n\[({]/))),
1523
+ alias($._not_in, '!in'),
1019
1524
  ];
1020
1525
  return choice(...ops.map(op => prec.left(PREC.RELATIONAL, seq(
1021
1526
  field('element', $._expression),
@@ -1041,15 +1546,34 @@ module.exports = grammar({
1041
1546
  ))));
1042
1547
  },
1043
1548
 
1044
- // §3.2 / §5.15 — `new Foo(args)`. We only handle the plain
1045
- // constructor-call form here; array creation `new Foo[10]`,
1046
- // generic types, and array initialisers land later. PREC.PRIMARY
1047
- // so it composes with the access tier from the left
1048
- // (`new Foo().bar`).
1549
+ // §3.2 — `new Foo(args)` and the anonymous inner class
1550
+ // `new Foo(args) { members }`. Array creation `new Foo[10]` and
1551
+ // array initialisers land later. PREC.PRIMARY only labels the
1552
+ // §3.1 tier. The number decides nothing: the rule's one conflict
1553
+ // (below) is against itself, where it cancels out, and
1554
+ // `new Foo().bar` composes without any precedence.
1555
+ //
1556
+ // The optional body takes every `{` that follows the arguments.
1557
+ // Right associativity does that statically — the shift into
1558
+ // `class_body` beats reducing the bodiless form — so no conflict
1559
+ // is declared and the closure reading never forks.
1560
+ //
1561
+ // Apache is narrower. Its `creator` has no `nls` before the body,
1562
+ // so `new T()\n{ … }` is a closure called on the new object
1563
+ // (observed on Groovy 4.0.33). By the same grammar a same-line
1564
+ // `{` whose content cannot be class members should be one too
1565
+ // (`new T() { x -> x }`; not run through the compiler). Here both
1566
+ // are read as a body, usually with an ERROR in it (divergence 11).
1567
+ // Parsing them needs a declared conflict on this rule with
1568
+ // `prec.dynamic` on the body, and that form was not taken: a body
1569
+ // holding one member `class_body` cannot parse, or one still
1570
+ // being typed, would then fall back silently to the closure tree
1571
+ // that #68 reported.
1049
1572
  object_creation_expression: $ => prec.right(PREC.PRIMARY, seq(
1050
1573
  'new',
1051
1574
  field('type', choice($._type, alias($._diamond_type, $.generic_type))),
1052
1575
  field('arguments', $.argument_list),
1576
+ optional(field('body', $.class_body)),
1053
1577
  )),
1054
1578
 
1055
1579
  // §3.2 — Apache's createdName permits diamond, but ordinary types
@@ -1069,12 +1593,47 @@ module.exports = grammar({
1069
1593
  // by tree-sitter's GLR; declared as a conflict if needed).
1070
1594
  // PREC.UNARY right-associative so `(Foo) -x` parses as
1071
1595
  // `(Foo)(-x)` and the type binds to the rightward expression.
1072
- parenthesized_type_cast: $ => prec.right(PREC.UNARY, seq(
1073
- '(',
1074
- field('type', $._type),
1075
- ')',
1076
- field('value', $._expression),
1077
- )),
1596
+ //
1597
+ // Two weights rank the cast against the other reading of the same
1598
+ // tokens, a parenthesized expression followed by something. Both
1599
+ // follow Apache's `castParExpression castOperandExpression`.
1600
+ //
1601
+ // With the operand on the line of the `)`, the cast wins wherever
1602
+ // it parses, as the cast alternative comes first in Apache's
1603
+ // `expression`: `(a) + b`, `(a) [0]` and `(a) (b)` are casts.
1604
+ // `_cast_close` (§6.11) is the `)` that has something after it on
1605
+ // its line.
1606
+ //
1607
+ // With the operand on a later line, the cast loses to any other
1608
+ // complete reading. Apache's rule has no `nls` between the two
1609
+ // parts, so where a line break can end a statement, `x = (a)`
1610
+ // followed by `foo()` is two statements. Inside `(…)` and `[…]`
1611
+ // Groovy ignores line breaks and reads a cast. Rejecting the cast
1612
+ // outright would lose every such case: the scanner cannot tell
1613
+ // which brackets enclose it. Ranking it last keeps the ones where
1614
+ // nothing else parses, `foo((String)` followed by `x)`. It loses
1615
+ // the ones where the later line can also continue the expression:
1616
+ // `foo((a)` followed by `- b)` is a subtraction here and a cast
1617
+ // in Groovy (divergence 15, #99).
1618
+ //
1619
+ // Without the weights nothing ranked the two readings and the
1620
+ // stack order decided. Inside a closure or block, `a = (int) y`
1621
+ // followed by a line that starts with a literal lost the cast
1622
+ // once #83 added its forks.
1623
+ parenthesized_type_cast: $ => choice(
1624
+ prec.dynamic(1, prec.right(PREC.UNARY, seq(
1625
+ '(',
1626
+ field('type', $._type),
1627
+ alias($._cast_close, ')'),
1628
+ field('value', $._expression),
1629
+ ))),
1630
+ prec.dynamic(-1, prec.right(PREC.UNARY, seq(
1631
+ '(',
1632
+ field('type', $._type),
1633
+ ')',
1634
+ field('value', $._expression),
1635
+ ))),
1636
+ ),
1078
1637
 
1079
1638
  // §4 — `_type`. Supports unqualified type identifiers,
1080
1639
  // qualified types (`java.util.List`), array types
@@ -1101,7 +1660,7 @@ module.exports = grammar({
1101
1660
  repeat1(seq('.', alias($.identifier, $.type_identifier))),
1102
1661
  )),
1103
1662
 
1104
- array_type: $ => prec(PREC.ARRAY_TYPE, seq($._type, '[', ']')),
1663
+ array_type: $ => prec(PREC.ARRAY_TYPE, seq($._type, alias($._subscript_open, '['), ']')),
1105
1664
 
1106
1665
  // §4 / §5.14 — Java-style generic type arguments. Allows nested
1107
1666
  // generics (`Map<String, List<Integer>>`) and bounded wildcards
@@ -1190,7 +1749,7 @@ module.exports = grammar({
1190
1749
  // keywords, or special chars. `map."key with spaces"` and
1191
1750
  // `def "abstract"() { … }` both rely on this.
1192
1751
  _property_name: $ => choice(
1193
- $.identifier,
1752
+ reserved('property', $.identifier),
1194
1753
  alias($.string_literal, $.quoted_identifier),
1195
1754
  ),
1196
1755
 
@@ -1256,7 +1815,7 @@ module.exports = grammar({
1256
1815
  // §3.2 / §5.11 — argument list. Positional args are `_expression`;
1257
1816
  // named args (Groovy's `k: v` in call position) are `map_entry`
1258
1817
  // aliased to `named_argument` so downstream tools can tell them
1259
- // apart from positional values. Spread (`*expr`) lands later.
1818
+ // apart from positional values.
1260
1819
  argument_list: $ => seq(
1261
1820
  '(',
1262
1821
  optional(seq(
@@ -1285,9 +1844,12 @@ module.exports = grammar({
1285
1844
  // explicit ask of dekobon #247 for the `?[]` row. Both at
1286
1845
  // PREC.POSTFIX, left-associative — `a[b][c]` parses as
1287
1846
  // `(a[b])[c]`.
1847
+ // `[` must be on the object's line (see `_subscript_open`): a Grails
1848
+ // controller action that ends in `[model: value]` on its own line returns
1849
+ // a map; it isn't a subscript of the statement before it.
1288
1850
  subscript_expression: $ => prec.left(PREC.POSTFIX, seq(
1289
1851
  field('object', $._expression),
1290
- '[',
1852
+ alias($._subscript_open, '['),
1291
1853
  field('index', $._expression),
1292
1854
  ']',
1293
1855
  )),
@@ -1295,6 +1857,9 @@ module.exports = grammar({
1295
1857
  // `?[` is one token. `a ? [b] : c` (with space) still parses
1296
1858
  // as ternary plus list because tree-sitter's lexer never
1297
1859
  // crosses a whitespace boundary to extend a multi-char token.
1860
+ // Unlike `[` (see `_subscript_open`), `?[` may still follow a
1861
+ // newline: no statement starts with `?[`, so there is nothing
1862
+ // to split off.
1298
1863
  safe_subscript_expression: $ => prec.left(PREC.POSTFIX, seq(
1299
1864
  field('object', $._expression),
1300
1865
  '?[',
@@ -1448,7 +2013,7 @@ module.exports = grammar({
1448
2013
  ['%', PREC.MULTIPLICATIVE],
1449
2014
  // SHIFT — §3.1 level 6. Ranges (`..`, `..<`, etc.) share
1450
2015
  // this precedence level but use distinct node kinds, so
1451
- // they live in their own rule (lands later).
2016
+ // they live in their own rule.
1452
2017
  ['<<', PREC.SHIFT_OR_RANGE],
1453
2018
  ['>>', PREC.SHIFT_OR_RANGE],
1454
2019
  ['>>>', PREC.SHIFT_OR_RANGE],
@@ -1486,7 +2051,12 @@ module.exports = grammar({
1486
2051
  // form; `{ a, b -> body }` has identifier parameters;
1487
2052
  // `{ String a, int b -> body }` has typed parameters; `{ body }`
1488
2053
  // has no `->` and an implicit `it` parameter (we do NOT emit a
1489
- // synthetic `it` per §5.8). Default values and varargs land later.
2054
+ // synthetic `it` per §5.8). A parameter takes what a method
2055
+ // parameter does (Apache's closure uses `formalParameterList`):
2056
+ // annotations, `final`, then `def`, `var` or a type (varargs
2057
+ // included), and a default; both rules are `parameter()`. The
2058
+ // body may open with the same words, so the `->` decides between
2059
+ // the two readings.
1490
2060
  closure: $ => seq(
1491
2061
  '{',
1492
2062
  optional($.closure_parameters),
@@ -1502,18 +2072,18 @@ module.exports = grammar({
1502
2072
  '->',
1503
2073
  ),
1504
2074
 
1505
- closure_parameter: $ => seq(
1506
- optional(field('type', $._type)),
1507
- field('name', $.identifier),
1508
- ),
2075
+ closure_parameter: $ => parameter($),
1509
2076
 
1510
2077
  // §3.2 PRIMARY / §5.13 — list literal with trailing-comma support.
1511
2078
  // Empty list is `[]`; the empty map literal is the distinct `[:]`
1512
- // form (see map_literal). Tree-sitter splits the parse between
1513
- // list_literal and map_literal until a `:` or `]` disambiguates;
1514
- // the conflict declaration above keeps both alternatives alive.
2079
+ // form (see map_literal). After the first element, a `:` or its
2080
+ // absence tells a list from a map within one token of lookahead,
2081
+ // so no conflict entry is needed.
2082
+ // Either `[` token opens a literal, so a same-line `[` resolves as
2083
+ // it did with one token: `if (a) { } [1].each { }` is still a block
2084
+ // followed by a list, not a subscripted closure.
1515
2085
  list_literal: $ => seq(
1516
- '[',
2086
+ choice('[', alias($._subscript_open, '[')),
1517
2087
  optional(seq(
1518
2088
  $._expression,
1519
2089
  repeat(seq(',', $._expression)),
@@ -1531,7 +2101,7 @@ module.exports = grammar({
1531
2101
  map_literal: $ => {
1532
2102
  const entry = choice($.map_entry, $.spread_map_entry);
1533
2103
  return seq(
1534
- '[',
2104
+ choice('[', alias($._subscript_open, '[')),
1535
2105
  choice(
1536
2106
  ':',
1537
2107
  seq(
@@ -1560,9 +2130,15 @@ module.exports = grammar({
1560
2130
  ),
1561
2131
 
1562
2132
  // §3.2 PRIMARY — `( expr )`. Distinct from `parenthesized_type_cast`
1563
- // (§5.15), which lands once we have `_type`. The parser disambiguates
1564
- // by what's inside the parens.
1565
- parenthesized_expression: $ => seq('(', $._expression, ')'),
2133
+ // (§5.15); the parser disambiguates by what's inside the parens
2134
+ // and after them. `_cast_close` is the `)` that has something
2135
+ // after it on its line (§6.11). It closes this rule too, so that
2136
+ // `(a) * b` and `((a))` stay open to both readings.
2137
+ parenthesized_expression: $ => seq(
2138
+ '(',
2139
+ $._expression,
2140
+ choice(')', alias($._cast_close, ')')),
2141
+ ),
1566
2142
 
1567
2143
  // §3.2 — single `unary_expression` node kind but two precedence
1568
2144
  // alternatives, matching Apache §3.1:
@@ -1673,17 +2249,27 @@ module.exports = grammar({
1673
2249
 
1674
2250
  // §5.7 — triple-double GString. Like `_double_quoted_string`
1675
2251
  // but newlines and embedded `"` / `""` are part of the body.
2252
+ //
2253
+ // One or two quotes are text when an ordinary character or an
2254
+ // escape follows them. Before `$` they are lexed one at a time, as
2255
+ // fragments of their own: the text token must not take a `$` that
2256
+ // starts an interpolation (`"""say "$name"""`), and a regex
2257
+ // cannot look ahead. The closer is longer than one quote, so it
2258
+ // still wins at `"""`.
1676
2259
  _triple_double_quoted_string: $ => seq(
1677
2260
  '"""',
1678
- repeat(gstringPart($, $._triple_gstring_text)),
2261
+ repeat(choice(
2262
+ gstringPart($, $._triple_gstring_text),
2263
+ alias(token.immediate('"'), $.string_fragment),
2264
+ )),
1679
2265
  token.immediate('"""'),
1680
2266
  ),
1681
2267
 
1682
2268
  _triple_gstring_text: _ => token.immediate(repeat1(choice(
1683
2269
  /[^"\\$]/,
1684
2270
  /\\[\s\S]/,
1685
- /"[^"]/,
1686
- /""[^"]/,
2271
+ /"(\\[\s\S]|[^"\\$])/,
2272
+ /""(\\[\s\S]|[^"\\$])/,
1687
2273
  ))),
1688
2274
 
1689
2275
  // §5.7 — `$identifier(.identifier)*` interpolation. The whole
@@ -1697,9 +2283,9 @@ module.exports = grammar({
1697
2283
  )),
1698
2284
  ),
1699
2285
 
1700
- _gstring_dollar_path: _ => token.immediate(
1701
- /\$[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*/,
1702
- ),
2286
+ _gstring_dollar_path: _ => token.immediate(new RustRegex(
2287
+ String.raw`\$${identifierPattern(false)}(?:\.${identifierPattern(false)})*`,
2288
+ )),
1703
2289
 
1704
2290
  // §5.7 / §6.3 — `${expression}` interpolation.
1705
2291
  gstring_brace_interpolation: $ => seq(
@@ -1715,15 +2301,25 @@ module.exports = grammar({
1715
2301
  // `$$` (literal `$`), `$/` (literal `/`), and any other
1716
2302
  // non-`/` non-`$` char. The closer `/$` is `token.immediate`
1717
2303
  // so it always wins over text when `/` is followed by `$`.
2304
+ //
2305
+ // A run of slashes is text only up to an ordinary character
2306
+ // (`a//b`). The text token must not take a `/` that the closer
2307
+ // needs, and a regex cannot look ahead, so the slashes of a run
2308
+ // that ends at `$` are lexed one at a time: for `//$` the single
2309
+ // `/` matches first, then `/$` is the longer match and closes
2310
+ // the string. Each such slash is its own `string_fragment`.
1718
2311
  _dollar_slashy_string: $ => seq(
1719
2312
  '$/',
1720
- repeat(gstringPart($, $._dollar_slashy_text)),
2313
+ repeat(choice(
2314
+ gstringPart($, $._dollar_slashy_text),
2315
+ alias(token.immediate('/'), $.string_fragment),
2316
+ )),
1721
2317
  token.immediate('/$'),
1722
2318
  ),
1723
2319
 
1724
2320
  _dollar_slashy_text: _ => token.immediate(repeat1(choice(
1725
2321
  /[^/$]/,
1726
- /\/[^$]/,
2322
+ /\/+[^/$]/,
1727
2323
  /\$\$/,
1728
2324
  /\$\//,
1729
2325
  ))),
@@ -1741,6 +2337,8 @@ module.exports = grammar({
1741
2337
  /[0-9][0-9_]*[GgLlIiDdFf]?/,
1742
2338
  )),
1743
2339
 
1744
- identifier: _ => /[A-Za-z_$][A-Za-z0-9_$]*/,
2340
+ // Groovy's lexer takes any Java letter, not only ASCII; see
2341
+ // `identifierPattern` above for the classes.
2342
+ identifier: _ => new RustRegex(identifierPattern(true)),
1745
2343
  },
1746
2344
  });