@grimoirelabs/core 0.3.0 → 0.5.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/dist/compiler/grimoire/errors.d.ts +0 -7
- package/dist/compiler/grimoire/errors.d.ts.map +1 -1
- package/dist/compiler/grimoire/errors.js +0 -7
- package/dist/compiler/grimoire/errors.js.map +1 -1
- package/dist/compiler/grimoire/parser.d.ts +7 -7
- package/dist/compiler/grimoire/parser.d.ts.map +1 -1
- package/dist/compiler/grimoire/parser.js +183 -277
- package/dist/compiler/grimoire/parser.js.map +1 -1
- package/dist/compiler/grimoire/tokenizer.d.ts +6 -7
- package/dist/compiler/grimoire/tokenizer.d.ts.map +1 -1
- package/dist/compiler/grimoire/tokenizer.js +51 -86
- package/dist/compiler/grimoire/tokenizer.js.map +1 -1
- package/dist/compiler/grimoire/transformer.d.ts.map +1 -1
- package/dist/compiler/grimoire/transformer.js +17 -7
- package/dist/compiler/grimoire/transformer.js.map +1 -1
- package/dist/compiler/ir-generator.js +57 -0
- package/dist/compiler/ir-generator.js.map +1 -1
- package/dist/runtime/steps/action.d.ts.map +1 -1
- package/dist/runtime/steps/action.js +49 -0
- package/dist/runtime/steps/action.js.map +1 -1
- package/dist/types/actions.d.ts +11 -1
- package/dist/types/actions.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/wallet/executor.d.ts.map +1 -1
- package/dist/wallet/executor.js +38 -0
- package/dist/wallet/executor.js.map +1 -1
- package/dist/wallet/tx-builder.d.ts.map +1 -1
- package/dist/wallet/tx-builder.js +2 -0
- package/dist/wallet/tx-builder.js.map +1 -1
- package/package.json +1 -1
|
@@ -90,28 +90,20 @@ export class Parser {
|
|
|
90
90
|
/** Parse a complete spell file */
|
|
91
91
|
parseSpellFile() {
|
|
92
92
|
this.skipNewlines();
|
|
93
|
-
// Expect: spell Name
|
|
93
|
+
// Expect: spell Name {
|
|
94
94
|
this.expect("KEYWORD", "spell");
|
|
95
95
|
const nameToken = this.expect("IDENTIFIER");
|
|
96
96
|
const name = nameToken.value;
|
|
97
|
-
this.expectNewline();
|
|
98
97
|
this.skipNewlines();
|
|
98
|
+
this.expect("LBRACE");
|
|
99
99
|
// Parse sections and triggers
|
|
100
100
|
const sections = [];
|
|
101
101
|
const triggers = [];
|
|
102
102
|
const imports = [];
|
|
103
103
|
const blocks = [];
|
|
104
|
-
|
|
105
|
-
if (!this.check("INDENT")) {
|
|
106
|
-
throw new ParseError("Expected indented spell body", {
|
|
107
|
-
location: this.current().location,
|
|
108
|
-
source: this.source,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
this.advance(); // INDENT
|
|
112
|
-
while (!this.check("DEDENT") && !this.check("EOF")) {
|
|
104
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
113
105
|
this.skipNewlines();
|
|
114
|
-
if (this.check("
|
|
106
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
115
107
|
break;
|
|
116
108
|
// Check for import or block or trigger
|
|
117
109
|
if (this.check("KEYWORD", "import")) {
|
|
@@ -128,10 +120,7 @@ export class Parser {
|
|
|
128
120
|
}
|
|
129
121
|
this.skipNewlines();
|
|
130
122
|
}
|
|
131
|
-
|
|
132
|
-
if (this.check("DEDENT")) {
|
|
133
|
-
this.advance();
|
|
134
|
-
}
|
|
123
|
+
this.expect("RBRACE");
|
|
135
124
|
return {
|
|
136
125
|
kind: "spell",
|
|
137
126
|
name,
|
|
@@ -168,7 +157,7 @@ export class Parser {
|
|
|
168
157
|
node.span = this.makeSpan(startToken);
|
|
169
158
|
return node;
|
|
170
159
|
}
|
|
171
|
-
/** Parse block definition: block name(
|
|
160
|
+
/** Parse block definition: block name(args) { ... } */
|
|
172
161
|
parseBlock() {
|
|
173
162
|
const startToken = this.current();
|
|
174
163
|
this.expect("KEYWORD", "block");
|
|
@@ -185,9 +174,7 @@ export class Parser {
|
|
|
185
174
|
}
|
|
186
175
|
this.expect("RPAREN");
|
|
187
176
|
}
|
|
188
|
-
this.
|
|
189
|
-
this.expectNewline();
|
|
190
|
-
const body = this.parseStatementBlock();
|
|
177
|
+
const body = this.parseBraceBlock();
|
|
191
178
|
const node = { kind: "block", name, params, body };
|
|
192
179
|
node.span = this.makeSpan(startToken);
|
|
193
180
|
return node;
|
|
@@ -317,7 +304,7 @@ export class Parser {
|
|
|
317
304
|
source: this.source,
|
|
318
305
|
});
|
|
319
306
|
}
|
|
320
|
-
/** Parse assets: [USDC, USDT] or assets
|
|
307
|
+
/** Parse assets: [USDC, USDT] or assets: { ... } */
|
|
321
308
|
parseAssetsSection() {
|
|
322
309
|
this.expect("KEYWORD", "assets");
|
|
323
310
|
this.expect("COLON");
|
|
@@ -335,76 +322,65 @@ export class Parser {
|
|
|
335
322
|
this.expect("RBRACKET");
|
|
336
323
|
this.expectNewline();
|
|
337
324
|
}
|
|
338
|
-
else {
|
|
339
|
-
// Block form
|
|
340
|
-
this.
|
|
341
|
-
|
|
342
|
-
this.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
this.
|
|
350
|
-
|
|
351
|
-
this.
|
|
352
|
-
if (
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
325
|
+
else if (this.check("LBRACE")) {
|
|
326
|
+
// Block form: assets: { ... }
|
|
327
|
+
this.advance();
|
|
328
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
329
|
+
this.skipNewlines();
|
|
330
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
331
|
+
break;
|
|
332
|
+
const symbol = this.expect("IDENTIFIER").value;
|
|
333
|
+
const asset = { symbol };
|
|
334
|
+
this.expect("COLON");
|
|
335
|
+
if (this.check("LBRACE")) {
|
|
336
|
+
this.advance();
|
|
337
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
338
|
+
this.skipNewlines();
|
|
339
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
340
|
+
break;
|
|
341
|
+
const key = this.expect("IDENTIFIER").value;
|
|
342
|
+
this.expect("COLON");
|
|
343
|
+
if (key === "chain") {
|
|
344
|
+
const val = this.expect("NUMBER").value;
|
|
345
|
+
asset.chain = Number.parseInt(val, 10);
|
|
346
|
+
this.expectNewline();
|
|
357
347
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (this.check("DEDENT") || this.check("EOF"))
|
|
362
|
-
break;
|
|
363
|
-
const key = this.expect("IDENTIFIER").value;
|
|
364
|
-
this.expect("COLON");
|
|
365
|
-
if (key === "chain") {
|
|
366
|
-
const val = this.expect("NUMBER").value;
|
|
367
|
-
asset.chain = Number.parseInt(val, 10);
|
|
368
|
-
this.expectNewline();
|
|
369
|
-
}
|
|
370
|
-
else if (key === "address") {
|
|
371
|
-
if (this.check("ADDRESS")) {
|
|
372
|
-
asset.address = this.advance().value;
|
|
373
|
-
}
|
|
374
|
-
else if (this.check("STRING")) {
|
|
375
|
-
asset.address = this.advance().value;
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
throw new ParseError("Expected address value", {
|
|
379
|
-
location: this.current().location,
|
|
380
|
-
source: this.source,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
this.expectNewline();
|
|
348
|
+
else if (key === "address") {
|
|
349
|
+
if (this.check("ADDRESS")) {
|
|
350
|
+
asset.address = this.advance().value;
|
|
384
351
|
}
|
|
385
|
-
else if (
|
|
386
|
-
|
|
387
|
-
asset.decimals = Number.parseInt(val, 10);
|
|
388
|
-
this.expectNewline();
|
|
352
|
+
else if (this.check("STRING")) {
|
|
353
|
+
asset.address = this.advance().value;
|
|
389
354
|
}
|
|
390
355
|
else {
|
|
391
|
-
|
|
392
|
-
|
|
356
|
+
throw new ParseError("Expected address value", {
|
|
357
|
+
location: this.current().location,
|
|
358
|
+
source: this.source,
|
|
359
|
+
});
|
|
393
360
|
}
|
|
361
|
+
this.expectNewline();
|
|
362
|
+
}
|
|
363
|
+
else if (key === "decimals") {
|
|
364
|
+
const val = this.expect("NUMBER").value;
|
|
365
|
+
asset.decimals = Number.parseInt(val, 10);
|
|
366
|
+
this.expectNewline();
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.parseExpression();
|
|
370
|
+
this.expectNewline();
|
|
394
371
|
}
|
|
395
|
-
if (this.check("DEDENT"))
|
|
396
|
-
this.advance();
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
// Inline asset defaults: assets: SYMBOL: <ignored>
|
|
400
|
-
this.parseExpression();
|
|
401
|
-
this.expectNewline();
|
|
402
372
|
}
|
|
403
|
-
|
|
373
|
+
this.expect("RBRACE");
|
|
404
374
|
}
|
|
405
|
-
|
|
406
|
-
|
|
375
|
+
else {
|
|
376
|
+
// Inline asset defaults: SYMBOL: <value>
|
|
377
|
+
this.parseExpression();
|
|
378
|
+
this.expectNewline();
|
|
379
|
+
}
|
|
380
|
+
items.push(asset);
|
|
381
|
+
this.skipNewlines();
|
|
407
382
|
}
|
|
383
|
+
this.expect("RBRACE");
|
|
408
384
|
}
|
|
409
385
|
return { kind: "assets", items };
|
|
410
386
|
}
|
|
@@ -412,30 +388,22 @@ export class Parser {
|
|
|
412
388
|
parseParamsSection() {
|
|
413
389
|
this.expect("KEYWORD", "params");
|
|
414
390
|
this.expect("COLON");
|
|
415
|
-
this.expectNewline();
|
|
416
391
|
const items = [];
|
|
417
|
-
if (this.check("
|
|
392
|
+
if (this.check("LBRACE")) {
|
|
418
393
|
this.advance();
|
|
419
|
-
while (!this.check("
|
|
394
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
420
395
|
this.skipNewlines();
|
|
421
|
-
if (this.check("
|
|
396
|
+
if (this.check("RBRACE"))
|
|
422
397
|
break;
|
|
423
398
|
const name = this.expect("IDENTIFIER").value;
|
|
424
399
|
this.expect("COLON");
|
|
425
400
|
const item = { name };
|
|
426
|
-
// Block form: param:
|
|
427
|
-
if (this.check("
|
|
428
|
-
this.expectNewline();
|
|
429
|
-
if (!this.check("INDENT")) {
|
|
430
|
-
throw new ParseError("Expected indented param block", {
|
|
431
|
-
location: this.current().location,
|
|
432
|
-
source: this.source,
|
|
433
|
-
});
|
|
434
|
-
}
|
|
401
|
+
// Block form: param: { ... }
|
|
402
|
+
if (this.check("LBRACE")) {
|
|
435
403
|
this.advance();
|
|
436
|
-
while (!this.check("
|
|
404
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
437
405
|
this.skipNewlines();
|
|
438
|
-
if (this.check("
|
|
406
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
439
407
|
break;
|
|
440
408
|
const keyToken = this.current();
|
|
441
409
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD"))) {
|
|
@@ -494,8 +462,7 @@ export class Parser {
|
|
|
494
462
|
this.expectNewline();
|
|
495
463
|
}
|
|
496
464
|
}
|
|
497
|
-
|
|
498
|
-
this.advance();
|
|
465
|
+
this.expect("RBRACE");
|
|
499
466
|
}
|
|
500
467
|
else {
|
|
501
468
|
// Inline form: name: value
|
|
@@ -505,8 +472,7 @@ export class Parser {
|
|
|
505
472
|
items.push(item);
|
|
506
473
|
this.skipNewlines();
|
|
507
474
|
}
|
|
508
|
-
|
|
509
|
-
this.advance();
|
|
475
|
+
this.expect("RBRACE");
|
|
510
476
|
}
|
|
511
477
|
return { kind: "params", items };
|
|
512
478
|
}
|
|
@@ -514,13 +480,12 @@ export class Parser {
|
|
|
514
480
|
parseLimitsSection() {
|
|
515
481
|
this.expect("KEYWORD", "limits");
|
|
516
482
|
this.expect("COLON");
|
|
517
|
-
this.expectNewline();
|
|
518
483
|
const items = [];
|
|
519
|
-
if (this.check("
|
|
484
|
+
if (this.check("LBRACE")) {
|
|
520
485
|
this.advance();
|
|
521
|
-
while (!this.check("
|
|
486
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
522
487
|
this.skipNewlines();
|
|
523
|
-
if (this.check("
|
|
488
|
+
if (this.check("RBRACE"))
|
|
524
489
|
break;
|
|
525
490
|
const name = this.expect("IDENTIFIER").value;
|
|
526
491
|
this.expect("COLON");
|
|
@@ -529,8 +494,7 @@ export class Parser {
|
|
|
529
494
|
this.expectNewline();
|
|
530
495
|
this.skipNewlines();
|
|
531
496
|
}
|
|
532
|
-
|
|
533
|
-
this.advance();
|
|
497
|
+
this.expect("RBRACE");
|
|
534
498
|
}
|
|
535
499
|
return { kind: "limits", items };
|
|
536
500
|
}
|
|
@@ -538,13 +502,12 @@ export class Parser {
|
|
|
538
502
|
parseVenuesSection() {
|
|
539
503
|
this.expect("KEYWORD", "venues");
|
|
540
504
|
this.expect("COLON");
|
|
541
|
-
this.expectNewline();
|
|
542
505
|
const groups = [];
|
|
543
|
-
if (this.check("
|
|
506
|
+
if (this.check("LBRACE")) {
|
|
544
507
|
this.advance();
|
|
545
|
-
while (!this.check("
|
|
508
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
546
509
|
this.skipNewlines();
|
|
547
|
-
if (this.check("
|
|
510
|
+
if (this.check("RBRACE"))
|
|
548
511
|
break;
|
|
549
512
|
const name = this.expect("IDENTIFIER").value;
|
|
550
513
|
this.expect("COLON");
|
|
@@ -572,8 +535,7 @@ export class Parser {
|
|
|
572
535
|
this.expectNewline();
|
|
573
536
|
this.skipNewlines();
|
|
574
537
|
}
|
|
575
|
-
|
|
576
|
-
this.advance();
|
|
538
|
+
this.expect("RBRACE");
|
|
577
539
|
}
|
|
578
540
|
return { kind: "venues", groups };
|
|
579
541
|
}
|
|
@@ -581,24 +543,22 @@ export class Parser {
|
|
|
581
543
|
parseStateSection() {
|
|
582
544
|
this.expect("KEYWORD", "state");
|
|
583
545
|
this.expect("COLON");
|
|
584
|
-
this.expectNewline();
|
|
585
546
|
const persistent = [];
|
|
586
547
|
const ephemeral = [];
|
|
587
|
-
if (this.check("
|
|
548
|
+
if (this.check("LBRACE")) {
|
|
588
549
|
this.advance();
|
|
589
|
-
while (!this.check("
|
|
550
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
590
551
|
this.skipNewlines();
|
|
591
|
-
if (this.check("
|
|
552
|
+
if (this.check("RBRACE"))
|
|
592
553
|
break;
|
|
593
554
|
const scope = this.expect("KEYWORD").value;
|
|
594
555
|
this.expect("COLON");
|
|
595
|
-
this.expectNewline();
|
|
596
556
|
const items = scope === "persistent" ? persistent : ephemeral;
|
|
597
|
-
if (this.check("
|
|
557
|
+
if (this.check("LBRACE")) {
|
|
598
558
|
this.advance();
|
|
599
|
-
while (!this.check("
|
|
559
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
600
560
|
this.skipNewlines();
|
|
601
|
-
if (this.check("
|
|
561
|
+
if (this.check("RBRACE"))
|
|
602
562
|
break;
|
|
603
563
|
const name = this.expect("IDENTIFIER").value;
|
|
604
564
|
this.expect("COLON");
|
|
@@ -607,13 +567,11 @@ export class Parser {
|
|
|
607
567
|
this.expectNewline();
|
|
608
568
|
this.skipNewlines();
|
|
609
569
|
}
|
|
610
|
-
|
|
611
|
-
this.advance();
|
|
570
|
+
this.expect("RBRACE");
|
|
612
571
|
}
|
|
613
572
|
this.skipNewlines();
|
|
614
573
|
}
|
|
615
|
-
|
|
616
|
-
this.advance();
|
|
574
|
+
this.expect("RBRACE");
|
|
617
575
|
}
|
|
618
576
|
return { kind: "state", persistent, ephemeral };
|
|
619
577
|
}
|
|
@@ -622,25 +580,23 @@ export class Parser {
|
|
|
622
580
|
const startToken = this.current();
|
|
623
581
|
this.expect("KEYWORD", "skills");
|
|
624
582
|
this.expect("COLON");
|
|
625
|
-
this.expectNewline();
|
|
626
583
|
const items = [];
|
|
627
|
-
if (this.check("
|
|
584
|
+
if (this.check("LBRACE")) {
|
|
628
585
|
this.advance();
|
|
629
|
-
while (!this.check("
|
|
586
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
630
587
|
this.skipNewlines();
|
|
631
|
-
if (this.check("
|
|
588
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
632
589
|
break;
|
|
633
590
|
const name = this.expect("IDENTIFIER").value;
|
|
634
591
|
this.expect("COLON");
|
|
635
|
-
this.expectNewline();
|
|
636
592
|
let type;
|
|
637
593
|
const adapters = [];
|
|
638
594
|
let defaultMaxSlippage;
|
|
639
|
-
if (this.check("
|
|
595
|
+
if (this.check("LBRACE")) {
|
|
640
596
|
this.advance();
|
|
641
|
-
while (!this.check("
|
|
597
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
642
598
|
this.skipNewlines();
|
|
643
|
-
if (this.check("
|
|
599
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
644
600
|
break;
|
|
645
601
|
const keyToken = this.current();
|
|
646
602
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD"))) {
|
|
@@ -710,12 +666,11 @@ export class Parser {
|
|
|
710
666
|
this.expectNewline();
|
|
711
667
|
}
|
|
712
668
|
else if (key === "default_constraints") {
|
|
713
|
-
this.
|
|
714
|
-
if (this.check("INDENT")) {
|
|
669
|
+
if (this.check("LBRACE")) {
|
|
715
670
|
this.advance();
|
|
716
|
-
while (!this.check("
|
|
671
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
717
672
|
this.skipNewlines();
|
|
718
|
-
if (this.check("
|
|
673
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
719
674
|
break;
|
|
720
675
|
const dcKey = this.expect("IDENTIFIER").value;
|
|
721
676
|
this.expect("COLON");
|
|
@@ -725,8 +680,7 @@ export class Parser {
|
|
|
725
680
|
}
|
|
726
681
|
this.expectNewline();
|
|
727
682
|
}
|
|
728
|
-
|
|
729
|
-
this.advance();
|
|
683
|
+
this.expect("RBRACE");
|
|
730
684
|
}
|
|
731
685
|
}
|
|
732
686
|
else {
|
|
@@ -735,8 +689,7 @@ export class Parser {
|
|
|
735
689
|
this.expectNewline();
|
|
736
690
|
}
|
|
737
691
|
}
|
|
738
|
-
|
|
739
|
-
this.advance();
|
|
692
|
+
this.expect("RBRACE");
|
|
740
693
|
}
|
|
741
694
|
if (!type) {
|
|
742
695
|
throw new ParseError(`Skill '${name}' missing type`, {
|
|
@@ -752,8 +705,7 @@ export class Parser {
|
|
|
752
705
|
});
|
|
753
706
|
this.skipNewlines();
|
|
754
707
|
}
|
|
755
|
-
|
|
756
|
-
this.advance();
|
|
708
|
+
this.expect("RBRACE");
|
|
757
709
|
}
|
|
758
710
|
const node = { kind: "skills", items };
|
|
759
711
|
node.span = this.makeSpan(startToken);
|
|
@@ -764,26 +716,24 @@ export class Parser {
|
|
|
764
716
|
const startToken = this.current();
|
|
765
717
|
this.expect("KEYWORD", "advisors");
|
|
766
718
|
this.expect("COLON");
|
|
767
|
-
this.expectNewline();
|
|
768
719
|
const items = [];
|
|
769
|
-
if (this.check("
|
|
720
|
+
if (this.check("LBRACE")) {
|
|
770
721
|
this.advance();
|
|
771
|
-
while (!this.check("
|
|
722
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
772
723
|
this.skipNewlines();
|
|
773
|
-
if (this.check("
|
|
724
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
774
725
|
break;
|
|
775
726
|
const name = this.expect("IDENTIFIER").value;
|
|
776
727
|
this.expect("COLON");
|
|
777
|
-
this.expectNewline();
|
|
778
728
|
const advisor = {
|
|
779
729
|
name,
|
|
780
730
|
model: "sonnet",
|
|
781
731
|
};
|
|
782
|
-
if (this.check("
|
|
732
|
+
if (this.check("LBRACE")) {
|
|
783
733
|
this.advance();
|
|
784
|
-
while (!this.check("
|
|
734
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
785
735
|
this.skipNewlines();
|
|
786
|
-
if (this.check("
|
|
736
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
787
737
|
break;
|
|
788
738
|
const keyToken = this.current();
|
|
789
739
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD"))) {
|
|
@@ -842,12 +792,11 @@ export class Parser {
|
|
|
842
792
|
this.expectNewline();
|
|
843
793
|
}
|
|
844
794
|
else if (key === "rate_limit") {
|
|
845
|
-
this.
|
|
846
|
-
if (this.check("INDENT")) {
|
|
795
|
+
if (this.check("LBRACE")) {
|
|
847
796
|
this.advance();
|
|
848
|
-
while (!this.check("
|
|
797
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
849
798
|
this.skipNewlines();
|
|
850
|
-
if (this.check("
|
|
799
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
851
800
|
break;
|
|
852
801
|
const rlKey = this.expect("IDENTIFIER").value;
|
|
853
802
|
this.expect("COLON");
|
|
@@ -860,8 +809,7 @@ export class Parser {
|
|
|
860
809
|
}
|
|
861
810
|
this.expectNewline();
|
|
862
811
|
}
|
|
863
|
-
|
|
864
|
-
this.advance();
|
|
812
|
+
this.expect("RBRACE");
|
|
865
813
|
}
|
|
866
814
|
}
|
|
867
815
|
else {
|
|
@@ -870,31 +818,28 @@ export class Parser {
|
|
|
870
818
|
this.expectNewline();
|
|
871
819
|
}
|
|
872
820
|
}
|
|
873
|
-
|
|
874
|
-
this.advance();
|
|
821
|
+
this.expect("RBRACE");
|
|
875
822
|
}
|
|
876
823
|
items.push(advisor);
|
|
877
824
|
this.skipNewlines();
|
|
878
825
|
}
|
|
879
|
-
|
|
880
|
-
this.advance();
|
|
826
|
+
this.expect("RBRACE");
|
|
881
827
|
}
|
|
882
828
|
const node = { kind: "advisors", items };
|
|
883
829
|
node.span = this.makeSpan(startToken);
|
|
884
830
|
return node;
|
|
885
831
|
}
|
|
886
|
-
/** Parse guards section: guards
|
|
832
|
+
/** Parse guards section: guards: { id: expression } */
|
|
887
833
|
parseGuardsSection() {
|
|
888
834
|
const startToken = this.current();
|
|
889
835
|
this.expect("KEYWORD", "guards");
|
|
890
836
|
this.expect("COLON");
|
|
891
|
-
this.expectNewline();
|
|
892
837
|
const items = [];
|
|
893
|
-
if (this.check("
|
|
894
|
-
this.advance();
|
|
895
|
-
while (!this.check("
|
|
838
|
+
if (this.check("LBRACE")) {
|
|
839
|
+
this.advance();
|
|
840
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
896
841
|
this.skipNewlines();
|
|
897
|
-
if (this.check("
|
|
842
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
898
843
|
break;
|
|
899
844
|
// Each line: id: expression
|
|
900
845
|
const id = this.current().value;
|
|
@@ -933,8 +878,7 @@ export class Parser {
|
|
|
933
878
|
});
|
|
934
879
|
this.skipNewlines();
|
|
935
880
|
}
|
|
936
|
-
|
|
937
|
-
this.advance();
|
|
881
|
+
this.expect("RBRACE");
|
|
938
882
|
}
|
|
939
883
|
const node = { kind: "guards", items };
|
|
940
884
|
node.span = this.makeSpan(startToken);
|
|
@@ -943,13 +887,12 @@ export class Parser {
|
|
|
943
887
|
// ===========================================================================
|
|
944
888
|
// TRIGGER PARSING
|
|
945
889
|
// ===========================================================================
|
|
946
|
-
/** Parse trigger handler: on manual: ... */
|
|
890
|
+
/** Parse trigger handler: on manual: { ... } */
|
|
947
891
|
parseTriggerHandler() {
|
|
948
892
|
this.expect("KEYWORD", "on");
|
|
949
893
|
const triggerType = this.parseTriggerType();
|
|
950
894
|
this.expect("COLON");
|
|
951
|
-
this.
|
|
952
|
-
const body = this.parseStatementBlock();
|
|
895
|
+
const body = this.parseBraceBlock();
|
|
953
896
|
return {
|
|
954
897
|
kind: "trigger_handler",
|
|
955
898
|
trigger: triggerType,
|
|
@@ -1021,23 +964,19 @@ export class Parser {
|
|
|
1021
964
|
// ===========================================================================
|
|
1022
965
|
// STATEMENT PARSING
|
|
1023
966
|
// ===========================================================================
|
|
1024
|
-
/** Parse
|
|
1025
|
-
|
|
967
|
+
/** Parse a brace-delimited block of statements: { stmt... } */
|
|
968
|
+
parseBraceBlock() {
|
|
1026
969
|
const statements = [];
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
this.advance(); // INDENT
|
|
1031
|
-
while (!this.check("DEDENT") && !this.check("EOF")) {
|
|
970
|
+
this.skipNewlines();
|
|
971
|
+
this.expect("LBRACE");
|
|
972
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1032
973
|
this.skipNewlines();
|
|
1033
|
-
if (this.check("
|
|
974
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1034
975
|
break;
|
|
1035
976
|
statements.push(this.parseStatement());
|
|
1036
977
|
this.skipNewlines();
|
|
1037
978
|
}
|
|
1038
|
-
|
|
1039
|
-
this.advance();
|
|
1040
|
-
}
|
|
979
|
+
this.expect("RBRACE");
|
|
1041
980
|
return statements;
|
|
1042
981
|
}
|
|
1043
982
|
/** Parse a single statement */
|
|
@@ -1160,15 +1099,15 @@ export class Parser {
|
|
|
1160
1099
|
const advisor = this.expect("IDENTIFIER").value;
|
|
1161
1100
|
this.expect("COLON");
|
|
1162
1101
|
const prompt = this.expect("STRING").value;
|
|
1163
|
-
this.expectNewline();
|
|
1164
1102
|
let outputSchema;
|
|
1165
1103
|
let timeout;
|
|
1166
1104
|
let fallback;
|
|
1167
|
-
|
|
1105
|
+
this.skipNewlines();
|
|
1106
|
+
if (this.check("LBRACE")) {
|
|
1168
1107
|
this.advance();
|
|
1169
|
-
while (!this.check("
|
|
1108
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1170
1109
|
this.skipNewlines();
|
|
1171
|
-
if (this.check("
|
|
1110
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1172
1111
|
break;
|
|
1173
1112
|
const keyToken = this.current();
|
|
1174
1113
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD"))) {
|
|
@@ -1194,8 +1133,7 @@ export class Parser {
|
|
|
1194
1133
|
this.expectNewline();
|
|
1195
1134
|
}
|
|
1196
1135
|
}
|
|
1197
|
-
|
|
1198
|
-
this.advance();
|
|
1136
|
+
this.expect("RBRACE");
|
|
1199
1137
|
}
|
|
1200
1138
|
if (!outputSchema || timeout === undefined || fallback === undefined) {
|
|
1201
1139
|
throw new ParseError("Advise statement requires output, timeout, and fallback", {
|
|
@@ -1216,15 +1154,15 @@ export class Parser {
|
|
|
1216
1154
|
return node;
|
|
1217
1155
|
}
|
|
1218
1156
|
parseOutputSchemaBlock(keyToken) {
|
|
1219
|
-
if (!this.check("NEWLINE")) {
|
|
1157
|
+
if (!this.check("LBRACE") && !this.check("NEWLINE")) {
|
|
1220
1158
|
// Allow inline type: output: boolean
|
|
1221
1159
|
const inlineType = this.parseSchemaType();
|
|
1222
1160
|
this.expectNewline();
|
|
1223
1161
|
return { kind: "advisory_output_schema", type: inlineType };
|
|
1224
1162
|
}
|
|
1225
|
-
this.
|
|
1226
|
-
if (!this.check("
|
|
1227
|
-
throw new ParseError("Expected
|
|
1163
|
+
this.skipNewlines();
|
|
1164
|
+
if (!this.check("LBRACE")) {
|
|
1165
|
+
throw new ParseError("Expected '{' for output block", {
|
|
1228
1166
|
location: keyToken.location,
|
|
1229
1167
|
source: this.source,
|
|
1230
1168
|
});
|
|
@@ -1233,14 +1171,8 @@ export class Parser {
|
|
|
1233
1171
|
return this.parseSchemaObject(keyToken);
|
|
1234
1172
|
}
|
|
1235
1173
|
parseSchemaAfterColon(keyToken) {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (!this.check("INDENT")) {
|
|
1239
|
-
throw new ParseError("Expected indented schema block", {
|
|
1240
|
-
location: keyToken.location,
|
|
1241
|
-
source: this.source,
|
|
1242
|
-
});
|
|
1243
|
-
}
|
|
1174
|
+
this.skipNewlines();
|
|
1175
|
+
if (this.check("LBRACE")) {
|
|
1244
1176
|
this.advance();
|
|
1245
1177
|
return this.parseSchemaObject(keyToken);
|
|
1246
1178
|
}
|
|
@@ -1258,9 +1190,9 @@ export class Parser {
|
|
|
1258
1190
|
let pattern;
|
|
1259
1191
|
let fields;
|
|
1260
1192
|
let items;
|
|
1261
|
-
while (!this.check("
|
|
1193
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1262
1194
|
this.skipNewlines();
|
|
1263
|
-
if (this.check("
|
|
1195
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1264
1196
|
break;
|
|
1265
1197
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD"))) {
|
|
1266
1198
|
throw new ParseError(`Expected output schema field but got ${this.current().type} '${this.current().value}'`, { location: this.current().location, source: this.source });
|
|
@@ -1311,8 +1243,7 @@ export class Parser {
|
|
|
1311
1243
|
this.expectNewline();
|
|
1312
1244
|
}
|
|
1313
1245
|
}
|
|
1314
|
-
|
|
1315
|
-
this.advance();
|
|
1246
|
+
this.expect("RBRACE");
|
|
1316
1247
|
if (!outType) {
|
|
1317
1248
|
throw new ParseError("Advisory output type is required", {
|
|
1318
1249
|
location: keyToken.location,
|
|
@@ -1333,25 +1264,24 @@ export class Parser {
|
|
|
1333
1264
|
};
|
|
1334
1265
|
}
|
|
1335
1266
|
parseSchemaFields(keyToken) {
|
|
1336
|
-
this.
|
|
1337
|
-
if (!this.check("
|
|
1338
|
-
throw new ParseError("Expected
|
|
1267
|
+
this.skipNewlines();
|
|
1268
|
+
if (!this.check("LBRACE")) {
|
|
1269
|
+
throw new ParseError("Expected '{' for fields block", {
|
|
1339
1270
|
location: keyToken.location,
|
|
1340
1271
|
source: this.source,
|
|
1341
1272
|
});
|
|
1342
1273
|
}
|
|
1343
1274
|
this.advance();
|
|
1344
1275
|
const fields = {};
|
|
1345
|
-
while (!this.check("
|
|
1276
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1346
1277
|
this.skipNewlines();
|
|
1347
|
-
if (this.check("
|
|
1278
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1348
1279
|
break;
|
|
1349
1280
|
const fieldName = this.expect("IDENTIFIER").value;
|
|
1350
1281
|
this.expect("COLON");
|
|
1351
1282
|
fields[fieldName] = this.parseSchemaAfterColon(keyToken);
|
|
1352
1283
|
}
|
|
1353
|
-
|
|
1354
|
-
this.advance();
|
|
1284
|
+
this.expect("RBRACE");
|
|
1355
1285
|
return fields;
|
|
1356
1286
|
}
|
|
1357
1287
|
parseSchemaType() {
|
|
@@ -1392,9 +1322,7 @@ export class Parser {
|
|
|
1392
1322
|
: Number.parseInt(countToken.value, 10),
|
|
1393
1323
|
literalType: "number",
|
|
1394
1324
|
};
|
|
1395
|
-
this.
|
|
1396
|
-
this.expectNewline();
|
|
1397
|
-
const body = this.parseStatementBlock();
|
|
1325
|
+
const body = this.parseBraceBlock();
|
|
1398
1326
|
const node = { kind: "repeat", count, body };
|
|
1399
1327
|
node.span = this.makeSpan(startToken);
|
|
1400
1328
|
return node;
|
|
@@ -1411,9 +1339,7 @@ export class Parser {
|
|
|
1411
1339
|
const maxToken = this.expect("NUMBER");
|
|
1412
1340
|
maxIterations = Number.parseFloat(maxToken.value);
|
|
1413
1341
|
}
|
|
1414
|
-
this.
|
|
1415
|
-
this.expectNewline();
|
|
1416
|
-
const body = this.parseStatementBlock();
|
|
1342
|
+
const body = this.parseBraceBlock();
|
|
1417
1343
|
const node = { kind: "until", condition, maxIterations, body };
|
|
1418
1344
|
node.span = this.makeSpan(startToken);
|
|
1419
1345
|
return node;
|
|
@@ -1422,19 +1348,17 @@ export class Parser {
|
|
|
1422
1348
|
parseTryStatement() {
|
|
1423
1349
|
const startToken = this.current();
|
|
1424
1350
|
this.expect("KEYWORD", "try");
|
|
1425
|
-
this.
|
|
1426
|
-
this.
|
|
1427
|
-
const tryBody = this.parseStatementBlock();
|
|
1351
|
+
const tryBody = this.parseBraceBlock();
|
|
1352
|
+
this.skipNewlines();
|
|
1428
1353
|
const catches = [];
|
|
1429
1354
|
while (this.check("KEYWORD", "catch")) {
|
|
1430
1355
|
catches.push(this.parseCatchBlock());
|
|
1356
|
+
this.skipNewlines();
|
|
1431
1357
|
}
|
|
1432
1358
|
let finallyBody;
|
|
1433
1359
|
if (this.check("KEYWORD", "finally")) {
|
|
1434
1360
|
this.advance();
|
|
1435
|
-
this.
|
|
1436
|
-
this.expectNewline();
|
|
1437
|
-
finallyBody = this.parseStatementBlock();
|
|
1361
|
+
finallyBody = this.parseBraceBlock();
|
|
1438
1362
|
}
|
|
1439
1363
|
const node = { kind: "try", tryBody, catches, finallyBody };
|
|
1440
1364
|
node.span = this.makeSpan(startToken);
|
|
@@ -1451,16 +1375,15 @@ export class Parser {
|
|
|
1451
1375
|
else if (this.check("IDENTIFIER") || this.check("KEYWORD")) {
|
|
1452
1376
|
error = this.advance().value;
|
|
1453
1377
|
}
|
|
1454
|
-
this.expect("COLON");
|
|
1455
|
-
this.expectNewline();
|
|
1456
1378
|
const body = [];
|
|
1457
1379
|
let action;
|
|
1458
1380
|
let retry;
|
|
1459
|
-
|
|
1381
|
+
this.skipNewlines();
|
|
1382
|
+
if (this.check("LBRACE")) {
|
|
1460
1383
|
this.advance();
|
|
1461
|
-
while (!this.check("
|
|
1384
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1462
1385
|
this.skipNewlines();
|
|
1463
|
-
if (this.check("
|
|
1386
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1464
1387
|
break;
|
|
1465
1388
|
if ((this.check("IDENTIFIER") || this.check("KEYWORD")) &&
|
|
1466
1389
|
this.current().value === "action") {
|
|
@@ -1479,15 +1402,13 @@ export class Parser {
|
|
|
1479
1402
|
this.current().value === "retry") {
|
|
1480
1403
|
this.advance();
|
|
1481
1404
|
this.expect("COLON");
|
|
1482
|
-
this.expectNewline();
|
|
1483
1405
|
retry = this.parseRetrySpec();
|
|
1484
1406
|
continue;
|
|
1485
1407
|
}
|
|
1486
1408
|
body.push(this.parseStatement());
|
|
1487
1409
|
this.skipNewlines();
|
|
1488
1410
|
}
|
|
1489
|
-
|
|
1490
|
-
this.advance();
|
|
1411
|
+
this.expect("RBRACE");
|
|
1491
1412
|
}
|
|
1492
1413
|
const node = { kind: "catch", error, action, retry, body };
|
|
1493
1414
|
node.span = this.makeSpan(startToken);
|
|
@@ -1500,11 +1421,12 @@ export class Parser {
|
|
|
1500
1421
|
let backoff = "none";
|
|
1501
1422
|
let backoffBase;
|
|
1502
1423
|
let maxBackoff;
|
|
1503
|
-
|
|
1424
|
+
this.skipNewlines();
|
|
1425
|
+
if (this.check("LBRACE")) {
|
|
1504
1426
|
this.advance();
|
|
1505
|
-
while (!this.check("
|
|
1427
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1506
1428
|
this.skipNewlines();
|
|
1507
|
-
if (this.check("
|
|
1429
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1508
1430
|
break;
|
|
1509
1431
|
const key = this.expect("IDENTIFIER").value;
|
|
1510
1432
|
this.expect("COLON");
|
|
@@ -1530,8 +1452,7 @@ export class Parser {
|
|
|
1530
1452
|
}
|
|
1531
1453
|
this.expectNewline();
|
|
1532
1454
|
}
|
|
1533
|
-
|
|
1534
|
-
this.advance();
|
|
1455
|
+
this.expect("RBRACE");
|
|
1535
1456
|
}
|
|
1536
1457
|
const node = {
|
|
1537
1458
|
kind: "retry",
|
|
@@ -1549,8 +1470,8 @@ export class Parser {
|
|
|
1549
1470
|
this.expect("KEYWORD", "parallel");
|
|
1550
1471
|
let join;
|
|
1551
1472
|
let onFail;
|
|
1552
|
-
// Optional header config before
|
|
1553
|
-
while (!this.check("
|
|
1473
|
+
// Optional header config before brace: join=..., on_fail=...
|
|
1474
|
+
while (!this.check("LBRACE") && !this.check("NEWLINE") && !this.check("EOF")) {
|
|
1554
1475
|
if (!(this.check("IDENTIFIER") || this.check("KEYWORD")))
|
|
1555
1476
|
break;
|
|
1556
1477
|
const key = this.advance().value;
|
|
@@ -1605,25 +1526,20 @@ export class Parser {
|
|
|
1605
1526
|
this.parseExpression();
|
|
1606
1527
|
}
|
|
1607
1528
|
}
|
|
1608
|
-
this.
|
|
1609
|
-
this.
|
|
1529
|
+
this.skipNewlines();
|
|
1530
|
+
this.expect("LBRACE");
|
|
1610
1531
|
const branches = [];
|
|
1611
|
-
|
|
1612
|
-
this.
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
const body = this.parseStatementBlock();
|
|
1621
|
-
branches.push({ kind: "parallel_branch", name, body });
|
|
1622
|
-
this.skipNewlines();
|
|
1623
|
-
}
|
|
1624
|
-
if (this.check("DEDENT"))
|
|
1625
|
-
this.advance();
|
|
1532
|
+
while (!this.check("RBRACE") && !this.check("EOF")) {
|
|
1533
|
+
this.skipNewlines();
|
|
1534
|
+
if (this.check("RBRACE") || this.check("EOF"))
|
|
1535
|
+
break;
|
|
1536
|
+
const name = this.expect("IDENTIFIER").value;
|
|
1537
|
+
this.expect("COLON");
|
|
1538
|
+
const body = this.parseBraceBlock();
|
|
1539
|
+
branches.push({ kind: "parallel_branch", name, body });
|
|
1540
|
+
this.skipNewlines();
|
|
1626
1541
|
}
|
|
1542
|
+
this.expect("RBRACE");
|
|
1627
1543
|
const node = { kind: "parallel", join, onFail, branches };
|
|
1628
1544
|
node.span = this.makeSpan(startToken);
|
|
1629
1545
|
return node;
|
|
@@ -1661,8 +1577,7 @@ export class Parser {
|
|
|
1661
1577
|
}
|
|
1662
1578
|
}
|
|
1663
1579
|
this.expect("COLON");
|
|
1664
|
-
this.
|
|
1665
|
-
const body = this.parseStatementBlock();
|
|
1580
|
+
const body = this.parseBraceBlock();
|
|
1666
1581
|
if (body.length === 0 &&
|
|
1667
1582
|
(op === "map" || op === "filter" || op === "reduce" || op === "pmap")) {
|
|
1668
1583
|
throw new ParseError(`Pipeline stage '${op}' requires a body`, {
|
|
@@ -1715,7 +1630,7 @@ export class Parser {
|
|
|
1715
1630
|
parseIfStatement() {
|
|
1716
1631
|
const startToken = this.current();
|
|
1717
1632
|
this.expect("KEYWORD", "if");
|
|
1718
|
-
// Check for advisory condition: if **prompt
|
|
1633
|
+
// Check for advisory condition: if **prompt** { ... }
|
|
1719
1634
|
let condition;
|
|
1720
1635
|
if (this.check("ADVISORY")) {
|
|
1721
1636
|
const prompt = this.advance().value;
|
|
@@ -1731,26 +1646,22 @@ export class Parser {
|
|
|
1731
1646
|
else {
|
|
1732
1647
|
condition = this.parseExpression();
|
|
1733
1648
|
}
|
|
1734
|
-
this.
|
|
1735
|
-
this.expectNewline();
|
|
1736
|
-
const thenBody = this.parseStatementBlock();
|
|
1649
|
+
const thenBody = this.parseBraceBlock();
|
|
1737
1650
|
const elifs = [];
|
|
1738
1651
|
let elseBody = [];
|
|
1739
1652
|
// Check for elif
|
|
1653
|
+
this.skipNewlines();
|
|
1740
1654
|
while (this.check("KEYWORD", "elif")) {
|
|
1741
1655
|
this.advance();
|
|
1742
1656
|
const elifCondition = this.parseExpression();
|
|
1743
|
-
this.
|
|
1744
|
-
this.expectNewline();
|
|
1745
|
-
const elifBody = this.parseStatementBlock();
|
|
1657
|
+
const elifBody = this.parseBraceBlock();
|
|
1746
1658
|
elifs.push({ condition: elifCondition, body: elifBody });
|
|
1659
|
+
this.skipNewlines();
|
|
1747
1660
|
}
|
|
1748
1661
|
// Check for else
|
|
1749
1662
|
if (this.check("KEYWORD", "else")) {
|
|
1750
1663
|
this.advance();
|
|
1751
|
-
this.
|
|
1752
|
-
this.expectNewline();
|
|
1753
|
-
elseBody = this.parseStatementBlock();
|
|
1664
|
+
elseBody = this.parseBraceBlock();
|
|
1754
1665
|
}
|
|
1755
1666
|
const node = { kind: "if", condition, thenBody, elifs, elseBody };
|
|
1756
1667
|
node.span = this.makeSpan(startToken);
|
|
@@ -1763,29 +1674,24 @@ export class Parser {
|
|
|
1763
1674
|
const variable = this.expect("IDENTIFIER").value;
|
|
1764
1675
|
this.expect("KEYWORD", "in");
|
|
1765
1676
|
const iterable = this.parseExpression();
|
|
1766
|
-
this.
|
|
1767
|
-
this.expectNewline();
|
|
1768
|
-
const body = this.parseStatementBlock();
|
|
1677
|
+
const body = this.parseBraceBlock();
|
|
1769
1678
|
const node = { kind: "for", variable, iterable, body };
|
|
1770
1679
|
node.span = this.makeSpan(startToken);
|
|
1771
1680
|
return node;
|
|
1772
1681
|
}
|
|
1773
|
-
/** Parse atomic block: atomic
|
|
1682
|
+
/** Parse atomic block: atomic { ... } / atomic skip { ... } */
|
|
1774
1683
|
parseAtomicStatement() {
|
|
1775
1684
|
const startToken = this.current();
|
|
1776
1685
|
this.expect("KEYWORD", "atomic");
|
|
1777
1686
|
let onFailure;
|
|
1778
|
-
// Check for failure mode: atomic skip
|
|
1779
|
-
// Note: "halt" is a keyword, "skip" and "revert" are identifiers
|
|
1687
|
+
// Check for failure mode: atomic skip { ... } / atomic halt { ... } / atomic revert { ... }
|
|
1780
1688
|
const failureModes = ["skip", "halt", "revert"];
|
|
1781
1689
|
if ((this.check("IDENTIFIER") || this.check("KEYWORD")) &&
|
|
1782
1690
|
failureModes.includes(this.current().value)) {
|
|
1783
1691
|
onFailure = this.current().value;
|
|
1784
1692
|
this.advance();
|
|
1785
1693
|
}
|
|
1786
|
-
this.
|
|
1787
|
-
this.expectNewline();
|
|
1788
|
-
const body = this.parseStatementBlock();
|
|
1694
|
+
const body = this.parseBraceBlock();
|
|
1789
1695
|
const node = { kind: "atomic", body, onFailure };
|
|
1790
1696
|
node.span = this.makeSpan(startToken);
|
|
1791
1697
|
return node;
|