41
41
42
42
open Parsetree
43
43
44
+ (* *****************************************************************************)
45
+ (* * Collect all the extension-node-name-building machinery in one place so that
46
+ it can be changed all at once. *)
47
+
48
+ (* * An AST-style representation of the names used when generating extension
49
+ nodes for modular extensions; see the .mli file for more details. *)
50
+ module Extension_node_name : sig
51
+ (* * A nonempty list of name components, without the leading root [extension.];
52
+ see the .mli file for more details. *)
53
+ type t = ( :: ) of string * string list
54
+
55
+ (* * Convert a modular extension extension node's name to the string form used
56
+ in the OCaml AST; not exposed. *)
57
+ val to_string : t -> string
58
+
59
+ (* * Parse an OCaml extension node's name:
60
+ - [Some (Ok _)] if it's a legal modular extension name;
61
+ - [Some (Error ())] if it's the bare [extension]; and
62
+ - [None] if it doesn't start with the leading [extension].
63
+ Not exposed. *)
64
+ val of_string : string -> (t , unit ) result option
65
+
66
+ (* * Print out a modular extension extension node name, in quotes; for use in
67
+ error messages. *)
68
+ val pp_quoted_name : Format .formatter -> t -> unit
69
+
70
+ (* * Print out an empty extension node with a modular extension name,
71
+ accompanied by an indefinite article; for use in error messages. Not
72
+ exposed. *)
73
+ val pp_a_node : Format .formatter -> t -> unit
74
+
75
+ (* * Print out the illegal empty quasi-modular extension extension node with no
76
+ name beyond [extension]; for use in error messages. Not exposed. *)
77
+ val pp_bad_empty_node : Format .formatter -> unit -> unit
78
+ end = struct
79
+ (* * The three parameters that control how we encode modular extension
80
+ extension node names. When updating these, update comments that refer to
81
+ them! *)
82
+ module Config = struct
83
+ (* * The separator between name components *)
84
+ let separator = '.'
85
+
86
+ (* * The leading namespace that identifies this extension point as reserved
87
+ for a modular extension *)
88
+ let root = " extension"
89
+
90
+ (* * For printing purposes, the appropriate indefinite article for [root] *)
91
+ let article = " an"
92
+ end
93
+
94
+ include Config
95
+ let separator_str = String. make 1 separator
96
+
97
+ type t = ( :: ) of string * string list
98
+
99
+ let to_string (ext :: subparts ) =
100
+ String. concat separator_str (root :: ext :: subparts)
101
+
102
+ let of_string str = match String. split_on_char separator str with
103
+ | root' :: parts when String. equal root root' -> begin
104
+ match parts with
105
+ | ext :: subparts -> Some (Ok (ext :: subparts))
106
+ | [] -> Some (Error () )
107
+ end
108
+ | _ :: _ | [] -> None
109
+
110
+ let pp_quoted_name ppf t = Format. fprintf ppf " \" %s\" " (to_string t)
111
+
112
+ let pp_extension_node ppf id = Format. fprintf ppf " [%%%s]" id
113
+
114
+ let pp_a_node ppf t =
115
+ Format. fprintf ppf " %s %a" article pp_extension_node (to_string t)
116
+
117
+ let pp_bad_empty_node ppf () = pp_extension_node ppf root
118
+ end
119
+
44
120
(* *****************************************************************************)
45
121
module Error = struct
122
+ (* * Someone used [[%extension.EXTNAME]] wrong *)
46
123
type malformed_extension =
47
124
| Has_payload of payload
48
125
126
+ (* * An error triggered when desugaring a language extension from an OCaml
127
+ AST; should always be fatal *)
49
128
type error =
50
- | Malformed_extension of string list * malformed_extension
129
+ | Malformed_extension of Extension_node_name .t * malformed_extension
51
130
| Unknown_extension of string
52
131
| Disabled_extension of Language_extension .t
53
132
| Wrong_syntactic_category of Language_extension .t * string
54
133
| Unnamed_extension
55
- | Bad_introduction of string * string list
134
+ | Bad_introduction of Extension_node_name .t
56
135
136
+ (* * The exception type thrown when desugaring a language extension from an
137
+ OCaml AST *)
57
138
exception Error of Location. t * error
58
139
end
59
140
@@ -65,23 +146,21 @@ let assert_extension_enabled ~loc ext =
65
146
;;
66
147
67
148
let report_error ~loc = function
68
- | Malformed_extension (name , malformed ) -> begin
69
- let name = String. concat " ." (" extension" :: name) in
149
+ | Malformed_extension (ext_name , malformed ) -> begin
70
150
match malformed with
71
151
| Has_payload _payload ->
72
152
Location. errorf
73
153
~loc
74
154
" @[Modular extension nodes are not allowed to have a payload,@ \
75
- but \" %s \" does@]"
76
- name
155
+ but %a does@]"
156
+ Extension_node_name. pp_quoted_name ext_name
77
157
end
78
158
| Unknown_extension name ->
79
159
Location. errorf
80
160
~loc
81
- " @[Unknown extension \" %s\" referenced via an@ [%%extension.%s] \
82
- extension node@]"
83
- name
161
+ " @[Unknown extension \" %s\" referenced via@ %a extension node@]"
84
162
name
163
+ Extension_node_name. pp_a_node Extension_node_name. [name]
85
164
| Disabled_extension ext ->
86
165
Location. errorf
87
166
~loc
@@ -96,15 +175,16 @@ let report_error ~loc = function
96
175
| Unnamed_extension ->
97
176
Location. errorf
98
177
~loc
99
- " Cannot have an extension node named [%%extension]"
100
- | Bad_introduction (name , subnames ) ->
178
+ " Cannot have an extension node named %a"
179
+ Extension_node_name. pp_bad_empty_node ()
180
+ | Bad_introduction (ext :: _ as ext_name ) ->
101
181
Location. errorf
102
182
~loc
103
- " @[The extension \" %s\" was referenced improperly; it started with an@ \
104
- [%% extension.%s] extension node,@ not an [%%extension.%s] one@]"
105
- name
106
- ( String. concat " . " (name :: subnames))
107
- name
183
+ " @[The extension \" %s\" was referenced improperly; it started with@ %a \
184
+ extension node,@ not %a one@]"
185
+ ext
186
+ Extension_node_name. pp_a_node ext_name
187
+ Extension_node_name. pp_a_node Extension_node_name. [ext]
108
188
109
189
let () =
110
190
Location. register_error_of_exn
@@ -177,19 +257,19 @@ module type AST = sig
177
257
val wrap_desc :
178
258
?loc : Location .t -> attrs :Parsetree .attributes -> ast_desc -> ast
179
259
180
- val make_extension : string list -> ast -> ast_desc
260
+ val make_extension : Extension_node_name .t -> ast -> ast_desc
181
261
182
262
val make_entire_extension :
183
263
loc :Location .t -> string -> (unit -> ast ) -> ast_desc
184
264
185
- val match_extension : ast -> (string list * ast ) option
265
+ val match_extension : ast -> (Extension_node_name .t * ast ) option
186
266
end
187
267
188
268
(* Some extensions written before this file existed are handled in their own
189
269
way; this function filters them out. *)
190
- let uniformly_handled_extension names =
191
- match names with
192
- | [( " local" | " global" | " nonlocal" | " escape" | " include_functor" | " curry" )] -> false
270
+ let uniformly_handled_extension name =
271
+ match name with
272
+ | "local" |"global" |"nonlocal" |"escape" |"include_functor" |"curry" -> false
193
273
| _ -> true
194
274
195
275
(* * Given the [AST_parameters] for a syntactic category, produce the
@@ -201,12 +281,12 @@ module Make_AST (AST_parameters : AST_parameters) :
201
281
struct
202
282
include AST_parameters
203
283
204
- let make_extension names =
284
+ let make_extension ext_name =
205
285
make_extension_use
206
286
~extension_node:
207
287
(make_extension_node
208
- ({ txt = String. concat " . " ( " extension " :: names);
209
- loc = ! Ast_helper. default_loc },
288
+ ({ txt = Extension_node_name. to_string ext_name
289
+ ; loc = ! Ast_helper. default_loc },
210
290
PStr [] ))
211
291
212
292
let make_entire_extension ~loc name ast =
@@ -225,16 +305,19 @@ module Make_AST (AST_parameters : AST_parameters) :
225
305
match match_extension_use ast with
226
306
| Some (({txt = ext_name ; loc = ext_loc } , ext_payload ), body ) ->
227
307
begin
228
- match String. split_on_char '.' ext_name with
229
- | "extension" :: names when uniformly_handled_extension names -> begin
308
+ let raise_error err = raise (Error (ext_loc, err)) in
309
+ match Extension_node_name. of_string ext_name with
310
+ | Some (Ok (ext :: _ as ext_name))
311
+ when uniformly_handled_extension ext -> begin
230
312
let raise_malformed err =
231
- raise ( Error (ext_loc, Malformed_extension (names , err) ))
313
+ raise_error ( Malformed_extension (ext_name , err))
232
314
in
233
315
match ext_payload with
234
- | PStr [] -> Some (names , body)
316
+ | PStr [] -> Some (ext_name , body)
235
317
| _ -> raise_malformed (Has_payload ext_payload)
236
318
end
237
- | _ -> None
319
+ | Some (Error () ) -> raise_error Unnamed_extension
320
+ | Some (Ok (_ :: _ )) | None -> None
238
321
end
239
322
| None -> None
240
323
end
@@ -341,8 +424,6 @@ end = struct
341
424
end
342
425
| None -> raise_error (Unknown_extension name)
343
426
end
344
- | Some ([] , _ ) ->
345
- raise_error Unnamed_extension
346
- | Some (name :: subnames , _ ) ->
347
- raise_error (Bad_introduction (name, subnames))
427
+ | Some (_ :: _ :: _ as ext_name , _ ) ->
428
+ raise_error (Bad_introduction (ext_name))
348
429
end
0 commit comments