monad_ppx.ml 2.76 KiB
open Ast_mapper
open Ast_helper
open Asttypes
open Parsetree
open Longident
let monad_mapping =
[("run", "if_run");
("string", "if_string");
("object", "if_object");
("value", "if_value");
("prim", "if_prim");
("number", "if_number");
("some", "if_some");
("bool", "if_bool");
("void", "if_void");
("success", "if_success");
]
(* e.g.
let%some x = expr in cont
becomes
if_some expr (fun x -> cont)
let%if_spec (s,x) = expr in cont
becomes
if_spec expr (fun s x -> cont)
*)
let generate_mapper namesid = function argv ->
{ default_mapper with
expr = fun mapper expr ->
let aux e = mapper.expr mapper e in
match expr with
(* Is this an extension node? *)
| { pexp_desc =
Pexp_extension ({ txt = name; loc }, pstr)} ->
begin
try
let ident = List.assoc name namesid in
match pstr with
| PStr [{ pstr_desc =
Pstr_eval ({ pexp_loc = loc;
pexp_desc = Pexp_let
(rf,
[{pvb_pat = {ppat_desc = Ppat_var _} as p;
pvb_expr = e}],
cont)
}, _)}] ->
Exp.apply ~loc (Exp.ident
(Location.mkloc
(Longident.Lident ident) Location.none))
[("", aux e);
("", Exp.fun_ "" None p (aux cont))]
| PStr [{ pstr_desc =
Pstr_eval ({ pexp_loc = loc;
pexp_desc = Pexp_let
(rf,
[{pvb_pat =
{ppat_desc =
Ppat_tuple [p1;p2]};
pvb_expr = e}],
cont)
}, _)}] ->
Exp.apply ~loc (Exp.ident
(Location.mkloc
(Longident.Lident ident) Location.none))
[("", aux e);
("", Exp.fun_ "" None p1 (Exp.fun_ "" None p2 (aux cont)))]
| _ ->
raise (Location.Error (
Location.error ~loc ("error with let%"^name)))
with
| Not_found ->
raise (Location.Error (
Location.error ~loc ("no let%"^name)))
end
(* Delegate to the default mapper. *)
| x -> default_mapper.expr mapper x;
}
let () = register "my_monads" (generate_mapper monad_mapping)