tree-sitter-bynk 0.447.0 → 0.504.3
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 +376 -42
- package/package.json +2 -2
- package/queries/highlights.scm +27 -0
- package/src/grammar.json +1843 -359
- package/src/node-types.json +1658 -173
- package/src/parser.c +176367 -83672
- package/src/scanner.c +89 -2
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: ($) =>
|
|
@@ -259,6 +270,8 @@ module.exports = grammar({
|
|
|
259
270
|
$.consumes_decl,
|
|
260
271
|
$.env_clause,
|
|
261
272
|
$.stub_clause,
|
|
273
|
+
$.fixture_decl,
|
|
274
|
+
$.fn_decl,
|
|
262
275
|
$.case,
|
|
263
276
|
$.property_decl,
|
|
264
277
|
),
|
|
@@ -324,17 +337,49 @@ module.exports = grammar({
|
|
|
324
337
|
"}",
|
|
325
338
|
),
|
|
326
339
|
|
|
340
|
+
// -- Type parameters and bounds (constrained generics slice 0) --
|
|
341
|
+
|
|
342
|
+
// `T` or `T: Eq + C`. The constraint names are validated by the checker.
|
|
343
|
+
type_param: ($) =>
|
|
344
|
+
seq(
|
|
345
|
+
field("name", $.identifier),
|
|
346
|
+
optional(seq(":", sep1($.constraint, "+"))),
|
|
347
|
+
),
|
|
348
|
+
|
|
349
|
+
constraint: ($) => $.identifier,
|
|
350
|
+
|
|
351
|
+
where_clause: ($) => seq("where", sep1($.where_bound, ",")),
|
|
352
|
+
|
|
353
|
+
where_bound: ($) =>
|
|
354
|
+
seq(
|
|
355
|
+
field("param", $.identifier),
|
|
356
|
+
":",
|
|
357
|
+
sep1($.constraint, "+"),
|
|
358
|
+
),
|
|
359
|
+
|
|
327
360
|
// -- Type declarations --
|
|
328
361
|
|
|
362
|
+
// #2618: `private` before a `fn`, `type`, `messages`, `asset`, `embed` or
|
|
363
|
+
// `const` declaration makes it unit-private. The word is contextual: with
|
|
364
|
+
// `word` set to `identifier`, it lexes as a keyword only where a
|
|
365
|
+
// declaration may start, so `@cache(scope: private)` and a binding named
|
|
366
|
+
// `private` keep parsing as identifiers. Placement (a commons or context, never an
|
|
367
|
+
// adapter) is the compiler's call (`bynk.visibility.private_not_allowed`).
|
|
368
|
+
visibility_modifier: ($) => "private",
|
|
369
|
+
|
|
329
370
|
type_decl: ($) =>
|
|
330
371
|
seq(
|
|
372
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
331
373
|
"type",
|
|
332
374
|
field("name", $.identifier),
|
|
333
375
|
// v0.157 (ADR 0183): optional `[A, B]` type parameters — only a record
|
|
334
376
|
// body may be generic (enforced by the checker, not the grammar).
|
|
335
|
-
optional(seq("[", sep1(field("type_param", $.
|
|
377
|
+
optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
|
|
336
378
|
"=",
|
|
337
379
|
field("body", $._type_body),
|
|
380
|
+
// Constrained generics slice 1: a trailing `derives Ord` clause, `+`
|
|
381
|
+
// separated like a bound list. `derives` is a contextual word.
|
|
382
|
+
optional(seq("derives", sep1(field("derive", $.constraint), "+"))),
|
|
338
383
|
),
|
|
339
384
|
|
|
340
385
|
_type_body: ($) =>
|
|
@@ -404,6 +449,7 @@ module.exports = grammar({
|
|
|
404
449
|
// (`bynk.asset.outside_context_or_commons` rejects it in an adapter).
|
|
405
450
|
asset_decl: ($) =>
|
|
406
451
|
seq(
|
|
452
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
407
453
|
"asset",
|
|
408
454
|
field("name", $.identifier),
|
|
409
455
|
"=",
|
|
@@ -419,12 +465,41 @@ module.exports = grammar({
|
|
|
419
465
|
// rejects it in an adapter).
|
|
420
466
|
embed_decl: ($) =>
|
|
421
467
|
seq(
|
|
468
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
422
469
|
"embed",
|
|
423
470
|
field("name", $.identifier),
|
|
424
471
|
"=",
|
|
425
472
|
field("path", $.string_literal),
|
|
426
473
|
),
|
|
427
474
|
|
|
475
|
+
// #2841: `fixture name = "fixtures/…"` in a suite body — a project file's
|
|
476
|
+
// text as a `String` constant for the suite's cases. Contextual `fixture`.
|
|
477
|
+
fixture_decl: ($) =>
|
|
478
|
+
seq(
|
|
479
|
+
"fixture",
|
|
480
|
+
field("name", $.identifier),
|
|
481
|
+
"=",
|
|
482
|
+
field("path", $.string_literal),
|
|
483
|
+
),
|
|
484
|
+
|
|
485
|
+
// #2617 (named constants): `const Name: Type = <static expression>` — a
|
|
486
|
+
// named value. Admitted in every body like `embed`; placement
|
|
487
|
+
// (`bynk.resolve.const_outside_context_or_commons`), the name's case
|
|
488
|
+
// (`bynk.resolve.const_name_case`, upper-camel like `constant_name`) and
|
|
489
|
+
// the initialiser's static-ness are checker concerns. The name is an
|
|
490
|
+
// `identifier` because `word` unifies every word-shaped lexeme to it.
|
|
491
|
+
// A leading `private` makes it unit-private, as on `embed`.
|
|
492
|
+
const_decl: ($) =>
|
|
493
|
+
seq(
|
|
494
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
495
|
+
"const",
|
|
496
|
+
field("name", $.identifier),
|
|
497
|
+
":",
|
|
498
|
+
field("type", $._type_ref),
|
|
499
|
+
"=",
|
|
500
|
+
field("value", $._expression),
|
|
501
|
+
),
|
|
502
|
+
|
|
428
503
|
// v0.154 (ADR 0178): a sum body may carry a trailing `embeds E as V, …`
|
|
429
504
|
// clause declaring error embeddings the `?` operator auto-converts.
|
|
430
505
|
// `embeds`/`as` are contextual — matched only in this position.
|
|
@@ -498,6 +573,7 @@ module.exports = grammar({
|
|
|
498
573
|
"NonNegative",
|
|
499
574
|
"Positive",
|
|
500
575
|
"NonEmpty",
|
|
576
|
+
"IsoDate",
|
|
501
577
|
),
|
|
502
578
|
// v0.21/v0.142 (ADR 0166): a refinement-bound number may be negated —
|
|
503
579
|
// `InRange(-1_000, 1_000_000)` — mirroring `parse_signed_num_literal`'s
|
|
@@ -507,12 +583,22 @@ module.exports = grammar({
|
|
|
507
583
|
choice(
|
|
508
584
|
seq(optional("-"), $.number_literal),
|
|
509
585
|
seq(optional("-"), $.float_literal),
|
|
586
|
+
seq(optional("-"), $.decimal_literal),
|
|
510
587
|
$.string_literal,
|
|
511
588
|
),
|
|
512
589
|
|
|
513
590
|
_base_type: ($) => $.base_type,
|
|
514
591
|
base_type: () =>
|
|
515
|
-
choice(
|
|
592
|
+
choice(
|
|
593
|
+
"Int",
|
|
594
|
+
"String",
|
|
595
|
+
"Bool",
|
|
596
|
+
"Float",
|
|
597
|
+
"Duration",
|
|
598
|
+
"Instant",
|
|
599
|
+
"Bytes",
|
|
600
|
+
"Decimal",
|
|
601
|
+
),
|
|
516
602
|
|
|
517
603
|
_type_ref: ($) =>
|
|
518
604
|
choice(
|
|
@@ -617,15 +703,21 @@ module.exports = grammar({
|
|
|
617
703
|
|
|
618
704
|
fn_decl: ($) =>
|
|
619
705
|
seq(
|
|
706
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
620
707
|
"fn",
|
|
621
708
|
field("name", choice($.method_name, $.identifier)),
|
|
622
709
|
// v0.20a: optional `[A, B]` type parameters (functions only).
|
|
623
|
-
optional(seq("[", sep1(field("type_param", $.
|
|
710
|
+
optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
|
|
624
711
|
"(",
|
|
625
712
|
optional($._params),
|
|
626
713
|
")",
|
|
627
714
|
"->",
|
|
628
715
|
field("return_type", $._type_ref),
|
|
716
|
+
// #2868: a context function's capabilities, after the return type.
|
|
717
|
+
optional(field("given", $.given_clause)),
|
|
718
|
+
// Constrained generics slice 0: a method's `where A: Eq` clause bounds
|
|
719
|
+
// a receiver type's parameter.
|
|
720
|
+
optional($.where_clause),
|
|
629
721
|
// v0.115: contract clauses between the return type and the body.
|
|
630
722
|
repeat($.requires_clause),
|
|
631
723
|
repeat($.ensures_clause),
|
|
@@ -681,7 +773,7 @@ module.exports = grammar({
|
|
|
681
773
|
// #926: optional `[T, …]` type parameters on the op itself — resolved
|
|
682
774
|
// only from an explicit type argument at the call site (mirroring
|
|
683
775
|
// `fn_decl`'s own `[A, B]` slot, `grammar.js:525`).
|
|
684
|
-
optional(seq("[", sep1(field("type_param", $.
|
|
776
|
+
optional(seq("[", sep1(field("type_param", $.type_param), ","), "]")),
|
|
685
777
|
"(",
|
|
686
778
|
optional(sep1($.param, ",")),
|
|
687
779
|
optional(","),
|
|
@@ -701,6 +793,7 @@ module.exports = grammar({
|
|
|
701
793
|
// mirroring `service_decl`/`agent_decl`'s existing permissive placement.
|
|
702
794
|
messages_decl: ($) =>
|
|
703
795
|
seq(
|
|
796
|
+
optional(field("visibility", $.visibility_modifier)),
|
|
704
797
|
"messages",
|
|
705
798
|
field("tag", $.string_literal),
|
|
706
799
|
repeat(field("annotation", $.store_annotation)),
|
|
@@ -763,6 +856,9 @@ module.exports = grammar({
|
|
|
763
856
|
// v0.142 (ADR 0166): the optional `limits { }` policy, likewise a
|
|
764
857
|
// header-position `from http` concern restricted by the checker.
|
|
765
858
|
optional(field("limits", $.limits_policy)),
|
|
859
|
+
// #2858: the optional `json { }` policy, likewise a header-position
|
|
860
|
+
// `from http` concern restricted by the checker.
|
|
861
|
+
optional(field("json", $.json_policy)),
|
|
766
862
|
// v0.140 (ADR 0163): a handler may carry one or more `@name(args)`
|
|
767
863
|
// annotations (`@cache(maxAge: 5.minutes)`, `@limit(maxBody: …)`) —
|
|
768
864
|
// the same shape `store_annotation` already gives store fields.
|
|
@@ -805,6 +901,18 @@ module.exports = grammar({
|
|
|
805
901
|
),
|
|
806
902
|
limits_field: ($) =>
|
|
807
903
|
seq(field("name", $.identifier), ":", field("value", $._expression)),
|
|
904
|
+
// #2858: `json { <name>: <value>, … }`. `json` is a contextual keyword (like
|
|
905
|
+
// `limits`); the one field name, `options`, is an ordinary identifier matched
|
|
906
|
+
// by the checker.
|
|
907
|
+
json_policy: ($) =>
|
|
908
|
+
seq(
|
|
909
|
+
"json",
|
|
910
|
+
"{",
|
|
911
|
+
repeat(seq($.json_field, optional(","))),
|
|
912
|
+
"}",
|
|
913
|
+
),
|
|
914
|
+
json_field: ($) =>
|
|
915
|
+
seq(field("name", $.identifier), ":", field("value", $._expression)),
|
|
808
916
|
// v0.44: `from <protocol>` on the service header.
|
|
809
917
|
// v0.103: `from websocket(in: I, out: O)` binds the inbound/outbound frame
|
|
810
918
|
// types. `websocket`, `in`, and `out` are contextual (resolved by `word`).
|
|
@@ -865,14 +973,21 @@ module.exports = grammar({
|
|
|
865
973
|
// than nested inside it. Nested inside the `Events` choice arm, not a
|
|
866
974
|
// free-standing clause any protocol could carry — `via` on `http`/
|
|
867
975
|
// `cron`/`queue`/`websocket` is a syntax error, not a checker
|
|
868
|
-
// diagnostic.
|
|
869
|
-
//
|
|
976
|
+
// diagnostic. A literal, an integer range (`via schema(2..)`, #990 —
|
|
977
|
+
// the same `int_range` a match pattern uses, #2699) or `_`.
|
|
870
978
|
schema_dispatch_clause: ($) =>
|
|
871
979
|
seq(
|
|
872
980
|
"via",
|
|
873
981
|
"schema",
|
|
874
982
|
"(",
|
|
875
|
-
field(
|
|
983
|
+
field(
|
|
984
|
+
"version",
|
|
985
|
+
choice(
|
|
986
|
+
$.int_range,
|
|
987
|
+
seq(optional("-"), $.number_literal),
|
|
988
|
+
$.wildcard_pattern,
|
|
989
|
+
),
|
|
990
|
+
),
|
|
876
991
|
")",
|
|
877
992
|
),
|
|
878
993
|
event_pattern_field: ($) =>
|
|
@@ -1239,8 +1354,9 @@ module.exports = grammar({
|
|
|
1239
1354
|
// v0.118 (testing track slice 6): a test-scope stub for one capability
|
|
1240
1355
|
// operation — `stub Cap.op(<arg pattern>, …) <rhs>`. Only admitted inside a
|
|
1241
1356
|
// suite/case body. An arg pattern is `_` (any) or a value expression; the
|
|
1242
|
-
// right-hand side is `returns <expr
|
|
1243
|
-
// scripted sequence, where an outcome is `fails` or an expr),
|
|
1357
|
+
// right-hand side is `returns <expr> [after <expr>]`, `returns each [ <outcome>, … ]`
|
|
1358
|
+
// (a scripted sequence, where an outcome is `fails` or an expr), `fails`, or
|
|
1359
|
+
// `never`.
|
|
1244
1360
|
// `returns`/`each`/`fails` are contextual words. Keyword `stub` since the
|
|
1245
1361
|
// keyword-hygiene batch (#548); formerly a pun on `provides`.
|
|
1246
1362
|
stub_clause: ($) =>
|
|
@@ -1270,8 +1386,16 @@ module.exports = grammar({
|
|
|
1270
1386
|
),
|
|
1271
1387
|
"]",
|
|
1272
1388
|
),
|
|
1273
|
-
|
|
1389
|
+
// #2683: `returns <v> after <d>` completes on the test clock once
|
|
1390
|
+
// `d` has passed; `never` does not complete. `after` and `never` are
|
|
1391
|
+
// contextual words.
|
|
1392
|
+
seq(
|
|
1393
|
+
"returns",
|
|
1394
|
+
field("value", $._expression),
|
|
1395
|
+
optional(seq("after", field("after", $._expression))),
|
|
1396
|
+
),
|
|
1274
1397
|
"fails",
|
|
1398
|
+
"never",
|
|
1275
1399
|
),
|
|
1276
1400
|
),
|
|
1277
1401
|
// #2134: a suite- or case-scoped `env { NAME = "value" … }` clause — the
|
|
@@ -1343,6 +1467,7 @@ module.exports = grammar({
|
|
|
1343
1467
|
$.do_stmt,
|
|
1344
1468
|
$.assign_stmt,
|
|
1345
1469
|
$.advance_stmt,
|
|
1470
|
+
$.par_stmt,
|
|
1346
1471
|
prec(1, $.expect_expr),
|
|
1347
1472
|
),
|
|
1348
1473
|
|
|
@@ -1374,28 +1499,50 @@ module.exports = grammar({
|
|
|
1374
1499
|
// lenient (a bare-name `variant_pattern` is admitted) because the compiler,
|
|
1375
1500
|
// not the highlighter, reports `bynk.parse.let_else_on_binding`.
|
|
1376
1501
|
let_else_stmt: ($) =>
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1502
|
+
choice(
|
|
1503
|
+
seq(
|
|
1504
|
+
"let",
|
|
1505
|
+
field("pattern", choice($._let_pattern, alias($._let_or_pattern, $.or_pattern))),
|
|
1506
|
+
field("bind", choice("=", "<-")),
|
|
1507
|
+
field("value", $._expression),
|
|
1508
|
+
optional(field("principal", $.call_site_actor)),
|
|
1509
|
+
"else",
|
|
1510
|
+
field("else", choice($.block, $.let_else_match)),
|
|
1511
|
+
),
|
|
1512
|
+
// #2654 (patterns track, slice 2): `let Item { sku, .. } = item` — the
|
|
1513
|
+
// `else` is optional when the pattern is a record pattern (the compiler further
|
|
1514
|
+
// requires it to be irrefutable, `let_pattern_without_else`; whether a
|
|
1515
|
+
// field's sub-pattern is a binding or a variant is a matter of
|
|
1516
|
+
// capitalisation, which this grammar cannot see). Parentheses around
|
|
1517
|
+
// the pattern are transparent.
|
|
1518
|
+
seq(
|
|
1519
|
+
"let",
|
|
1520
|
+
field("pattern", choice($.record_pattern, alias($._let_paren_record_pattern, $.paren_pattern))),
|
|
1521
|
+
field("bind", choice("=", "<-")),
|
|
1522
|
+
field("value", $._expression),
|
|
1523
|
+
optional(field("principal", $.call_site_actor)),
|
|
1524
|
+
optional(seq("else", field("else", choice($.block, $.let_else_match)))),
|
|
1525
|
+
),
|
|
1385
1526
|
),
|
|
1527
|
+
_let_paren_record_pattern: ($) => seq("(", $.record_pattern, ")"),
|
|
1386
1528
|
// #2010: the patterns that may open a `let … else`, mirroring the Rust
|
|
1387
1529
|
// parser's `let_pattern_ahead`: a literal, a parenthesised pattern, or a
|
|
1388
1530
|
// variant with a payload or a qualifier. A bare name stays a binding (and
|
|
1389
1531
|
// a bare `_` a discard), so `let x = …` is never ambiguous here.
|
|
1390
1532
|
_let_pattern: ($) =>
|
|
1391
1533
|
choice(
|
|
1534
|
+
$.int_range,
|
|
1392
1535
|
$.literal_pattern,
|
|
1393
1536
|
$.paren_pattern,
|
|
1537
|
+
$.list_pattern,
|
|
1394
1538
|
alias($._let_variant_pattern, $.variant_pattern),
|
|
1395
1539
|
),
|
|
1396
1540
|
// `let Ok(x) | Err(x) = …`: an or-chain whose first alternative opens a
|
|
1397
1541
|
// pattern; the rest are any patterns.
|
|
1398
|
-
|
|
1542
|
+
// #2654: a record pattern may open the chain too (`let Item { .. } | …`),
|
|
1543
|
+
// though on its own it is the `else`-less alternative of `let_else_stmt`.
|
|
1544
|
+
_let_or_pattern: ($) =>
|
|
1545
|
+
prec.left(1, seq(choice($._let_pattern, $.record_pattern), "|", $._pattern)),
|
|
1399
1546
|
_let_variant_pattern: ($) => {
|
|
1400
1547
|
const payload = seq("(", optional(sep1($._pattern_binding, ",")), optional(","), ")");
|
|
1401
1548
|
return prec.right(
|
|
@@ -1456,6 +1603,28 @@ module.exports = grammar({
|
|
|
1456
1603
|
field("amount", $._expression),
|
|
1457
1604
|
),
|
|
1458
1605
|
|
|
1606
|
+
// #2640 (concurrent effects, slice 0): `par { let a <- e1 let b <- e2 }` —
|
|
1607
|
+
// issue every effect, then wait for them all. `par` is contextual: it opens
|
|
1608
|
+
// a statement only before `{`. The grammar stays permissive about the
|
|
1609
|
+
// block's contents (any statement parses); the compiler admits only
|
|
1610
|
+
// `let x <- e` and `do e` (`bynk.par.invalid_statement`).
|
|
1611
|
+
par_stmt: ($) => seq("par", "{", repeat($._par_statement), "}"),
|
|
1612
|
+
|
|
1613
|
+
// Any statement but `let … else`, which would take the rest of the block as
|
|
1614
|
+
// its arm and so has no room inside a `par` (the compiler's parser refuses
|
|
1615
|
+
// it with `bynk.par.invalid_statement`).
|
|
1616
|
+
_par_statement: ($) =>
|
|
1617
|
+
choice(
|
|
1618
|
+
$.let_stmt,
|
|
1619
|
+
$.effect_let_stmt,
|
|
1620
|
+
$.effect_send_stmt,
|
|
1621
|
+
$.do_stmt,
|
|
1622
|
+
$.assign_stmt,
|
|
1623
|
+
$.advance_stmt,
|
|
1624
|
+
$.par_stmt,
|
|
1625
|
+
prec(1, $.expect_expr),
|
|
1626
|
+
),
|
|
1627
|
+
|
|
1459
1628
|
// A let/effect-let may bind the discard name `_`.
|
|
1460
1629
|
_binding_name: ($) => choice($.identifier, alias("_", $.wildcard)),
|
|
1461
1630
|
|
|
@@ -1482,7 +1651,10 @@ module.exports = grammar({
|
|
|
1482
1651
|
PREC.expect,
|
|
1483
1652
|
seq(
|
|
1484
1653
|
"expect",
|
|
1485
|
-
field(
|
|
1654
|
+
field(
|
|
1655
|
+
"cond",
|
|
1656
|
+
choice($.observation_expr, $.faults_expr, $.snapshot_expr, $._expression),
|
|
1657
|
+
),
|
|
1486
1658
|
),
|
|
1487
1659
|
),
|
|
1488
1660
|
|
|
@@ -1499,6 +1671,18 @@ module.exports = grammar({
|
|
|
1499
1671
|
"faults",
|
|
1500
1672
|
),
|
|
1501
1673
|
|
|
1674
|
+
// #2842: a snapshot claim — `expect <value> matches snapshot "<name>"`
|
|
1675
|
+
// compares the value's canonical JSON with a stored snapshot. `matches` and
|
|
1676
|
+
// `snapshot` are contextual, as `faults` is: an expression is never followed
|
|
1677
|
+
// by a bare identifier, so the words alone decide.
|
|
1678
|
+
snapshot_expr: ($) =>
|
|
1679
|
+
seq(
|
|
1680
|
+
field("value", $._expression),
|
|
1681
|
+
"matches",
|
|
1682
|
+
"snapshot",
|
|
1683
|
+
field("name", $.string_literal),
|
|
1684
|
+
),
|
|
1685
|
+
|
|
1502
1686
|
// v0.117: an observation — a `Cap.op` seam reference followed by one of the
|
|
1503
1687
|
// sugar matchers. `called` / `never` / `once` / `times` / `with` / `before`
|
|
1504
1688
|
// are contextual (state-lexed as keywords only here; ordinary identifiers
|
|
@@ -1601,11 +1785,62 @@ module.exports = grammar({
|
|
|
1601
1785
|
_pattern: ($) =>
|
|
1602
1786
|
choice(
|
|
1603
1787
|
$.wildcard_pattern,
|
|
1788
|
+
$.int_range,
|
|
1604
1789
|
$.literal_pattern,
|
|
1605
1790
|
$.variant_pattern,
|
|
1791
|
+
$.record_pattern,
|
|
1792
|
+
$.list_pattern,
|
|
1606
1793
|
$.or_pattern,
|
|
1607
1794
|
$.paren_pattern,
|
|
1608
1795
|
),
|
|
1796
|
+
// #2641 (patterns track, slice 1): `Order { status: Paid, total, .. }`. Always
|
|
1797
|
+
// open, with the trailing `..` mandatory so that adding a field to the record
|
|
1798
|
+
// never breaks a pattern — the rule `event_pattern` already applies to
|
|
1799
|
+
// events. A field is a bare name (binding it to a local of the same name) or
|
|
1800
|
+
// `name: pattern`. After `is` a record pattern must be parenthesised (see
|
|
1801
|
+
// `_is_pattern`), because there the `{` would also open the `if`'s block.
|
|
1802
|
+
record_pattern: ($) =>
|
|
1803
|
+
seq(
|
|
1804
|
+
field("type", $.identifier),
|
|
1805
|
+
"{",
|
|
1806
|
+
repeat(seq($.record_pattern_field, ",")),
|
|
1807
|
+
"..",
|
|
1808
|
+
"}",
|
|
1809
|
+
),
|
|
1810
|
+
// #2680 (patterns track, slice 4): `[]`, `[p, …]`, `[p, …, ..]`,
|
|
1811
|
+
// `[p, …, ..rest]`. The rest marker is last and at most once; `..` takes a
|
|
1812
|
+
// name or nothing (a literal after it is reserved for range patterns, and
|
|
1813
|
+
// the compiler reports it). It needs no parentheses after `is`, where the
|
|
1814
|
+
// pattern closes at `]`.
|
|
1815
|
+
list_pattern: ($) =>
|
|
1816
|
+
seq(
|
|
1817
|
+
"[",
|
|
1818
|
+
repeat(seq($._pattern, ",")),
|
|
1819
|
+
optional(choice($._pattern, seq($.list_rest, optional(",")))),
|
|
1820
|
+
"]",
|
|
1821
|
+
),
|
|
1822
|
+
list_rest: ($) => seq("..", optional(field("name", $.identifier))),
|
|
1823
|
+
record_pattern_field: ($) =>
|
|
1824
|
+
choice(
|
|
1825
|
+
seq(field("name", $.identifier), ":", field("pattern", $._pattern)),
|
|
1826
|
+
field("name", $.identifier),
|
|
1827
|
+
),
|
|
1828
|
+
// #2641: the patterns an `is` accepts without parentheses — `_pattern`
|
|
1829
|
+
// without a record pattern at its tail, at the top level or as an
|
|
1830
|
+
// or-alternative. Parenthesised, a record pattern is allowed anywhere (the
|
|
1831
|
+
// hand-written parser's `is_pattern_tail` restriction).
|
|
1832
|
+
_is_base_pattern: ($) =>
|
|
1833
|
+
choice(
|
|
1834
|
+
$.wildcard_pattern,
|
|
1835
|
+
$.literal_pattern,
|
|
1836
|
+
$.variant_pattern,
|
|
1837
|
+
$.list_pattern,
|
|
1838
|
+
$.paren_pattern,
|
|
1839
|
+
),
|
|
1840
|
+
_is_pattern: ($) =>
|
|
1841
|
+
choice($._is_base_pattern, alias($._is_or_pattern, $.or_pattern)),
|
|
1842
|
+
_is_or_pattern: ($) =>
|
|
1843
|
+
prec.left(1, seq($._is_pattern, "|", $._is_base_pattern)),
|
|
1609
1844
|
// #474 §2.3.4: `p₁ | p₂ | … | pₙ` — an or-pattern, left-associative;
|
|
1610
1845
|
// matches if any alternative matches. `|` is a pattern-position operator
|
|
1611
1846
|
// only — not a valid expression operator, and lexically distinct from
|
|
@@ -1621,6 +1856,29 @@ module.exports = grammar({
|
|
|
1621
1856
|
// never nested, parenthesized, or one alternative of an outer `|`-chain).
|
|
1622
1857
|
paren_pattern: ($) => seq("(", $._pattern, ")"),
|
|
1623
1858
|
wildcard_pattern: () => "_",
|
|
1859
|
+
// #2699 (patterns track, slice 5; events slice 4b, #990): an inclusive
|
|
1860
|
+
// integer range — `lo..hi`, `lo..` or `..hi`, each bound an optionally
|
|
1861
|
+
// negative `Int` literal. One production shared by match patterns and
|
|
1862
|
+
// `via schema(...)`. A bare `..` is never a range (it is `list_rest`), and
|
|
1863
|
+
// `0..9` lexes as `number_literal ".." number_literal` since a float needs
|
|
1864
|
+
// a digit on both sides of its `.`.
|
|
1865
|
+
int_range: ($) => {
|
|
1866
|
+
// Spelled out in each position (not a shared rule), so the parser does
|
|
1867
|
+
// not have to reduce a bound before it can tell a range from a literal.
|
|
1868
|
+
const bound = seq(optional("-"), $.number_literal);
|
|
1869
|
+
return choice(
|
|
1870
|
+
// Right-associative: after `x is 5..` a `-` is the high bound's sign
|
|
1871
|
+
// (the hand-written parser reads it greedily), never a subtraction.
|
|
1872
|
+
prec.right(
|
|
1873
|
+
seq(
|
|
1874
|
+
field("lo", bound),
|
|
1875
|
+
"..",
|
|
1876
|
+
optional(field("hi", bound)),
|
|
1877
|
+
),
|
|
1878
|
+
),
|
|
1879
|
+
seq("..", field("hi", bound)),
|
|
1880
|
+
);
|
|
1881
|
+
},
|
|
1624
1882
|
// v0.130 §2.3.4: a literal pattern — an integer (optionally negated), a
|
|
1625
1883
|
// string, or a boolean. A closed set (ADR 0001); no `Float`, no `()`.
|
|
1626
1884
|
literal_pattern: ($) =>
|
|
@@ -1666,7 +1924,7 @@ module.exports = grammar({
|
|
|
1666
1924
|
is_expr: ($) =>
|
|
1667
1925
|
prec.left(
|
|
1668
1926
|
PREC.is,
|
|
1669
|
-
seq(field("value", $._expression), "is", field("pattern", $.
|
|
1927
|
+
seq(field("value", $._expression), "is", field("pattern", $._is_pattern)),
|
|
1670
1928
|
),
|
|
1671
1929
|
|
|
1672
1930
|
binary_expr: ($) =>
|
|
@@ -1709,6 +1967,7 @@ module.exports = grammar({
|
|
|
1709
1967
|
$.block,
|
|
1710
1968
|
$.number_literal,
|
|
1711
1969
|
$.float_literal,
|
|
1970
|
+
$.decimal_literal,
|
|
1712
1971
|
$.string_literal,
|
|
1713
1972
|
$.boolean_literal,
|
|
1714
1973
|
$.unit_literal,
|
|
@@ -1717,7 +1976,7 @@ module.exports = grammar({
|
|
|
1717
1976
|
$._contextual_identifier,
|
|
1718
1977
|
),
|
|
1719
1978
|
|
|
1720
|
-
// `trace` and `
|
|
1979
|
+
// `trace`, `advance` and `par` are contextual in the compiler — ordinary
|
|
1721
1980
|
// identifiers outside `trace(Cap.op)` / `advance Clock by …`. Here, as
|
|
1722
1981
|
// `word`-shaped literals, they are extracted as keyword tokens, and where an
|
|
1723
1982
|
// identifier and the keyword are both valid (an expression or statement
|
|
@@ -1725,7 +1984,8 @@ module.exports = grammar({
|
|
|
1725
1984
|
// `identifier` in exactly those positions. The next tokens decide: `advance`
|
|
1726
1985
|
// followed by an identifier can only open an `advance_stmt`, and `trace (`
|
|
1727
1986
|
// is a declared conflict that `trace_expr`'s dynamic precedence settles.
|
|
1728
|
-
_contextual_identifier: ($) =>
|
|
1987
|
+
_contextual_identifier: ($) =>
|
|
1988
|
+
alias(choice("trace", "advance", "par"), $.identifier),
|
|
1729
1989
|
|
|
1730
1990
|
// v0.20a: a lambda — `(params) => expr | block`. Conflicts with
|
|
1731
1991
|
// paren_expr/unit_literal until the `=>` disambiguates (GLR conflict
|
|
@@ -1739,11 +1999,44 @@ module.exports = grammar({
|
|
|
1739
1999
|
field("body", choice($._expression, $.block)),
|
|
1740
2000
|
),
|
|
1741
2001
|
|
|
2002
|
+
// #2712 (patterns track, slice 6): a parameter is a name with an optional
|
|
2003
|
+
// annotation, or an unannotated record pattern whose fields are bindings.
|
|
1742
2004
|
lambda_param: ($) =>
|
|
2005
|
+
choice(
|
|
2006
|
+
seq(
|
|
2007
|
+
field("name", choice($.identifier, $._contextual_identifier)),
|
|
2008
|
+
optional(seq(":", field("type", $._type_ref))),
|
|
2009
|
+
),
|
|
2010
|
+
field("pattern", alias($._lambda_record_pattern, $.record_pattern)),
|
|
2011
|
+
),
|
|
2012
|
+
// The irrefutable subset a lambda parameter admits: each field is a bare
|
|
2013
|
+
// name, `name: binding`, `name: _`, or a nested such pattern. (A bare
|
|
2014
|
+
// capitalised name is a variant, a refutable pattern the compiler reports.)
|
|
2015
|
+
_lambda_record_pattern: ($) =>
|
|
1743
2016
|
seq(
|
|
1744
|
-
field("
|
|
1745
|
-
|
|
2017
|
+
field("type", $.identifier),
|
|
2018
|
+
"{",
|
|
2019
|
+
repeat(seq(alias($._lambda_record_field, $.record_pattern_field), ",")),
|
|
2020
|
+
"..",
|
|
2021
|
+
"}",
|
|
1746
2022
|
),
|
|
2023
|
+
_lambda_record_field: ($) =>
|
|
2024
|
+
choice(
|
|
2025
|
+
seq(
|
|
2026
|
+
field("name", $.identifier),
|
|
2027
|
+
":",
|
|
2028
|
+
field(
|
|
2029
|
+
"pattern",
|
|
2030
|
+
choice(
|
|
2031
|
+
$._lambda_field_binding,
|
|
2032
|
+
$.wildcard_pattern,
|
|
2033
|
+
alias($._lambda_record_pattern, $.record_pattern),
|
|
2034
|
+
),
|
|
2035
|
+
),
|
|
2036
|
+
),
|
|
2037
|
+
field("name", $.identifier),
|
|
2038
|
+
),
|
|
2039
|
+
_lambda_field_binding: ($) => $.identifier,
|
|
1747
2040
|
|
|
1748
2041
|
paren_expr: ($) => seq("(", $._expression, ")"),
|
|
1749
2042
|
|
|
@@ -1760,7 +2053,7 @@ module.exports = grammar({
|
|
|
1760
2053
|
field("method", $.identifier),
|
|
1761
2054
|
// v0.22b: optional explicit type arguments on a qualified static —
|
|
1762
2055
|
// `Json.decode[T](…)` (same-line rule as `call` type application).
|
|
1763
|
-
optional(seq("[", sep1(field("type_arg", $._type_ref), ","), "]")),
|
|
2056
|
+
optional(seq(alias($._type_app_open, "["), sep1(field("type_arg", $._type_ref), ","), "]")),
|
|
1764
2057
|
"(",
|
|
1765
2058
|
optional(sep1(field("arg", $._expression), ",")),
|
|
1766
2059
|
optional(","),
|
|
@@ -1775,12 +2068,25 @@ module.exports = grammar({
|
|
|
1775
2068
|
),
|
|
1776
2069
|
|
|
1777
2070
|
call: ($) =>
|
|
1778
|
-
|
|
1779
|
-
|
|
2071
|
+
choice(
|
|
2072
|
+
prec.left(
|
|
2073
|
+
PREC.postfix,
|
|
2074
|
+
seq(
|
|
2075
|
+
field("name", choice($.identifier, $._contextual_identifier)),
|
|
2076
|
+
"(",
|
|
2077
|
+
optional(sep1(field("arg", $._expression), ",")),
|
|
2078
|
+
optional(","),
|
|
2079
|
+
")",
|
|
2080
|
+
),
|
|
2081
|
+
),
|
|
2082
|
+
// v0.20a: explicit type arguments — `name[T, U](…)`. The `[` is the
|
|
2083
|
+
// same-line external token (#2700), so a list-pattern arm on the next
|
|
2084
|
+
// line is never read as a type application.
|
|
1780
2085
|
seq(
|
|
1781
2086
|
field("name", choice($.identifier, $._contextual_identifier)),
|
|
1782
|
-
|
|
1783
|
-
|
|
2087
|
+
alias($._type_app_open, "["),
|
|
2088
|
+
sep1(field("type_arg", $._type_ref), ","),
|
|
2089
|
+
"]",
|
|
1784
2090
|
"(",
|
|
1785
2091
|
optional(sep1(field("arg", $._expression), ",")),
|
|
1786
2092
|
optional(","),
|
|
@@ -1888,20 +2194,48 @@ module.exports = grammar({
|
|
|
1888
2194
|
// as a method call on an integer literal.
|
|
1889
2195
|
float_literal: () =>
|
|
1890
2196
|
/[0-9]+(_[0-9]+)*\.[0-9]+(_[0-9]+)*([eE][+-]?[0-9]+(_[0-9]+)*)?|[0-9]+(_[0-9]+)*[eE][+-]?[0-9]+(_[0-9]+)*/,
|
|
2197
|
+
// #2622: a decimal literal - digits, an optional fraction, a trailing `d`.
|
|
2198
|
+
decimal_literal: () => /[0-9]+(_[0-9]+)*(\.[0-9]+(_[0-9]+)*)?d/,
|
|
1891
2199
|
string_literal: ($) =>
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2200
|
+
choice(
|
|
2201
|
+
seq(
|
|
2202
|
+
'"',
|
|
2203
|
+
// #2203: string text is one high-precedence immediate token, so a
|
|
2204
|
+
// `//` inside a string (a URL) is text, not a line comment.
|
|
2205
|
+
repeat(
|
|
2206
|
+
choice(
|
|
2207
|
+
token.immediate(prec(1, /[^"\\\n]+/)),
|
|
2208
|
+
$.escape_sequence,
|
|
2209
|
+
$.string_interpolation,
|
|
2210
|
+
),
|
|
1901
2211
|
),
|
|
2212
|
+
'"',
|
|
1902
2213
|
),
|
|
1903
|
-
|
|
1904
|
-
|
|
2214
|
+
// #2619: a multi-line string. The opening `"""` is followed by a
|
|
2215
|
+
// newline; the body may hold lone or doubled quotes; escapes and
|
|
2216
|
+
// interpolation are those of an ordinary string. (Indentation stripping
|
|
2217
|
+
// is a value rule, not a shape: the compiler checks it.)
|
|
2218
|
+
seq(
|
|
2219
|
+
token(/"""\r?\n/),
|
|
2220
|
+
repeat(
|
|
2221
|
+
choice(
|
|
2222
|
+
token.immediate(prec(1, /[^"\\]+/)),
|
|
2223
|
+
token.immediate(prec(1, /"{1,2}[^"\\]/)),
|
|
2224
|
+
$.escape_sequence,
|
|
2225
|
+
$.string_interpolation,
|
|
2226
|
+
),
|
|
2227
|
+
),
|
|
2228
|
+
'"""',
|
|
2229
|
+
),
|
|
2230
|
+
// #2619: a raw string (`r"…"`, `r#"…"#`, `r"""…"""`): no escapes, no
|
|
2231
|
+
// interpolation. An external token — the `#` count is not regular.
|
|
2232
|
+
$.raw_string,
|
|
2233
|
+
),
|
|
2234
|
+
// `\n \t \r \0 \" \\` and `\u{1–6 hex digits}` (#2619). Whether a `\u{…}`
|
|
2235
|
+
// names a scalar value (not a surrogate, at most 10FFFF) is the compiler's
|
|
2236
|
+
// check.
|
|
2237
|
+
escape_sequence: () =>
|
|
2238
|
+
token.immediate(choice(/\\[ntr0"\\]/, /\\u\{[0-9a-fA-F]{1,6}\}/)),
|
|
1905
2239
|
// v0.43: an interpolation hole `\(expr)`. A bare `\(` was an invalid
|
|
1906
2240
|
// escape, so this is backward-compatible; `\\(` is an escaped backslash
|
|
1907
2241
|
// followed by a literal `(`, so it is not a hole.
|