@dekobon/tree-sitter-groovy 0.3.0 → 0.5.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 +21 -0
- package/grammar.js +270 -57
- package/package.json +9 -3
- 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/src/grammar.json +590 -167
- package/src/node-types.json +135 -3
- package/src/parser.c +138298 -124064
- package/src/scanner.c +135 -5
- package/tree-sitter.json +1 -1
package/README.md
CHANGED
|
@@ -166,6 +166,27 @@ These are documented in detail in
|
|
|
166
166
|
as `a + b` rather than splitting into two statements. Idiomatic
|
|
167
167
|
Groovy places continuation operators at the end of the previous
|
|
168
168
|
line.
|
|
169
|
+
- **A `{` after `new T(...)` is always an anonymous class body** --
|
|
170
|
+
Groovy instead calls a closure on the new object when the `{`
|
|
171
|
+
starts a later line (outside parentheses and brackets) or cannot be
|
|
172
|
+
a class body, so `new ArrayList()\n{ list.add(1) }` and
|
|
173
|
+
`new T() { x -> x }` get an `ERROR` inside a `class_body`. Write
|
|
174
|
+
`new ArrayList().call { ... }` to keep the call.
|
|
175
|
+
- **A `{ ... }` straight after a field with no initializer is an
|
|
176
|
+
instance initializer block** -- `int x { ... }` parses with no
|
|
177
|
+
`ERROR`. A record's compact constructor (`public Name { ... }`),
|
|
178
|
+
which is unsupported, takes the same reading. After a field *with*
|
|
179
|
+
an initializer a next-line `{` is that expression's trailing
|
|
180
|
+
closure, as in Groovy: end the field with `;` to get an
|
|
181
|
+
initializer block.
|
|
182
|
+
- **`sealed` and `trait` are keywords where a class member can
|
|
183
|
+
start** -- a field or enum constant named `sealed` or `trait` is an
|
|
184
|
+
`ERROR` when it follows a modifier (`private boolean sealed`) or
|
|
185
|
+
opens the member (`static trait = 1`, `enum E { trait }`).
|
|
186
|
+
`boolean sealed` and `String trait`, with no modifier, parse.
|
|
187
|
+
`record` is not affected: it is a keyword only directly before a
|
|
188
|
+
record header (`record Name(`), so `private Record record` and
|
|
189
|
+
`record.key()` parse.
|
|
169
190
|
|
|
170
191
|
## Contributing
|
|
171
192
|
|
package/grammar.js
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
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 three context-sensitive
|
|
11
11
|
* lexing situations that pure grammar rules cannot disambiguate:
|
|
12
12
|
* - Slashy-string-start vs. division
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
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
16
|
* See SPECIFICATION.md §6.
|
|
17
17
|
*/
|
|
18
18
|
|
|
@@ -79,6 +79,18 @@ module.exports = grammar({
|
|
|
79
79
|
// is the contract this rule set will fulfil.
|
|
80
80
|
word: $ => $.identifier,
|
|
81
81
|
|
|
82
|
+
// §5.2 — `new` is a hard keyword. Keyword extraction alone still
|
|
83
|
+
// lexes it as `identifier` wherever the keyword has no action,
|
|
84
|
+
// which let `def f = (Foo) new T()` after another member split
|
|
85
|
+
// into a field `= (Foo)` and a method `T()` returning `new`. The
|
|
86
|
+
// empty `property` set keeps `foo.new` (Apache `namePart`) valid;
|
|
87
|
+
// `_property_name` also names methods, so `new` is not reserved
|
|
88
|
+
// where a method name may follow (`def new`, `int new`).
|
|
89
|
+
reserved: {
|
|
90
|
+
global: _ => ['new'],
|
|
91
|
+
property: _ => [],
|
|
92
|
+
},
|
|
93
|
+
|
|
82
94
|
extras: $ => [
|
|
83
95
|
/\s/,
|
|
84
96
|
$.line_comment,
|
|
@@ -102,6 +114,7 @@ module.exports = grammar({
|
|
|
102
114
|
$.line_comment,
|
|
103
115
|
$.block_comment,
|
|
104
116
|
$.groovydoc_comment,
|
|
117
|
+
$._record_keyword,
|
|
105
118
|
],
|
|
106
119
|
|
|
107
120
|
conflicts: $ => [
|
|
@@ -109,7 +122,7 @@ module.exports = grammar({
|
|
|
109
122
|
// (list_literal vs map_literal — tree-sitter resolves without
|
|
110
123
|
// an explicit conflict because `:` after the first element
|
|
111
124
|
// always disambiguates within one token of lookahead.)
|
|
112
|
-
|
|
125
|
+
|
|
113
126
|
// §5.15 — inside `( … )` an identifier could be either an
|
|
114
127
|
// _expression (parenthesized_expression) or a _type
|
|
115
128
|
// (parenthesized_type_cast). Tree-sitter explores both via
|
|
@@ -145,6 +158,25 @@ module.exports = grammar({
|
|
|
145
158
|
// decides; the conflict keeps both alternatives alive until
|
|
146
159
|
// then.
|
|
147
160
|
[$.variable_declarator, $._property_name],
|
|
161
|
+
|
|
162
|
+
// §4 — `static NAME` inside a class body: after one or more
|
|
163
|
+
// modifiers and one identifier, that identifier could be the
|
|
164
|
+
// modifier-only field_declaration's variable_declarator name
|
|
165
|
+
// (`static MEDIUM_TTL = 900`) or the start of a typed
|
|
166
|
+
// field_declaration/method_declaration's `_type` (`static Foo
|
|
167
|
+
// bar`). The next token (`=`/`,`/`;` vs a second identifier)
|
|
168
|
+
// disambiguates.
|
|
169
|
+
[$.variable_declarator, $._type],
|
|
170
|
+
|
|
171
|
+
// §4 — `enum E { E(v, w) { } }`: after `E(` an identifier could be
|
|
172
|
+
// a constant's argument (`_expression`) or a constructor's untyped
|
|
173
|
+
// parameter (`formal_parameter`); the `{` after `)` decides. The
|
|
174
|
+
// conflict is global by necessity — it is between the two
|
|
175
|
+
// reductions, not their containers — and was checked inert
|
|
176
|
+
// outside an enum body: declaring it on the v0.3.0 grammar makes
|
|
177
|
+
// tree-sitter report it unnecessary. Regenerate without it to
|
|
178
|
+
// confirm that still holds.
|
|
179
|
+
[$.formal_parameter, $._expression],
|
|
148
180
|
],
|
|
149
181
|
|
|
150
182
|
rules: {
|
|
@@ -232,9 +264,9 @@ module.exports = grammar({
|
|
|
232
264
|
field('statement', $._statement),
|
|
233
265
|
)),
|
|
234
266
|
|
|
235
|
-
// §4 — block of statements
|
|
236
|
-
//
|
|
237
|
-
// closure (§5.8). A `prec(1, …)` keeps block preferred at use
|
|
267
|
+
// §4 — block of statements: control-flow, method and constructor
|
|
268
|
+
// bodies, static / instance initializers. Shares `{ ... }` syntax
|
|
269
|
+
// with closure (§5.8). A `prec(1, …)` keeps block preferred at use
|
|
238
270
|
// sites where both `block` and a closure-bearing `_statement`
|
|
239
271
|
// are valid alternatives (e.g. the body slot of `if` / `while`).
|
|
240
272
|
block: $ => prec(1, seq(
|
|
@@ -390,9 +422,10 @@ module.exports = grammar({
|
|
|
390
422
|
|
|
391
423
|
// §4 — `catch_formal_parameter` accepts either a single _type
|
|
392
424
|
// or a multi_type for Java 7+ / Groovy multi-catch. Closes
|
|
393
|
-
// murtaza64 #39.
|
|
425
|
+
// murtaza64 #39. The type itself is optional — Groovy allows a
|
|
426
|
+
// bare `catch (e) { … }`, implicitly typed as Exception.
|
|
394
427
|
catch_formal_parameter: $ => seq(
|
|
395
|
-
field('type', choice($._type, $.multi_type)),
|
|
428
|
+
optional(field('type', choice($._type, $.multi_type))),
|
|
396
429
|
field('name', $.identifier),
|
|
397
430
|
),
|
|
398
431
|
|
|
@@ -525,23 +558,56 @@ module.exports = grammar({
|
|
|
525
558
|
field('body', $.class_body),
|
|
526
559
|
),
|
|
527
560
|
|
|
528
|
-
// §4 —
|
|
529
|
-
//
|
|
561
|
+
// §4 — member list shared by class / interface / trait / record /
|
|
562
|
+
// `@interface` bodies and the anonymous inner class body of
|
|
563
|
+
// `object_creation_expression`.
|
|
530
564
|
// The body accepts `;` as an empty member / terminator the same
|
|
531
565
|
// way statement lists do (§5.10): a field or abstract method is
|
|
532
566
|
// commonly written `int x = 1;` / `void f();`, and a stray `;` is
|
|
533
567
|
// a no-op member. `;` is anonymous, so it never appears in the AST.
|
|
568
|
+
//
|
|
569
|
+
// A bare `block` is an instance initializer. It sits in the member
|
|
570
|
+
// repeat — here and in the three identical repeats of `enum_body` —
|
|
571
|
+
// rather than in `_class_member`, because `enum_body` also places
|
|
572
|
+
// a lone `_class_member` directly after its constants. A block in
|
|
573
|
+
// that slot is an LR conflict on `A() {` (constructor, or constant
|
|
574
|
+
// plus initializer) and, once that is resolved, silently accepts
|
|
575
|
+
// `A { }` (a constant with an anonymous class body, unsupported)
|
|
576
|
+
// as constant-plus-initializer.
|
|
534
577
|
class_body: $ => seq(
|
|
535
578
|
'{',
|
|
536
|
-
repeat(choice($._class_member, ';')),
|
|
579
|
+
repeat(choice($._class_member, $.block, ';')),
|
|
537
580
|
'}',
|
|
538
581
|
),
|
|
539
582
|
|
|
583
|
+
// Nested type declarations are members, as in Apache's
|
|
584
|
+
// `memberDeclaration`. Each kind must be listed: a declaration
|
|
585
|
+
// keyword with no action at member start lexes as an identifier,
|
|
586
|
+
// so `class Inner { … }` would silently parse as a field `Inner`
|
|
587
|
+
// of type `class` followed by an instance initializer block, and
|
|
588
|
+
// a nested `record R(int x) { }` as a method `R` returning
|
|
589
|
+
// `record`. The record keyword comes from the scanner (§6.7), so
|
|
590
|
+
// listing it here does not reserve `record` as a member name.
|
|
591
|
+
//
|
|
592
|
+
// The price: `trait` and `sealed` are keywords wherever a member
|
|
593
|
+
// can start, as they already are where a statement can. A member
|
|
594
|
+
// cannot open with one of them as a plain identifier, with or
|
|
595
|
+
// without modifiers (`static trait = 1`, `sealed() { }`), nor use
|
|
596
|
+
// one as the name after `modifier(s) Type`, because `private Foo`
|
|
597
|
+
// is already a complete field (`private boolean sealed` is an
|
|
598
|
+
// ERROR; `boolean sealed` is not). See divergence 12. No
|
|
599
|
+
// `conflicts` entry is needed.
|
|
540
600
|
_class_member: $ => choice(
|
|
541
601
|
$.method_declaration,
|
|
542
602
|
$.field_declaration,
|
|
543
603
|
$.constructor_declaration,
|
|
544
604
|
$.static_initializer,
|
|
605
|
+
$.enum_declaration,
|
|
606
|
+
$.class_declaration,
|
|
607
|
+
$.interface_declaration,
|
|
608
|
+
$.trait_declaration,
|
|
609
|
+
$.record_declaration,
|
|
610
|
+
$.annotation_type_declaration,
|
|
545
611
|
),
|
|
546
612
|
|
|
547
613
|
// §4 — constructors share the method_declaration shape but have
|
|
@@ -573,12 +639,28 @@ module.exports = grammar({
|
|
|
573
639
|
// more declarators (each with optional initializer). Method
|
|
574
640
|
// declarations share the same prefix; `prec(2, …)` on
|
|
575
641
|
// `method_declaration` and the trailing `(` discriminate.
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
642
|
+
//
|
|
643
|
+
// A modifier alone (no `def`, no type) also introduces a field —
|
|
644
|
+
// `static MEDIUM_TTL = 900` infers Object, a common constant-field
|
|
645
|
+
// idiom. Gated behind `repeat1($._modifier)` (not `repeat`) so this
|
|
646
|
+
// alternative can't match a bare, modifier-less identifier, which
|
|
647
|
+
// would collide with a plain expression_statement.
|
|
648
|
+
field_declaration: $ => choice(
|
|
649
|
+
// Prefer the typed field when both parses succeed, rather than
|
|
650
|
+
// splitting `private final int v\n C() {}` after `int`.
|
|
651
|
+
prec.dynamic(1, seq(
|
|
652
|
+
repeat($.annotation),
|
|
653
|
+
repeat($._modifier),
|
|
654
|
+
choice('def', field('type', $._type)),
|
|
655
|
+
$.variable_declarator,
|
|
656
|
+
repeat(seq(',', $.variable_declarator)),
|
|
657
|
+
)),
|
|
658
|
+
seq(
|
|
659
|
+
repeat($.annotation),
|
|
660
|
+
repeat1($._modifier),
|
|
661
|
+
$.variable_declarator,
|
|
662
|
+
repeat(seq(',', $.variable_declarator)),
|
|
663
|
+
),
|
|
582
664
|
),
|
|
583
665
|
|
|
584
666
|
// §4 — `def name(params) body`. Typed return type (`String foo()
|
|
@@ -626,10 +708,13 @@ module.exports = grammar({
|
|
|
626
708
|
')',
|
|
627
709
|
),
|
|
628
710
|
|
|
629
|
-
// §5.13 — formal parameter with optional
|
|
630
|
-
//
|
|
711
|
+
// §5.13 — formal parameter with optional annotations (Spring's
|
|
712
|
+
// `@PathVariable`, `@RequestBody`, JPA's `@Param`, … — ubiquitous
|
|
713
|
+
// on framework-facing methods), optional type, optional varargs
|
|
714
|
+
// marker (`Type... name`), and optional default value
|
|
631
715
|
// (`name = expr`).
|
|
632
716
|
formal_parameter: $ => seq(
|
|
717
|
+
repeat($.annotation),
|
|
633
718
|
optional(field('type', choice($._type, $.varargs_type))),
|
|
634
719
|
field('name', $.identifier),
|
|
635
720
|
optional(seq('=', field('default', $._expression))),
|
|
@@ -637,13 +722,36 @@ module.exports = grammar({
|
|
|
637
722
|
|
|
638
723
|
varargs_type: $ => seq($._type, '...'),
|
|
639
724
|
|
|
640
|
-
// §4 — enum. Closes murtaza64 #36 first half. Constants
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
//
|
|
725
|
+
// §4 — enum. Closes murtaza64 #36 first half. Constants may
|
|
726
|
+
// carry constructor arguments (`RED(0xff0000)`) via the optional
|
|
727
|
+
// argument_list.
|
|
728
|
+
//
|
|
729
|
+
// The body follows GroovyParser.g4 `classBody` for `t == 2`:
|
|
730
|
+
// after the constants either a trailing `,` closes the list, or
|
|
731
|
+
// members follow after `;`, `,;`, or nothing at all — Groovy's
|
|
732
|
+
// own parser treats the newline as the separator (GROOVY-7773,
|
|
733
|
+
// GROOVY-9306), and newlines are extras here, so the member
|
|
734
|
+
// simply follows the last constant. `A,` directly before a
|
|
735
|
+
// member is rejected, as in Groovy. With no constants the body
|
|
736
|
+
// is an ordinary member list.
|
|
737
|
+
//
|
|
738
|
+
// An instance initializer (`block`) is accepted wherever the
|
|
739
|
+
// member list repeats — after `;`, after a first member, or with
|
|
740
|
+
// no constants — but not directly after a constant. Newlines are
|
|
741
|
+
// extras, so `A\n{ … }` (in the .g4 a constant, then an
|
|
742
|
+
// initializer) cannot be told from `A { … }` (a constant with an
|
|
743
|
+
// anonymous class body, unsupported); both stay errors.
|
|
744
|
+
//
|
|
745
|
+
// The three member repeats are spelled out, and must stay
|
|
746
|
+
// identical to the one in `class_body`, so that the generator
|
|
747
|
+
// folds all four into one aux symbol (`aux_sym_class_body_repeat1`).
|
|
748
|
+
// A differing copy, or a hidden rule that is not inlined, adds a
|
|
749
|
+
// symbol and renumbers every id after it — the alias kinds
|
|
750
|
+
// `named_argument`, `quoted_identifier` and `type_identifier`
|
|
751
|
+
// included — which a patch release must not do.
|
|
645
752
|
enum_declaration: $ => seq(
|
|
646
753
|
repeat($.annotation),
|
|
754
|
+
repeat($._modifier),
|
|
647
755
|
'enum',
|
|
648
756
|
field('name', $.identifier),
|
|
649
757
|
field('body', $.enum_body),
|
|
@@ -651,30 +759,77 @@ module.exports = grammar({
|
|
|
651
759
|
|
|
652
760
|
enum_body: $ => seq(
|
|
653
761
|
'{',
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
762
|
+
choice(
|
|
763
|
+
seq(
|
|
764
|
+
$.enum_constant,
|
|
765
|
+
repeat(seq(',', $.enum_constant)),
|
|
766
|
+
optional(choice(
|
|
767
|
+
',',
|
|
768
|
+
seq(optional(','), ';', repeat(choice($._class_member, $.block, ';'))),
|
|
769
|
+
seq($._class_member, repeat(choice($._class_member, $.block, ';'))),
|
|
770
|
+
)),
|
|
771
|
+
),
|
|
772
|
+
repeat(choice($._class_member, $.block, ';')),
|
|
773
|
+
),
|
|
660
774
|
'}',
|
|
661
775
|
),
|
|
662
776
|
|
|
663
|
-
|
|
777
|
+
// §4 — `prec(1)` makes a bare identifier at the start of the body
|
|
778
|
+
// a constant rather than the type of the first member: `A\n E() { }`
|
|
779
|
+
// is a constant followed by a constructor, not a method `E`
|
|
780
|
+
// returning `A`. The mirror case with no constants, `int f() { }`
|
|
781
|
+
// as the first thing in the body, therefore reads as constant `int`
|
|
782
|
+
// plus constructor `f` — a newline is whitespace here and nothing
|
|
783
|
+
// else tells the two apart; a modifier, `def`, or a leading `;`
|
|
784
|
+
// makes it a member. Static precedence rather than `prec.dynamic`
|
|
785
|
+
// with an `[enum_constant, _type]` conflict: both yield the same
|
|
786
|
+
// tree on every valid shape, but the GLR form silently accepts
|
|
787
|
+
// `A\n B` (constants missing their comma, which Groovy rejects) as
|
|
788
|
+
// a field `A B`, where this form reports the ERROR. Annotations
|
|
789
|
+
// share the prefix with an annotated member; the same precedence
|
|
790
|
+
// decides after them, so `@Foo A\n int x` is a constant and a
|
|
791
|
+
// field.
|
|
792
|
+
enum_constant: $ => prec(1, seq(
|
|
793
|
+
repeat($.annotation),
|
|
664
794
|
field('name', $.identifier),
|
|
665
795
|
optional(field('arguments', $.argument_list)),
|
|
666
|
-
),
|
|
796
|
+
)),
|
|
667
797
|
|
|
668
|
-
// §4 — record (Groovy 4+)
|
|
669
|
-
// `record
|
|
670
|
-
//
|
|
671
|
-
|
|
798
|
+
// §4 — record (Groovy 4+), after Apache's `classDeclaration`:
|
|
799
|
+
// `[modifiers] record Name[<T>](Type a, Type b) [implements I] [{ body }]`.
|
|
800
|
+
// Records cannot `extends`, and the body is optional here where
|
|
801
|
+
// Groovy requires it.
|
|
802
|
+
// §5.2 / §6.7 — `record` is a contextual keyword. The keyword
|
|
803
|
+
// comes from the external scanner, which emits it only when a
|
|
804
|
+
// name follows on the same line and `(` or `<` after that; in
|
|
805
|
+
// every other position the word lexes as `identifier`. A grammar literal
|
|
806
|
+
// cannot do this: keyword extraction yields the keyword wherever
|
|
807
|
+
// it has an action, which made `record.key()` at statement start,
|
|
808
|
+
// and `private Record record` once record_declaration became a
|
|
809
|
+
// class member, errors. The alias keeps the anonymous `record`
|
|
810
|
+
// node that the queries capture.
|
|
811
|
+
//
|
|
812
|
+
// The dynamic precedence settles a GLR tie the scanner creates.
|
|
813
|
+
// After `private Record`, the `[variable_declarator, _type]`
|
|
814
|
+
// conflict forks on the next word: `record` is the field's name
|
|
815
|
+
// in one branch and a type in the other. When a record header
|
|
816
|
+
// follows on the next line, the first branch lexes its `record`
|
|
817
|
+
// as the keyword and the second as that field's name, and both
|
|
818
|
+
// survive (`private Record` / `record record` / constructor
|
|
819
|
+
// `Inner(int x) { }` is a valid member list). Without a weight,
|
|
820
|
+
// which tree wins depends on tree shape, and a comment between
|
|
821
|
+
// the two lines flipped it. Favouring the record declaration is
|
|
822
|
+
// right whenever both parse.
|
|
823
|
+
record_declaration: $ => prec.dynamic(1, prec.right(seq(
|
|
672
824
|
repeat($.annotation),
|
|
673
|
-
|
|
825
|
+
repeat($._modifier),
|
|
826
|
+
alias($._record_keyword, 'record'),
|
|
674
827
|
field('name', $.identifier),
|
|
828
|
+
optional(field('type_parameters', $.type_parameters)),
|
|
675
829
|
field('components', $.record_components),
|
|
830
|
+
optional($.super_interfaces),
|
|
676
831
|
optional(field('body', $.class_body)),
|
|
677
|
-
)),
|
|
832
|
+
))),
|
|
678
833
|
|
|
679
834
|
record_components: $ => seq(
|
|
680
835
|
'(',
|
|
@@ -779,16 +934,18 @@ module.exports = grammar({
|
|
|
779
934
|
optional(field('arguments', $.argument_list)),
|
|
780
935
|
),
|
|
781
936
|
|
|
782
|
-
// §4 — `for (x in xs)
|
|
783
|
-
//
|
|
784
|
-
//
|
|
785
|
-
//
|
|
786
|
-
//
|
|
937
|
+
// §4 — `for (x in xs)`, plus the Java-compatible enhanced-for
|
|
938
|
+
// form Groovy accepts side by side: `for (Type x : xs)` / `for
|
|
939
|
+
// (def x : xs)`. The `in` / `:` keyword here is a structural
|
|
940
|
+
// delimiter, not the membership_expression operator or a
|
|
941
|
+
// labelled_statement colon — context disambiguates because the
|
|
942
|
+
// for-header is not an expression position.
|
|
787
943
|
for_in_statement: $ => seq(
|
|
788
944
|
'for',
|
|
789
945
|
'(',
|
|
946
|
+
optional(choice('def', field('type', $._type))),
|
|
790
947
|
field('variable', $.identifier),
|
|
791
|
-
'in',
|
|
948
|
+
choice('in', ':'),
|
|
792
949
|
field('value', $._expression),
|
|
793
950
|
')',
|
|
794
951
|
field('body', choice($.block, $._statement)),
|
|
@@ -965,17 +1122,48 @@ module.exports = grammar({
|
|
|
965
1122
|
))));
|
|
966
1123
|
},
|
|
967
1124
|
|
|
968
|
-
// §3.2
|
|
969
|
-
//
|
|
970
|
-
//
|
|
971
|
-
//
|
|
972
|
-
// (
|
|
1125
|
+
// §3.2 — `new Foo(args)` and the anonymous inner class
|
|
1126
|
+
// `new Foo(args) { members }`. Array creation `new Foo[10]` and
|
|
1127
|
+
// array initialisers land later. PREC.PRIMARY only labels the
|
|
1128
|
+
// §3.1 tier. The number decides nothing: the rule's one conflict
|
|
1129
|
+
// (below) is against itself, where it cancels out, and
|
|
1130
|
+
// `new Foo().bar` composes without any precedence.
|
|
1131
|
+
//
|
|
1132
|
+
// The optional body takes every `{` that follows the arguments.
|
|
1133
|
+
// Right associativity does that statically — the shift into
|
|
1134
|
+
// `class_body` beats reducing the bodiless form — so no conflict
|
|
1135
|
+
// is declared and the closure reading never forks.
|
|
1136
|
+
//
|
|
1137
|
+
// Apache is narrower. Its `creator` has no `nls` before the body,
|
|
1138
|
+
// so `new T()\n{ … }` is a closure called on the new object
|
|
1139
|
+
// (observed on Groovy 4.0.33). By the same grammar a same-line
|
|
1140
|
+
// `{` whose content cannot be class members should be one too
|
|
1141
|
+
// (`new T() { x -> x }`; not run through the compiler). Here both
|
|
1142
|
+
// are read as a body, usually with an ERROR in it (divergence 11).
|
|
1143
|
+
// Parsing them needs a declared conflict on this rule with
|
|
1144
|
+
// `prec.dynamic` on the body, and that form was not taken: a body
|
|
1145
|
+
// holding one member `class_body` cannot parse, or one still
|
|
1146
|
+
// being typed, would then fall back silently to the closure tree
|
|
1147
|
+
// that #68 reported.
|
|
973
1148
|
object_creation_expression: $ => prec.right(PREC.PRIMARY, seq(
|
|
974
1149
|
'new',
|
|
975
|
-
field('type', $._type),
|
|
1150
|
+
field('type', choice($._type, alias($._diamond_type, $.generic_type))),
|
|
976
1151
|
field('arguments', $.argument_list),
|
|
1152
|
+
optional(field('body', $.class_body)),
|
|
977
1153
|
)),
|
|
978
1154
|
|
|
1155
|
+
// §3.2 — Apache's createdName permits diamond, but ordinary types
|
|
1156
|
+
// (including nested type arguments) do not. Keep the public shape.
|
|
1157
|
+
_diamond_type: $ => prec.right(PREC.ARRAY_TYPE, seq(
|
|
1158
|
+
field('base', choice(
|
|
1159
|
+
alias($.identifier, $.type_identifier),
|
|
1160
|
+
$.qualified_type,
|
|
1161
|
+
)),
|
|
1162
|
+
field('arguments', alias($._diamond_type_arguments, $.type_arguments)),
|
|
1163
|
+
)),
|
|
1164
|
+
|
|
1165
|
+
_diamond_type_arguments: _ => seq(token.immediate('<'), '>'),
|
|
1166
|
+
|
|
979
1167
|
// §5.15 — C-style cast `(Foo) x`. Distinct from
|
|
980
1168
|
// `parenthesized_expression` followed by something (resolved
|
|
981
1169
|
// by tree-sitter's GLR; declared as a conflict if needed).
|
|
@@ -1102,7 +1290,7 @@ module.exports = grammar({
|
|
|
1102
1290
|
// keywords, or special chars. `map."key with spaces"` and
|
|
1103
1291
|
// `def "abstract"() { … }` both rely on this.
|
|
1104
1292
|
_property_name: $ => choice(
|
|
1105
|
-
$.identifier,
|
|
1293
|
+
reserved('property', $.identifier),
|
|
1106
1294
|
alias($.string_literal, $.quoted_identifier),
|
|
1107
1295
|
),
|
|
1108
1296
|
|
|
@@ -1135,10 +1323,35 @@ module.exports = grammar({
|
|
|
1135
1323
|
// expression so subscript / future field_access / future
|
|
1136
1324
|
// safe_navigation chains compose naturally. PREC.POSTFIX
|
|
1137
1325
|
// matches subscript so chains like `obj[i](x)[j]` work.
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1326
|
+
//
|
|
1327
|
+
// Trailing closure (§5.5's command_chain covers the bare-
|
|
1328
|
+
// identifier statement form; this covers the general expression
|
|
1329
|
+
// form used constantly on property-access chains: `list.find {
|
|
1330
|
+
// it > 5 }`, `list.inject(0) { acc, x -> acc + x }`). Groovy
|
|
1331
|
+
// treats a closure literal as the call's last argument whether
|
|
1332
|
+
// or not parens are present, so `argument_list` becomes optional
|
|
1333
|
+
// once a trailing closure is there to anchor the call.
|
|
1334
|
+
//
|
|
1335
|
+
// The args-and-closure alternative sits one precedence level
|
|
1336
|
+
// above plain POSTFIX so `f(x) { … }` reduces to a single
|
|
1337
|
+
// method_invocation node (arguments AND closure fields on the
|
|
1338
|
+
// same node) instead of GLR instead reaching the same span by
|
|
1339
|
+
// nesting a closure-only method_invocation around a plain call.
|
|
1340
|
+
method_invocation: $ => choice(
|
|
1341
|
+
prec.left(PREC.POSTFIX + 1, seq(
|
|
1342
|
+
field('function', $._expression),
|
|
1343
|
+
field('arguments', $.argument_list),
|
|
1344
|
+
field('closure', $.closure),
|
|
1345
|
+
)),
|
|
1346
|
+
prec.left(PREC.POSTFIX, seq(
|
|
1347
|
+
field('function', $._expression),
|
|
1348
|
+
field('arguments', $.argument_list),
|
|
1349
|
+
)),
|
|
1350
|
+
prec.left(PREC.POSTFIX, seq(
|
|
1351
|
+
field('function', $._expression),
|
|
1352
|
+
field('closure', $.closure),
|
|
1353
|
+
)),
|
|
1354
|
+
),
|
|
1142
1355
|
|
|
1143
1356
|
// §3.2 / §5.11 — argument list. Positional args are `_expression`;
|
|
1144
1357
|
// named args (Groovy's `k: v` in call position) are `map_entry`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dekobon/tree-sitter-groovy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Apache Groovy grammar for tree-sitter (dekobon fork)",
|
|
5
5
|
"main": "bindings/node",
|
|
6
6
|
"types": "bindings/node",
|
|
@@ -67,10 +67,16 @@
|
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"eslint": "^
|
|
70
|
+
"eslint": "^10.14.0",
|
|
71
71
|
"eslint-config-treesitter": "^1.0.2",
|
|
72
|
+
"globals": "^17.14.0",
|
|
72
73
|
"prebuildify": "^6.0.1",
|
|
73
|
-
"tree-sitter-cli": "^0.
|
|
74
|
+
"tree-sitter-cli": "^0.27.2"
|
|
75
|
+
},
|
|
76
|
+
"overrides": {
|
|
77
|
+
"eslint-config-treesitter": {
|
|
78
|
+
"eslint-plugin-jsdoc": "^62.9.0"
|
|
79
|
+
}
|
|
74
80
|
},
|
|
75
81
|
"tree-sitter": [
|
|
76
82
|
{
|
|
Binary file
|
|
Binary file
|
|
Binary file
|