1
- (* Copyright (C) 2017 Petter A. Urkedal <[email protected] >
1
+ (* Copyright (C) 2017--2021 Petter A. Urkedal <[email protected] >
2
2
*
3
3
* This library is free software; you can redistribute it and/or modify it
4
4
* under the terms of the GNU Lesser General Public License as published by
14
14
* along with this library. If not, see <http://www.gnu.org/licenses/>.
15
15
*)
16
16
17
- open Migrate_parsetree
18
- open Ast_409
19
- let ocaml_version = Versions. ocaml_409
17
+ open Ppxlib
18
+ open Ast_builder.Default
20
19
21
- open Ast_mapper
22
- open Ast_helper
23
- open Asttypes
24
- open Longident
25
- open Parsetree
26
- open Printf
27
-
28
- let error ~loc msg = raise (Location. Error (Location. error ~loc msg))
20
+ let error = Location. raise_errorf
29
21
30
22
let warn ~loc msg e =
31
- let e_msg = Exp. constant (Const. string msg) in
32
- let structure = {pstr_desc = Pstr_eval (e_msg, [] ); pstr_loc = loc} in
33
- Exp. attr e (Attr. mk ~loc {txt = " ocaml.ppwarning" ; loc} (PStr [structure]))
23
+ let e_msg = estring ~loc msg in
24
+ let name = {txt = " ocaml.ppwarning" ; loc} in
25
+ let payload = PStr [{pstr_desc = Pstr_eval (e_msg, [] ); pstr_loc = loc}] in
26
+ {e with pexp_attributes = attribute ~loc ~name ~payload :: e.pexp_attributes}
34
27
35
28
module List = struct
36
29
include List
@@ -54,11 +47,11 @@ module Regexp = struct
54
47
| Repeat ({Location. txt = (i , _ ); _} , e ) ->
55
48
recurse (must_match && i > 0 ) e
56
49
| Nongreedy e -> recurse must_match e
57
- | Capture _ -> error ~loc " Unnamed capture is not allowed for %pcre."
50
+ | Capture _ -> error ~loc " Unnamed capture is not allowed for %% pcre."
58
51
| Capture_as (idr , e ) ->
59
52
fun (nG , bs ) ->
60
53
recurse must_match e (nG + 1 , (idr, Some nG, must_match) :: bs)
61
- | Call _ -> error ~loc " (&...) is not implemented for %pcre." )
54
+ | Call _ -> error ~loc " (&...) is not implemented for %% pcre." )
62
55
in
63
56
(function
64
57
| {Location. txt = Capture_as (idr , e ); _} ->
@@ -87,11 +80,11 @@ module Regexp = struct
87
80
| Repeat ({Location. txt = (i , j_opt ); _} , e ) ->
88
81
let j_str = match j_opt with None -> " " | Some j -> string_of_int j in
89
82
delimit_if (p > p_suffix)
90
- (sprintf " %s{%d,%s}" (recurse p_atom e) i j_str)
83
+ (Printf. sprintf " %s{%d,%s}" (recurse p_atom e) i j_str)
91
84
| Nongreedy e -> recurse p_suffix e ^ " ?"
92
- | Capture _ -> error ~loc " Unnamed capture is not allowed for %pcre."
85
+ | Capture _ -> error ~loc " Unnamed capture is not allowed for %% pcre."
93
86
| Capture_as (_ , e ) -> " (" ^ recurse p_alt e ^ " )"
94
- | Call _ -> error ~loc " (&...) is not implemented for %pcre." )
87
+ | Call _ -> error ~loc " (&...) is not implemented for %% pcre." )
95
88
in
96
89
(function
97
90
| {Location. txt = Capture_as (_ , e ); _} ->
@@ -100,11 +93,6 @@ module Regexp = struct
100
93
recurse 0 e)
101
94
end
102
95
103
- let dyn_bindings = ref []
104
- let clear_bindings () = dyn_bindings := []
105
- let add_binding binding = dyn_bindings := binding :: ! dyn_bindings
106
- let get_bindings () = ! dyn_bindings
107
-
108
96
let fresh_var =
109
97
let c = ref 0 in
110
98
fun () -> incr c; Printf. sprintf " _ppx_regexp_%d" ! c
@@ -129,7 +117,8 @@ let extract_bindings ~pos s =
129
117
let r = Regexp. parse_exn ~pos s in
130
118
let nG, bs = Regexp. bindings r in
131
119
let re_str = Regexp. to_string r in
132
- (Exp. constant (Const. string re_str), bs, nG)
120
+ let loc = Location. none in
121
+ (estring ~loc re_str, bs, nG)
133
122
134
123
let rec wrap_group_bindings ~loc rhs offG = function
135
124
| [] -> rhs
@@ -138,22 +127,22 @@ let rec wrap_group_bindings ~loc rhs offG = function
138
127
| None ->
139
128
[% expr Re.Group. get _g 0 ]
140
129
| Some iG ->
141
- [% expr Re.Group. get _g [% e Exp. constant ( Const. int (offG + iG + 1 ) )]]
130
+ [% expr Re.Group. get _g [% e eint ~loc (offG + iG + 1 )]]
142
131
in
143
132
let eG =
144
133
if mustG then eG else
145
134
[% expr try Some [% e eG] with Not_found -> None ]
146
135
in
147
136
[% expr
148
- let [% p Pat. var varG] = [% e eG] in
137
+ let [% p ppat_var ~loc varG] = [% e eG] in
149
138
[% e wrap_group_bindings ~loc rhs offG bs]]
150
139
151
- let transform_cases ~mapper ~ loc cases =
140
+ let transform_cases ~loc cases =
152
141
let aux case =
153
142
if case.pc_guard <> None then
154
- error ~loc " Guards are not implemented for match%pcre." else
143
+ error ~loc " Guards are not implemented for match%% pcre." else
155
144
(match case.pc_lhs with
156
- | { ppat_desc = Ppat_constant (Pconst_string (re_src, re_delim));
145
+ | { ppat_desc = Ppat_constant (Pconst_string (re_src, _loc, re_delim));
157
146
ppat_loc = {loc_start; _}; _ } ->
158
147
let re_offset =
159
148
(match re_delim with Some s -> String. length s + 2 | None -> 1 ) in
@@ -176,87 +165,86 @@ let transform_cases ~mapper ~loc cases =
176
165
| {ppat_loc = loc ; _} ->
177
166
error ~loc " Regular expression pattern should be a string." )
178
167
in
179
- let rewrite_case case = {case with pc_rhs = mapper.expr mapper case.pc_rhs} in
180
168
let cases, default_rhs =
181
- (match List. rev_map rewrite_case cases with
169
+ (match List. rev (* _map rewrite_case*) cases with
182
170
| {pc_lhs = {ppat_desc = Ppat_any ; _} ; pc_rhs; pc_guard = None } :: cases ->
183
171
(cases, pc_rhs)
184
172
| {pc_lhs = {ppat_desc = Ppat_var var; _}; pc_rhs; pc_guard = None } ::
185
173
cases ->
186
- (cases, [% expr let [% p Pat. var var] = _ppx_regexp_v in [% e pc_rhs]])
174
+ let rhs =
175
+ [% expr let [% p ppat_var ~loc var] = _ppx_regexp_v in [% e pc_rhs]] in
176
+ (cases, rhs)
187
177
| cases ->
188
178
let open Lexing in
189
179
let pos = loc.Location. loc_start in
190
- let e0 = Exp. constant ( Const. string pos.pos_fname) in
191
- let e1 = Exp. constant ( Const. int pos.pos_lnum) in
192
- let e2 = Exp. constant ( Const. int (pos.pos_cnum - pos.pos_bol) ) in
180
+ let e0 = estring ~loc pos.pos_fname in
181
+ let e1 = eint ~loc pos.pos_lnum in
182
+ let e2 = eint ~loc (pos.pos_cnum - pos.pos_bol) in
193
183
let e = [% expr raise (Match_failure ([% e e0], [% e e1], [% e e2]))] in
194
184
(cases, warn ~loc " A universal case is recommended for %pcre." e))
195
185
in
196
186
let cases = List. rev_map aux cases in
197
- let res = Exp. array (List. map (fun (re , _ , _ , _ ) -> re) cases) in
187
+ let res = pexp_array ~loc (List. map (fun (re , _ , _ , _ ) -> re) cases) in
198
188
let comp = [% expr
199
189
let a = Array. map (fun s -> Re. mark (Re.Perl. re s)) [% e res] in
200
190
let marks = Array. map fst a in
201
191
let re = Re. compile (Re. alt (Array. to_list (Array. map snd a))) in
202
192
(re, marks)
203
193
] in
204
194
let var = fresh_var () in
205
- add_binding (Vb. mk (Pat. var {txt = var; loc}) comp);
206
- let e_comp = Exp. ident {txt = Lident var; loc} in
195
+ let re_binding =
196
+ value_binding ~loc ~pat: (ppat_var ~loc {txt = var; loc}) ~expr: comp
197
+ in
198
+ let e_comp = pexp_ident ~loc {txt = Lident var; loc} in
207
199
208
200
let rec handle_cases i offG = function
209
201
| [] -> [% expr assert false ]
210
202
| (_ , nG , bs , rhs ) :: cases ->
211
- let e_i = Exp. constant (Const. int i) in
212
203
[% expr
213
- if Re.Mark. test _g (snd [% e e_comp]).([% e e_i ]) then
204
+ if Re.Mark. test _g (snd [% e e_comp]).([% e eint ~loc i ]) then
214
205
[% e wrap_group_bindings ~loc rhs offG bs]
215
206
else
216
207
[% e handle_cases (i + 1 ) (offG + nG) cases]]
217
208
in
218
- [% expr
219
- (match Re. exec_opt (fst [% e e_comp]) _ppx_regexp_v with
220
- | None -> [% e default_rhs]
221
- | Some _g -> [% e handle_cases 0 0 cases])]
222
-
223
- let rewrite_expr mapper e_ext =
224
- (match e_ext.pexp_desc with
225
- | Pexp_extension ({txt = " pcre" ; _},
226
- PStr [{pstr_desc = Pstr_eval (e, _); _}]) ->
227
- let loc = e.pexp_loc in
228
- (match e.pexp_desc with
229
- | Pexp_match (e , cases ) ->
230
- [% expr
231
- let _ppx_regexp_v = [% e e] in
232
- [% e transform_cases ~mapper ~loc cases]]
233
- | Pexp_function (cases ) ->
234
- [% expr
235
- fun _ppx_regexp_v ->
236
- [% e transform_cases ~mapper ~loc cases]]
237
- | _ ->
238
- error ~loc " [%pcre] only applies to match an function." )
239
- | _ -> default_mapper.expr mapper e_ext)
209
+ let cases =
210
+ [% expr
211
+ (match Re. exec_opt (fst [% e e_comp]) _ppx_regexp_v with
212
+ | None -> [% e default_rhs]
213
+ | Some _g -> [% e handle_cases 0 0 cases])]
214
+ in
215
+ (cases, re_binding)
216
+
217
+ let transformation = object
218
+ inherit [value_binding list ] Ast_traverse. fold_map as super
219
+
220
+ method! expression e_ext acc =
221
+ let e_ext, acc = super#expression e_ext acc in
222
+ (match e_ext.pexp_desc with
223
+ | Pexp_extension
224
+ ({txt = " pcre" ; _}, PStr [{pstr_desc = Pstr_eval (e, _); _}]) ->
225
+ let loc = e.pexp_loc in
226
+ (match e.pexp_desc with
227
+ | Pexp_match (e , cases ) ->
228
+ let cases, binding = transform_cases ~loc cases in
229
+ ([% expr let _ppx_regexp_v = [% e e] in [% e cases]], binding :: acc)
230
+ | Pexp_function (cases ) ->
231
+ let cases, binding = transform_cases ~loc cases in
232
+ ([% expr fun _ppx_regexp_v -> [% e cases]], binding :: acc)
233
+ | _ ->
234
+ error ~loc " [%%pcre] only applies to match an function." )
235
+ | _ -> (e_ext, acc))
236
+ end
240
237
241
- let rewrite_structure _mapper sis =
242
- let mapper = {default_mapper with expr = rewrite_expr} in
243
- let sis' = default_mapper.structure mapper sis in
244
- (match get_bindings () |> List. rev with
245
- | [] -> sis'
246
- | bindings ->
247
- clear_bindings () ;
248
- let local_sis =
249
- [% str
250
- module Ppx_regexp__local = struct
251
- [%% s [{
252
- pstr_desc = Pstr_value (Nonrecursive , bindings);
253
- pstr_loc = Location. none;
254
- }]]
255
- end
256
- open Ppx_regexp__local ]
257
- in
258
- local_sis @ sis')
238
+ let impl str =
239
+ let str, rev_bindings = transformation#structure str [] in
240
+ let re_str =
241
+ let loc = Location. none in
242
+ [% str
243
+ module Ppx_regexp__local = struct
244
+ [%% i pstr_value ~loc Nonrecursive rev_bindings]
245
+ end
246
+ open Ppx_regexp__local ]
247
+ in
248
+ re_str @ str
259
249
260
- let () = Driver. register ~name: " ppx_regexp" ocaml_version
261
- (fun _config _cookies ->
262
- {default_mapper with structure = rewrite_structure; expr = rewrite_expr})
250
+ let () = Driver. register_transformation ~impl " ppx_regexp"
0 commit comments