tree-sitter-bynk 0.447.0 → 0.492.1

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
@@ -39,7 +39,7 @@ const PREC = {
39
39
  module.exports = grammar({
40
40
  name: "bynk",
41
41
 
42
- externals: ($) => [$.doc_block, $.doc_line],
42
+ externals: ($) => [$.doc_block, $.doc_line, $.raw_string, $._type_app_open, $._error_sentinel],
43
43
 
44
44
  extras: ($) => [/\s+/, $.doc_line, $.line_comment, $.doc_block],
45
45
 
@@ -48,6 +48,10 @@ module.exports = grammar({
48
48
  word: ($) => $.identifier,
49
49
 
50
50
  conflicts: ($) => [
51
+ // #2654: `let (T { … })` is a parenthesised pattern either way; only the
52
+ // end of the statement (an `else` or none) says whether the record
53
+ // pattern stood alone.
54
+ [$._pattern, $._let_paren_record_pattern],
51
55
  // `match e { … }` / `if e { … }`: after a bare identifier `e`,
52
56
  // the `{` is ambiguous between opening the match/if body and opening a
53
57
  // record construction/spread `e { … }`. Keep all parses alive; the body
@@ -58,6 +62,10 @@ module.exports = grammar({
58
62
  // parenthesised expression (and `()` the unit literal) until the
59
63
  // closing `)` is followed — or not — by `=>`.
60
64
  [$.lambda_param, $._primary],
65
+ // #2712: `(T { f, …` opens a record construction or a record-pattern lambda
66
+ // parameter; the pattern's mandatory `..` (never an expression) settles it.
67
+ [$.field_init, $._lambda_record_field],
68
+ [$._primary, $._lambda_field_binding],
61
69
  [$._primary, $.lambda_expr],
62
70
  // v0.145: a match-arm `if`-guard is an `_expression` immediately followed by
63
71
  // the arm's `=>`. When the guard opens with `(`, one token can't tell a unit
@@ -208,6 +216,7 @@ module.exports = grammar({
208
216
  $.event_decl,
209
217
  $.asset_decl,
210
218
  $.embed_decl,
219
+ $.const_decl,
211
220
  ),
212
221
 
213
222
  _context_body_item: ($) =>
@@ -226,6 +235,7 @@ module.exports = grammar({
226
235
  $.event_decl,
227
236
  $.asset_decl,
228
237
  $.embed_decl,
238
+ $.const_decl,
229
239
  $.removed_agent_decl,
230
240
  ),
231
241
 
@@ -251,6 +261,7 @@ module.exports = grammar({
251
261
  $.event_decl,
252
262
  $.asset_decl,
253
263
  $.embed_decl,
264
+ $.const_decl,
254
265
  ),
255
266
 
256
267
  _test_body_item: ($) =>
@@ -324,17 +335,49 @@ module.exports = grammar({
324
335
  "}",
325
336
  ),
326
337
 
338
+ // -- Type parameters and bounds (constrained generics slice 0) --
339
+
340
+ // `T` or `T: Eq + C`. The constraint names are validated by the checker.
341
+ type_param: ($) =>
342
+ seq(
343
+ field("name", $.identifier),
344
+ optional(seq(":", sep1($.constraint, "+"))),
345
+ ),
346
+
347
+ constraint: ($) => $.identifier,
348
+
349
+ where_clause: ($) => seq("where", sep1($.where_bound, ",")),
350
+
351
+ where_bound: ($) =>
352
+ seq(
353
+ field("param", $.identifier),
354
+ ":",
355
+ sep1($.constraint, "+"),
356
+ ),
357
+
327
358
  // -- Type declarations --
328
359
 
360
+ // #2618: `private` before a `fn`, `type`, `messages`, `asset`, `embed` or
361
+ // `const` declaration makes it unit-private. The word is contextual: with
362
+ // `word` set to `identifier`, it lexes as a keyword only where a
363
+ // declaration may start, so `@cache(scope: private)` and a binding named
364
+ // `private` keep parsing as identifiers. Placement (a commons or context, never an
365
+ // adapter) is the compiler's call (`bynk.visibility.private_not_allowed`).
366
+ visibility_modifier: ($) => "private",
367
+
329
368
  type_decl: ($) =>
330
369
  seq(
370
+ optional(field("visibility", $.visibility_modifier)),
331
371
  "type",
332
372
  field("name", $.identifier),
333
373
  // v0.157 (ADR 0183): optional `[A, B]` type parameters — only a record
334
374
  // body may be generic (enforced by the checker, not the grammar).
335
- optional(seq("[", sep1(field("type_param", $.identifier), ","), "]")),
375
+ optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
336
376
  "=",
337
377
  field("body", $._type_body),
378
+ // Constrained generics slice 1: a trailing `derives Ord` clause, `+`
379
+ // separated like a bound list. `derives` is a contextual word.
380
+ optional(seq("derives", sep1(field("derive", $.constraint), "+"))),
338
381
  ),
339
382
 
340
383
  _type_body: ($) =>
@@ -404,6 +447,7 @@ module.exports = grammar({
404
447
  // (`bynk.asset.outside_context_or_commons` rejects it in an adapter).
405
448
  asset_decl: ($) =>
406
449
  seq(
450
+ optional(field("visibility", $.visibility_modifier)),
407
451
  "asset",
408
452
  field("name", $.identifier),
409
453
  "=",
@@ -419,12 +463,31 @@ module.exports = grammar({
419
463
  // rejects it in an adapter).
420
464
  embed_decl: ($) =>
421
465
  seq(
466
+ optional(field("visibility", $.visibility_modifier)),
422
467
  "embed",
423
468
  field("name", $.identifier),
424
469
  "=",
425
470
  field("path", $.string_literal),
426
471
  ),
427
472
 
473
+ // #2617 (named constants): `const Name: Type = <static expression>` — a
474
+ // named value. Admitted in every body like `embed`; placement
475
+ // (`bynk.resolve.const_outside_context_or_commons`), the name's case
476
+ // (`bynk.resolve.const_name_case`, upper-camel like `constant_name`) and
477
+ // the initialiser's static-ness are checker concerns. The name is an
478
+ // `identifier` because `word` unifies every word-shaped lexeme to it.
479
+ // A leading `private` makes it unit-private, as on `embed`.
480
+ const_decl: ($) =>
481
+ seq(
482
+ optional(field("visibility", $.visibility_modifier)),
483
+ "const",
484
+ field("name", $.identifier),
485
+ ":",
486
+ field("type", $._type_ref),
487
+ "=",
488
+ field("value", $._expression),
489
+ ),
490
+
428
491
  // v0.154 (ADR 0178): a sum body may carry a trailing `embeds E as V, …`
429
492
  // clause declaring error embeddings the `?` operator auto-converts.
430
493
  // `embeds`/`as` are contextual — matched only in this position.
@@ -507,12 +570,22 @@ module.exports = grammar({
507
570
  choice(
508
571
  seq(optional("-"), $.number_literal),
509
572
  seq(optional("-"), $.float_literal),
573
+ seq(optional("-"), $.decimal_literal),
510
574
  $.string_literal,
511
575
  ),
512
576
 
513
577
  _base_type: ($) => $.base_type,
514
578
  base_type: () =>
515
- choice("Int", "String", "Bool", "Float", "Duration", "Instant", "Bytes"),
579
+ choice(
580
+ "Int",
581
+ "String",
582
+ "Bool",
583
+ "Float",
584
+ "Duration",
585
+ "Instant",
586
+ "Bytes",
587
+ "Decimal",
588
+ ),
516
589
 
517
590
  _type_ref: ($) =>
518
591
  choice(
@@ -617,15 +690,19 @@ module.exports = grammar({
617
690
 
618
691
  fn_decl: ($) =>
619
692
  seq(
693
+ optional(field("visibility", $.visibility_modifier)),
620
694
  "fn",
621
695
  field("name", choice($.method_name, $.identifier)),
622
696
  // v0.20a: optional `[A, B]` type parameters (functions only).
623
- optional(seq("[", sep1(field("type_param", $.identifier), ","), "]")),
697
+ optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
624
698
  "(",
625
699
  optional($._params),
626
700
  ")",
627
701
  "->",
628
702
  field("return_type", $._type_ref),
703
+ // Constrained generics slice 0: a method's `where A: Eq` clause bounds
704
+ // a receiver type's parameter.
705
+ optional($.where_clause),
629
706
  // v0.115: contract clauses between the return type and the body.
630
707
  repeat($.requires_clause),
631
708
  repeat($.ensures_clause),
@@ -681,7 +758,7 @@ module.exports = grammar({
681
758
  // #926: optional `[T, …]` type parameters on the op itself — resolved
682
759
  // only from an explicit type argument at the call site (mirroring
683
760
  // `fn_decl`'s own `[A, B]` slot, `grammar.js:525`).
684
- optional(seq("[", sep1(field("type_param", $.identifier), ","), "]")),
761
+ optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
685
762
  "(",
686
763
  optional(sep1($.param, ",")),
687
764
  optional(","),
@@ -701,6 +778,7 @@ module.exports = grammar({
701
778
  // mirroring `service_decl`/`agent_decl`'s existing permissive placement.
702
779
  messages_decl: ($) =>
703
780
  seq(
781
+ optional(field("visibility", $.visibility_modifier)),
704
782
  "messages",
705
783
  field("tag", $.string_literal),
706
784
  repeat(field("annotation", $.store_annotation)),
@@ -865,14 +943,21 @@ module.exports = grammar({
865
943
  // than nested inside it. Nested inside the `Events` choice arm, not a
866
944
  // free-standing clause any protocol could carry — `via` on `http`/
867
945
  // `cron`/`queue`/`websocket` is a syntax error, not a checker
868
- // diagnostic. Literal only (v1 of this clause); a range pattern
869
- // (`via schema(2..)`) is unbuilt grammar, left to a future slice.
946
+ // diagnostic. A literal, an integer range (`via schema(2..)`, #990 —
947
+ // the same `int_range` a match pattern uses, #2699) or `_`.
870
948
  schema_dispatch_clause: ($) =>
871
949
  seq(
872
950
  "via",
873
951
  "schema",
874
952
  "(",
875
- field("version", seq(optional("-"), $.number_literal)),
953
+ field(
954
+ "version",
955
+ choice(
956
+ $.int_range,
957
+ seq(optional("-"), $.number_literal),
958
+ $.wildcard_pattern,
959
+ ),
960
+ ),
876
961
  ")",
877
962
  ),
878
963
  event_pattern_field: ($) =>
@@ -1239,8 +1324,9 @@ module.exports = grammar({
1239
1324
  // v0.118 (testing track slice 6): a test-scope stub for one capability
1240
1325
  // operation — `stub Cap.op(<arg pattern>, …) <rhs>`. Only admitted inside a
1241
1326
  // suite/case body. An arg pattern is `_` (any) or a value expression; the
1242
- // right-hand side is `returns <expr>`, `returns each [ <outcome>, … ]` (a
1243
- // scripted sequence, where an outcome is `fails` or an expr), or `fails`.
1327
+ // right-hand side is `returns <expr> [after <expr>]`, `returns each [ <outcome>, … ]`
1328
+ // (a scripted sequence, where an outcome is `fails` or an expr), `fails`, or
1329
+ // `never`.
1244
1330
  // `returns`/`each`/`fails` are contextual words. Keyword `stub` since the
1245
1331
  // keyword-hygiene batch (#548); formerly a pun on `provides`.
1246
1332
  stub_clause: ($) =>
@@ -1270,8 +1356,16 @@ module.exports = grammar({
1270
1356
  ),
1271
1357
  "]",
1272
1358
  ),
1273
- seq("returns", field("value", $._expression)),
1359
+ // #2683: `returns <v> after <d>` completes on the test clock once
1360
+ // `d` has passed; `never` does not complete. `after` and `never` are
1361
+ // contextual words.
1362
+ seq(
1363
+ "returns",
1364
+ field("value", $._expression),
1365
+ optional(seq("after", field("after", $._expression))),
1366
+ ),
1274
1367
  "fails",
1368
+ "never",
1275
1369
  ),
1276
1370
  ),
1277
1371
  // #2134: a suite- or case-scoped `env { NAME = "value" … }` clause — the
@@ -1343,6 +1437,7 @@ module.exports = grammar({
1343
1437
  $.do_stmt,
1344
1438
  $.assign_stmt,
1345
1439
  $.advance_stmt,
1440
+ $.par_stmt,
1346
1441
  prec(1, $.expect_expr),
1347
1442
  ),
1348
1443
 
@@ -1374,28 +1469,50 @@ module.exports = grammar({
1374
1469
  // lenient (a bare-name `variant_pattern` is admitted) because the compiler,
1375
1470
  // not the highlighter, reports `bynk.parse.let_else_on_binding`.
1376
1471
  let_else_stmt: ($) =>
1377
- seq(
1378
- "let",
1379
- field("pattern", choice($._let_pattern, alias($._let_or_pattern, $.or_pattern))),
1380
- field("bind", choice("=", "<-")),
1381
- field("value", $._expression),
1382
- optional(field("principal", $.call_site_actor)),
1383
- "else",
1384
- field("else", choice($.block, $.let_else_match)),
1472
+ choice(
1473
+ seq(
1474
+ "let",
1475
+ field("pattern", choice($._let_pattern, alias($._let_or_pattern, $.or_pattern))),
1476
+ field("bind", choice("=", "<-")),
1477
+ field("value", $._expression),
1478
+ optional(field("principal", $.call_site_actor)),
1479
+ "else",
1480
+ field("else", choice($.block, $.let_else_match)),
1481
+ ),
1482
+ // #2654 (patterns track, slice 2): `let Item { sku, .. } = item` — the
1483
+ // `else` is optional when the pattern is a record pattern (the compiler further
1484
+ // requires it to be irrefutable, `let_pattern_without_else`; whether a
1485
+ // field's sub-pattern is a binding or a variant is a matter of
1486
+ // capitalisation, which this grammar cannot see). Parentheses around
1487
+ // the pattern are transparent.
1488
+ seq(
1489
+ "let",
1490
+ field("pattern", choice($.record_pattern, alias($._let_paren_record_pattern, $.paren_pattern))),
1491
+ field("bind", choice("=", "<-")),
1492
+ field("value", $._expression),
1493
+ optional(field("principal", $.call_site_actor)),
1494
+ optional(seq("else", field("else", choice($.block, $.let_else_match)))),
1495
+ ),
1385
1496
  ),
1497
+ _let_paren_record_pattern: ($) => seq("(", $.record_pattern, ")"),
1386
1498
  // #2010: the patterns that may open a `let … else`, mirroring the Rust
1387
1499
  // parser's `let_pattern_ahead`: a literal, a parenthesised pattern, or a
1388
1500
  // variant with a payload or a qualifier. A bare name stays a binding (and
1389
1501
  // a bare `_` a discard), so `let x = …` is never ambiguous here.
1390
1502
  _let_pattern: ($) =>
1391
1503
  choice(
1504
+ $.int_range,
1392
1505
  $.literal_pattern,
1393
1506
  $.paren_pattern,
1507
+ $.list_pattern,
1394
1508
  alias($._let_variant_pattern, $.variant_pattern),
1395
1509
  ),
1396
1510
  // `let Ok(x) | Err(x) = …`: an or-chain whose first alternative opens a
1397
1511
  // pattern; the rest are any patterns.
1398
- _let_or_pattern: ($) => prec.left(1, seq($._let_pattern, "|", $._pattern)),
1512
+ // #2654: a record pattern may open the chain too (`let Item { .. } | …`),
1513
+ // though on its own it is the `else`-less alternative of `let_else_stmt`.
1514
+ _let_or_pattern: ($) =>
1515
+ prec.left(1, seq(choice($._let_pattern, $.record_pattern), "|", $._pattern)),
1399
1516
  _let_variant_pattern: ($) => {
1400
1517
  const payload = seq("(", optional(sep1($._pattern_binding, ",")), optional(","), ")");
1401
1518
  return prec.right(
@@ -1456,6 +1573,28 @@ module.exports = grammar({
1456
1573
  field("amount", $._expression),
1457
1574
  ),
1458
1575
 
1576
+ // #2640 (concurrent effects, slice 0): `par { let a <- e1 let b <- e2 }` —
1577
+ // issue every effect, then wait for them all. `par` is contextual: it opens
1578
+ // a statement only before `{`. The grammar stays permissive about the
1579
+ // block's contents (any statement parses); the compiler admits only
1580
+ // `let x <- e` and `do e` (`bynk.par.invalid_statement`).
1581
+ par_stmt: ($) => seq("par", "{", repeat($._par_statement), "}"),
1582
+
1583
+ // Any statement but `let … else`, which would take the rest of the block as
1584
+ // its arm and so has no room inside a `par` (the compiler's parser refuses
1585
+ // it with `bynk.par.invalid_statement`).
1586
+ _par_statement: ($) =>
1587
+ choice(
1588
+ $.let_stmt,
1589
+ $.effect_let_stmt,
1590
+ $.effect_send_stmt,
1591
+ $.do_stmt,
1592
+ $.assign_stmt,
1593
+ $.advance_stmt,
1594
+ $.par_stmt,
1595
+ prec(1, $.expect_expr),
1596
+ ),
1597
+
1459
1598
  // A let/effect-let may bind the discard name `_`.
1460
1599
  _binding_name: ($) => choice($.identifier, alias("_", $.wildcard)),
1461
1600
 
@@ -1601,11 +1740,62 @@ module.exports = grammar({
1601
1740
  _pattern: ($) =>
1602
1741
  choice(
1603
1742
  $.wildcard_pattern,
1743
+ $.int_range,
1604
1744
  $.literal_pattern,
1605
1745
  $.variant_pattern,
1746
+ $.record_pattern,
1747
+ $.list_pattern,
1606
1748
  $.or_pattern,
1607
1749
  $.paren_pattern,
1608
1750
  ),
1751
+ // #2641 (patterns track, slice 1): `Order { status: Paid, total, .. }`. Always
1752
+ // open, with the trailing `..` mandatory so that adding a field to the record
1753
+ // never breaks a pattern — the rule `event_pattern` already applies to
1754
+ // events. A field is a bare name (binding it to a local of the same name) or
1755
+ // `name: pattern`. After `is` a record pattern must be parenthesised (see
1756
+ // `_is_pattern`), because there the `{` would also open the `if`'s block.
1757
+ record_pattern: ($) =>
1758
+ seq(
1759
+ field("type", $.identifier),
1760
+ "{",
1761
+ repeat(seq($.record_pattern_field, ",")),
1762
+ "..",
1763
+ "}",
1764
+ ),
1765
+ // #2680 (patterns track, slice 4): `[]`, `[p, …]`, `[p, …, ..]`,
1766
+ // `[p, …, ..rest]`. The rest marker is last and at most once; `..` takes a
1767
+ // name or nothing (a literal after it is reserved for range patterns, and
1768
+ // the compiler reports it). It needs no parentheses after `is`, where the
1769
+ // pattern closes at `]`.
1770
+ list_pattern: ($) =>
1771
+ seq(
1772
+ "[",
1773
+ repeat(seq($._pattern, ",")),
1774
+ optional(choice($._pattern, seq($.list_rest, optional(",")))),
1775
+ "]",
1776
+ ),
1777
+ list_rest: ($) => seq("..", optional(field("name", $.identifier))),
1778
+ record_pattern_field: ($) =>
1779
+ choice(
1780
+ seq(field("name", $.identifier), ":", field("pattern", $._pattern)),
1781
+ field("name", $.identifier),
1782
+ ),
1783
+ // #2641: the patterns an `is` accepts without parentheses — `_pattern`
1784
+ // without a record pattern at its tail, at the top level or as an
1785
+ // or-alternative. Parenthesised, a record pattern is allowed anywhere (the
1786
+ // hand-written parser's `is_pattern_tail` restriction).
1787
+ _is_base_pattern: ($) =>
1788
+ choice(
1789
+ $.wildcard_pattern,
1790
+ $.literal_pattern,
1791
+ $.variant_pattern,
1792
+ $.list_pattern,
1793
+ $.paren_pattern,
1794
+ ),
1795
+ _is_pattern: ($) =>
1796
+ choice($._is_base_pattern, alias($._is_or_pattern, $.or_pattern)),
1797
+ _is_or_pattern: ($) =>
1798
+ prec.left(1, seq($._is_pattern, "|", $._is_base_pattern)),
1609
1799
  // #474 §2.3.4: `p₁ | p₂ | … | pₙ` — an or-pattern, left-associative;
1610
1800
  // matches if any alternative matches. `|` is a pattern-position operator
1611
1801
  // only — not a valid expression operator, and lexically distinct from
@@ -1621,6 +1811,29 @@ module.exports = grammar({
1621
1811
  // never nested, parenthesized, or one alternative of an outer `|`-chain).
1622
1812
  paren_pattern: ($) => seq("(", $._pattern, ")"),
1623
1813
  wildcard_pattern: () => "_",
1814
+ // #2699 (patterns track, slice 5; events slice 4b, #990): an inclusive
1815
+ // integer range — `lo..hi`, `lo..` or `..hi`, each bound an optionally
1816
+ // negative `Int` literal. One production shared by match patterns and
1817
+ // `via schema(...)`. A bare `..` is never a range (it is `list_rest`), and
1818
+ // `0..9` lexes as `number_literal ".." number_literal` since a float needs
1819
+ // a digit on both sides of its `.`.
1820
+ int_range: ($) => {
1821
+ // Spelled out in each position (not a shared rule), so the parser does
1822
+ // not have to reduce a bound before it can tell a range from a literal.
1823
+ const bound = seq(optional("-"), $.number_literal);
1824
+ return choice(
1825
+ // Right-associative: after `x is 5..` a `-` is the high bound's sign
1826
+ // (the hand-written parser reads it greedily), never a subtraction.
1827
+ prec.right(
1828
+ seq(
1829
+ field("lo", bound),
1830
+ "..",
1831
+ optional(field("hi", bound)),
1832
+ ),
1833
+ ),
1834
+ seq("..", field("hi", bound)),
1835
+ );
1836
+ },
1624
1837
  // v0.130 §2.3.4: a literal pattern — an integer (optionally negated), a
1625
1838
  // string, or a boolean. A closed set (ADR 0001); no `Float`, no `()`.
1626
1839
  literal_pattern: ($) =>
@@ -1666,7 +1879,7 @@ module.exports = grammar({
1666
1879
  is_expr: ($) =>
1667
1880
  prec.left(
1668
1881
  PREC.is,
1669
- seq(field("value", $._expression), "is", field("pattern", $._pattern)),
1882
+ seq(field("value", $._expression), "is", field("pattern", $._is_pattern)),
1670
1883
  ),
1671
1884
 
1672
1885
  binary_expr: ($) =>
@@ -1709,6 +1922,7 @@ module.exports = grammar({
1709
1922
  $.block,
1710
1923
  $.number_literal,
1711
1924
  $.float_literal,
1925
+ $.decimal_literal,
1712
1926
  $.string_literal,
1713
1927
  $.boolean_literal,
1714
1928
  $.unit_literal,
@@ -1717,7 +1931,7 @@ module.exports = grammar({
1717
1931
  $._contextual_identifier,
1718
1932
  ),
1719
1933
 
1720
- // `trace` and `advance` are contextual in the compiler — ordinary
1934
+ // `trace`, `advance` and `par` are contextual in the compiler — ordinary
1721
1935
  // identifiers outside `trace(Cap.op)` / `advance Clock by …`. Here, as
1722
1936
  // `word`-shaped literals, they are extracted as keyword tokens, and where an
1723
1937
  // identifier and the keyword are both valid (an expression or statement
@@ -1725,7 +1939,8 @@ module.exports = grammar({
1725
1939
  // `identifier` in exactly those positions. The next tokens decide: `advance`
1726
1940
  // followed by an identifier can only open an `advance_stmt`, and `trace (`
1727
1941
  // is a declared conflict that `trace_expr`'s dynamic precedence settles.
1728
- _contextual_identifier: ($) => alias(choice("trace", "advance"), $.identifier),
1942
+ _contextual_identifier: ($) =>
1943
+ alias(choice("trace", "advance", "par"), $.identifier),
1729
1944
 
1730
1945
  // v0.20a: a lambda — `(params) => expr | block`. Conflicts with
1731
1946
  // paren_expr/unit_literal until the `=>` disambiguates (GLR conflict
@@ -1739,11 +1954,44 @@ module.exports = grammar({
1739
1954
  field("body", choice($._expression, $.block)),
1740
1955
  ),
1741
1956
 
1957
+ // #2712 (patterns track, slice 6): a parameter is a name with an optional
1958
+ // annotation, or an unannotated record pattern whose fields are bindings.
1742
1959
  lambda_param: ($) =>
1960
+ choice(
1961
+ seq(
1962
+ field("name", choice($.identifier, $._contextual_identifier)),
1963
+ optional(seq(":", field("type", $._type_ref))),
1964
+ ),
1965
+ field("pattern", alias($._lambda_record_pattern, $.record_pattern)),
1966
+ ),
1967
+ // The irrefutable subset a lambda parameter admits: each field is a bare
1968
+ // name, `name: binding`, `name: _`, or a nested such pattern. (A bare
1969
+ // capitalised name is a variant, a refutable pattern the compiler reports.)
1970
+ _lambda_record_pattern: ($) =>
1743
1971
  seq(
1744
- field("name", choice($.identifier, $._contextual_identifier)),
1745
- optional(seq(":", field("type", $._type_ref))),
1972
+ field("type", $.identifier),
1973
+ "{",
1974
+ repeat(seq(alias($._lambda_record_field, $.record_pattern_field), ",")),
1975
+ "..",
1976
+ "}",
1746
1977
  ),
1978
+ _lambda_record_field: ($) =>
1979
+ choice(
1980
+ seq(
1981
+ field("name", $.identifier),
1982
+ ":",
1983
+ field(
1984
+ "pattern",
1985
+ choice(
1986
+ $._lambda_field_binding,
1987
+ $.wildcard_pattern,
1988
+ alias($._lambda_record_pattern, $.record_pattern),
1989
+ ),
1990
+ ),
1991
+ ),
1992
+ field("name", $.identifier),
1993
+ ),
1994
+ _lambda_field_binding: ($) => $.identifier,
1747
1995
 
1748
1996
  paren_expr: ($) => seq("(", $._expression, ")"),
1749
1997
 
@@ -1760,7 +2008,7 @@ module.exports = grammar({
1760
2008
  field("method", $.identifier),
1761
2009
  // v0.22b: optional explicit type arguments on a qualified static —
1762
2010
  // `Json.decode[T](…)` (same-line rule as `call` type application).
1763
- optional(seq("[", sep1(field("type_arg", $._type_ref), ","), "]")),
2011
+ optional(seq(alias($._type_app_open, "["), sep1(field("type_arg", $._type_ref), ","), "]")),
1764
2012
  "(",
1765
2013
  optional(sep1(field("arg", $._expression), ",")),
1766
2014
  optional(","),
@@ -1775,12 +2023,25 @@ module.exports = grammar({
1775
2023
  ),
1776
2024
 
1777
2025
  call: ($) =>
1778
- prec.left(
1779
- PREC.postfix,
2026
+ choice(
2027
+ prec.left(
2028
+ PREC.postfix,
2029
+ seq(
2030
+ field("name", choice($.identifier, $._contextual_identifier)),
2031
+ "(",
2032
+ optional(sep1(field("arg", $._expression), ",")),
2033
+ optional(","),
2034
+ ")",
2035
+ ),
2036
+ ),
2037
+ // v0.20a: explicit type arguments — `name[T, U](…)`. The `[` is the
2038
+ // same-line external token (#2700), so a list-pattern arm on the next
2039
+ // line is never read as a type application.
1780
2040
  seq(
1781
2041
  field("name", choice($.identifier, $._contextual_identifier)),
1782
- // v0.20a: optional explicit type arguments — `name[T, U](…)`.
1783
- optional(seq("[", sep1(field("type_arg", $._type_ref), ","), "]")),
2042
+ alias($._type_app_open, "["),
2043
+ sep1(field("type_arg", $._type_ref), ","),
2044
+ "]",
1784
2045
  "(",
1785
2046
  optional(sep1(field("arg", $._expression), ",")),
1786
2047
  optional(","),
@@ -1888,20 +2149,48 @@ module.exports = grammar({
1888
2149
  // as a method call on an integer literal.
1889
2150
  float_literal: () =>
1890
2151
  /[0-9]+(_[0-9]+)*\.[0-9]+(_[0-9]+)*([eE][+-]?[0-9]+(_[0-9]+)*)?|[0-9]+(_[0-9]+)*[eE][+-]?[0-9]+(_[0-9]+)*/,
2152
+ // #2622: a decimal literal - digits, an optional fraction, a trailing `d`.
2153
+ decimal_literal: () => /[0-9]+(_[0-9]+)*(\.[0-9]+(_[0-9]+)*)?d/,
1891
2154
  string_literal: ($) =>
1892
- seq(
1893
- '"',
1894
- // #2203: string text is one high-precedence immediate token, so a
1895
- // `//` inside a string (a URL) is text, not a line comment.
1896
- repeat(
1897
- choice(
1898
- token.immediate(prec(1, /[^"\\\n]+/)),
1899
- /\\[nt"\\]/,
1900
- $.string_interpolation,
2155
+ choice(
2156
+ seq(
2157
+ '"',
2158
+ // #2203: string text is one high-precedence immediate token, so a
2159
+ // `//` inside a string (a URL) is text, not a line comment.
2160
+ repeat(
2161
+ choice(
2162
+ token.immediate(prec(1, /[^"\\\n]+/)),
2163
+ $.escape_sequence,
2164
+ $.string_interpolation,
2165
+ ),
1901
2166
  ),
2167
+ '"',
1902
2168
  ),
1903
- '"',
1904
- ),
2169
+ // #2619: a multi-line string. The opening `"""` is followed by a
2170
+ // newline; the body may hold lone or doubled quotes; escapes and
2171
+ // interpolation are those of an ordinary string. (Indentation stripping
2172
+ // is a value rule, not a shape: the compiler checks it.)
2173
+ seq(
2174
+ token(/"""\r?\n/),
2175
+ repeat(
2176
+ choice(
2177
+ token.immediate(prec(1, /[^"\\]+/)),
2178
+ token.immediate(prec(1, /"{1,2}[^"\\]/)),
2179
+ $.escape_sequence,
2180
+ $.string_interpolation,
2181
+ ),
2182
+ ),
2183
+ '"""',
2184
+ ),
2185
+ // #2619: a raw string (`r"…"`, `r#"…"#`, `r"""…"""`): no escapes, no
2186
+ // interpolation. An external token — the `#` count is not regular.
2187
+ $.raw_string,
2188
+ ),
2189
+ // `\n \t \r \0 \" \\` and `\u{1–6 hex digits}` (#2619). Whether a `\u{…}`
2190
+ // names a scalar value (not a surrogate, at most 10FFFF) is the compiler's
2191
+ // check.
2192
+ escape_sequence: () =>
2193
+ token.immediate(choice(/\\[ntr0"\\]/, /\\u\{[0-9a-fA-F]{1,6}\}/)),
1905
2194
  // v0.43: an interpolation hole `\(expr)`. A bare `\(` was an invalid
1906
2195
  // escape, so this is backward-compatible; `\\(` is an escaped backslash
1907
2196
  // followed by a literal `(`, so it is not a hole.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-bynk",
3
- "version": "0.447.0",
3
+ "version": "0.492.1",
4
4
  "description": "Tree-sitter grammar for the Bynk language.",
5
5
  "main": "bindings/node",
6
6
  "types": "bindings/node",
@@ -30,7 +30,7 @@
30
30
  "node-gyp-build": "^4.8.0"
31
31
  },
32
32
  "peerDependencies": {
33
- "tree-sitter": "^0.21.0"
33
+ "tree-sitter": "^0.25.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "tree-sitter": {