@@ -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,6 +191,7 @@ 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
@@ -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 try_ ts es ($4 c') }
506
+ | TRY labeling_opt block DELEGATE var
507
+ { fun c -> let c' = $2 c [] in
508
+ let ts, es = $3 c' in try_ ts es (delegate ($5 c label)) }
498
509
499
510
block :
500
511
| type_use block_param_body
@@ -524,6 +535,40 @@ 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 c -> catch (handlers c $1) None }
541
+ | catch_list_instr catch_all END
542
+ { fun c -> catch (handlers c $1) (Some ($2 c)) }
543
+ | catch_all END
544
+ { fun c -> catch [] (Some ($1 c)) }
545
+ | END { fun c -> catch [] None }
546
+
547
+ catch_list_instr :
548
+ | catch catch_list_instr { $1 :: $2 }
549
+ | catch { [$1] }
550
+
551
+ handler :
552
+ | catch_list
553
+ { fun _ c' -> catch (List.map (fun (l, i) -> (l c' event, i c')) $1) None }
554
+ | catch_list LPAR catch_all RPAR
555
+ { fun _ c' -> catch (List.map (fun (l, i) -> (l c' event, i c')) $1) (Some ($3 c')) }
556
+ | LPAR catch_all RPAR
557
+ { fun _ c' -> catch [] (Some ($2 c')) }
558
+ | LPAR DELEGATE var RPAR
559
+ { fun c _ -> delegate ($3 c label) }
560
+ | /* empty */ { fun c _ -> catch [] None }
561
+
562
+ catch_list :
563
+ | catch_list LPAR catch RPAR { $1 @ [$3] }
564
+ | LPAR catch RPAR { [$2] }
565
+
566
+ catch :
567
+ | CATCH var instr_list { ($2, $3) }
568
+
569
+ catch_all :
570
+ | CATCH_ALL instr_list { $2 }
571
+
527
572
528
573
expr : /* Sugar */
529
574
| LPAR expr1 RPAR
@@ -545,6 +590,9 @@ expr1 : /* Sugar */
545
590
| IF labeling_opt if_block
546
591
{ fun c -> let c' = $2 c [] in
547
592
let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 }
593
+ | TRY labeling_opt try_block
594
+ { fun c -> let c' = $2 c [] in
595
+ let bt, (es, h) = $3 c c' in [], try_ bt es h }
548
596
549
597
select_expr_results :
550
598
| LPAR RESULT value_type_list RPAR select_expr_results
@@ -614,6 +662,38 @@ if_ :
614
662
| LPAR THEN instr_list RPAR /* Sugar */
615
663
{ fun c c' -> [], $3 c', [] }
616
664
665
+ try_block :
666
+ | type_use try_block_param_body
667
+ { let at = at () in
668
+ fun c c' ->
669
+ VarBlockType (inline_type_explicit c' ($1 c' type_) (fst $2) at),
670
+ snd $2 c c' }
671
+ | try_block_param_body /* Sugar */
672
+ { let at = at () in
673
+ fun c c' ->
674
+ let bt =
675
+ match fst $1 with
676
+ | FuncType ([], []) -> ValBlockType None
677
+ | FuncType ([], [t]) -> ValBlockType (Some t)
678
+ | ft -> VarBlockType (inline_type c' ft at)
679
+ in bt, snd $1 c c' }
680
+
681
+ try_block_param_body :
682
+ | try_block_result_body { $1 }
683
+ | LPAR PARAM value_type_list RPAR try_block_param_body
684
+ { let FuncType (ins, out) = fst $5 in
685
+ FuncType ($3 @ ins, out), snd $5 }
686
+
687
+ try_block_result_body :
688
+ | try_ { FuncType ([], []), $1 }
689
+ | LPAR RESULT value_type_list RPAR try_block_result_body
690
+ { let FuncType (ins, out) = fst $5 in
691
+ FuncType (ins, $3 @ out), snd $5 }
692
+
693
+ try_ :
694
+ | LPAR DO instr_list RPAR handler
695
+ { fun c c' -> $3 c', $5 c c' }
696
+
617
697
instr_list :
618
698
| /* empty */ { fun c -> [] }
619
699
| select_instr { fun c -> [$1 c] }
0 commit comments