-
Notifications
You must be signed in to change notification settings - Fork 16
Named handlers #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: named-handlers
Are you sure you want to change the base?
Named handlers #129
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -58,6 +58,7 @@ type frame = | |||||||||
} | ||||||||||
|
||||||||||
type code = value stack * admin_instr list | ||||||||||
and handler_name = exn | ||||||||||
|
||||||||||
and admin_instr = admin_instr' phrase | ||||||||||
and admin_instr' = | ||||||||||
|
@@ -72,25 +73,28 @@ and admin_instr' = | |||||||||
| Label of int * instr list * code | ||||||||||
| Frame of int * frame * code | ||||||||||
| Handler of int * catch list * code | ||||||||||
| Prompt of handle_table * code | ||||||||||
| Suspending of tag_inst * value stack * (int32 * ref_) option * ctxt | ||||||||||
| Prompt of handler_name option * handle_table * code | ||||||||||
| Suspending of tag_inst * value stack * (int32 * ref_) option * ref_ option * ctxt | ||||||||||
|
||||||||||
and ctxt = code -> code | ||||||||||
and handle_table = (tag_inst * idx) list * tag_inst list | ||||||||||
|
||||||||||
type cont = int32 * ctxt (* TODO: represent type properly *) | ||||||||||
type ref_ += ContRef of cont option ref | ||||||||||
| HandlerRef of handler_name option ref | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
let () = | ||||||||||
let type_of_ref' = !Value.type_of_ref' in | ||||||||||
Value.type_of_ref' := function | ||||||||||
| ContRef _ -> ContHT | ||||||||||
| HandlerRef _ -> HandlerHT | ||||||||||
| r -> type_of_ref' r | ||||||||||
|
||||||||||
let () = | ||||||||||
let string_of_ref' = !Value.string_of_ref' in | ||||||||||
Value.string_of_ref' := function | ||||||||||
| ContRef _ -> "cont" | ||||||||||
| HandlerRef _ -> "handler" | ||||||||||
| r -> string_of_ref' r | ||||||||||
|
||||||||||
let plain e = Plain e.it @@ e.at | ||||||||||
|
@@ -379,7 +383,18 @@ let rec step (c : config) : config = | |||||||||
let tagt = tag c.frame.inst x in | ||||||||||
let FuncT (ts, _) = func_type_of_tag_type c.frame.inst (Tag.type_of tagt) in | ||||||||||
let args, vs' = i32_split (Lib.List32.length ts) vs e.at in | ||||||||||
vs', [Suspending (tagt, args, None, fun code -> code) @@ e.at] | ||||||||||
vs', [Suspending (tagt, args, None, None, fun code -> code) @@ e.at] | ||||||||||
|
||||||||||
| SuspendTo (x, y), vs -> | ||||||||||
let tagt = tag c.frame.inst y in | ||||||||||
let FuncT (ts, _) = func_type_of_tag_type c.frame.inst (Tag.type_of tagt) in | ||||||||||
let args, vs' = i32_split (Int32.add (Lib.List32.length ts) 1l) vs e.at in | ||||||||||
let args, href = | ||||||||||
match args with | ||||||||||
| Ref r :: rest -> rest, r | ||||||||||
| _ -> Crash.error e.at "type mismatch at suspend to" | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
in | ||||||||||
vs', [Suspending (tagt, args, None, Some href, fun code -> code) @@ e.at] | ||||||||||
|
||||||||||
| Resume (x, xls), Ref (NullRef _) :: vs -> | ||||||||||
vs, [Trapping "null continuation reference" @@ e.at] | ||||||||||
|
@@ -391,7 +406,7 @@ let rec step (c : config) : config = | |||||||||
let hs = handle_table c xls in | ||||||||||
let args, vs' = i32_split n vs e.at in | ||||||||||
cont := None; | ||||||||||
vs', [Prompt (hs, ctxt (args, [])) @@ e.at] | ||||||||||
vs', [Prompt (None, hs, ctxt (args, [])) @@ e.at] | ||||||||||
|
||||||||||
| ResumeThrow (x, y, xls), Ref (NullRef _) :: vs -> | ||||||||||
vs, [Trapping "null continuation reference" @@ e.at] | ||||||||||
|
@@ -405,7 +420,23 @@ let rec step (c : config) : config = | |||||||||
let hs = handle_table c xls in | ||||||||||
let args, vs' = i32_split (Lib.List32.length ts) vs e.at in | ||||||||||
cont := None; | ||||||||||
vs', [Prompt (hs, ctxt ([], [Throwing (tagt, args) @@ e.at])) @@ e.at] | ||||||||||
vs', [Prompt (None, hs, ctxt ([], [Throwing (tagt, args) @@ e.at])) @@ e.at] | ||||||||||
|
||||||||||
| ResumeWith (x, xls), Ref (NullRef _) :: vs -> | ||||||||||
vs, [Trapping "null continuation reference" @@ e.at] | ||||||||||
|
||||||||||
| ResumeWith (x, xls), Ref (ContRef {contents = None}) :: vs -> | ||||||||||
vs, [Trapping "continuation already consumed" @@ e.at] | ||||||||||
|
||||||||||
| ResumeWith (x, xls), Ref (ContRef ({contents = Some (n, ctxt)} as cont)) :: vs -> | ||||||||||
let hs = handle_table c xls in | ||||||||||
let args, vs' = i32_split (Int32.sub n 1l) vs e.at in | ||||||||||
let exception Name in | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of abusing exceptions, can we define our own extensible datatype prompt_name above and extend that here? Unfortunately, this:
Suggested change
doesn't work, you'll have to do
Suggested change
and use |
||||||||||
let name = | ||||||||||
Ref (HandlerRef (ref (Some Name))) | ||||||||||
in | ||||||||||
Comment on lines
+435
to
+437
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
cont := None; | ||||||||||
vs', [Prompt (Some Name, hs, ctxt (name :: args, [])) @@ e.at] | ||||||||||
|
||||||||||
| Switch (x, y), Ref (NullRef _) :: vs -> | ||||||||||
vs, [Trapping "null continuation reference" @@ e.at] | ||||||||||
|
@@ -419,7 +450,7 @@ let rec step (c : config) : config = | |||||||||
let arity = Lib.List32.length ts' in | ||||||||||
let tagt = tag c.frame.inst y in | ||||||||||
let args, vs' = i32_split (Int32.sub n 1l) vs e.at in | ||||||||||
vs', [Suspending (tagt, args, Some (arity, ContRef cont), fun code -> code) @@ e.at] | ||||||||||
vs', [Suspending (tagt, args, Some (arity, ContRef cont), None, fun code -> code) @@ e.at] | ||||||||||
|
||||||||||
| ReturnCall x, vs -> | ||||||||||
(match (step {c with code = (vs, [Plain (Call x) @@ e.at])}).code with | ||||||||||
|
@@ -1180,9 +1211,9 @@ let rec step (c : config) : config = | |||||||||
| Label (n, es0, (vs', [])), vs -> | ||||||||||
vs' @ vs, [] | ||||||||||
|
||||||||||
| Label (n, es0, (vs', {it = Suspending (tagt, vs1, contref, ctxt); at} :: es')), vs -> | ||||||||||
| Label (n, es0, (vs', {it = Suspending (tagt, vs1, contref, href, ctxt); at} :: es')), vs -> | ||||||||||
let ctxt' code = [], [Label (n, es0, compose (ctxt code) (vs', es')) @@ e.at] in | ||||||||||
vs, [Suspending (tagt, vs1, contref, ctxt') @@ at] | ||||||||||
vs, [Suspending (tagt, vs1, contref, href, ctxt') @@ at] | ||||||||||
|
||||||||||
| Label (n, es0, (vs', {it = ReturningInvoke (vs0, f); at} :: es')), vs -> | ||||||||||
vs, [ReturningInvoke (vs0, f) @@ at] | ||||||||||
|
@@ -1209,9 +1240,9 @@ let rec step (c : config) : config = | |||||||||
| Frame (n, frame', (vs', {it = Throwing (a, vs0); at} :: es')), vs -> | ||||||||||
vs, [Throwing (a, vs0) @@ at] | ||||||||||
|
||||||||||
| Frame (n, frame', (vs', {it = Suspending (tagt, vs1, contref, ctxt); at} :: es')), vs -> | ||||||||||
| Frame (n, frame', (vs', {it = Suspending (tagt, vs1, contref, href, ctxt); at} :: es')), vs -> | ||||||||||
let ctxt' code = [], [Frame (n, frame', compose (ctxt code) (vs', es')) @@ e.at] in | ||||||||||
vs, [Suspending (tagt, vs1, contref, ctxt') @@ at] | ||||||||||
vs, [Suspending (tagt, vs1, contref, href, ctxt') @@ at] | ||||||||||
|
||||||||||
| Frame (n, frame', (vs', {it = Returning vs0; at} :: es')), vs -> | ||||||||||
take n vs0 e.at @ vs, [] | ||||||||||
|
@@ -1251,9 +1282,9 @@ let rec step (c : config) : config = | |||||||||
| Handler (n, [], (vs', {it = Throwing (a, vs0); at} :: es')), vs -> | ||||||||||
vs, [Throwing (a, vs0) @@ at] | ||||||||||
|
||||||||||
| Handler (n, cs, (vs', {it = Suspending (tagt, vs1, contref, ctxt); at} :: es')), vs -> | ||||||||||
| Handler (n, cs, (vs', {it = Suspending (tagt, vs1, contref, href, ctxt); at} :: es')), vs -> | ||||||||||
let ctxt' code = [], [Handler (n, cs, compose (ctxt code) (vs', es')) @@ e.at] in | ||||||||||
vs, [Suspending (tagt, vs1, contref, ctxt') @@ at] | ||||||||||
vs, [Suspending (tagt, vs1, contref, href, ctxt') @@ at] | ||||||||||
|
||||||||||
| Handler (n, cs, (vs', e' :: es')), vs when is_jumping e' -> | ||||||||||
vs, [e'] | ||||||||||
|
@@ -1285,36 +1316,44 @@ let rec step (c : config) : config = | |||||||||
with Crash (_, msg) -> Crash.error e.at msg) | ||||||||||
) | ||||||||||
|
||||||||||
| Prompt (hso, (vs', [])), vs -> | ||||||||||
| Prompt (name, hso, (vs', [])), vs -> | ||||||||||
vs' @ vs, [] | ||||||||||
|
||||||||||
| Prompt ((hs, _), (vs', {it = Suspending (tagt, vs1, None, ctxt); at} :: es')), vs | ||||||||||
| Prompt (name, (hs, _), (vs', {it = Suspending (tagt, vs1, None, None, ctxt); at} :: es')), vs | ||||||||||
when List.mem_assq tagt hs -> | ||||||||||
let FuncT (_, ts) = func_type_of_tag_type c.frame.inst (Tag.type_of tagt) in | ||||||||||
let ctxt' code = compose (ctxt code) (vs', es') in | ||||||||||
[Ref (ContRef (ref (Some (Lib.List32.length ts, ctxt'))))] @ vs1 @ vs, | ||||||||||
[Plain (Br (List.assq tagt hs)) @@ e.at] | ||||||||||
|
||||||||||
| Prompt ((_, hs) as hso, (vs', {it = Suspending (tagt, vs1, Some (ar, ContRef ({contents = Some (_, ctxt)} as cont)), ctxt'); at} :: es')), vs | ||||||||||
when List.memq tagt hs -> | ||||||||||
let ctxt'' code = compose (ctxt' code) (vs', es') in | ||||||||||
let cont' = Ref (ContRef (ref (Some (ar, ctxt'')))) in | ||||||||||
let args = cont' :: vs1 in | ||||||||||
cont := None; | ||||||||||
vs' @ vs, [Prompt (hso, ctxt (args, [])) @@ e.at] | ||||||||||
| Prompt (Some h, (hs, _), (vs', {it = Suspending (tagt, vs1, None, Some (HandlerRef ({contents = Some h'} as href)), ctxt); at} :: es')), vs | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we can avoid doubling the rules by factoring out an auxiliary
|
||||||||||
when h == h' && List.mem_assq tagt hs -> | ||||||||||
let FuncT (_, ts) = func_type_of_tag_type c.frame.inst (Tag.type_of tagt) in | ||||||||||
let ctxt' code = compose (ctxt code) (vs', es') in | ||||||||||
href := None; | ||||||||||
[Ref (ContRef (ref (Some (Int32.add (Lib.List32.length ts) 1l, ctxt'))))] @ vs1 @ vs, | ||||||||||
[Plain (Br (List.assq tagt hs)) @@ e.at] | ||||||||||
|
||||||||||
| Prompt (None, ((_, hs) as hso), (vs', {it = Suspending (tagt, vs1, Some (ar, ContRef ({contents = Some (_, ctxt)} as cont)), None, ctxt'); at} :: es')), vs | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this missing an equivalent rule for bubbling a named Suspending? (But see previous comment about avoiding duplication.) |
||||||||||
when List.memq tagt hs -> | ||||||||||
let ctxt'' code = compose (ctxt' code) (vs', es') in | ||||||||||
let cont' = Ref (ContRef (ref (Some (ar, ctxt'')))) in | ||||||||||
let args = cont' :: vs1 in | ||||||||||
cont := None; | ||||||||||
vs' @ vs, [Prompt (None, hso, ctxt (args, [])) @@ e.at] | ||||||||||
|
||||||||||
| Prompt (hso, (vs', {it = Suspending (tagt, vs1, contref, ctxt); at} :: es')), vs -> | ||||||||||
let ctxt' code = [], [Prompt (hso, compose (ctxt code) (vs', es')) @@ e.at] in | ||||||||||
vs, [Suspending (tagt, vs1, contref, ctxt') @@ at] | ||||||||||
| Prompt (name, hso, (vs', {it = Suspending (tagt, vs1, contref, href, ctxt); at} :: es')), vs -> | ||||||||||
let ctxt' code = [], [Prompt (name, hso, compose (ctxt code) (vs', es')) @@ e.at] in | ||||||||||
vs, [Suspending (tagt, vs1, contref, href, ctxt') @@ at] | ||||||||||
|
||||||||||
| Prompt (hso, (vs', e' :: es')), vs when is_jumping e' -> | ||||||||||
| Prompt (name, hso, (vs', e' :: es')), vs when is_jumping e' -> | ||||||||||
vs, [e'] | ||||||||||
|
||||||||||
| Prompt (hso, code'), vs -> | ||||||||||
| Prompt (name, hso, code'), vs -> | ||||||||||
let c' = step {c with code = code'} in | ||||||||||
vs, [Prompt (hso, c'.code) @@ e.at] | ||||||||||
vs, [Prompt (name, hso, c'.code) @@ e.at] | ||||||||||
|
||||||||||
| Suspending (_, _, _, _), _ -> assert false | ||||||||||
| Suspending (_, _, _, _, _), _ -> assert false | ||||||||||
|
||||||||||
in {c with code = vs', es' @ List.tl es} | ||||||||||
|
||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's getting crowded here...