@@ -9,11 +9,13 @@ open Source
9
9
10
10
module Link = Error. Make ()
11
11
module Trap = Error. Make ()
12
+ module Exception = Error. Make ()
12
13
module Crash = Error. Make ()
13
14
module Exhaustion = Error. Make ()
14
15
15
16
exception Link = Link. Error
16
17
exception Trap = Trap. Error
18
+ exception Exception = Exception. Error
17
19
exception Crash = Crash. Error (* failure that cannot happen in valid code *)
18
20
exception Exhaustion = Exhaustion. Error
19
21
@@ -62,8 +64,14 @@ and admin_instr' =
62
64
| Trapping of string
63
65
| Returning of value stack
64
66
| Breaking of int32 * value stack
67
+ | Throwing of Tag. t * value stack
68
+ | Rethrowing of int32 * (admin_instr -> admin_instr )
65
69
| Label of int32 * instr list * code
66
70
| 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
67
75
68
76
type config =
69
77
{
@@ -205,6 +213,32 @@ let rec step (c : config) : config =
205
213
else
206
214
vs, [Invoke func @@ e.at]
207
215
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
+
208
242
| Drop , v :: vs' ->
209
243
vs', []
210
244
@@ -482,6 +516,15 @@ let rec step (c : config) : config =
482
516
| Breaking (k , vs' ), vs ->
483
517
Crash. error e.at " undefined label"
484
518
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
+
485
528
| Label (n , es0 , (vs' , [] )), vs ->
486
529
vs' @ vs, []
487
530
@@ -497,6 +540,18 @@ let rec step (c : config) : config =
497
540
| Label (n , es0 , (vs' , {it = Breaking (k , vs0 ); at} :: es' )), vs ->
498
541
vs, [Breaking (Int32. sub k 1l , vs0) @@ at]
499
542
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
+
500
555
| Label (n , es0 , code' ), vs ->
501
556
let c' = step {c with code = code'} in
502
557
vs, [Label (n, es0, c'.code) @@ e.at]
@@ -510,10 +565,70 @@ let rec step (c : config) : config =
510
565
| Frame (n , frame' , (vs' , {it = Returning vs0 ; at} :: es' )), vs ->
511
566
take n vs0 e.at @ vs, []
512
567
568
+ | Frame (n , frame' , (vs' , {it = Throwing (a , vs0 ); at} :: es' )), vs ->
569
+ vs, [Throwing (a, vs0) @@ at]
570
+
513
571
| Frame (n , frame' , code' ), vs ->
514
572
let c' = step {frame = frame'; code = code'; budget = c.budget - 1 } in
515
573
vs, [Frame (n, c'.frame, c'.code) @@ e.at]
516
574
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
+
517
632
| Invoke func , vs when c.budget = 0 ->
518
633
Exhaustion. error e.at " call stack exhausted"
519
634
@@ -543,6 +658,10 @@ let rec eval (c : config) : value stack =
543
658
| vs , {it = Trapping msg ; at} :: _ ->
544
659
Trap. error at msg
545
660
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
+
546
665
| vs , es ->
547
666
eval (step c)
548
667
0 commit comments