Skip to content

Instantly share code, notes, and snippets.

@hcarty
Last active August 11, 2017 10:57
Show Gist options
  • Save hcarty/2e817c5541b5f2758686 to your computer and use it in GitHub Desktop.
Save hcarty/2e817c5541b5f2758686 to your computer and use it in GitHub Desktop.
ppx_defer example
all:
ocamlbuild -use-ocamlfind -package ppx_tools,ppx_tools.metaquot ppx_defer.native
ocamlfind ppx_tools/rewriter ./ppx_defer.native test.ml
ocamlfind c -ppx ./ppx_defer.native test2.ml
open Ast_mapper
open Parsetree
(**
{[
[%defer later];
now
]}
will evaluate [later] after [now]. For example:
{[
let ic = open_in_bin "test.ml" in
[%defer close_in ic];
let length = in_channel_length ic in
let bytes = really_input_string ic length in
print_endline bytes
]}
will close [ic] after reading and printing its content.
*)
let make_defer ~later ~now =
[%expr
match [%e now] with
| __ppx_defer_actual_result ->
[%e later]; __ppx_defer_actual_result
| exception __ppx_defer_actual_exception ->
[%e later]; raise __ppx_defer_actual_exception
] [@metaloc now.pexp_loc]
let defer_mapper _args =
{
default_mapper with
expr = (
fun mapper expr ->
(*
Ast_helper.with_default_loc expr.pexp_loc (
fun () ->
*)
match expr with
| [%expr [%defer [%e? later]] ; [%e? now]] ->
let generated = make_defer ~later ~now in
{ generated with pexp_loc = { generated.pexp_loc with Location.loc_ghost = true } }
| _ ->
default_mapper.expr mapper expr
(* ) *)
)
}
let () = register "defer" defer_mapper
let () =
let ic = open_in_bin "test.ml" in
[%defer close_in ic];
let length = in_channel_length ic in
let bytes = really_input_string ic length in
print_endline bytes
(* Made to fail *)
let x : string =
[%defer ()] ;
3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment