@dekobon/tree-sitter-groovy 0.4.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 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 four context-sensitive
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
- * - Automatic-semicolon (newline-as-terminator)
14
- * - Labelled-statement colon
15
- * - Block-comment / Groovydoc single-token emit
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: $ => [
@@ -251,9 +264,9 @@ module.exports = grammar({
251
264
  field('statement', $._statement),
252
265
  )),
253
266
 
254
- // §4 — block of statements, used in control-flow bodies and
255
- // (eventually) method bodies. Shares `{ ... }` syntax with
256
- // closure (§5.8). A `prec(1, …)` keeps block preferred at use
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
257
270
  // sites where both `block` and a closure-bearing `_statement`
258
271
  // are valid alternatives (e.g. the body slot of `if` / `while`).
259
272
  block: $ => prec(1, seq(
@@ -545,29 +558,56 @@ module.exports = grammar({
545
558
  field('body', $.class_body),
546
559
  ),
547
560
 
548
- // §4 — `{ method* }` for v1. Field declarations, static
549
- // initialisers, and inner classes land later.
561
+ // §4 — member list shared by class / interface / trait / record /
562
+ // `@interface` bodies and the anonymous inner class body of
563
+ // `object_creation_expression`.
550
564
  // The body accepts `;` as an empty member / terminator the same
551
565
  // way statement lists do (§5.10): a field or abstract method is
552
566
  // commonly written `int x = 1;` / `void f();`, and a stray `;` is
553
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.
554
577
  class_body: $ => seq(
555
578
  '{',
556
- repeat(choice($._class_member, ';')),
579
+ repeat(choice($._class_member, $.block, ';')),
557
580
  '}',
558
581
  ),
559
582
 
560
- // A nested enum (`static enum EventType { … }` inside a domain
561
- // class) is common enough in real Groovy that leaving it out
562
- // silently misparses `enum` as a field_declaration's type name.
563
- // Nested class/interface/trait land separately (bigger surface,
564
- // own conflict set) — out of scope here.
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.
565
600
  _class_member: $ => choice(
566
601
  $.method_declaration,
567
602
  $.field_declaration,
568
603
  $.constructor_declaration,
569
604
  $.static_initializer,
570
605
  $.enum_declaration,
606
+ $.class_declaration,
607
+ $.interface_declaration,
608
+ $.trait_declaration,
609
+ $.record_declaration,
610
+ $.annotation_type_declaration,
571
611
  ),
572
612
 
573
613
  // §4 — constructors share the method_declaration shape but have
@@ -693,10 +733,22 @@ module.exports = grammar({
693
733
  // GROOVY-9306), and newlines are extras here, so the member
694
734
  // simply follows the last constant. `A,` directly before a
695
735
  // member is rejected, as in Groovy. With no constants the body
696
- // is an ordinary member list. The member list is spelled three
697
- // times rather than shared with `class_body` through a hidden
698
- // rule: a new rule renumbers the aux symbols and ~100 symbol ids,
699
- // which a patch release must not do.
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.
700
752
  enum_declaration: $ => seq(
701
753
  repeat($.annotation),
702
754
  repeat($._modifier),
@@ -713,11 +765,11 @@ module.exports = grammar({
713
765
  repeat(seq(',', $.enum_constant)),
714
766
  optional(choice(
715
767
  ',',
716
- seq(optional(','), ';', repeat(choice($._class_member, ';'))),
717
- seq($._class_member, repeat(choice($._class_member, ';'))),
768
+ seq(optional(','), ';', repeat(choice($._class_member, $.block, ';'))),
769
+ seq($._class_member, repeat(choice($._class_member, $.block, ';'))),
718
770
  )),
719
771
  ),
720
- repeat(choice($._class_member, ';')),
772
+ repeat(choice($._class_member, $.block, ';')),
721
773
  ),
722
774
  '}',
723
775
  ),
@@ -733,22 +785,51 @@ module.exports = grammar({
733
785
  // with an `[enum_constant, _type]` conflict: both yield the same
734
786
  // tree on every valid shape, but the GLR form silently accepts
735
787
  // `A\n B` (constants missing their comma, which Groovy rejects) as
736
- // a field `A B`, where this form reports the ERROR.
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.
737
792
  enum_constant: $ => prec(1, seq(
793
+ repeat($.annotation),
738
794
  field('name', $.identifier),
739
795
  optional(field('arguments', $.argument_list)),
740
796
  )),
741
797
 
742
- // §4 — record (Groovy 4+). `record Name(Type a, Type b) [{ body }]`.
743
- // `record` is a contextual keyword — tree-sitter's word: directive
744
- // keeps `record` usable as a plain identifier elsewhere.
745
- record_declaration: $ => prec.right(seq(
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(
746
824
  repeat($.annotation),
747
- 'record',
825
+ repeat($._modifier),
826
+ alias($._record_keyword, 'record'),
748
827
  field('name', $.identifier),
828
+ optional(field('type_parameters', $.type_parameters)),
749
829
  field('components', $.record_components),
830
+ optional($.super_interfaces),
750
831
  optional(field('body', $.class_body)),
751
- )),
832
+ ))),
752
833
 
753
834
  record_components: $ => seq(
754
835
  '(',
@@ -1041,15 +1122,34 @@ module.exports = grammar({
1041
1122
  ))));
1042
1123
  },
1043
1124
 
1044
- // §3.2 / §5.15 — `new Foo(args)`. We only handle the plain
1045
- // constructor-call form here; array creation `new Foo[10]`,
1046
- // generic types, and array initialisers land later. PREC.PRIMARY
1047
- // so it composes with the access tier from the left
1048
- // (`new Foo().bar`).
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.
1049
1148
  object_creation_expression: $ => prec.right(PREC.PRIMARY, seq(
1050
1149
  'new',
1051
1150
  field('type', choice($._type, alias($._diamond_type, $.generic_type))),
1052
1151
  field('arguments', $.argument_list),
1152
+ optional(field('body', $.class_body)),
1053
1153
  )),
1054
1154
 
1055
1155
  // §3.2 — Apache's createdName permits diamond, but ordinary types
@@ -1190,7 +1290,7 @@ module.exports = grammar({
1190
1290
  // keywords, or special chars. `map."key with spaces"` and
1191
1291
  // `def "abstract"() { … }` both rely on this.
1192
1292
  _property_name: $ => choice(
1193
- $.identifier,
1293
+ reserved('property', $.identifier),
1194
1294
  alias($.string_literal, $.quoted_identifier),
1195
1295
  ),
1196
1296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dekobon/tree-sitter-groovy",
3
- "version": "0.4.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",
package/src/grammar.json CHANGED
@@ -1607,6 +1607,10 @@
1607
1607
  "type": "SYMBOL",
1608
1608
  "name": "_class_member"
1609
1609
  },
1610
+ {
1611
+ "type": "SYMBOL",
1612
+ "name": "block"
1613
+ },
1610
1614
  {
1611
1615
  "type": "STRING",
1612
1616
  "value": ";"
@@ -1642,6 +1646,26 @@
1642
1646
  {
1643
1647
  "type": "SYMBOL",
1644
1648
  "name": "enum_declaration"
1649
+ },
1650
+ {
1651
+ "type": "SYMBOL",
1652
+ "name": "class_declaration"
1653
+ },
1654
+ {
1655
+ "type": "SYMBOL",
1656
+ "name": "interface_declaration"
1657
+ },
1658
+ {
1659
+ "type": "SYMBOL",
1660
+ "name": "trait_declaration"
1661
+ },
1662
+ {
1663
+ "type": "SYMBOL",
1664
+ "name": "record_declaration"
1665
+ },
1666
+ {
1667
+ "type": "SYMBOL",
1668
+ "name": "annotation_type_declaration"
1645
1669
  }
1646
1670
  ]
1647
1671
  },
@@ -2230,6 +2254,10 @@
2230
2254
  "type": "SYMBOL",
2231
2255
  "name": "_class_member"
2232
2256
  },
2257
+ {
2258
+ "type": "SYMBOL",
2259
+ "name": "block"
2260
+ },
2233
2261
  {
2234
2262
  "type": "STRING",
2235
2263
  "value": ";"
@@ -2255,6 +2283,10 @@
2255
2283
  "type": "SYMBOL",
2256
2284
  "name": "_class_member"
2257
2285
  },
2286
+ {
2287
+ "type": "SYMBOL",
2288
+ "name": "block"
2289
+ },
2258
2290
  {
2259
2291
  "type": "STRING",
2260
2292
  "value": ";"
@@ -2282,6 +2314,10 @@
2282
2314
  "type": "SYMBOL",
2283
2315
  "name": "_class_member"
2284
2316
  },
2317
+ {
2318
+ "type": "SYMBOL",
2319
+ "name": "block"
2320
+ },
2285
2321
  {
2286
2322
  "type": "STRING",
2287
2323
  "value": ";"
@@ -2303,6 +2339,13 @@
2303
2339
  "content": {
2304
2340
  "type": "SEQ",
2305
2341
  "members": [
2342
+ {
2343
+ "type": "REPEAT",
2344
+ "content": {
2345
+ "type": "SYMBOL",
2346
+ "name": "annotation"
2347
+ }
2348
+ },
2306
2349
  {
2307
2350
  "type": "FIELD",
2308
2351
  "name": "name",
@@ -2331,55 +2374,99 @@
2331
2374
  }
2332
2375
  },
2333
2376
  "record_declaration": {
2334
- "type": "PREC_RIGHT",
2335
- "value": 0,
2377
+ "type": "PREC_DYNAMIC",
2378
+ "value": 1,
2336
2379
  "content": {
2337
- "type": "SEQ",
2338
- "members": [
2339
- {
2340
- "type": "REPEAT",
2341
- "content": {
2342
- "type": "SYMBOL",
2343
- "name": "annotation"
2344
- }
2345
- },
2346
- {
2347
- "type": "STRING",
2348
- "value": "record"
2349
- },
2350
- {
2351
- "type": "FIELD",
2352
- "name": "name",
2353
- "content": {
2354
- "type": "SYMBOL",
2355
- "name": "identifier"
2356
- }
2357
- },
2358
- {
2359
- "type": "FIELD",
2360
- "name": "components",
2361
- "content": {
2362
- "type": "SYMBOL",
2363
- "name": "record_components"
2364
- }
2365
- },
2366
- {
2367
- "type": "CHOICE",
2368
- "members": [
2369
- {
2370
- "type": "FIELD",
2371
- "name": "body",
2372
- "content": {
2373
- "type": "SYMBOL",
2374
- "name": "class_body"
2375
- }
2380
+ "type": "PREC_RIGHT",
2381
+ "value": 0,
2382
+ "content": {
2383
+ "type": "SEQ",
2384
+ "members": [
2385
+ {
2386
+ "type": "REPEAT",
2387
+ "content": {
2388
+ "type": "SYMBOL",
2389
+ "name": "annotation"
2390
+ }
2391
+ },
2392
+ {
2393
+ "type": "REPEAT",
2394
+ "content": {
2395
+ "type": "SYMBOL",
2396
+ "name": "_modifier"
2397
+ }
2398
+ },
2399
+ {
2400
+ "type": "ALIAS",
2401
+ "content": {
2402
+ "type": "SYMBOL",
2403
+ "name": "_record_keyword"
2376
2404
  },
2377
- {
2378
- "type": "BLANK"
2405
+ "named": false,
2406
+ "value": "record"
2407
+ },
2408
+ {
2409
+ "type": "FIELD",
2410
+ "name": "name",
2411
+ "content": {
2412
+ "type": "SYMBOL",
2413
+ "name": "identifier"
2379
2414
  }
2380
- ]
2381
- }
2382
- ]
2415
+ },
2416
+ {
2417
+ "type": "CHOICE",
2418
+ "members": [
2419
+ {
2420
+ "type": "FIELD",
2421
+ "name": "type_parameters",
2422
+ "content": {
2423
+ "type": "SYMBOL",
2424
+ "name": "type_parameters"
2425
+ }
2426
+ },
2427
+ {
2428
+ "type": "BLANK"
2429
+ }
2430
+ ]
2431
+ },
2432
+ {
2433
+ "type": "FIELD",
2434
+ "name": "components",
2435
+ "content": {
2436
+ "type": "SYMBOL",
2437
+ "name": "record_components"
2438
+ }
2439
+ },
2440
+ {
2441
+ "type": "CHOICE",
2442
+ "members": [
2443
+ {
2444
+ "type": "SYMBOL",
2445
+ "name": "super_interfaces"
2446
+ },
2447
+ {
2448
+ "type": "BLANK"
2449
+ }
2450
+ ]
2451
+ },
2452
+ {
2453
+ "type": "CHOICE",
2454
+ "members": [
2455
+ {
2456
+ "type": "FIELD",
2457
+ "name": "body",
2458
+ "content": {
2459
+ "type": "SYMBOL",
2460
+ "name": "class_body"
2461
+ }
2462
+ },
2463
+ {
2464
+ "type": "BLANK"
2465
+ }
2466
+ ]
2467
+ }
2468
+ ]
2469
+ }
2383
2470
  }
2384
2471
  },
2385
2472
  "record_components": {
@@ -3610,6 +3697,22 @@
3610
3697
  "type": "SYMBOL",
3611
3698
  "name": "argument_list"
3612
3699
  }
3700
+ },
3701
+ {
3702
+ "type": "CHOICE",
3703
+ "members": [
3704
+ {
3705
+ "type": "FIELD",
3706
+ "name": "body",
3707
+ "content": {
3708
+ "type": "SYMBOL",
3709
+ "name": "class_body"
3710
+ }
3711
+ },
3712
+ {
3713
+ "type": "BLANK"
3714
+ }
3715
+ ]
3613
3716
  }
3614
3717
  ]
3615
3718
  }
@@ -4098,8 +4201,12 @@
4098
4201
  "type": "CHOICE",
4099
4202
  "members": [
4100
4203
  {
4101
- "type": "SYMBOL",
4102
- "name": "identifier"
4204
+ "type": "RESERVED",
4205
+ "content": {
4206
+ "type": "SYMBOL",
4207
+ "name": "identifier"
4208
+ },
4209
+ "context_name": "property"
4103
4210
  },
4104
4211
  {
4105
4212
  "type": "ALIAS",
@@ -6943,9 +7050,21 @@
6943
7050
  {
6944
7051
  "type": "SYMBOL",
6945
7052
  "name": "groovydoc_comment"
7053
+ },
7054
+ {
7055
+ "type": "SYMBOL",
7056
+ "name": "_record_keyword"
6946
7057
  }
6947
7058
  ],
6948
7059
  "inline": [],
6949
7060
  "supertypes": [],
6950
- "reserved": {}
7061
+ "reserved": {
7062
+ "global": [
7063
+ {
7064
+ "type": "STRING",
7065
+ "value": "new"
7066
+ }
7067
+ ],
7068
+ "property": []
7069
+ }
6951
7070
  }