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