tree-sitter-bynk 0.142.0 → 0.163.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
@@ -59,6 +59,12 @@ module.exports = grammar({
59
59
  // closing `)` is followed — or not — by `=>`.
60
60
  [$.lambda_param, $._primary],
61
61
  [$._primary, $.lambda_expr],
62
+ // v0.145: a match-arm `if`-guard is an `_expression` immediately followed by
63
+ // the arm's `=>`. When the guard opens with `(`, one token can't tell a unit
64
+ // literal `()` (a guard, with `=>` opening the arm) from a zero-param lambda
65
+ // `() =>` (the guard itself). GLR keeps both alive; only the unit parse
66
+ // completes the arm.
67
+ [$.lambda_expr, $.unit_literal],
62
68
  // v0.117: after `expect Cap.op called`, one token of lookahead can't tell a
63
69
  // following `<n> times` count from the end of the observation — GLR keeps
64
70
  // both parses alive until the next token decides.
@@ -220,7 +226,7 @@ module.exports = grammar({
220
226
  ),
221
227
 
222
228
  _test_body_item: ($) =>
223
- choice($.uses_decl, $.consumes_decl, $.provides_clause, $.case, $.property_decl),
229
+ choice($.uses_decl, $.consumes_decl, $.stub_clause, $.case, $.property_decl),
224
230
 
225
231
  // -- Headers / clauses --
226
232
 
@@ -278,6 +284,9 @@ module.exports = grammar({
278
284
  seq(
279
285
  "type",
280
286
  field("name", $.identifier),
287
+ // v0.157 (ADR 0183): optional `[A, B]` type parameters — only a record
288
+ // body may be generic (enforced by the checker, not the grammar).
289
+ optional(seq("[", sep1(field("type_param", $.identifier), ","), "]")),
281
290
  "=",
282
291
  field("body", $._type_body),
283
292
  ),
@@ -326,7 +335,28 @@ module.exports = grammar({
326
335
  optional(seq("=", field("init", $._expression))),
327
336
  ),
328
337
 
329
- sum_type: ($) => prec.right(repeat1($.sum_variant)),
338
+ // v0.154 (ADR 0178): a sum body may carry a trailing `embeds E as V, …`
339
+ // clause declaring error embeddings the `?` operator auto-converts.
340
+ // `embeds`/`as` are contextual — matched only in this position.
341
+ sum_type: ($) =>
342
+ prec.right(
343
+ seq(
344
+ repeat1($.sum_variant),
345
+ optional(
346
+ seq(
347
+ "embeds",
348
+ sep1(
349
+ seq(
350
+ field("source", $._type_ref),
351
+ "as",
352
+ field("variant", $.constant_name),
353
+ ),
354
+ ",",
355
+ ),
356
+ ),
357
+ ),
358
+ ),
359
+ ),
330
360
  sum_variant: ($) =>
331
361
  seq(
332
362
  "|",
@@ -356,7 +386,10 @@ module.exports = grammar({
356
386
  "}",
357
387
  ),
358
388
 
359
- refinement: ($) => sep1($._refinement_pred, "and"),
389
+ // #548: refinement predicates join with `&&` — the one conjunction spelling,
390
+ // shared with contracts/`expect` (was the `and` keyword before the
391
+ // keyword-hygiene batch). The catalogue stays conjunction-only (no `||`/`!`).
392
+ refinement: ($) => sep1($._refinement_pred, "&&"),
360
393
  _refinement_pred: ($) =>
361
394
  choice(
362
395
  $.pred_call,
@@ -388,9 +421,21 @@ module.exports = grammar({
388
421
  $.unit_type,
389
422
  $.validation_error_type,
390
423
  $.generic_type_ref,
424
+ $.applied_type_ref,
391
425
  $.identifier,
392
426
  ),
393
427
 
428
+ // v0.157 (ADR 0183): `Name[Arg, …]` — an application of a user-declared
429
+ // generic type. Distinct from `generic_type_ref` (the fixed built-in
430
+ // generics); the head is a user identifier.
431
+ applied_type_ref: ($) =>
432
+ seq(
433
+ field("name", $.identifier),
434
+ "[",
435
+ sep1(field("arg", $._type_ref), ","),
436
+ "]",
437
+ ),
438
+
394
439
  // v0.20a: a function type — `A -> B`, `(A, B) -> C`, `() -> B`,
395
440
  // right-associative (prec.right). A parenthesised parameter list is only
396
441
  // a function type when followed by `->`; bare `()` stays the unit type.
@@ -404,6 +449,7 @@ module.exports = grammar({
404
449
  $.unit_type,
405
450
  $.validation_error_type,
406
451
  $.generic_type_ref,
452
+ $.applied_type_ref,
407
453
  $.identifier,
408
454
  seq("(", sep1($._type_ref, ","), optional(","), ")"),
409
455
  ),
@@ -540,6 +586,10 @@ module.exports = grammar({
540
586
  "service",
541
587
  field("name", $.identifier),
542
588
  optional(field("protocol", $.service_protocol)),
589
+ // v0.155: optional service-level `by`/`given` defaults on the header —
590
+ // the ambient contract every handler inherits unless it declares its own.
591
+ optional(field("default_by", $.by_clause)),
592
+ optional(field("default_given", $.given_clause)),
543
593
  "{",
544
594
  // v0.131 (ADR 0158): the optional `cors { }` policy, in header position
545
595
  // before the handlers (a `from http` concern; the checker restricts it).
@@ -590,8 +640,10 @@ module.exports = grammar({
590
640
  limits_field: ($) =>
591
641
  seq(field("name", $.identifier), ":", field("value", $._expression)),
592
642
  // v0.44: `from <protocol>` on the service header.
593
- // v0.103: `from WebSocket(in: I, out: O)` binds the inbound/outbound frame
594
- // types. `WebSocket`, `in`, and `out` are contextual (resolved by `word`).
643
+ // v0.103: `from websocket(in: I, out: O)` binds the inbound/outbound frame
644
+ // types. `websocket`, `in`, and `out` are contextual (resolved by `word`).
645
+ // #548: `websocket` lowercased to match the other protocol sources (was
646
+ // `WebSocket`).
595
647
  service_protocol: ($) =>
596
648
  seq(
597
649
  "from",
@@ -600,7 +652,7 @@ module.exports = grammar({
600
652
  "cron",
601
653
  seq("queue", "(", field("name", $.string_literal), ")"),
602
654
  seq(
603
- "WebSocket",
655
+ "websocket",
604
656
  "(",
605
657
  "in",
606
658
  ":",
@@ -703,13 +755,13 @@ module.exports = grammar({
703
755
  "on",
704
756
  "call",
705
757
  optional(field("method", $.identifier)),
706
- optional(field("by", $.by_clause)),
707
758
  "(",
708
759
  optional(sep1($.param, ",")),
709
760
  optional(","),
710
761
  ")",
711
762
  "->",
712
763
  field("return_type", $._type_ref),
764
+ optional(field("by", $.by_clause)),
713
765
  optional(field("given", $.given_clause)),
714
766
  field("body", $.block),
715
767
  ),
@@ -722,13 +774,13 @@ module.exports = grammar({
722
774
  "(",
723
775
  field("path", $.string_literal),
724
776
  ")",
725
- optional(field("by", $.by_clause)),
726
777
  "(",
727
778
  optional(sep1($.param, ",")),
728
779
  optional(","),
729
780
  ")",
730
781
  "->",
731
782
  field("return_type", $._type_ref),
783
+ optional(field("by", $.by_clause)),
732
784
  optional(field("given", $.given_clause)),
733
785
  field("body", $.block),
734
786
  ),
@@ -741,13 +793,13 @@ module.exports = grammar({
741
793
  "(",
742
794
  field("schedule", $.string_literal),
743
795
  ")",
744
- optional(field("by", $.by_clause)),
745
796
  "(",
746
797
  optional(sep1($.param, ",")),
747
798
  optional(","),
748
799
  ")",
749
800
  "->",
750
801
  field("return_type", $._type_ref),
802
+ optional(field("by", $.by_clause)),
751
803
  optional(field("given", $.given_clause)),
752
804
  field("body", $.block),
753
805
  ),
@@ -757,30 +809,30 @@ module.exports = grammar({
757
809
  seq(
758
810
  "on",
759
811
  "message",
760
- optional(field("by", $.by_clause)),
761
812
  "(",
762
813
  optional(sep1($.param, ",")),
763
814
  optional(","),
764
815
  ")",
765
816
  "->",
766
817
  field("return_type", $._type_ref),
818
+ optional(field("by", $.by_clause)),
767
819
  optional(field("given", $.given_clause)),
768
820
  field("body", $.block),
769
821
  ),
770
822
  // v0.103/v0.106: `on open` / `on close` lifecycle handlers of a
771
- // `from WebSocket` service. `open`/`close` are contextual (resolved by
823
+ // `from websocket` service. `open`/`close` are contextual (resolved by
772
824
  // `word`). `on message` (the inbound-frame handler) reuses queue_handler.
773
825
  ws_open_handler: ($) =>
774
826
  seq(
775
827
  "on",
776
828
  "open",
777
- optional(field("by", $.by_clause)),
778
829
  "(",
779
830
  optional(sep1($.param, ",")),
780
831
  optional(","),
781
832
  ")",
782
833
  "->",
783
834
  field("return_type", $._type_ref),
835
+ optional(field("by", $.by_clause)),
784
836
  optional(field("given", $.given_clause)),
785
837
  field("body", $.block),
786
838
  ),
@@ -788,13 +840,13 @@ module.exports = grammar({
788
840
  seq(
789
841
  "on",
790
842
  "close",
791
- optional(field("by", $.by_clause)),
792
843
  "(",
793
844
  optional(sep1($.param, ",")),
794
845
  optional(","),
795
846
  ")",
796
847
  "->",
797
848
  field("return_type", $._type_ref),
849
+ optional(field("by", $.by_clause)),
798
850
  optional(field("given", $.given_clause)),
799
851
  field("body", $.block),
800
852
  ),
@@ -804,9 +856,18 @@ module.exports = grammar({
804
856
  seq("given", sep1(field("capability", $.qualified_name), ",")),
805
857
 
806
858
  // v0.45: an actor declaration — a boundary contract. Normal form
807
- // `actor Name { auth = Scheme (, identity = Type)? }`; the reserved
808
- // refinement form `actor Admin = Base where <predicate>` is parsed (and
809
- // rejected by the checker in Foundations).
859
+ // `actor Name { auth = Scheme (, identity = Type)? }`. The refinement form
860
+ // `actor Admin = Base where <predicate>` narrows a base actor by an
861
+ // authorisation claim (`actor Admin = User where hasClaim("admin")`).
862
+ //
863
+ // #548: the predicate is a full `_expression`, matching what the compiler
864
+ // parses (a general expression). It is *not* the type-refinement catalogue
865
+ // (`Matches`/`InRange`/…, rule `refinement`) — that mis-modelled `hasClaim`
866
+ // as an ERROR. As with function contracts, the grammar parses the broad
867
+ // expression and a static-semantics rule restricts it to the closed
868
+ // actor-claim catalogue (`hasClaim`/`claimEquals` composed with `&&`/`||`/`!`;
869
+ // `bynk.actor.refinement_predicate_unsupported`). See spec §5 / grammar
870
+ // reference for the three `where` predicate tiers.
810
871
  actor_decl: ($) =>
811
872
  seq(
812
873
  "actor",
@@ -829,13 +890,14 @@ module.exports = grammar({
829
890
  "=",
830
891
  field("base", $.identifier),
831
892
  "where",
832
- field("predicate", $.refinement),
893
+ field("predicate", $._expression),
833
894
  ),
834
895
  ),
835
896
  ),
836
- // The closed, compiler-known scheme set. `None`/`Internal` are admitted in
837
- // Foundations; `Bearer`/`Signature` are reserved-and-rejected.
838
- scheme: () => choice("None", "Internal", "Bearer", "Signature"),
897
+ // The closed, compiler-known scheme set. `None`/`Internal` are zero-crypto;
898
+ // `Bearer` (JWT/HS256), `Signature` (HMAC over the body), and `Oidc`
899
+ // (JWKS/RS256+ES256) are compiler-generated verifiers.
900
+ scheme: () => choice("None", "Internal", "Bearer", "Signature", "Oidc"),
839
901
  // v0.51: the keyed-args scheme config — `(key = value, …)`. Values are
840
902
  // string or integer literals; the checker validates which keys each scheme
841
903
  // admits (Bearer: secret; Signature: secret/header/timestamp/tolerance).
@@ -869,16 +931,15 @@ module.exports = grammar({
869
931
  // -- v0.7: test bodies --
870
932
 
871
933
  // v0.118 (testing track slice 6): a test-scope stub for one capability
872
- // operation — `provides Cap.op(<arg pattern>, …) <rhs>`. Distinguished from
873
- // the production provider declaration (`provides Cap = Impl …`) by the
874
- // `.op(` shape, and only admitted inside a suite/case body. An arg pattern
875
- // is `_` (any) or a value expression; the right-hand side is
876
- // `returns <expr>`, `returns each [ <outcome>, … ]` (a scripted sequence,
877
- // where an outcome is `fails` or an expr), or `fails`. `returns`/`each`/
878
- // `fails` are contextual words.
879
- provides_clause: ($) =>
934
+ // operation — `stub Cap.op(<arg pattern>, …) <rhs>`. Only admitted inside a
935
+ // suite/case body. An arg pattern is `_` (any) or a value expression; the
936
+ // right-hand side is `returns <expr>`, `returns each [ <outcome>, … ]` (a
937
+ // scripted sequence, where an outcome is `fails` or an expr), or `fails`.
938
+ // `returns`/`each`/`fails` are contextual words. Keyword `stub` since the
939
+ // keyword-hygiene batch (#548); formerly a pun on `provides`.
940
+ stub_clause: ($) =>
880
941
  seq(
881
- "provides",
942
+ "stub",
882
943
  field("cap", $.identifier),
883
944
  ".",
884
945
  field("op", $.identifier),
@@ -908,7 +969,7 @@ module.exports = grammar({
908
969
  ),
909
970
  ),
910
971
  // v0.118: an optional `as <tier>` classifier plus a body of leading
911
- // `provides` stubs, then the ordinary statements and tail. The tier words
972
+ // `stub` clauses, then the ordinary statements and tail. The tier words
912
973
  // (`unit`/`integration`/`system`) are contextual, as on `suite_decl`.
913
974
  case: ($) =>
914
975
  seq(
@@ -916,7 +977,7 @@ module.exports = grammar({
916
977
  field("name", $.string_literal),
917
978
  optional(seq("as", field("tier", choice("unit", "integration", "system")))),
918
979
  "{",
919
- repeat($.provides_clause),
980
+ repeat($.stub_clause),
920
981
  repeat($._statement),
921
982
  optional(field("tail", $._expression)),
922
983
  "}",
@@ -963,6 +1024,7 @@ module.exports = grammar({
963
1024
  $.let_stmt,
964
1025
  $.effect_let_stmt,
965
1026
  $.effect_send_stmt,
1027
+ $.do_stmt,
966
1028
  $.assign_stmt,
967
1029
  prec(1, $.expect_expr),
968
1030
  ),
@@ -985,6 +1047,9 @@ module.exports = grammar({
985
1047
  ),
986
1048
  // v0.79: `~> expr` — an asynchronous fire-and-forget send (no binder).
987
1049
  effect_send_stmt: ($) => seq("~>", field("value", $._expression)),
1050
+ // v0.146 (ADR 0170): `do expr` — perform a unit effect as a statement
1051
+ // (the binder-free `let _ <- expr` for an `Effect[()]`).
1052
+ do_stmt: ($) => seq("do", field("value", $._expression)),
988
1053
  // v0.81 (storage track): `name := expr` — a `Cell` store write.
989
1054
  assign_stmt: ($) =>
990
1055
  seq(field("target", $.identifier), ":=", field("value", $._expression)),
@@ -1058,13 +1123,14 @@ module.exports = grammar({
1058
1123
  ),
1059
1124
  ),
1060
1125
 
1126
+ // v0.146 (ADR 0170): `else` is optional. A missing `else` defaults to a
1127
+ // unit branch (legal only for a unit then-branch, enforced by the checker).
1061
1128
  if_expr: ($) =>
1062
1129
  seq(
1063
1130
  "if",
1064
1131
  field("cond", $._expression),
1065
1132
  field("then", $.block),
1066
- "else",
1067
- field("else", choice($.if_expr, $.block)),
1133
+ optional(seq("else", field("else", choice($.if_expr, $.block)))),
1068
1134
  ),
1069
1135
 
1070
1136
  match_expr: ($) =>
@@ -1081,6 +1147,10 @@ module.exports = grammar({
1081
1147
  prec.right(
1082
1148
  seq(
1083
1149
  field("pattern", $._pattern),
1150
+ // v0.145 (ADR 0169): an optional trailing `if <Bool-expr>` guard,
1151
+ // between the pattern and `=>`, gating the arm over its bindings. The
1152
+ // `if` reuses the existing keyword token (already highlighted).
1153
+ optional(seq("if", field("guard", $._expression))),
1084
1154
  "=>",
1085
1155
  // `_expression` already includes `block` via `_primary`, so a
1086
1156
  // `{ … }` arm body is covered without a separate alternative.
@@ -1120,14 +1190,19 @@ module.exports = grammar({
1120
1190
  ),
1121
1191
  ),
1122
1192
  ),
1193
+ // v0.145 (ADR 0169, decision B): a variant payload matches its field against
1194
+ // a full sub-`_pattern` (one recursion point), so `Some(Ok(x))` /
1195
+ // `Err(PollClosed)` parse as nested `variant_pattern` nodes rather than flat
1196
+ // bindings. A bare lowercase identifier is a payload-less `variant_pattern`
1197
+ // (a binding, recovered in the highlight query by capitalisation); `_` is a
1198
+ // `wildcard_pattern`; an uppercase-led one discriminates a nested variant.
1123
1199
  _pattern_binding: ($) =>
1124
1200
  choice(
1125
1201
  $.named_binding,
1126
- $.positional_binding,
1202
+ $._pattern,
1127
1203
  ),
1128
1204
  named_binding: ($) =>
1129
- seq(field("field", $.identifier), ":", field("name", choice($.identifier, "_"))),
1130
- positional_binding: ($) => choice($.identifier, "_"),
1205
+ seq(field("field", $.identifier), ":", field("name", $._pattern)),
1131
1206
 
1132
1207
  is_expr: ($) =>
1133
1208
  prec.left(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-bynk",
3
- "version": "0.142.0",
3
+ "version": "0.163.0",
4
4
  "description": "Tree-sitter grammar for the Bynk DSL (v0–v0.16).",
5
5
  "main": "bindings/node",
6
6
  "types": "bindings/node",
@@ -12,6 +12,7 @@
12
12
  "match"
13
13
  "is"
14
14
  "expect"
15
+ "do"
15
16
  "on"
16
17
  "given"
17
18
  "call"
@@ -19,6 +20,7 @@
19
20
  "http"
20
21
  "cron"
21
22
  "queue"
23
+ "websocket"
22
24
  "schedule"
23
25
  "message"
24
26
  ] @keyword
@@ -36,6 +38,7 @@
36
38
  "fn"
37
39
  "capability"
38
40
  "provides"
41
+ "stub"
39
42
  "service"
40
43
  "agent"
41
44
  "store"
@@ -60,11 +63,11 @@
60
63
 
61
64
  [
62
65
  "where"
63
- "and"
64
66
  "implies"
65
67
  "enum"
66
68
  "for"
67
69
  "all"
70
+ "embeds"
68
71
  ] @keyword.operator
69
72
 
70
73
  ; v0.117: the observation sugar words — contextual (these tokens exist only
@@ -80,7 +83,7 @@
80
83
  ] @keyword.operator
81
84
 
82
85
  ; v0.118: the contextual test-tier words on a `suite`/`case` header (after `as`)
83
- ; and the `provides` stub right-hand-side words. Like the observation words,
86
+ ; and the `stub` clause right-hand-side words. Like the observation words,
84
87
  ; these tokens exist only in their clauses, so a global match never repaints an
85
88
  ; ordinary identifier of the same spelling.
86
89
  [
@@ -109,6 +112,10 @@
109
112
  (type_decl name: (identifier) @type)
110
113
  (opaque_type) @type
111
114
  (generic_type_ref arg: (identifier) @type)
115
+ ; v0.157 (ADR 0183): a user generic-type application — the head name and each
116
+ ; argument are types.
117
+ (applied_type_ref name: (identifier) @type)
118
+ (applied_type_ref arg: (identifier) @type)
112
119
  (record_field type: (identifier) @type)
113
120
  (variant_payload_field type: (identifier) @type)
114
121
  (param type: (identifier) @type)
@@ -151,7 +158,6 @@
151
158
  (field_init name: (identifier) @field)
152
159
  (field_init shorthand: (identifier) @field)
153
160
  (named_binding field: (identifier) @field)
154
- (positional_binding (identifier) @variable)
155
161
 
156
162
  ; -- Variants & constants --
157
163
 
@@ -161,6 +167,12 @@
161
167
  ; pattern variant as a constant.
162
168
  ((variant_pattern variant: (identifier) @constant)
163
169
  (#match? @constant "^[A-Z]"))
170
+ ; v0.145 (ADR 0169): a lowercase-led pattern variant is a payload *binding* (the
171
+ ; universal capitalisation convention) — a bare `n` or the leaf of a nested
172
+ ; pattern like `Some(n)`. Highlight it as a variable, mirroring the retired
173
+ ; `positional_binding` capture now that the payload position is a full pattern.
174
+ ((variant_pattern variant: (identifier) @variable)
175
+ (#match? @variable "^[a-z_]"))
164
176
  (boolean_literal) @constant.builtin
165
177
 
166
178
  ; -- Literals --