Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 9e852b6

Browse files
committed
[interpreter] Add support for exception validation
1 parent 9fda8b6 commit 9e852b6

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

interpreter/valid/valid.ml

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ let require b at s = if not b then error at s
1414

1515
(* Context *)
1616

17+
type label_kind = BodyLabel | BlockLabel | TryLabel | CatchLabel
18+
1719
type context =
1820
{
1921
types : func_type list;
@@ -26,7 +28,7 @@ type context =
2628
datas : unit list;
2729
locals : value_type list;
2830
results : value_type list;
29-
labels : stack_type list;
31+
labels : (label_kind * stack_type) list;
3032
refs : Free.t;
3133
}
3234

@@ -229,32 +231,35 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
229231

230232
| Block (bt, es) ->
231233
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;
233235
ts1 --> ts2
234236

235237
| Loop (bt, es) ->
236238
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;
238240
ts1 --> ts2
239241

240242
| If (bt, es1, es2) ->
241243
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;
244246
(ts1 @ [NumType I32Type]) --> ts2
245247

246248
| Br x ->
247-
label c x -->... []
249+
let (_, ts) = label c x in
250+
ts -->... []
248251

249252
| BrIf x ->
250-
(label c x @ [NumType I32Type]) --> label c x
253+
let (_, ts) = label c x in
254+
(ts @ [NumType I32Type]) --> ts
251255

252256
| 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)]) -~>... []
258263

259264
| Return ->
260265
c.results -->... []
@@ -402,10 +407,31 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
402407
let t1, t2 = type_cvtop e.at cvtop in
403408
[NumType t1] --> [NumType t2]
404409

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+
[] --> []
409435

410436
and check_seq (c : context) (s : infer_stack_type) (es : instr list)
411437
: infer_stack_type =
@@ -427,6 +453,13 @@ and check_block (c : context) (es : instr list) (ft : func_type) at =
427453
("type mismatch: block requires " ^ string_of_stack_type ts2 ^
428454
" but stack has " ^ string_of_infer_types (snd s))
429455

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+
430463

431464
(* Types *)
432465

@@ -491,7 +524,7 @@ let check_type (t : type_) =
491524
let check_func (c : context) (f : func) =
492525
let {ftype; locals; body} = f.it in
493526
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
495528
check_block c' body (FuncType ([], ts2)) f.at
496529

497530
let check_tag (c : context) (t : tag) =

0 commit comments

Comments
 (0)