1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
[@@@ocamlformat "disable"]
open Ppxlib
(* Simple demo without [as__] and [drop] *)
let ___1 =
let loc = Location.none in
let ast = [%expr List.length xs = 0] in
let pat =
let open Ast_pattern in
let length () =
pexp_apply
(pexp_ident (ldot (lident (string "List")) (string "length")))
((nolabel ** __) ^:: nil)
in
let zero () = pexp_constant (pconst_integer (string "0") none) in
pexp_apply
(pexp_ident (lident (string "=")))
((nolabel ** length ()) ^:: (nolabel ** zero ()) ^:: nil)
in
Ast_pattern.parse pat loc ast
~on_error:(fun () -> "Error")
(fun _length_argument -> "Success. As expected")
[%%expect{|
val ___1 : string = "Success. As expected"
|}]
(* We could use [as__] to capture whole [List.length ...] expression,
and use [drop] to ignore length's argument *)
let ___2 =
let loc = Location.none in
let ast = [%expr List.length xs = 0] in
let pat =
let open Ast_pattern in
let length () =
as__
(pexp_apply
(pexp_ident (ldot (lident (string "List")) (string "length")))
((nolabel ** drop) ^:: nil))
in
let zero () = as__ (pexp_constant (pconst_integer (string "0") none)) in
pexp_apply
(pexp_ident (lident (string "=")))
((nolabel ** length ()) ^:: (nolabel ** zero ()) ^:: nil)
in
Ast_pattern.parse pat loc ast
~on_error:(fun () -> "error")
(fun l r ->
Format.asprintf "Success with '%a' and '%a'. As expected" Pprintast.expression l Pprintast.expression r
)
[%%expect{|
val ___2 : string = "Success with 'List.length xs' and '0'. As expected"
|}]
(* Pitfall. If we forget unit argument and will use [as__], the success case
will be fired before the error case. *)
let ___3 =
let loc = Location.none in
let ast = [%expr 1] in
let pat () =
let open Ast_pattern in
as__ (pexp_constant (pconst_integer (string "0") none))
in
let rez = Buffer.create 100 in
Ast_pattern.parse (pat ()) loc ast
~on_error:(fun () -> Printf.bprintf rez "An error")
(fun zero_expr -> Buffer.add_string rez
(Format.asprintf "Successfully got '%a' but error right after that (NOT EXPECTED). " Pprintast.expression zero_expr));
Buffer.contents rez
[%%expect{|
val ___3 : string =
"Successfully got '1' but error right after that (NOT EXPECTED). An error"
|}]
(* To avoid the pitfall above we could add extra () to delay evaluation *)
let ___4 =
let loc = Location.none in
let ast = [%expr 1] in
let pat () =
let open Ast_pattern in
as__ (pexp_constant (pconst_integer (string "0") none))
in
Ast_pattern.parse (pat ()) loc ast
~on_error:(fun () () -> "Error, as expected")
(fun _zero_expr () -> "Success and error after that\n%!")
()
[%%expect{|
val ___4 : string = "Error, as expected"
|}]
(* But this pitfall is not introduced by [as__], it existed before too. *)
let ___5 =
let loc = Location.none in
let ast = [%expr string_of_int 43] in
let pat =
let open Ast_pattern in
pexp_apply
(pexp_ident (lident __))
((nolabel ** eint (int 42)) ^::
(nolabel ** (pexp_ident (lident __))) ^::
nil)
in
let b = Buffer.create 10 in
let () = Ast_pattern.parse pat loc ast
~on_error:(fun () -> Buffer.add_string b "It's an error")
(fun s ->
Printf.bprintf b "Partial success with '%s', but actually not, because... " s;
(fun _ -> Printf.bprintf b "no, it's total success"))
in
Buffer.contents b
[%%expect{|
val ___5 : string =
"Partial success with 'string_of_int', but actually not, because... It's an error"
|}]
|