mirror of
https://github.com/ocaml/ocaml.git
synced 2026-08-01 06:50:29 +08:00
160 lines
5.1 KiB
OCaml
160 lines
5.1 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* KC Sivaramakrishnan, Indian Institute of Technology, Madras *)
|
|
(* *)
|
|
(* Copyright 2021 Indian Institute of Technology, Madras *)
|
|
(* *)
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
type 'a t = 'a eff = ..
|
|
external perform : 'a t -> 'a = "%perform"
|
|
|
|
type exn += Unhandled: 'a t -> exn
|
|
exception Continuation_already_resumed
|
|
|
|
let () =
|
|
let printer = function
|
|
| Unhandled x ->
|
|
let msg = Printf.sprintf "Stdlib.Effect.Unhandled(%s)"
|
|
(Printexc.string_of_extension_constructor @@ Obj.repr x)
|
|
in
|
|
Some msg
|
|
| _ -> None
|
|
in
|
|
Printexc.register_printer printer
|
|
|
|
(* Register the exceptions so that the runtime can access it *)
|
|
type _ t += Should_not_see_this__ : unit t
|
|
let _ = Callback.register_exception "Effect.Unhandled"
|
|
(Unhandled Should_not_see_this__)
|
|
let _ = Callback.register_exception "Effect.Continuation_already_resumed"
|
|
Continuation_already_resumed
|
|
|
|
type ('a, 'b) stack [@@immediate]
|
|
|
|
external resume :
|
|
('a, 'b) stack -> ('c -> 'a) -> 'c -> 'b = "%resume"
|
|
external runstack : ('a, 'b) stack -> ('c -> 'a) -> 'c -> 'b = "%runstack"
|
|
|
|
module Deep = struct
|
|
|
|
type nonrec ('a,'b) continuation = ('a,'b) continuation
|
|
|
|
external take_cont_noexc : ('a, 'b) continuation -> ('a, 'b) stack =
|
|
"caml_continuation_use_noexc" [@@noalloc]
|
|
external alloc_stack :
|
|
('a -> 'b) ->
|
|
(exn -> 'b) ->
|
|
('c t -> ('c, 'b) continuation -> 'b) ->
|
|
('a, 'b) stack = "caml_alloc_stack"
|
|
|
|
let continue k v =
|
|
resume (take_cont_noexc k) (fun x -> x) v
|
|
|
|
let discontinue k e =
|
|
resume (take_cont_noexc k) (fun e -> raise e) e
|
|
|
|
let discontinue_with_backtrace k e bt =
|
|
resume (take_cont_noexc k) (fun e -> Printexc.raise_with_backtrace e bt) e
|
|
|
|
type ('a,'b) handler =
|
|
{ retc: 'a -> 'b;
|
|
exnc: exn -> 'b;
|
|
effc: 'c.'c t -> (('c,'b) continuation -> 'b) option }
|
|
|
|
external reperform : 'a t -> ('a, 'b) continuation -> 'b = "%reperform"
|
|
|
|
let match_with comp arg handler =
|
|
let effc eff k =
|
|
match handler.effc eff with
|
|
| Some f -> f k
|
|
| None -> reperform eff k
|
|
in
|
|
let s = alloc_stack handler.retc handler.exnc effc in
|
|
runstack s comp arg
|
|
|
|
type 'a effect_handler =
|
|
{ effc: 'b. 'b t -> (('b,'a) continuation -> 'a) option }
|
|
|
|
let try_with comp arg handler =
|
|
let effc' eff k =
|
|
match handler.effc eff with
|
|
| Some f -> f k
|
|
| None -> reperform eff k
|
|
in
|
|
let s = alloc_stack (fun x -> x) (fun e -> raise e) effc' in
|
|
runstack s comp arg
|
|
|
|
external get_callstack :
|
|
('a,'b) continuation -> int -> Printexc.raw_backtrace =
|
|
"caml_get_continuation_callstack"
|
|
end
|
|
|
|
module Shallow = struct
|
|
|
|
type ('a,'b) continuation
|
|
|
|
external alloc_stack :
|
|
('a -> 'b) ->
|
|
(exn -> 'b) ->
|
|
('c t -> ('c, 'b) continuation -> 'b) ->
|
|
('a, 'b) stack = "caml_alloc_stack"
|
|
|
|
let fiber : type a b. (a -> b) -> (a, b) continuation = fun f ->
|
|
let module M = struct type _ t += Initial_setup__ : a t end in
|
|
let exception E of (a,b) continuation in
|
|
let f' () = f (perform M.Initial_setup__) in
|
|
let error _ = failwith "impossible" in
|
|
let effc eff k =
|
|
match eff with
|
|
| M.Initial_setup__ -> raise_notrace (E k)
|
|
| _ -> error ()
|
|
in
|
|
let s = alloc_stack error error effc in
|
|
match runstack s f' () with
|
|
| exception E k -> k
|
|
| _ -> error ()
|
|
|
|
type ('a,'b) handler =
|
|
{ retc: 'a -> 'b;
|
|
exnc: exn -> 'b;
|
|
effc: 'c.'c t -> (('c,'a) continuation -> 'b) option }
|
|
|
|
external update_handler :
|
|
('a,'b) continuation ->
|
|
('b -> 'c) ->
|
|
(exn -> 'c) ->
|
|
('d t -> ('d,'b) continuation -> 'c) ->
|
|
('a,'c) stack = "caml_continuation_use_and_update_handler_noexc" [@@noalloc]
|
|
|
|
external reperform : 'a t -> ('a, 'b) continuation -> 'c = "%reperform"
|
|
|
|
let continue_gen k resume_fun v handler =
|
|
let effc eff k =
|
|
match handler.effc eff with
|
|
| Some f -> f k
|
|
| None -> reperform eff k
|
|
in
|
|
let stack = update_handler k handler.retc handler.exnc effc in
|
|
resume stack resume_fun v
|
|
|
|
let continue_with k v handler =
|
|
continue_gen k (fun x -> x) v handler
|
|
|
|
let discontinue_with k v handler =
|
|
continue_gen k (fun e -> raise e) v handler
|
|
|
|
let discontinue_with_backtrace k v bt handler =
|
|
continue_gen k (fun e -> Printexc.raise_with_backtrace e bt) v handler
|
|
|
|
external get_callstack :
|
|
('a,'b) continuation -> int -> Printexc.raw_backtrace =
|
|
"caml_get_continuation_callstack"
|
|
end
|