@@ -10,12 +10,14 @@ open Source
10
10
module Link = Error. Make ()
11
11
module Trap = Error. Make ()
12
12
module Exception = Error. Make ()
13
+ module Suspension = Error. Make ()
13
14
module Exhaustion = Error. Make ()
14
15
module Crash = Error. Make ()
15
16
16
17
exception Link = Link. Error
17
18
exception Trap = Trap. Error
18
19
exception Exception = Exception. Error
20
+ exception Suspension = Suspension. Error
19
21
exception Exhaustion = Exhaustion. Error
20
22
exception Crash = Crash. Error (* failure that cannot happen in valid code *)
21
23
@@ -44,7 +46,7 @@ let numeric_error at = function
44
46
| exn -> raise exn
45
47
46
48
47
- (* Administrative Expressions & Configurations *)
49
+ (* Administrative Expressions & Continuations *)
48
50
49
51
type 'a stack = 'a list
50
52
@@ -61,15 +63,48 @@ and admin_instr' =
61
63
| Plain of instr'
62
64
| Refer of ref_
63
65
| Invoke of func_inst
66
+ | Label of int * instr list * code
67
+ | Local of int * value list * code
68
+ | Frame of int * frame * code
69
+ | Catch of int * event_inst option * instr list * code
70
+ | Handle of (event_inst * idx) list option * code
64
71
| Trapping of string
65
72
| Throwing of event_inst * value stack
73
+ | Suspending of event_inst * value stack * ctxt
66
74
| Returning of value stack
67
75
| ReturningInvoke of value stack * func_inst
68
76
| Breaking of int32 * value stack
69
- | Label of int * instr list * code
70
- | Local of int * value list * code
71
- | Frame of int * frame * code
72
- | Catch of int * event_inst option * instr list * code
77
+
78
+ and ctxt = code -> code
79
+
80
+ type cont = int * ctxt (* TODO: represent type properly *)
81
+ type ref_ + = ContRef of cont
82
+
83
+ let () =
84
+ let type_of_ref' = ! Value. type_of_ref' in
85
+ Value. type_of_ref' := function
86
+ | ContRef _ -> BotHeapType (* TODO *)
87
+ | r -> type_of_ref' r
88
+
89
+ let () =
90
+ let string_of_ref' = ! Value. string_of_ref' in
91
+ Value. string_of_ref' := function
92
+ | ContRef _ -> " cont"
93
+ | r -> string_of_ref' r
94
+
95
+ let plain e = Plain e.it @@ e.at
96
+
97
+ let is_jumping e =
98
+ match e.it with
99
+ | Trapping _ | Throwing _ | Suspending _
100
+ | Returning _ | ReturningInvoke _ | Breaking _ ->
101
+ true
102
+ | _ -> false
103
+
104
+ let compose (vs1 , es1 ) (vs2 , es2 ) = vs1 @ vs2, es1 @ es2
105
+
106
+
107
+ (* Configurations *)
73
108
74
109
type config =
75
110
{
@@ -81,14 +116,6 @@ type config =
81
116
let frame inst = {inst; locals = [] }
82
117
let config inst vs es = {frame = frame inst; code = vs, es; budget = 300 }
83
118
84
- let plain e = Plain e.it @@ e.at
85
-
86
- let is_jumping e =
87
- match e.it with
88
- | Trapping _ | Throwing _ | Returning _ | ReturningInvoke _ | Breaking _ ->
89
- true
90
- | _ -> false
91
-
92
119
let lookup category list x =
93
120
try Lib.List32. nth list x.it with Failure _ ->
94
121
Crash. error x.at (" undefined " ^ category ^ " " ^ Int32. to_string x.it)
@@ -191,12 +218,12 @@ let rec step (c : config) : config =
191
218
vs', [Plain (Block (bt, es1)) @@ e.at]
192
219
193
220
| Let (bt , locals , es' ), vs ->
194
- let vs0 , vs' = split (List. length locals) vs e.at in
221
+ let locs , vs' = split (List. length locals) vs e.at in
195
222
let FuncType (ts1, ts2) = block_type c.frame.inst bt e.at in
196
- let vs1, vs2 = split (List. length ts1) vs' e.at in
197
- vs2 , [
198
- Local (List. length ts2, List. rev vs0 ,
199
- (vs1 , [Plain (Block (bt, es')) @@ e.at])
223
+ let args, vs'' = split (List. length ts1) vs' e.at in
224
+ vs'' , [
225
+ Local (List. length ts2, List. rev locs ,
226
+ (args , [Plain (Block (bt, es')) @@ e.at])
200
227
) @@ e.at
201
228
]
202
229
@@ -209,7 +236,10 @@ let rec step (c : config) : config =
209
236
vs', [Catch (n2, exno, es2, ([] , [Label (n2, [] , (args, List. map plain es1)) @@ e.at])) @@ e.at]
210
237
211
238
| Throw x , vs ->
212
- [] , [Throwing (event c.frame.inst x, vs) @@ e.at]
239
+ let evt = event c.frame.inst x in
240
+ let EventType (FuncType (ts, _), _) = Event. type_of evt in
241
+ let vs0, vs' = split (List. length ts) vs e.at in
242
+ vs', [Throwing (evt, vs0) @@ e.at]
213
243
214
244
| Br x , vs ->
215
245
[] , [Breaking (x.it, vs) @@ e.at]
@@ -278,6 +308,47 @@ let rec step (c : config) : config =
278
308
let f' = Func. alloc_closure (type_ c.frame.inst x) f args in
279
309
Ref (FuncRef f') :: vs', []
280
310
311
+ | ContNew x , Ref (NullRef _ ) :: vs ->
312
+ vs, [Trapping " null function reference" @@ e.at]
313
+
314
+ | ContNew x , Ref (FuncRef f ) :: vs ->
315
+ let FuncType (ts, _) = Func. type_of f in
316
+ let ctxt code = compose code ([] , [Invoke f @@ e.at]) in
317
+ Ref (ContRef (List. length ts, ctxt)) :: vs, []
318
+
319
+ | Suspend x , vs ->
320
+ let evt = event c.frame.inst x in
321
+ let EventType (FuncType (ts, _), _) = Event. type_of evt in
322
+ let args, vs' = split (List. length ts) vs e.at in
323
+ vs', [Suspending (evt, args, fun code -> code) @@ e.at]
324
+
325
+ | Resume xls , Ref (NullRef _ ) :: vs ->
326
+ vs, [Trapping " null continuation reference" @@ e.at]
327
+
328
+ | Resume xls , Ref (ContRef (n , ctxt )) :: vs ->
329
+ let hs = List. map (fun (x , l ) -> event c.frame.inst x, l) xls in
330
+ let args, vs' = split n vs e.at in
331
+ vs', [Handle (Some hs, ctxt (args, [] )) @@ e.at]
332
+
333
+ | ResumeThrow x , Ref (NullRef _ ) :: vs ->
334
+ vs, [Trapping " null continuation reference" @@ e.at]
335
+
336
+ | ResumeThrow x , Ref (ContRef (n , ctxt )) :: vs ->
337
+ let evt = event c.frame.inst x in
338
+ let EventType (FuncType (ts, _), _) = Event. type_of evt in
339
+ let args, vs' = split (List. length ts) vs e.at in
340
+ let vs1', es1' = ctxt (args, [Plain (Throw x) @@ e.at]) in
341
+ vs1' @ vs', es1'
342
+
343
+ | Guard (bt , es' ), vs ->
344
+ let FuncType (ts1, _) = block_type c.frame.inst bt e.at in
345
+ let args, vs' = split (List. length ts1) vs e.at in
346
+ vs', [
347
+ Handle (None ,
348
+ (args, [Plain (Block (bt, es')) @@ e.at])
349
+ ) @@ e.at
350
+ ]
351
+
281
352
| Drop , v :: vs' ->
282
353
vs', []
283
354
@@ -557,6 +628,10 @@ let rec step (c : config) : config =
557
628
| Label (n , es0 , (vs' , [] )), vs ->
558
629
vs' @ vs, []
559
630
631
+ | Label (n , es0 , (vs' , {it = Suspending (evt , vs1 , ctxt ); at} :: es' )), vs ->
632
+ let ctxt' code = [], [Label (n, es0, compose (ctxt code) (vs', es')) @@ e.at] in
633
+ vs, [Suspending (evt, vs1, ctxt') @@ at]
634
+
560
635
| Label (n , es0 , (vs' , {it = Breaking (0l , vs0 ); at} :: es' )), vs ->
561
636
take n vs0 e.at @ vs, List. map plain es0
562
637
@@ -573,6 +648,10 @@ let rec step (c : config) : config =
573
648
| Local (n , vs0 , (vs' , [] )), vs ->
574
649
vs' @ vs, []
575
650
651
+ | Local (n , vs0 , (vs' , {it = Suspending (evt , vs1 , ctxt ); at} :: es' )), vs ->
652
+ let ctxt' code = [], [Local (n, vs0, compose (ctxt code) (vs', es')) @@ e.at] in
653
+ vs, [Suspending (evt, vs1, ctxt') @@ at]
654
+
576
655
| Local (n , vs0 , (vs' , e' :: es' )), vs when is_jumping e' ->
577
656
vs, [e']
578
657
@@ -585,6 +664,10 @@ let rec step (c : config) : config =
585
664
| Frame (n , frame' , (vs' , [] )), vs ->
586
665
vs' @ vs, []
587
666
667
+ | Frame (n , frame' , (vs' , {it = Suspending (evt , vs1 , ctxt ); at} :: es' )), vs ->
668
+ let ctxt' code = [], [Frame (n, frame', compose (ctxt code) (vs', es')) @@ e.at] in
669
+ vs, [Suspending (evt, vs1, ctxt') @@ at]
670
+
588
671
| Frame (n , frame' , (vs' , {it = Returning vs0 ; at} :: es' )), vs ->
589
672
take n vs0 e.at @ vs, []
590
673
@@ -630,14 +713,16 @@ let rec step (c : config) : config =
630
713
| Catch (n , exno , es0 , (vs' , [] )), vs ->
631
714
vs' @ vs, []
632
715
716
+ | Catch (n , exno , es0 , (vs' , {it = Suspending (evt , vs1 , ctxt ); at} :: es' )), vs ->
717
+ let ctxt' code = [], [Catch (n, exno, es0, compose (ctxt code) (vs', es')) @@ e.at] in
718
+ vs, [Suspending (evt, vs1, ctxt') @@ at]
719
+
633
720
| Catch (n , None, es0 , (vs' , {it = Throwing (exn , vs0 ); at} :: _ )), vs ->
634
721
vs, [Label (n, [] , ([] , List. map plain es0)) @@ e.at]
635
722
636
723
| Catch (n, Some exn , es0, (vs', {it = Throwing (exn0, vs0); at} :: _)), vs
637
724
when exn0 == exn ->
638
- let EventType (FuncType (ts, _), _) = Event. type_of exn in
639
- let n' = List. length ts in
640
- vs, [Label (n, [] , (take n' vs0 at, List. map plain es0)) @@ e.at]
725
+ vs, [Label (n, [] , (vs0, List. map plain es0)) @@ e.at]
641
726
642
727
| Catch (n , exno , es0 , (vs' , e' :: es' )), vs when is_jumping e' ->
643
728
vs, [e']
@@ -646,15 +731,36 @@ let rec step (c : config) : config =
646
731
let c' = step {c with code = code'} in
647
732
vs, [Catch (n, exno, es0, c'.code) @@ e.at]
648
733
649
- | Returning _, vs
650
- | ReturningInvoke _ , vs ->
651
- Crash. error e.at " undefined frame"
734
+ | Handle (hso , (vs' , [] )), vs ->
735
+ vs' @ vs, []
736
+
737
+ | Handle (None, (vs' , {it = Suspending _ ; at} :: es' )), vs ->
738
+ vs, [Trapping " guard suspended" @@ at]
739
+
740
+ | Handle (Some hs, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs
741
+ when List. mem_assq evt hs ->
742
+ let EventType (FuncType (_, ts), _) = Event. type_of evt in
743
+ let ctxt' code = compose (ctxt code) (vs', es') in
744
+ [Ref (ContRef (List. length ts, ctxt'))] @ vs1 @ vs,
745
+ [Plain (Br (List. assq evt hs)) @@ e.at]
652
746
653
- | Breaking (k , vs' ), vs ->
654
- Crash. error e.at " undefined label"
747
+ | Handle (hso , (vs' , {it = Suspending (evt , vs1 , ctxt ); at} :: es' )), vs ->
748
+ let ctxt' code = [], [Handle (hso, compose (ctxt code) (vs', es')) @@ e.at] in
749
+ vs, [Suspending (evt, vs1, ctxt') @@ at]
655
750
656
- | Trapping _, vs
657
- | Throwing _ , vs ->
751
+ | Handle (hso , (vs' , e' :: es' )), vs when is_jumping e' ->
752
+ vs, [e']
753
+
754
+ | Handle (hso , code' ), vs ->
755
+ let c' = step {c with code = code'} in
756
+ vs, [Handle (hso, c'.code) @@ e.at]
757
+
758
+ | Trapping _, _
759
+ | Throwing _, _
760
+ | Suspending _, _
761
+ | Returning _, _
762
+ | ReturningInvoke _, _
763
+ | Breaking _ , _ ->
658
764
assert false
659
765
660
766
in {c with code = vs', es' @ List. tl es}
@@ -665,13 +771,17 @@ let rec eval (c : config) : value stack =
665
771
| vs , [] ->
666
772
vs
667
773
668
- | vs , {it = Trapping msg ; at} :: _ ->
669
- Trap. error at msg
670
-
671
- | vs , {it = Throwing _ ; at} :: _ ->
672
- Exception. error at " uncaught exception"
673
-
674
- | vs , es ->
774
+ | vs , e ::_ when is_jumping e ->
775
+ (match e.it with
776
+ | Trapping msg -> Trap. error e.at msg
777
+ | Throwing _ -> Exception. error e.at " unhandled exception"
778
+ | Suspending _ -> Suspension. error e.at " unhandled event"
779
+ | Returning _ | ReturningInvoke _ -> Crash. error e.at " undefined frame"
780
+ | Breaking _ -> Crash. error e.at " undefined label"
781
+ | _ -> assert false
782
+ )
783
+
784
+ | _ ->
675
785
eval (step c)
676
786
677
787
0 commit comments