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

Commit 8cece8d

Browse files
committed
[interpreter] Add evaluation support for exceptions
1 parent 9e852b6 commit 8cece8d

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

interpreter/exec/eval.ml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ open Source
99

1010
module Link = Error.Make ()
1111
module Trap = Error.Make ()
12+
module Exception = Error.Make ()
1213
module Crash = Error.Make ()
1314
module Exhaustion = Error.Make ()
1415

1516
exception Link = Link.Error
1617
exception Trap = Trap.Error
18+
exception Exception = Exception.Error
1719
exception Crash = Crash.Error (* failure that cannot happen in valid code *)
1820
exception Exhaustion = Exhaustion.Error
1921

@@ -62,8 +64,14 @@ and admin_instr' =
6264
| Trapping of string
6365
| Returning of value stack
6466
| Breaking of int32 * value stack
67+
| Throwing of Tag.t * value stack
68+
| Rethrowing of int32 * (admin_instr -> admin_instr)
6569
| Label of int32 * instr list * code
6670
| Frame of int32 * frame * code
71+
| Catch of int32 * (Tag.t * instr list) list * instr list option * code
72+
| Caught of int32 * Tag.t * value stack * code
73+
| Delegate of int32 * code
74+
| Delegating of int32 * Tag.t * value stack
6775

6876
type config =
6977
{
@@ -205,6 +213,32 @@ let rec step (c : config) : config =
205213
else
206214
vs, [Invoke func @@ e.at]
207215

216+
| Throw x, vs ->
217+
let t = tag frame.inst x in
218+
let FuncType (ts, _) = Tag.type_of t in
219+
let n = Lib.List32.length ts in
220+
let args, vs' = take n vs e.at, drop n vs e.at in
221+
vs', [Throwing (t, args) @@ e.at]
222+
223+
| Rethrow x, vs ->
224+
vs, [Rethrowing (x.it, fun e -> e) @@ e.at]
225+
226+
| TryCatch (bt, es', cts, ca), vs ->
227+
let FuncType (ts1, ts2) = block_type frame.inst bt in
228+
let n1 = Lib.List32.length ts1 in
229+
let n2 = Lib.List32.length ts2 in
230+
let args, vs' = take n1 vs e.at, drop n1 vs e.at in
231+
let cts' = List.map (fun (x, es'') -> ((tag frame.inst x), es'')) cts in
232+
vs', [Label (n2, [], ([], [Catch (n2, cts', ca, (args, List.map plain es')) @@ e.at])) @@ e.at]
233+
234+
| TryDelegate (bt, es', x), vs ->
235+
let FuncType (ts1, ts2) = block_type frame.inst bt in
236+
let n1 = Lib.List32.length ts1 in
237+
let n2 = Lib.List32.length ts2 in
238+
let args, vs' = take n1 vs e.at, drop n1 vs e.at in
239+
let k = Int32.succ x.it in
240+
vs', [Label (n2, [], ([], [Delegate (k, (args, List.map plain es')) @@ e.at])) @@ e.at]
241+
208242
| Drop, v :: vs' ->
209243
vs', []
210244

@@ -482,6 +516,15 @@ let rec step (c : config) : config =
482516
| Breaking (k, vs'), vs ->
483517
Crash.error e.at "undefined label"
484518

519+
| Throwing _, _ ->
520+
assert false
521+
522+
| Rethrowing _, _ ->
523+
Crash.error e.at "undefined catch label"
524+
525+
| Delegating _, _ ->
526+
Crash.error e.at "undefined delegate label"
527+
485528
| Label (n, es0, (vs', [])), vs ->
486529
vs' @ vs, []
487530

@@ -497,6 +540,18 @@ let rec step (c : config) : config =
497540
| Label (n, es0, (vs', {it = Breaking (k, vs0); at} :: es')), vs ->
498541
vs, [Breaking (Int32.sub k 1l, vs0) @@ at]
499542

543+
| Label (n, es0, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
544+
vs, [Throwing (a, vs0) @@ at]
545+
546+
| Label (n, es0, (vs', {it = Delegating (0l, a, vs0); at} :: es')), vs ->
547+
vs, [Throwing (a, vs0) @@ at]
548+
549+
| Label (n, es0, (vs', {it = Delegating (k, a, vs0); at} :: es')), vs ->
550+
vs, [Delegating (Int32.sub k 1l, a, vs0) @@ at]
551+
552+
| Label (n, es0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs ->
553+
vs, [Rethrowing (Int32.sub k 1l, (fun e -> Label (n, es0, (vs', (cont e) :: es')) @@ e.at)) @@ at]
554+
500555
| Label (n, es0, code'), vs ->
501556
let c' = step {c with code = code'} in
502557
vs, [Label (n, es0, c'.code) @@ e.at]
@@ -510,10 +565,70 @@ let rec step (c : config) : config =
510565
| Frame (n, frame', (vs', {it = Returning vs0; at} :: es')), vs ->
511566
take n vs0 e.at @ vs, []
512567

568+
| Frame (n, frame', (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
569+
vs, [Throwing (a, vs0) @@ at]
570+
513571
| Frame (n, frame', code'), vs ->
514572
let c' = step {frame = frame'; code = code'; budget = c.budget - 1} in
515573
vs, [Frame (n, c'.frame, c'.code) @@ e.at]
516574

575+
| Catch (n, cts, ca, (vs', [])), vs ->
576+
vs' @ vs, []
577+
578+
| Catch (n, cts, ca, (vs', {it = Delegating (0l, a, vs0); at} :: es')), vs ->
579+
vs, [Catch (n, cts, ca, (vs', (Throwing (a, vs0) @@ at) :: es')) @@ e.at]
580+
581+
| Catch (n, cts, ca, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Delegating _; at} as e) :: es')), vs ->
582+
vs, [e]
583+
584+
| Catch (n, cts, ca, (vs', {it = Rethrowing (k, cont); at} :: es')), vs ->
585+
vs, [Rethrowing (k, (fun e -> Catch (n, cts, ca, (vs', (cont e) :: es')) @@ e.at)) @@ at]
586+
587+
| Catch (n, (a', es'') :: cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
588+
if a == a' then
589+
vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at]
590+
else
591+
vs, [Catch (n, cts, ca, (vs', {it = Throwing (a, vs0); at} :: es')) @@ e.at]
592+
593+
| Catch (n, [], Some es'', (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
594+
vs, [Caught (n, a, vs0, (vs0, List.map plain es'')) @@ at]
595+
596+
| Catch (n, [], None, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
597+
vs, [Throwing (a, vs0) @@ at]
598+
599+
| Catch (n, cts, ca, code'), vs ->
600+
let c' = step {c with code = code'} in
601+
vs, [Catch (n, cts, ca, c'.code) @@ e.at]
602+
603+
| Caught (n, a, vs0, (vs', [])), vs ->
604+
vs' @ vs, []
605+
606+
| Caught (n, a, vs0, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Throwing _ | Delegating _; at} as e) :: es')), vs ->
607+
vs, [e]
608+
609+
| Caught (n, a, vs0, (vs', {it = Rethrowing (0l, cont); at} :: es')), vs ->
610+
vs, [Caught (n, a, vs0, (vs', (cont (Throwing (a, vs0) @@ at)) :: es')) @@ e.at]
611+
612+
| Caught (n, a, vs0, (vs', {it = Rethrowing (k, cont); at} :: es')), vs ->
613+
vs, [Rethrowing (k, (fun e -> Caught (n, a, vs0, (vs', (cont e) :: es')) @@ e.at)) @@ at]
614+
615+
| Caught (n, a, vs0, code'), vs ->
616+
let c' = step {c with code = code'} in
617+
vs, [Caught (n, a, vs0, c'.code) @@ e.at]
618+
619+
| Delegate (l, (vs', [])), vs ->
620+
vs' @ vs, []
621+
622+
| Delegate (l, (vs', ({it = Trapping _ | Breaking _ | Returning _ | Rethrowing _ | Delegating _; at} as e) :: es')), vs ->
623+
vs, [e]
624+
625+
| Delegate (l, (vs', {it = Throwing (a, vs0); at} :: es')), vs ->
626+
vs, [Delegating (l, a, vs0) @@ e.at]
627+
628+
| Delegate (l, code'), vs ->
629+
let c' = step {c with code = code'} in
630+
vs, [Delegate (l, c'.code) @@ e.at]
631+
517632
| Invoke func, vs when c.budget = 0 ->
518633
Exhaustion.error e.at "call stack exhausted"
519634

@@ -543,6 +658,10 @@ let rec eval (c : config) : value stack =
543658
| vs, {it = Trapping msg; at} :: _ ->
544659
Trap.error at msg
545660

661+
| vs, {it = Throwing (a, args); at} :: _ ->
662+
let msg = "uncaught exception with args (" ^ string_of_values args ^ ")" in
663+
Exception.error at msg
664+
546665
| vs, es ->
547666
eval (step c)
548667

interpreter/exec/eval.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ open Instance
33

44
exception Link of Source.region * string
55
exception Trap of Source.region * string
6+
exception Exception of Source.region * string
67
exception Crash of Source.region * string
78
exception Exhaustion of Source.region * string
89

0 commit comments

Comments
 (0)