@@ -9,11 +9,13 @@ open Source
99
1010module Link = Error. Make ()
1111module Trap = Error. Make ()
12+ module Exception = Error. Make ()
1213module Crash = Error. Make ()
1314module Exhaustion = Error. Make ()
1415
1516exception Link = Link. Error
1617exception Trap = Trap. Error
18+ exception Exception = Exception. Error
1719exception Crash = Crash. Error (* failure that cannot happen in valid code *)
1820exception 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
6876type 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
0 commit comments