@@ -14,6 +14,8 @@ let require b at s = if not b then error at s
14
14
15
15
(* Context *)
16
16
17
+ type label_kind = BodyLabel | BlockLabel | TryLabel | CatchLabel
18
+
17
19
type context =
18
20
{
19
21
types : func_type list ;
@@ -26,7 +28,7 @@ type context =
26
28
datas : unit list ;
27
29
locals : value_type list ;
28
30
results : value_type list ;
29
- labels : stack_type list ;
31
+ labels : ( label_kind * stack_type ) list ;
30
32
refs : Free .t ;
31
33
}
32
34
@@ -229,32 +231,35 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
229
231
230
232
| Block (bt , es ) ->
231
233
let FuncType (ts1, ts2) as ft = check_block_type c bt in
232
- check_block {c with labels = ts2 :: c .labels} es ft e.at;
234
+ check_block {c with labels = ( BlockLabel , ts2) :: c.labels} es ft e.at;
233
235
ts1 --> ts2
234
236
235
237
| Loop (bt , es ) ->
236
238
let FuncType (ts1, ts2) as ft = check_block_type c bt in
237
- check_block {c with labels = ts1 :: c .labels} es ft e.at;
239
+ check_block {c with labels = ( BlockLabel , ts1) :: c.labels} es ft e.at;
238
240
ts1 --> ts2
239
241
240
242
| If (bt , es1 , es2 ) ->
241
243
let FuncType (ts1, ts2) as ft = check_block_type c bt in
242
- check_block {c with labels = ts2 :: c .labels} es1 ft e.at;
243
- check_block {c with labels = ts2 :: c .labels} es2 ft e.at;
244
+ check_block {c with labels = ( BlockLabel , ts2) :: c.labels} es1 ft e.at;
245
+ check_block {c with labels = ( BlockLabel , ts2) :: c.labels} es2 ft e.at;
244
246
(ts1 @ [NumType I32Type ]) --> ts2
245
247
246
248
| Br x ->
247
- label c x -->... []
249
+ let (_, ts) = label c x in
250
+ ts -->... []
248
251
249
252
| BrIf x ->
250
- (label c x @ [NumType I32Type ]) --> label c x
253
+ let (_, ts) = label c x in
254
+ (ts @ [NumType I32Type ]) --> ts
251
255
252
256
| BrTable (xs , x ) ->
253
- let n = List. length (label c x) in
254
- let ts = Lib.List. table n (fun i -> peek (n - i) s) in
255
- check_stack ts (known (label c x)) x.at;
256
- List. iter (fun x' -> check_stack ts (known (label c x')) x'.at) xs;
257
- (ts @ [Some (NumType I32Type )]) -~>... []
257
+ let (_, ts) = label c x in
258
+ let n = List. length ts in
259
+ let ts' = Lib.List. table n (fun i -> peek (n - i) s) in
260
+ check_stack ts' (known ts) x.at;
261
+ List. iter (fun x' -> check_stack ts' (known (snd (label c x'))) x'.at) xs;
262
+ (ts' @ [Some (NumType I32Type )]) -~>... []
258
263
259
264
| Return ->
260
265
c.results -->... []
@@ -402,10 +407,31 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
402
407
let t1, t2 = type_cvtop e.at cvtop in
403
408
[NumType t1] --> [NumType t2]
404
409
405
- | TryCatch _ -> [] --> [] (* TODO *)
406
- | TryDelegate _ -> [] --> [] (* TODO *)
407
- | Throw _ -> [] --> [] (* TODO *)
408
- | Rethrow _ -> [] --> [] (* TODO *)
410
+ | TryCatch (bt , es , cts , ca ) ->
411
+ let FuncType (ts1, ts2) as ft = check_block_type c bt in
412
+ let c_try = {c with labels = (TryLabel , ts2) :: c.labels} in
413
+ let c_catch = {c with labels = (CatchLabel , ts2) :: c.labels} in
414
+ check_block c_try es ft e.at;
415
+ List. iter (fun ct -> check_catch ct c_catch ft e.at) cts;
416
+ Lib.Option. app (fun es -> check_block c_catch es ft e.at) ca;
417
+ ts1 --> ts2
418
+
419
+ | TryDelegate (bt , es , x ) ->
420
+ let FuncType (ts1, ts2) as ft = check_block_type c bt in
421
+ let (kind, _) = label c x in
422
+ require (kind = TryLabel || kind = BodyLabel ) e.at " invalid delegate label" ;
423
+ check_block {c with labels = (TryLabel , ts2) :: c.labels} es ft e.at;
424
+ ts1 --> ts2
425
+
426
+ | Throw x ->
427
+ let TagType y = tag c x in
428
+ let FuncType (ts1, _) = type_ c (y @@ e.at) in
429
+ ts1 -->... []
430
+
431
+ | Rethrow x ->
432
+ let (kind, _) = label c x in
433
+ require (kind = CatchLabel ) e.at " invalid rethrow label" ;
434
+ [] --> []
409
435
410
436
and check_seq (c : context ) (s : infer_stack_type ) (es : instr list )
411
437
: infer_stack_type =
@@ -427,6 +453,13 @@ and check_block (c : context) (es : instr list) (ft : func_type) at =
427
453
(" type mismatch: block requires " ^ string_of_stack_type ts2 ^
428
454
" but stack has " ^ string_of_infer_types (snd s))
429
455
456
+ and check_catch (ct : var * instr list ) (c : context ) (ft : func_type ) at =
457
+ let (x, es) = ct in
458
+ let TagType y = tag c x in
459
+ let FuncType (ts1, _) = type_ c (y @@ at) in
460
+ let FuncType (_, ts2) = ft in
461
+ check_block c es (FuncType (ts1, ts2)) at
462
+
430
463
431
464
(* Types *)
432
465
@@ -491,7 +524,7 @@ let check_type (t : type_) =
491
524
let check_func (c : context ) (f : func ) =
492
525
let {ftype; locals; body} = f.it in
493
526
let FuncType (ts1, ts2) = type_ c ftype in
494
- let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in
527
+ let c' = {c with locals = ts1 @ locals; results = ts2; labels = [( BodyLabel , ts2) ]} in
495
528
check_block c' body (FuncType ([] , ts2)) f.at
496
529
497
530
let check_tag (c : context ) (t : tag ) =
0 commit comments