@dekobon/tree-sitter-groovy 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.js CHANGED
@@ -91,10 +91,12 @@ module.exports = grammar({
91
91
  // Tokens the spec §6 proposes as external scanner branches but
92
92
  // that this grammar implements in-grammar (GString interpolation
93
93
  // via regex tokens, slashy body via in-grammar `_slashy_text`,
94
- // statement boundaries via `repeat($._statement)`, label colon
95
- // via grammar precedence) are intentionally NOT listed — listing
96
- // an unwired external token would let dormant scanner branches
97
- // mis-fire in error-recovery states.
94
+ // label colon via grammar precedence, and statement boundaries
95
+ // via `repeat(choice($._statement, ';'))` — newline is `extras`
96
+ // whitespace and `;` is an anonymous list element, see §5.10)
97
+ // are intentionally NOT listed: listing an unwired external token
98
+ // would let dormant scanner branches mis-fire in error-recovery
99
+ // states.
98
100
  externals: $ => [
99
101
  $._slashy_string_start,
100
102
  $.line_comment,
@@ -150,7 +152,7 @@ module.exports = grammar({
150
152
  // SPECIFICATION.md §4 (statement and declaration coverage).
151
153
  source_file: $ => seq(
152
154
  optional($.shebang),
153
- repeat($._statement),
155
+ repeat(choice($._statement, ';')),
154
156
  ),
155
157
 
156
158
  // §4 — `#!/usr/bin/env groovy` line at file start. Single
@@ -237,19 +239,26 @@ module.exports = grammar({
237
239
  // are valid alternatives (e.g. the body slot of `if` / `while`).
238
240
  block: $ => prec(1, seq(
239
241
  '{',
240
- repeat($._statement),
242
+ repeat(choice($._statement, ';')),
241
243
  '}',
242
244
  )),
243
245
 
244
246
  // §4 — if / else. `prec.right` resolves the dangling-else
245
247
  // ambiguity in favour of the closest `if`. Body accepts either
246
- // an explicit block (preferred) or a single statement.
248
+ // an explicit block (preferred) or a single statement. The
249
+ // `optional(';')` after the consequence keeps the else attached
250
+ // when a braceless consequence is terminated by a semicolon
251
+ // (`if (x) a(); else b()`); without it the `;` is claimed by the
252
+ // enclosing statement list (§5.10) and the `else` is severed. It
253
+ // sits outside the else clause so the no-else form (`if (x) a();
254
+ // b()`) does not require an `else` after eating the `;`.
247
255
  if_statement: $ => prec.right(seq(
248
256
  'if',
249
257
  '(',
250
258
  field('condition', $._expression),
251
259
  ')',
252
260
  field('consequence', choice($.block, $._statement)),
261
+ optional(';'),
253
262
  optional(seq(
254
263
  'else',
255
264
  field('alternative', choice($.block, $._statement)),
@@ -266,13 +275,17 @@ module.exports = grammar({
266
275
  ),
267
276
 
268
277
  // §4 — C-style for. init / condition / update slots all
269
- // optional; bare `for (;;)` is the infinite-loop idiom.
270
- // Typed variable declarations in init (`int i = 0`) land with
271
- // local_variable_declaration in a later iteration.
278
+ // optional; bare `for (;;)` is the infinite-loop idiom. The init
279
+ // slot accepts a single expression (`i = 0`) or a variable
280
+ // declaration (`int i = 0`, `def i = 0`, incl. multiple
281
+ // declarators). Apache `GroovyParser.g4` `forInit:
282
+ // localVariableDeclaration | expressionList` also allows a
283
+ // comma-separated expression list (`i = 0, j = 1`); that form is
284
+ // not yet supported.
272
285
  for_statement: $ => seq(
273
286
  'for',
274
287
  '(',
275
- optional(field('init', $._expression)),
288
+ optional(field('init', choice($._expression, $.local_variable_declaration))),
276
289
  ';',
277
290
  optional(field('condition', $._expression)),
278
291
  ';',
@@ -282,9 +295,13 @@ module.exports = grammar({
282
295
  ),
283
296
 
284
297
  // §4 — do-while. Body is required; condition follows the body.
298
+ // `optional(';')` lets a braceless body be terminated before
299
+ // `while` (`do a(); while (c)`, the Java/Groovy `do S while (e);`
300
+ // form); without it the `;` errors since `while` is required next.
285
301
  do_while_statement: $ => seq(
286
302
  'do',
287
303
  field('body', choice($.block, $._statement)),
304
+ optional(';'),
288
305
  'while',
289
306
  '(',
290
307
  field('condition', $._expression),
@@ -510,9 +527,13 @@ module.exports = grammar({
510
527
 
511
528
  // §4 — `{ method* }` for v1. Field declarations, static
512
529
  // initialisers, and inner classes land later.
530
+ // The body accepts `;` as an empty member / terminator the same
531
+ // way statement lists do (§5.10): a field or abstract method is
532
+ // commonly written `int x = 1;` / `void f();`, and a stray `;` is
533
+ // a no-op member. `;` is anonymous, so it never appears in the AST.
513
534
  class_body: $ => seq(
514
535
  '{',
515
- repeat($._class_member),
536
+ repeat(choice($._class_member, ';')),
516
537
  '}',
517
538
  ),
518
539
 
@@ -635,7 +656,7 @@ module.exports = grammar({
635
656
  repeat(seq(',', $.enum_constant)),
636
657
  optional(','),
637
658
  )),
638
- optional(seq(';', repeat($._class_member))),
659
+ optional(seq(';', repeat(choice($._class_member, ';')))),
639
660
  '}',
640
661
  ),
641
662
 
@@ -847,21 +868,26 @@ module.exports = grammar({
847
868
  'case',
848
869
  field('value', $._expression),
849
870
  ':',
850
- repeat($._statement),
871
+ repeat(choice($._statement, ';')),
851
872
  ),
852
873
 
874
+ // The arrow body may be terminated by `;` (`case 1 -> foo();`),
875
+ // matching the Java/Groovy `case L -> expr;` arrow form. The `;`
876
+ // is anonymous and absorbed here rather than by the switch block,
877
+ // which has no statement-list of its own.
853
878
  switch_arrow_case: $ => seq(
854
879
  'case',
855
880
  field('value', $._expression),
856
881
  '->',
857
882
  field('body', choice($.block, $._statement)),
883
+ optional(';'),
858
884
  ),
859
885
 
860
886
  switch_default: $ => seq(
861
887
  'default',
862
888
  choice(
863
- seq(':', repeat($._statement)),
864
- seq('->', field('body', choice($.block, $._statement))),
889
+ seq(':', repeat(choice($._statement, ';'))),
890
+ seq('->', field('body', choice($.block, $._statement)), optional(';')),
865
891
  ),
866
892
  ),
867
893
 
@@ -1351,7 +1377,7 @@ module.exports = grammar({
1351
1377
  closure: $ => seq(
1352
1378
  '{',
1353
1379
  optional($.closure_parameters),
1354
- repeat($._statement),
1380
+ repeat(choice($._statement, ';')),
1355
1381
  '}',
1356
1382
  ),
1357
1383
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dekobon/tree-sitter-groovy",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Apache Groovy grammar for tree-sitter (dekobon fork)",
5
5
  "main": "bindings/node",
6
6
  "types": "bindings/node",
@@ -70,7 +70,7 @@
70
70
  "eslint": "^9.39.4",
71
71
  "eslint-config-treesitter": "^1.0.2",
72
72
  "prebuildify": "^6.0.1",
73
- "tree-sitter-cli": "^0.26.9"
73
+ "tree-sitter-cli": "^0.26.13"
74
74
  },
75
75
  "tree-sitter": [
76
76
  {
package/src/grammar.json CHANGED
@@ -21,8 +21,17 @@
21
21
  {
22
22
  "type": "REPEAT",
23
23
  "content": {
24
- "type": "SYMBOL",
25
- "name": "_statement"
24
+ "type": "CHOICE",
25
+ "members": [
26
+ {
27
+ "type": "SYMBOL",
28
+ "name": "_statement"
29
+ },
30
+ {
31
+ "type": "STRING",
32
+ "value": ";"
33
+ }
34
+ ]
26
35
  }
27
36
  }
28
37
  ]
@@ -268,8 +277,17 @@
268
277
  {
269
278
  "type": "REPEAT",
270
279
  "content": {
271
- "type": "SYMBOL",
272
- "name": "_statement"
280
+ "type": "CHOICE",
281
+ "members": [
282
+ {
283
+ "type": "SYMBOL",
284
+ "name": "_statement"
285
+ },
286
+ {
287
+ "type": "STRING",
288
+ "value": ";"
289
+ }
290
+ ]
273
291
  }
274
292
  },
275
293
  {
@@ -322,6 +340,18 @@
322
340
  ]
323
341
  }
324
342
  },
343
+ {
344
+ "type": "CHOICE",
345
+ "members": [
346
+ {
347
+ "type": "STRING",
348
+ "value": ";"
349
+ },
350
+ {
351
+ "type": "BLANK"
352
+ }
353
+ ]
354
+ },
325
355
  {
326
356
  "type": "CHOICE",
327
357
  "members": [
@@ -419,8 +449,17 @@
419
449
  "type": "FIELD",
420
450
  "name": "init",
421
451
  "content": {
422
- "type": "SYMBOL",
423
- "name": "_expression"
452
+ "type": "CHOICE",
453
+ "members": [
454
+ {
455
+ "type": "SYMBOL",
456
+ "name": "_expression"
457
+ },
458
+ {
459
+ "type": "SYMBOL",
460
+ "name": "local_variable_declaration"
461
+ }
462
+ ]
424
463
  }
425
464
  },
426
465
  {
@@ -515,6 +554,18 @@
515
554
  ]
516
555
  }
517
556
  },
557
+ {
558
+ "type": "CHOICE",
559
+ "members": [
560
+ {
561
+ "type": "STRING",
562
+ "value": ";"
563
+ },
564
+ {
565
+ "type": "BLANK"
566
+ }
567
+ ]
568
+ },
518
569
  {
519
570
  "type": "STRING",
520
571
  "value": "while"
@@ -1542,8 +1593,17 @@
1542
1593
  {
1543
1594
  "type": "REPEAT",
1544
1595
  "content": {
1545
- "type": "SYMBOL",
1546
- "name": "_class_member"
1596
+ "type": "CHOICE",
1597
+ "members": [
1598
+ {
1599
+ "type": "SYMBOL",
1600
+ "name": "_class_member"
1601
+ },
1602
+ {
1603
+ "type": "STRING",
1604
+ "value": ";"
1605
+ }
1606
+ ]
1547
1607
  }
1548
1608
  },
1549
1609
  {
@@ -2090,8 +2150,17 @@
2090
2150
  {
2091
2151
  "type": "REPEAT",
2092
2152
  "content": {
2093
- "type": "SYMBOL",
2094
- "name": "_class_member"
2153
+ "type": "CHOICE",
2154
+ "members": [
2155
+ {
2156
+ "type": "SYMBOL",
2157
+ "name": "_class_member"
2158
+ },
2159
+ {
2160
+ "type": "STRING",
2161
+ "value": ";"
2162
+ }
2163
+ ]
2095
2164
  }
2096
2165
  }
2097
2166
  ]
@@ -2915,8 +2984,17 @@
2915
2984
  {
2916
2985
  "type": "REPEAT",
2917
2986
  "content": {
2918
- "type": "SYMBOL",
2919
- "name": "_statement"
2987
+ "type": "CHOICE",
2988
+ "members": [
2989
+ {
2990
+ "type": "SYMBOL",
2991
+ "name": "_statement"
2992
+ },
2993
+ {
2994
+ "type": "STRING",
2995
+ "value": ";"
2996
+ }
2997
+ ]
2920
2998
  }
2921
2999
  }
2922
3000
  ]
@@ -2956,6 +3034,18 @@
2956
3034
  }
2957
3035
  ]
2958
3036
  }
3037
+ },
3038
+ {
3039
+ "type": "CHOICE",
3040
+ "members": [
3041
+ {
3042
+ "type": "STRING",
3043
+ "value": ";"
3044
+ },
3045
+ {
3046
+ "type": "BLANK"
3047
+ }
3048
+ ]
2959
3049
  }
2960
3050
  ]
2961
3051
  },
@@ -2979,8 +3069,17 @@
2979
3069
  {
2980
3070
  "type": "REPEAT",
2981
3071
  "content": {
2982
- "type": "SYMBOL",
2983
- "name": "_statement"
3072
+ "type": "CHOICE",
3073
+ "members": [
3074
+ {
3075
+ "type": "SYMBOL",
3076
+ "name": "_statement"
3077
+ },
3078
+ {
3079
+ "type": "STRING",
3080
+ "value": ";"
3081
+ }
3082
+ ]
2984
3083
  }
2985
3084
  }
2986
3085
  ]
@@ -3008,6 +3107,18 @@
3008
3107
  }
3009
3108
  ]
3010
3109
  }
3110
+ },
3111
+ {
3112
+ "type": "CHOICE",
3113
+ "members": [
3114
+ {
3115
+ "type": "STRING",
3116
+ "value": ";"
3117
+ },
3118
+ {
3119
+ "type": "BLANK"
3120
+ }
3121
+ ]
3011
3122
  }
3012
3123
  ]
3013
3124
  }
@@ -5606,8 +5717,17 @@
5606
5717
  {
5607
5718
  "type": "REPEAT",
5608
5719
  "content": {
5609
- "type": "SYMBOL",
5610
- "name": "_statement"
5720
+ "type": "CHOICE",
5721
+ "members": [
5722
+ {
5723
+ "type": "SYMBOL",
5724
+ "name": "_statement"
5725
+ },
5726
+ {
5727
+ "type": "STRING",
5728
+ "value": ";"
5729
+ }
5730
+ ]
5611
5731
  }
5612
5732
  },
5613
5733
  {
@@ -4121,6 +4121,10 @@
4121
4121
  "type": "list_literal",
4122
4122
  "named": true
4123
4123
  },
4124
+ {
4125
+ "type": "local_variable_declaration",
4126
+ "named": true
4127
+ },
4124
4128
  {
4125
4129
  "type": "logical_implication_expression",
4126
4130
  "named": true