File: test.ml

package info (click to toggle)
ppxlib 0.37.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,804 kB
  • sloc: ml: 66,587; sh: 103; makefile: 40; python: 36
file content (127 lines) | stat: -rw-r--r-- 3,623 bytes parent folder | download | duplicates (3)
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"
|}]