@@ -112,6 +112,8 @@ let func_type (c : context) x =
112
112
try (Lib.List32.nth c.types.list x.it).it
113
113
with Failure _ -> error x.at ("unknown type " ^ Int32.to_string x.it)
114
114
115
+ let handlers (c : context) h =
116
+ List.map (fun (l, i) -> (l c event, i c)) h
115
117
116
118
let anon category space n =
117
119
let i = space.count in
@@ -179,7 +181,8 @@ let inline_type_explicit (c : context) x ft at =
179
181
%token NAT INT FLOAT STRING VAR
180
182
%token NUM_TYPE FUNCREF EXTERNREF EXTERN MUT
181
183
%token UNREACHABLE NOP DROP SELECT
182
- %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE
184
+ %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE TRY DO CATCH CATCH_ALL
185
+ %token DELEGATE
183
186
%token CALL CALL_INDIRECT RETURN
184
187
%token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET
185
188
%token TABLE_GET TABLE_SET
@@ -188,12 +191,13 @@ let inline_type_explicit (c : context) x ft at =
188
191
%token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
189
192
%token CONST UNARY BINARY TEST COMPARE CONVERT
190
193
%token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL
194
+ %token THROW RETHROW
191
195
%token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
192
196
%token TABLE ELEM MEMORY EVENT DATA DECLARE OFFSET ITEM IMPORT EXPORT
193
197
%token MODULE BIN QUOTE
194
198
%token SCRIPT REGISTER INVOKE GET
195
199
%token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE
196
- %token ASSERT_RETURN ASSERT_TRAP ASSERT_EXHAUSTION
200
+ %token ASSERT_RETURN ASSERT_TRAP ASSERT_EXCEPTION ASSERT_EXHAUSTION
197
201
%token NAN
198
202
%token INPUT OUTPUT
199
203
%token EOF
@@ -358,6 +362,8 @@ plain_instr :
358
362
br_table xs x }
359
363
| RETURN { fun c -> return }
360
364
| CALL var { fun c -> call ($2 c func) }
365
+ | THROW var { fun c -> throw ($2 c event) }
366
+ | RETHROW var { fun c -> rethrow ($2 c label) }
361
367
| LOCAL_GET var { fun c -> local_get ($2 c local) }
362
368
| LOCAL_SET var { fun c -> local_set ($2 c local) }
363
369
| LOCAL_TEE var { fun c -> local_tee ($2 c local) }
@@ -398,7 +404,6 @@ plain_instr :
398
404
| BINARY { fun c -> $1 }
399
405
| CONVERT { fun c -> $1 }
400
406
401
-
402
407
select_instr :
403
408
| SELECT select_instr_results
404
409
{ let at = at () in fun c -> let b, ts = $2 in
@@ -495,6 +500,12 @@ block_instr :
495
500
| IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt
496
501
{ fun c -> let c' = $2 c ($5 @ $8) in
497
502
let ts, es1 = $3 c' in if_ ts es1 ($6 c') }
503
+ | TRY labeling_opt block handler_instr
504
+ { fun c -> let c' = $2 c [] in
505
+ let ts, es = $3 c' in $4 ts es c' }
506
+ | TRY labeling_opt block DELEGATE var
507
+ { fun c -> let c' = $2 c [] in
508
+ let ts, es = $3 c' in try_delegate ts es ($5 c label) }
498
509
499
510
block :
500
511
| type_use block_param_body
@@ -524,6 +535,44 @@ block_result_body :
524
535
{ let FuncType (ins, out) = fst $5 in
525
536
FuncType (ins, $3 @ out), snd $5 }
526
537
538
+ handler_instr :
539
+ | catch_list_instr END
540
+ { fun bt es c -> try_catch bt es (handlers c $1) None }
541
+ | catch_list_instr catch_all END
542
+ { fun bt es c -> try_catch bt es (handlers c $1) (Some ($2 c)) }
543
+ | catch_all END
544
+ { fun bt es c -> try_catch bt es [] (Some ($1 c)) }
545
+ | END { fun bt es c -> try_catch bt es [] None }
546
+
547
+ catch_list_instr :
548
+ | catch catch_list_instr { $1 :: $2 }
549
+ | catch { [$1] }
550
+
551
+ handler :
552
+ | catch_list
553
+ { fun bt es _ c' ->
554
+ let cs = (List.map (fun (l, i) -> (l c' event, i c')) $1) in
555
+ try_catch bt es cs None }
556
+ | catch_list LPAR catch_all RPAR
557
+ { fun bt es _ c' ->
558
+ let cs = (List.map (fun (l, i) -> (l c' event, i c')) $1) in
559
+ try_catch bt es cs (Some ($3 c')) }
560
+ | LPAR catch_all RPAR
561
+ { fun bt es _ c' -> try_catch bt es [] (Some ($2 c')) }
562
+ | LPAR DELEGATE var RPAR
563
+ { fun bt es c _ -> try_delegate bt es ($3 c label) }
564
+ | /* empty */ { fun bt es c _ -> try_catch bt es [] None }
565
+
566
+ catch_list :
567
+ | catch_list LPAR catch RPAR { $1 @ [$3] }
568
+ | LPAR catch RPAR { [$2] }
569
+
570
+ catch :
571
+ | CATCH var instr_list { ($2, $3) }
572
+
573
+ catch_all :
574
+ | CATCH_ALL instr_list { $2 }
575
+
527
576
528
577
expr : /* Sugar */
529
578
| LPAR expr1 RPAR
@@ -545,6 +594,8 @@ expr1 : /* Sugar */
545
594
| IF labeling_opt if_block
546
595
{ fun c -> let c' = $2 c [] in
547
596
let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 }
597
+ | TRY labeling_opt try_block
598
+ { fun c -> let c' = $2 c [] in [], $3 c c' }
548
599
549
600
select_expr_results :
550
601
| LPAR RESULT value_type_list RPAR select_expr_results
@@ -614,6 +665,38 @@ if_ :
614
665
| LPAR THEN instr_list RPAR /* Sugar */
615
666
{ fun c c' -> [], $3 c', [] }
616
667
668
+ try_block :
669
+ | type_use try_block_param_body
670
+ { let at = at () in
671
+ fun c c' ->
672
+ let bt = VarBlockType (inline_type_explicit c' ($1 c' type_) (fst $2) at) in
673
+ snd $2 bt c c' }
674
+ | try_block_param_body /* Sugar */
675
+ { let at = at () in
676
+ fun c c' ->
677
+ let bt =
678
+ match fst $1 with
679
+ | FuncType ([], []) -> ValBlockType None
680
+ | FuncType ([], [t]) -> ValBlockType (Some t)
681
+ | ft -> VarBlockType (inline_type c' ft at)
682
+ in snd $1 bt c c' }
683
+
684
+ try_block_param_body :
685
+ | try_block_result_body { $1 }
686
+ | LPAR PARAM value_type_list RPAR try_block_param_body
687
+ { let FuncType (ins, out) = fst $5 in
688
+ FuncType ($3 @ ins, out), snd $5 }
689
+
690
+ try_block_result_body :
691
+ | try_ { FuncType ([], []), $1 }
692
+ | LPAR RESULT value_type_list RPAR try_block_result_body
693
+ { let FuncType (ins, out) = fst $5 in
694
+ FuncType (ins, $3 @ out), snd $5 }
695
+
696
+ try_ :
697
+ | LPAR DO instr_list RPAR handler
698
+ { fun bt c c' -> $5 bt ($3 c') c c' }
699
+
617
700
instr_list :
618
701
| /* empty */ { fun c -> [] }
619
702
| select_instr { fun c -> [$1 c] }
@@ -1085,6 +1168,8 @@ assertion :
1085
1168
{ AssertUninstantiable (snd $3, $4) @@ at () }
1086
1169
| LPAR ASSERT_RETURN action result_list RPAR { AssertReturn ($3, $4) @@ at () }
1087
1170
| LPAR ASSERT_TRAP action STRING RPAR { AssertTrap ($3, $4) @@ at () }
1171
+ | LPAR ASSERT_EXCEPTION action RPAR
1172
+ { AssertUncaughtException $3 @@ at () }
1088
1173
| LPAR ASSERT_EXHAUSTION action STRING RPAR { AssertExhaustion ($3, $4) @@ at () }
1089
1174
1090
1175
cmd :
0 commit comments