tree-sitter-compact 0.0.0-stage → 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 ADDED
@@ -0,0 +1,865 @@
1
+ // This file is part of compact-tree-sitter.
2
+ // Copyright (C) 2025 Midnight Foundation
3
+ // Modifications Copyright (C) 2025 Nick Pappas and compact-tree-sitter contributors
4
+ // SPDX-License-Identifier: Apache-2.0
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // You may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ /**
18
+ * @file A zero-knowledge smart contract programming language
19
+ * @author Lucas Rosa <lucas.rosa@shielded.io>
20
+ * @author Nick Pappas <https://github.com/1NickPappas>
21
+ * @license Apache-2.0
22
+ *
23
+ * Community fork targeting the Compact toolchain 0.31.1 (language 0.23.0),
24
+ * which is the version supported on Midnight mainnet. See NOTICE for attribution.
25
+ */
26
+
27
+ /// <reference types="tree-sitter-cli/dsl" />
28
+ // @ts-check
29
+
30
+ module.exports = grammar({
31
+ name: 'compact',
32
+
33
+ conflicts: ($) => [
34
+ [$.fun, $.term, $.tref],
35
+ [$.fun, $.pattern, $.term],
36
+ [$.pattern, $.term],
37
+ [$.fun, $.term],
38
+ [$.fun, $.pattern],
39
+ [$.pattern, $.array_literal],
40
+ ],
41
+
42
+ extras: ($) => [
43
+ /[\s\n]+/,
44
+ $.comment, // Add comments as extras
45
+ ],
46
+
47
+ rules: {
48
+ // Compact (program)
49
+ //
50
+ // program → pelt … pelt eof
51
+ source_file: ($) => repeat($._pelt),
52
+
53
+ // Comments
54
+ //
55
+ // Line comments start with // and run to the end of the line.
56
+ // Block comments are delimited by /* and */ and do not nest.
57
+ comment: ($) =>
58
+ choice(
59
+ token(seq('//', /[^\n]*/)),
60
+ token(/\/\*([^*]|\*[^\/])*\*\//),
61
+ ),
62
+
63
+ // Program-element (pelt)
64
+ //
65
+ // pelt → pragma
66
+ // → incld
67
+ // → mdefn
68
+ // → idecl
69
+ // → xdecl
70
+ // → ldecl
71
+ // → lconstructor
72
+ // → cdefn
73
+ // → wdecl
74
+ // → ecdecl
75
+ // → struct
76
+ // → enumdef
77
+ // → contract-implements-declaration
78
+ _pelt: ($) =>
79
+ choice(
80
+ $.pragma,
81
+ $.incld,
82
+ $.mdefn,
83
+ $.idecl,
84
+ $.xdecl,
85
+ $.ldecl,
86
+ $.lconstructor,
87
+ $.cdefn,
88
+ $.wdecl,
89
+ $.ecdecl,
90
+ $.struct,
91
+ $.enumdef,
92
+ $.contract_implements_declaration,
93
+ $.type_alias_declaration,
94
+ ),
95
+
96
+ // Pragma rules
97
+ //
98
+ // pragma → pragma id version-expr ;
99
+ pragma: ($) => seq(
100
+ 'pragma',
101
+ field('id', $.id),
102
+ $._version_expr,
103
+ ';',
104
+ ),
105
+
106
+ // Version-expression (version-expr)
107
+ //
108
+ // version-expr → version-expr || version-expr0
109
+ // → version-expr0
110
+ _version_expr: ($) =>
111
+ prec.left(
112
+ 1,
113
+ choice(seq($._version_expr, $.or, $._version_expr0), $._version_expr0),
114
+ ),
115
+
116
+ // Version-expression0 (version-expr0)
117
+ //
118
+ // version-expr0 → version-expr0 && version-term
119
+ // → version-term
120
+ _version_expr0: ($) =>
121
+ prec.left(
122
+ 2,
123
+ choice(seq($._version_expr0, $.and, $._version_term), $._version_term),
124
+ ),
125
+
126
+ // Version-Term (version-term)
127
+ //
128
+ // version-term → version-atom
129
+ // → ! version-term
130
+ // → < version-atom
131
+ // → <= version-atom
132
+ // → >= version-atom
133
+ // → > version-atom
134
+ // → ( version-expr )
135
+ _version_term: ($) =>
136
+ choice(
137
+ $._version_atom,
138
+ field('version_expression', seq($._version_op, $._version_atom)),
139
+ seq('(', $._version_expr, ')'),
140
+ ),
141
+
142
+ // Version-atom (version-atom)
143
+ //
144
+ // version-atom → nat
145
+ // → version
146
+ _version_atom: ($) => choice($.nat, $.version),
147
+
148
+ _version_op: ($) =>
149
+ choice(
150
+ $.not,
151
+ $.greater_than,
152
+ $.less_than,
153
+ $.greater_than_or_equal,
154
+ $.less_than_or_equal,
155
+ ),
156
+
157
+ // Type-declaration (type-alias-declaration)
158
+ //
159
+ // type-alias-declaration → export^opt new^opt type type-name gparams^opt = type ;
160
+ type_alias_declaration: ($) =>
161
+ seq(
162
+ optional(field('export', $.export)),
163
+ optional('new'),
164
+ 'type',
165
+ field('name', $.type_name),
166
+ optional(field('gparams', $.gparams)),
167
+ '=',
168
+ field('type', $.type),
169
+ ';',
170
+ ),
171
+
172
+ // Include (incld)
173
+ //
174
+ // incld → include file ;
175
+ incld: ($) => seq('include', field('file', $.file), ';'),
176
+
177
+ // Module-definition (mdefn)
178
+ //
179
+ // mdefn → export^opt module module-name gparams^opt { pelt … pelt }
180
+ mdefn: ($) =>
181
+ seq(
182
+ optional(field('export', $.export)),
183
+ 'module',
184
+ field('name', $.module_name),
185
+ optional(field('gparams', $.gparams)),
186
+ '{',
187
+ repeat(field('module_element', $._pelt)),
188
+ '}',
189
+ ),
190
+
191
+ // Generic-parameter-list (gparams)
192
+ //
193
+ // gparams → < generic-param , … , generic-param >
194
+ gparams: ($) => seq('<', commaSep1(field('gparam', $.generic_param)), '>'),
195
+
196
+ // Generic-parameter (generic-param)
197
+ //
198
+ // generic-param → # tvar-name
199
+ // → tvar-name
200
+ generic_param: ($) => choice(seq('#', $.tvar_name), $.tvar_name),
201
+
202
+ // Import-declaration (idecl)
203
+ //
204
+ // idecl → import import-selection^opt import-name gargs^opt prefix^opt ;
205
+ idecl: ($) =>
206
+ seq(
207
+ 'import',
208
+ optional(field('selection', $.import_selection)),
209
+ field('id', $.import_name),
210
+ optional(field('gargs', $.gargs)),
211
+ optional(field('prefix', $.prefix)),
212
+ ';',
213
+ ),
214
+
215
+ // Import-selection (import-selection)
216
+ //
217
+ // import-selection → { import-element , … , import-element ,^opt } from
218
+ import_selection: ($) =>
219
+ seq('{', commaSep(field('element', $.import_element)), '}', 'from'),
220
+
221
+ // Import-element (import-element)
222
+ //
223
+ // import-element → id
224
+ // → id as id
225
+ import_element: ($) =>
226
+ seq(field('id', $.id), optional(seq('as', field('alias', $.id)))),
227
+
228
+ // Import-name (import-name)
229
+ //
230
+ // import-name → id
231
+ // → file
232
+ import_name: ($) => choice($.id, $.file),
233
+
234
+ // Generic-argument-list (gargs)
235
+ //
236
+ // gargs → < garg , … , garg >
237
+ gargs: ($) => seq('<', commaSep1(field('garg', $.garg)), '>'),
238
+
239
+ // Import-prefix (prefix)
240
+ //
241
+ // prefix → prefix id
242
+ prefix: ($) => seq('prefix', field('id', $.id)),
243
+
244
+ // Export-modifier (export)
245
+ //
246
+ // export → export
247
+ export: ($) => 'export',
248
+
249
+ // Sealed-modifier (sealed)
250
+ //
251
+ // sealed → sealed
252
+ sealed: ($) => 'sealed',
253
+
254
+ // Pure-modifier (pure)
255
+ //
256
+ // pure → pure
257
+ pure: ($) => 'pure',
258
+
259
+ // Export-declaration (xdecl)
260
+ //
261
+ // xdecl → export { id , … , id } ;^opt
262
+ xdecl: ($) => seq('export', '{', commaSep1(field('id', $.id)), '}', optional(';')),
263
+
264
+ // Ledger-declaration (ldecl)
265
+ //
266
+ // ldecl → export^opt sealed^opt ledger id : type ;
267
+ ldecl: ($) =>
268
+ seq(
269
+ optional(field('export', $.export)),
270
+ optional(field('sealed', $.sealed)),
271
+ 'ledger',
272
+ field('name', $.id),
273
+ ':',
274
+ field('type', $.type),
275
+ ';',
276
+ ),
277
+
278
+ // Constructor (lconstructor)
279
+ //
280
+ // lconstructor → constructor ( parg , … , parg ) block ;opt
281
+ lconstructor: ($) =>
282
+ seq('constructor', '(', commaSep(field('parg', $.parg)), ')', field('body', $.block), optional(';')),
283
+
284
+ // Circuit-definition (cdefn)
285
+ //
286
+ // cdefn → export^opt pure^opt circuit function-name gparams^opt ( parg , … , parg ) : type block
287
+ cdefn: ($) =>
288
+ seq(
289
+ optional(field('export', $.export)),
290
+ optional(field('pure', $.pure)),
291
+ 'circuit',
292
+ field('id', $.function_name),
293
+ optional(field('gparams', $.gparams)),
294
+ '(',
295
+ commaSep(field('parg', $.parg)),
296
+ ')',
297
+ ':',
298
+ field('type', $.type),
299
+ field('body', $.block),
300
+ ),
301
+
302
+ // Witness-declaration (wdecl)
303
+ //
304
+ // wdecl → export^opt witness id gparams^opt ( arg , … , arg ) : type ;
305
+ wdecl: ($) =>
306
+ seq(
307
+ optional(field('export', $.export)),
308
+ 'witness',
309
+ field('id', $.function_name),
310
+ optional(field('gparams', $.gparams)),
311
+ '(',
312
+ field('args', commaSep(field('arg', $.arg))),
313
+ ')',
314
+ ':',
315
+ field('type', $.type),
316
+ ';',
317
+ ),
318
+
319
+ // External-contract-declaration (ecdecl)
320
+ //
321
+ // ecdecl → export^opt contract contract-name { ecdecl-circuit ; … ; ecdecl-circuit ;^opt } ;^opt
322
+ // → export^opt contract contract-name { ecdecl-circuit , … , ecdecl-circuit ,^opt } ;^opt
323
+ ecdecl: ($) =>
324
+ seq(
325
+ optional(field('export', $.export)),
326
+ 'contract',
327
+ field('name', $.contract_name),
328
+ '{',
329
+ optional($._ecdecl_circuits),
330
+ '}',
331
+ optional(';'),
332
+ ),
333
+
334
+ // Circuits may be separated by semicolons or commas, with an optional
335
+ // trailing separator.
336
+ _ecdecl_circuits: ($) =>
337
+ seq(
338
+ field('contract_circuit', $.ecdecl_circuit),
339
+ repeat(seq(choice(';', ','), field('contract_circuit', $.ecdecl_circuit))),
340
+ optional(choice(';', ',')),
341
+ ),
342
+
343
+ // External-contract-circuit (ecdecl-circuit)
344
+ //
345
+ // ecdecl-circuit → pure^opt circuit id ( arg , … , arg ) : type
346
+ ecdecl_circuit: ($) =>
347
+ seq(
348
+ optional(field('pure', $.pure)),
349
+ 'circuit',
350
+ field('id', $.id),
351
+ '(',
352
+ commaSep(field('arg', $.arg)),
353
+ ')',
354
+ ':',
355
+ field('type', $.type),
356
+ ),
357
+
358
+ // Contract-implements-declaration (contract-implements-declaration)
359
+ //
360
+ // contract-implements-declaration → contract implements type ;
361
+ contract_implements_declaration: ($) =>
362
+ seq(
363
+ 'contract',
364
+ 'implements',
365
+ field('type', $.type),
366
+ ';',
367
+ ),
368
+
369
+ // Structure-definition (struct)
370
+ //
371
+ // struct → export^opt struct struct-name gparams^opt { arg ; … ; arg ;^opt } ;^opt
372
+ // → export^opt struct struct-name gparams^opt { arg , … , arg ,^opt } ;^opt
373
+ struct: ($) =>
374
+ seq(
375
+ optional(field('export', $.export)),
376
+ 'struct',
377
+ field('name', $.struct_name),
378
+ optional(field('gparams', $.gparams)),
379
+ choice($._struct_body_semicolon, $._struct_body_comma),
380
+ optional(';'),
381
+ ),
382
+
383
+ // { arg ; … ; arg ;^opt }
384
+ _struct_body_semicolon: ($) =>
385
+ seq(
386
+ '{',
387
+ optional(seq(field('arg', $.arg), repeat(seq(';', field('arg', $.arg))))),
388
+ optional(';'),
389
+ '}',
390
+ ),
391
+
392
+ // { arg , … , arg ,^opt }
393
+ _struct_body_comma: ($) =>
394
+ prec(
395
+ 1,
396
+ seq(
397
+ '{',
398
+ optional(seq(field('arg', $.arg), repeat(seq(',', field('arg', $.arg))))),
399
+ optional(','),
400
+ '}',
401
+ ),
402
+ ),
403
+
404
+ // Enum-definition (enumdef)
405
+ //
406
+ // enumdef → export^opt enum enum-name { id , …¹ , id ,^opt } ;^opt
407
+ enumdef: ($) =>
408
+ seq(
409
+ optional(field('export', $.export)),
410
+ 'enum',
411
+ field('name', $.enum_name),
412
+ '{',
413
+ commaSep1(field('id', $.id)),
414
+ optional(','),
415
+ '}',
416
+ optional(';'),
417
+ ),
418
+
419
+ // Argument (arg)
420
+ //
421
+ // arg → id : type
422
+ arg: ($) => seq(field('id', $.id), ':', field('type', $.type)),
423
+
424
+ // Pattern-argument (parg)
425
+ //
426
+ // parg → pattern : type
427
+ parg: ($) => seq(field('pattern', $.pattern), ':', field('type', $.type)),
428
+
429
+ // Type (type)
430
+ //
431
+ // type → tref
432
+ // → Boolean
433
+ // → Field
434
+ // → Uint < tsize >
435
+ // → Uint < tsize .. tsize >
436
+ // → Bytes < tsize >
437
+ // → Opaque < str >
438
+ // → Vector < tsize , type >
439
+ // → [ type , … , type ]
440
+ type: ($) =>
441
+ choice(
442
+ $.tref,
443
+ 'Boolean',
444
+ 'Field',
445
+ $.uint_type,
446
+ $.bytes_type,
447
+ $.opaque_type,
448
+ $.vector_type,
449
+ seq('[', commaSep($.type), ']'),
450
+ ),
451
+
452
+ uint_type: ($) => seq('Uint', '<', field('tsize', $.tsize), optional(seq('..', field('tsize', $.tsize))), '>'),
453
+ bytes_type: ($) => seq('Bytes', '<', field('tsize', $.tsize), '>'),
454
+ opaque_type: ($) => seq('Opaque', '<', $.str, '>'),
455
+ vector_type: ($) => seq('Vector', '<', field('tsize', $.tsize), ',', field('type', $.type), '>'),
456
+
457
+ // Type-reference (tref)
458
+ //
459
+ // tref → id gargs^opt
460
+ tref: ($) => prec.left(seq(field('id', $.id), optional(field('gargs', $.gargs)))),
461
+
462
+ // Type-size (tsize)
463
+ //
464
+ // tsize → nat
465
+ // → id
466
+ tsize: ($) => choice($.nat, $.id),
467
+
468
+ // Generic-argument (garg)
469
+ //
470
+ // garg → nat
471
+ // → type
472
+ garg: ($) => choice($.nat, $.type),
473
+
474
+ // Block (block)
475
+ //
476
+ // block → { stmt … stmt }
477
+ block: ($) => seq('{', repeat(field('stmt', $.stmt)), '}'),
478
+
479
+ // Statement (stmt)
480
+ //
481
+ // stmt → expr = expr ;
482
+ // → expr += expr ;
483
+ // → expr -= expr ;
484
+ // → expr-seq ;
485
+ // → return expr-seq ;
486
+ // → return ;
487
+ // → if ( expr-seq ) stmt else stmt
488
+ // → if ( expr-seq ) stmt
489
+ // → for ( const id of nat .. nat ) stmt
490
+ // → for ( const id of expr-seq ) stmt
491
+ // → assert expr str ;
492
+ // → const pattern = expr ;
493
+ // → const pattern : type = expr ;
494
+ // → block
495
+ stmt: ($) =>
496
+ prec.right(
497
+ choice(
498
+ $.expression_sequence_stmt,
499
+ $.return_stmt,
500
+ $.if_stmt,
501
+ $.for_stmt,
502
+ $.const_stmt,
503
+ $.block,
504
+ ),
505
+ ),
506
+
507
+ return_stmt: ($) => seq('return', optional(field('value', $.expr_seq)), ';'),
508
+ if_stmt: ($) => prec.right(seq('if', '(', field('condition', $.expr_seq), ')', field('then_branch', $.stmt), optional(seq('else', field('else_branch', $.stmt))))),
509
+ for_stmt: ($) => seq('for', '(', 'const', field('counter', $.id), 'of',
510
+ choice(
511
+ seq(field('range_start', $.tsize), '..', field('range_end', $.tsize)),
512
+ field('limit', $.expr_seq),
513
+ ),
514
+ ')', field('body', $.stmt)),
515
+ expression_sequence_stmt: ($) => seq($.expr_seq, ';'),
516
+ const_stmt: ($) => seq('const', commaSep1(field('binding', $.const_binding)), ';'),
517
+ const_binding: ($) => seq(field('pattern', $.pattern), optional(seq(':', field('type', $.type))), '=', field('value', $.expr)),
518
+
519
+ // Pattern (pattern)
520
+ //
521
+ // pattern → id
522
+ // → [ pattern-tuple-elt , … , pattern-tuple-elt ]
523
+ // → { pattern-struct-elt , … , pattern-struct-elt }
524
+ pattern: ($) =>
525
+ choice(
526
+ field('id', $.id),
527
+ field('pattern_tuple', seq('[', optional(commaSep(field('pattern_tuple_elt', $.pattern_tuple_elt))), ']')),
528
+ field('pattern_struct', seq('{', commaSep1(field('pattern_struct_elt', $.pattern_struct_elt)), '}')),
529
+ ),
530
+
531
+ // Pattern-tuple-element (pattern-tuple-elt)
532
+ //
533
+ // pattern-tuple-elt → (empty)
534
+ // → pattern
535
+ pattern_tuple_elt: ($) => $.pattern,
536
+
537
+ // Pattern-struct-element (pattern-struct-elt)
538
+ //
539
+ // pattern-struct-elt → id
540
+ // → id : pattern
541
+ pattern_struct_elt: ($) => choice(field('id', $.id), seq(field('id', $.id), ':', field('pattern', $.pattern))),
542
+
543
+ // Expression-sequence (expr-seq)
544
+ //
545
+ // expr-seq → expr
546
+ // → expr , …¹ , expr , expr
547
+ expr_seq: ($) => commaSep1(field('expr', $.expr)),
548
+
549
+ // Expression (expr)
550
+ //
551
+ // expr → expr0 ? expr : expr
552
+ // → expr0
553
+ conditional_expr: ($) =>
554
+ seq(
555
+ field('condition', $._expr0),
556
+ '?',
557
+ field('then_branch', $.expr),
558
+ ':',
559
+ field('else_branch', $.expr),
560
+ ),
561
+
562
+ expr: ($) => choice($.conditional_expr, $.assign_expr, $._expr0),
563
+
564
+ // Assignment expression
565
+ //
566
+ // expr → expr0 = expr
567
+ // → expr0 += expr
568
+ // → expr0 -= expr
569
+ assign_expr: ($) =>
570
+ prec.right(
571
+ seq(
572
+ field('left', $._expr0),
573
+ field('operator', choice('=', '+=', '-=')),
574
+ field('right', $.expr),
575
+ ),
576
+ ),
577
+
578
+ // Expression0 (expr0)
579
+ //
580
+ // expr0 → expr0 || expr1
581
+ // → expr1
582
+ or_expr: ($) => seq(field('left', $._expr0), $.or, field('right', $._expr1)),
583
+
584
+ _expr0: ($) => prec.left(choice($.or_expr, $._expr1)),
585
+
586
+ // Expression1 (expr1)
587
+ //
588
+ // expr1 → expr1 && expr2
589
+ // → expr2
590
+ and_expr: ($) => seq(field('left', $._expr1), $.and, field('right', $._expr2)),
591
+ _expr1: ($) => prec.left(choice($.and_expr, $._expr2)),
592
+
593
+ // Expression2 (expr2)
594
+ //
595
+ // expr2 → expr2 == expr3
596
+ // → expr2 != expr3
597
+ // → expr3
598
+ comparison_expr: ($) => seq(field('left', $._expr2), field('operator', choice($.equals, $.not_equals)), field('right', $._expr3)),
599
+ _expr2: ($) =>
600
+ prec.left(
601
+ choice(
602
+ $.comparison_expr,
603
+ $._expr3,
604
+ ),
605
+ ),
606
+
607
+ // Expression3 (expr3)
608
+ //
609
+ // expr3 → expr4 < expr4
610
+ // → expr4 <= expr4
611
+ // → expr4 >= expr4
612
+ // → expr4 > expr4
613
+ // → expr4
614
+ rel_comparison_expr: ($) => seq(field('left', $._expr3), field('operator', choice($.less_than, $.less_than_or_equal, $.greater_than_or_equal, $.greater_than)), field('right', $._expr4)),
615
+ _expr3: ($) =>
616
+ prec.left(
617
+ choice(
618
+ $.rel_comparison_expr,
619
+ $._expr4,
620
+ ),
621
+ ),
622
+
623
+ // Expression4 (expr4)
624
+ //
625
+ // expr4 → expr4 as type
626
+ // → expr5
627
+ cast_expr: ($) => seq(field('expr', $._expr4), 'as', field('type', $.type)),
628
+ _expr4: ($) => prec.left(4, choice($.cast_expr, $._expr5)),
629
+
630
+ // Expression5 (expr5)
631
+ //
632
+ // expr5 → expr5 + expr6
633
+ // → expr5 - expr6
634
+ // → expr6
635
+ bin_sum_expr: ($) => seq(field('left', $._expr5), field('operator', choice('+', '-')), field('right', $._expr6)),
636
+ _expr5: ($) =>
637
+ prec.left(
638
+ choice(
639
+ $.bin_sum_expr,
640
+ $._expr6,
641
+ ),
642
+ ),
643
+
644
+ // Expression6 (expr6)
645
+ //
646
+ // expr6 → expr6 * expr7
647
+ // → expr7
648
+ bin_mul_expr: ($) => prec.left(seq(field('left', $._expr6), field('operator', '*'), field('right', $._expr7))),
649
+ _expr6: ($) => choice($.bin_mul_expr, $._expr7),
650
+
651
+ // Expression7 (expr7)
652
+ //
653
+ // expr7 → ! expr7
654
+ // → expr8
655
+ not_expr: ($) => seq($.not, field('expr', $._expr7)),
656
+
657
+ _expr7: ($) => choice($.not_expr, $._expr8),
658
+
659
+ // Expression8 (expr8)
660
+ //
661
+ // expr8 → expr8 [ nat ]
662
+ // → expr8 . id
663
+ // → expr8 . id ( expr , … , expr )
664
+ // → term
665
+ index_access_expr: ($) => prec.left(seq(field('base', $._expr8), '[', field('index', $.expr), ']')),
666
+ member_access_expr: ($) => prec.left(seq(field('base', $._expr8), '.', field('member', $.id), optional(field('arguments', seq('(', commaSep(field('expr', $.expr)), ')'))))),
667
+ _expr8: ($) =>
668
+ prec.left(
669
+ choice(
670
+ $.index_access_expr,
671
+ $.member_access_expr,
672
+ $.term,
673
+ ),
674
+ ),
675
+
676
+ // Term (term)
677
+ //
678
+ // term → lit
679
+ // → default < type >
680
+ // → map ( fun , expr , …¹ , expr )
681
+ // → fold ( fun , expr , expr , …¹ , expr )
682
+ // → fun ( expr , … , expr )
683
+ // → disclose ( expr )
684
+ // → tref { struct-arg , … , struct-arg }
685
+ // → [ expr , … , expr ,opt ]
686
+ // → id
687
+ // → ( expr-seq )
688
+ term: ($) =>
689
+ choice(
690
+ $.lit, // Literal (true, false, nat, str, pad)
691
+ $.default_term, // Default value with type
692
+ $.map_term, // Map function with one or more expressions
693
+ $.fold_term, // Fold with initial value and list
694
+ $.function_call_term, // Function call with zero or more expressions
695
+ $.slice_term, // Slice with size and range expressions
696
+ $.disclose_term, // Disclose with single expression
697
+ $.assert_term, // Assert with condition and message
698
+ $.emit_term, // Emit with a single expression
699
+ $.bytes_literal, // Bytes literal with optional spread
700
+ $.struct_term, // Struct literal with type reference
701
+ $.array_literal, // Array literal with optional spread
702
+ $.id, // Identifier
703
+ $.expr_seq_term, // Parenthesized expression sequence
704
+ ),
705
+
706
+ default_term: ($) => seq('default', '<', field('type', $.type), '>'),
707
+ map_term: ($) => seq('map', '(', field('fun', $.fun), ',', commaSep1(field('expr', $.expr)), ')'),
708
+ fold_term: ($) => seq('fold', '(', field('fun', $.fun), ',', field('init_value', $.expr), ',', commaSep1(field('expr', $.expr)), ')'),
709
+ struct_term: ($) => seq(field('tref', $.tref), '{', commaSep($.struct_arg), '}'),
710
+ function_call_term: ($) => seq(field('fun', $.fun), '(', commaSep(field('expr', $.expr)), ')'),
711
+ slice_term: ($) => seq('slice', '<', field('tsize', $.tsize), '>', '(', field('expr', $.expr), ',', field('expr', $.expr), ')'),
712
+ disclose_term: ($) => seq('disclose', '(', field('expr', $.expr), ')'),
713
+ assert_term: ($) => prec(2, seq('assert', '(', field('condition', $.expr), ',', field('message', $.str), ')')),
714
+ emit_term: ($) => prec(2, seq('emit', '(', field('value', $.expr), ')')),
715
+ array_literal: ($) => seq('[', commaSep(field('element', $.tuple_arg)), ']'),
716
+ bytes_literal: ($) => seq('Bytes', '[', commaSep(field('element', $.tuple_arg)), ']'),
717
+ tuple_arg: ($) => choice($.spread_element, field('expr', $.expr)),
718
+ spread_element: ($) => seq('...', field('expr', $.expr)),
719
+ expr_seq_term: ($) => seq('(', $.expr_seq, ')'),
720
+
721
+ // Literal (lit)
722
+ //
723
+ // lit → true
724
+ // → false
725
+ // → nat
726
+ // → str
727
+ // → pad ( nat , str )
728
+ lit: ($) =>
729
+ choice(
730
+ 'true',
731
+ 'false',
732
+ $.nat,
733
+ $.str,
734
+ $.pad,
735
+ ),
736
+
737
+ pad: ($) => seq('pad', '(', field('nat', $.nat), ',', field('str', $.str), ')'),
738
+
739
+ // Structure-argument (struct-arg)
740
+ //
741
+ // struct-arg → expr
742
+ // → id : expr
743
+ // → ... expr
744
+ struct_arg: ($) =>
745
+ choice(
746
+ $.expr,
747
+ $.struct_named_field_initializer,
748
+ $.spread_element,
749
+ ),
750
+
751
+ struct_named_field_initializer: ($) => seq(field('id', $.id), ':', field('expr', $.expr)),
752
+
753
+ // Function (fun)
754
+ //
755
+ // fun → id gargs^opt
756
+ // → ( pattern-or-parg , … , pattern-or-parg ) return-type-decl^opt => block
757
+ // → ( pattern-or-parg , … , pattern-or-parg ) return-type-decl^opt => expr
758
+ // → ( fun )
759
+ fun: ($) =>
760
+ choice(
761
+ seq(field('id', $.id), optional(field('gargs', $.gargs))),
762
+ seq(
763
+ '(',
764
+ commaSep($._pattern_or_parg),
765
+ ')',
766
+ optional(field('return', $._return_type_decl)),
767
+ '=>',
768
+ choice(field('block', $.block), field('expr', $.expr)),
769
+ ),
770
+ seq('(', $.fun, ')'),
771
+ ),
772
+
773
+ // Return-type-declaration (return-type-decl)
774
+ //
775
+ // return-type-decl → : type
776
+ _return_type_decl: ($) => seq(':', $.type),
777
+
778
+ // Pattern-or-pattern-argument (pattern-or-parg)
779
+ //
780
+ // pattern-or-parg → pattern
781
+ // → parg
782
+ _pattern_or_parg: ($) => choice(field('pattern', $.pattern), field('parg', $.parg)),
783
+
784
+ // OPS
785
+ equals: ($) => '==',
786
+ not_equals: ($) => '!=',
787
+ greater_than: ($) => '>',
788
+ less_than: ($) => '<',
789
+ greater_than_or_equal: ($) => '>=',
790
+ less_than_or_equal: ($) => '<=',
791
+ not: ($) => '!',
792
+ and: ($) => '&&',
793
+ or: ($) => '||',
794
+
795
+ // LITERALS
796
+
797
+ // identifier (id, module-name, function-name, struct-name, enum-name, contract-name, tvar-name)
798
+ //
799
+ // Matches the compiler's identifier rule, which follows
800
+ // https://tc39.es/ecma262/#sec-names-and-keywords and
801
+ // https://www.unicode.org/reports/tr31/#Table_Lexical_Classes_for_Identifiers:
802
+ // an initial character in Lu, Ll, Lt, Lm, Lo, or Nl (or `_`/`$`), followed by
803
+ // those plus Mn, Mc, Nd, and Pc.
804
+ id: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
805
+ module_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
806
+ function_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
807
+ struct_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
808
+ enum_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
809
+ contract_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
810
+ tvar_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
811
+ type_name: ($) => /[\p{L}\p{Nl}_$][\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}$]*/,
812
+
813
+ // field-literal (nat)
814
+ //
815
+ // a field literal is 0 or a natural number formed from a sequence
816
+ // of digits starting with 1-9, e.g. 723, whose value does not exceed
817
+ // the maximum field value
818
+ // Decimal, binary (0b), octal (0o), and hexadecimal (0x) field literals.
819
+ nat: ($) =>
820
+ choice(
821
+ '0',
822
+ /[1-9][0-9]*/,
823
+ /0[bB][01]+/,
824
+ /0[oO][0-7]+/,
825
+ /0[xX][0-9a-fA-F]+/,
826
+ ),
827
+
828
+ // string-literal (str, file)
829
+ //
830
+ // Strings match TypeScript strings: single or double quoted, with
831
+ // backslash escape sequences.
832
+ str: ($) => token(choice(/"(?:[^"\\]|\\[\s\S])*"/, /'(?:[^'\\]|\\[\s\S])*'/)),
833
+ file: ($) => token(choice(/"(?:[^"\\]|\\[\s\S])*"/, /'(?:[^'\\]|\\[\s\S])*'/)),
834
+
835
+ // version-literal (version)
836
+ //
837
+ // a version literal takes the form nat or nat.nat or nat.nat.nat,
838
+ // e.g., 1.2 or 1.2.3, representing major, minor, and bugfix versions
839
+ version: ($) => /[0-9]+(\.[0-9]+){0,2}/,
840
+ },
841
+ });
842
+
843
+ /**
844
+ * Creates a rule for one or more comma-separated occurrences of another rule
845
+ *
846
+ * @param {Rule} rule - The rule to be repeated
847
+ * @returns {SeqRule} A rule that matches one or more occurrences of the input rule separated by commas
848
+ */
849
+ function commaSep1(rule) {
850
+ return seq(
851
+ rule,
852
+ repeat(seq(',', rule)),
853
+ optional(','), // Optional trailing comma
854
+ );
855
+ }
856
+
857
+ /**
858
+ * Creates a rule for zero or more comma-separated occurrences of another rule
859
+ *
860
+ * @param {Rule} rule - The rule to be repeated
861
+ * @returns {ChoiceRule} A rule that matches one or more occurrences of the input rule separated by commas
862
+ */
863
+ function commaSep(rule) {
864
+ return optional(seq(rule, repeat(seq(',', rule)), optional(',')));
865
+ }