@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/README.md +42 -0
- package/grammar.js +752 -154
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@dekobon+tree-sitter-groovy.node +0 -0
- package/prebuilds/linux-x64/@dekobon+tree-sitter-groovy.node +0 -0
- package/prebuilds/win32-x64/@dekobon+tree-sitter-groovy.node +0 -0
- package/queries/groovy/highlights.scm +10 -4
- package/queries/groovy/locals.scm +7 -0
- package/queries/groovy/tags.scm +32 -0
- package/src/grammar.json +1881 -439
- package/src/node-types.json +673 -1
- package/src/parser.c +195459 -140150
- package/src/scanner.c +391 -10
- package/tree-sitter.json +2 -1
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
|
|
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
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
//
|
|
79
|
-
//
|
|
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
|
-
//
|
|
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
|
|
221
|
-
//
|
|
222
|
-
// call on a bare identifier).
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
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',
|
|
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
|
-
//
|
|
247
|
-
//
|
|
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
|
|
255
|
-
//
|
|
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.
|
|
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(
|
|
397
|
-
|
|
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(
|
|
416
|
-
|
|
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
|
|
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
|
-
//
|
|
514
|
-
//
|
|
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 —
|
|
549
|
-
//
|
|
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
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
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: $ =>
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
627
|
-
//
|
|
628
|
-
//
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
//
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
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
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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.
|
|
695
|
-
//
|
|
696
|
-
//
|
|
697
|
-
//
|
|
698
|
-
//
|
|
699
|
-
//
|
|
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
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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+)
|
|
743
|
-
// `record
|
|
744
|
-
//
|
|
745
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1007
|
-
//
|
|
1008
|
-
//
|
|
1009
|
-
//
|
|
1010
|
-
//
|
|
1011
|
-
//
|
|
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
|
-
|
|
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
|
|
1045
|
-
//
|
|
1046
|
-
//
|
|
1047
|
-
//
|
|
1048
|
-
// (
|
|
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
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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.
|
|
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
|
|
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).
|
|
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: $ =>
|
|
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).
|
|
1513
|
-
//
|
|
1514
|
-
//
|
|
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)
|
|
1564
|
-
//
|
|
1565
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
});
|