Open panglesd opened 1 year ago
For instance,
open Ppxlib let ext = Extension.declare "example" Extension.Context.module_expr Ast_pattern.( ptyp (map0 ~f:"foo" @@ ptyp_constr (lident (string "foo")) nil ||| map0 ~f:"bar" @@ ptyp_constr (lident (string "bar")) nil)) (fun ~loc ~path:_ arg -> Stdlib.Printf.eprintf "expand: %s\n" arg; Ast_builder.Default.pmod_structure ~loc []) let () = Ppxlib.Driver.register_transformation "example" ~extensions:[ ext ]
applied on
module _ = [%example: bar]
will write
expand: foo expand: bar
instead of only
expand: bar
The reason is that map0 will actually call the continuation when this one has one argument, even though the "matching" is not finished:
map0
let map0 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (k f))
I think (but I'm not confident) that one way to fix this would be to abstract the continuation to make sure it is never executed too early:
type ('matched_value, 'k, 'k_result) t = | T of (context -> Location.t -> 'matched_value -> (unit -> 'k) -> 'k_result)
As a workaround before this is fixed, map_result can be used to protect the continuation to be executed:
map_result
open Ppxlib let ext = Extension.declare "example" Extension.Context.module_expr Ast_pattern.( ptyp (map0 ~f:"foo" @@ map_result ~f:(fun k -> k ()) @@ ptyp_constr (lident (string "foo")) nil ||| map0 ~f:"bar" @@ map_result ~f:(fun k -> k ()) @@ ptyp_constr (lident (string "bar")) nil)) (fun ~loc ~path:_ arg () -> Stdlib.Printf.eprintf "expand: %s\n" arg; Ast_builder.Default.pmod_structure ~loc []) let () = Ppxlib.Driver.register_transformation "example" ~extensions:[ ext ]
Thanks @ceastlund for finding the bug and the minimal example!
For instance,
applied on
will write
instead of only
The reason is that
map0
will actually call the continuation when this one has one argument, even though the "matching" is not finished:I think (but I'm not confident) that one way to fix this would be to abstract the continuation to make sure it is never executed too early:
As a workaround before this is fixed,
map_result
can be used to protect the continuation to be executed:Thanks @ceastlund for finding the bug and the minimal example!