Skip to content

Commit 1e04f06

Browse files
mvaledclaude
andauthored
Update grammar to cover array spreads, variant type spreads and newer operators. (#267)
* feat: add ReScript 12 operator support Add parser support for the ReScript 12 operator improvements that were missing from the grammar. This covers modulo, bitwise operators, and shift operators, and adds corpus and highlight updates for the new syntax. Unrelated untracked files are left out of the commit. * feat: add variant spread syntax support Add grammar support for variant type spreads and variant pattern spreads. This adds corpus coverage for type declarations and expressions, including a dedicated variant pattern spread example. Also ignore local uv lockfiles via .git/info/exclude. * feat: add array spread expression support Allow spread elements in array expressions. Add corpus coverage for array spread syntax using the ReScript 11.1 style example, including multiple spreads in the same array literal. * fix: make extensible type "= .." a dedicated node The ".." token for extensible variants (e.g. `type t = ..`) was included as a choice in the `_type_identifier` rule alongside `type_identifier` and `type_identifier_path`. Because `_type_identifier` is inlined, the tokenizer would see the three-dot spread operator "..." and greedily match ".." first, leaving a stray "." behind. This made every variant type spread (`| ...Foo.t`) produce an ERROR node, breaking font-lock for the rest of the file. Extensible variants are syntactically distinct: `type t = ..` is the only valid use of ".." in a type position — it cannot appear inside generics (`option<..>` is invalid) or be combined with other type constructors. Modelling it as a separate `extensible_type` node branching directly from `type_binding` reflects this and removes the ambiguity from the tokenizer entirely. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: avoid highlighting extension prefixes as operators Remove '%' from the unconditional operator query so leading percent signs in extension expressions like %foo and %%foo are not highlighted as operators. Highlight '%' only in binary_expression, matching how other context-sensitive operators such as '<', '>', and '/' are handled. * chore: align tree-sitter CLI version in package and CI Pin the GitHub Actions tree-sitter CLI to v0.26.3 so parser generation matches the version declared in the package metadata, and regenerate src/parser.c with that version. Keep the runtime tree-sitter peer dependency at ^0.21.1. The CLI and the runtime are versioned separately, so the CI toolchain update should not raise the consumer runtime requirement. Include package.json, package-lock.json, and .nvmrc in the CI path filters so toolchain-only changes still trigger the workflow. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 43c2f1f commit 1e04f06

8 files changed

Lines changed: 139813 additions & 115534 deletions

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
- test/**
99
- bindings/**
1010
- binding.gyp
11+
- package.json
12+
- package-lock.json
13+
- .nvmrc
1114
- .github/workflows/**
1215
pull_request:
1316
paths:
@@ -16,6 +19,9 @@ on:
1619
- test/**
1720
- bindings/**
1821
- binding.gyp
22+
- package.json
23+
- package-lock.json
24+
- .nvmrc
1925
- .github/workflows/**
2026

2127
concurrency:
@@ -36,6 +42,8 @@ jobs:
3642

3743
- name: Set up tree-sitter
3844
uses: tree-sitter/setup-action/cli@v2
45+
with:
46+
tree-sitter-ref: v0.26.3
3947

4048
- name: Run tests
4149
uses: tree-sitter/parser-test-action@v2

grammar.js

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ module.exports = grammar({
4545
"binary_times",
4646
"binary_pow",
4747
"binary_plus",
48+
"binary_shift",
4849
"binary_compare",
4950
"binary_relation",
51+
"binary_bitand",
52+
"binary_bitxor",
53+
"binary_bitor",
5054
"binary_and",
5155
"binary_or",
5256
"coercion_relation",
@@ -250,20 +254,25 @@ module.exports = grammar({
250254
field("name", choice($.type_identifier, $.type_identifier_path)),
251255
optional($.type_parameters),
252256
optional(
253-
seq(
254-
optional(seq("=", $._non_function_inline_type)),
255-
optional(
256-
seq(
257-
choice("=", "+="),
258-
optional("private"),
259-
field("body", $._type),
257+
choice(
258+
seq("=", $.extensible_type),
259+
seq(
260+
optional(seq("=", $._non_function_inline_type)),
261+
optional(
262+
seq(
263+
choice("=", "+="),
264+
optional("private"),
265+
field("body", $._type),
266+
),
260267
),
268+
repeat($.type_constraint),
261269
),
262-
repeat($.type_constraint),
263270
),
264271
),
265272
),
266273

274+
extensible_type: (_$) => "..",
275+
267276
type_parameters: ($) =>
268277
seq(
269278
"<",
@@ -305,7 +314,9 @@ module.exports = grammar({
305314
tuple_type: ($) => prec.dynamic(-1, seq("(", commaSep1t($._type), ")")),
306315

307316
variant_type: ($) =>
308-
prec.left(seq(optional("|"), barSep1($.variant_declaration))),
317+
prec.left(
318+
seq(optional("|"), barSep1(choice($.variant_declaration, $.variant_type_spread))),
319+
),
309320

310321
variant_declaration: ($) =>
311322
prec.right(
@@ -316,6 +327,8 @@ module.exports = grammar({
316327
),
317328
),
318329

330+
variant_type_spread: ($) => seq("...", $._type_identifier),
331+
319332
variant_parameters: ($) => seq("(", commaSep1t($._type), ")"),
320333

321334
polyvar_type: ($) =>
@@ -538,7 +551,7 @@ module.exports = grammar({
538551

539552
tuple: ($) => seq("(", commaSep2t($.expression), ")"),
540553

541-
array: ($) => seq("[", commaSept($.expression), "]"),
554+
array: ($) => seq("[", commaSept(choice($.spread_element, $.expression)), "]"),
542555

543556
list: ($) =>
544557
seq($._list_constructor, "{", optional(commaSep1t($._list_element)), "}"),
@@ -576,7 +589,7 @@ module.exports = grammar({
576589
-1,
577590
seq(
578591
"|",
579-
field("pattern", $._pattern),
592+
field("pattern", choice($.variant_spread_pattern, $._pattern)),
580593
optional($.guard),
581594
"=>",
582595
field(
@@ -590,6 +603,11 @@ module.exports = grammar({
590603

591604
polyvar_type_pattern: ($) => seq("#", "...", $._type_identifier),
592605

606+
variant_type_pattern: ($) => seq("...", $._type_identifier),
607+
608+
variant_spread_pattern: ($) =>
609+
seq($.variant_type_pattern, optional($.as_aliasing)),
610+
593611
try_expression: ($) =>
594612
seq("try", $.expression, "catch", "{", repeat($.switch_match), "}"),
595613

@@ -985,18 +1003,25 @@ module.exports = grammar({
9851003
binary_expression: ($) =>
9861004
choice(
9871005
...[
1006+
["&&&", "binary_bitand"],
9881007
["&&", "binary_and"],
1008+
["|||", "binary_bitor"],
9891009
["||", "binary_or"],
1010+
["^^^", "binary_bitxor"],
9901011
["++", "binary_plus"],
9911012
["+", "binary_plus"],
9921013
["+.", "binary_plus"],
9931014
["-", "binary_plus"],
9941015
["-.", "binary_plus"],
9951016
["*", "binary_times"],
9961017
["*.", "binary_times"],
1018+
["%", "binary_times"],
9971019
["**", "binary_pow"],
9981020
["/", "binary_times"],
9991021
["/.", "binary_times"],
1022+
["<<", "binary_shift"],
1023+
[">>>", "binary_shift"],
1024+
[">>", "binary_shift"],
10001025
["<", "binary_relation"],
10011026
["<=", "binary_relation"],
10021027
["==", "binary_relation"],
@@ -1030,6 +1055,7 @@ module.exports = grammar({
10301055
unary_expression: ($) =>
10311056
choice(
10321057
...[
1058+
["~~~", "unary_not"],
10331059
["!", "unary_not"],
10341060
["-", "unary_not"],
10351061
["-.", "unary_not"],
@@ -1085,7 +1111,7 @@ module.exports = grammar({
10851111
),
10861112

10871113
_type_identifier: ($) =>
1088-
choice($.type_identifier, $.type_identifier_path, ".."),
1114+
choice($.type_identifier, $.type_identifier_path),
10891115

10901116
type_identifier_path: ($) =>
10911117
seq($.module_primary_expression, ".", $.type_identifier),

queries/highlights.scm

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,22 @@
225225
"**"
226226
"*."
227227
"/."
228+
"<<"
229+
">>"
230+
">>>"
228231
"<="
229232
"=="
230233
"==="
231234
"!"
232235
"!="
233236
"!=="
234237
">="
238+
"&&&"
235239
"&&"
240+
"|||"
236241
"||"
242+
"^^^"
243+
"~~~"
237244
"="
238245
":="
239246
"->"
@@ -245,8 +252,8 @@
245252
] @operator
246253

247254
; Explicitly enclose these operators with binary_expression
248-
; to avoid confusion with JSX tag delimiters
249-
(binary_expression ["<" ">" "/"] @operator)
255+
; to avoid confusion with JSX tag delimiters and extension expressions.
256+
(binary_expression ["<" ">" "/" "%"] @operator)
250257

251258
[
252259
"("

0 commit comments

Comments
 (0)