1 (******************************************************************************
4 * Copyright (C) 2005- Jane Street Holding, LLC *
5 * Contact: opensource@janestreet.com *
6 * WWW: http://www.janestreet.com/ocaml *
7 * Author: Markus Mottl *
9 * This library is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU Lesser General Public *
11 * License as published by the Free Software Foundation; either *
12 * version 2 of the License, or (at your option) any later version. *
14 * This library is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
17 * Lesser General Public License for more details. *
19 * You should have received a copy of the GNU Lesser General Public *
20 * License along with this library; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
23 ******************************************************************************)
25 (** Sexp_intf: interface specification for handling S-expressions (I/O, etc.) *)
32 (** Type of S-expressions *)
33 type t
= Type.t
= Atom
of string | List
of t list
35 (** Type of bigstrings *)
36 type bigstring
= (char
, int8_unsigned_elt
, c_layout
) Array1.t
41 val default_indent
: int ref
42 (** [default_indent] reference to default indentation level for
43 human-readable conversions. Initialisation value: 2. *)
46 (** {6 S-expression size} *)
48 val size
: t
-> int * int
49 (** [size sexp] @return [(n_atoms, n_chars)], where [n_atoms] is
50 the number of atoms in S-expression [sexp], and [n_chars] is the
51 number of characters in the atoms of the S-expression. *)
54 (** {6 Scan functions} *)
56 val scan_sexp
: ?buf
: Buffer.t
-> Lexing.lexbuf
-> t
57 (** [scan_sexp ?buf lexbuf] scans an S-expression from lex buffer
58 [lexbuf] using the optional string buffer [buf] for storing
59 intermediate strings. *)
61 val scan_sexps
: ?buf
: Buffer.t
-> Lexing.lexbuf
-> t list
62 (** [scan_sexps ?buf lexbuf] reads a list of whitespace separated
63 S-expressions from lex buffer [lexbuf] using the optional string
64 buffer [buf] for storing intermediate strings. *)
67 ?buf
: Buffer.t
-> f
: (t
-> unit) -> Lexing.lexbuf
-> unit
68 (** [scan_iter_sexps ?buf ~f lexbuf] iterates over all whitespace
69 separated S-expressions scanned from lex buffer [lexbuf] using
70 function [f], and the optional string buffer [buf] for storing
71 intermediate strings. *)
74 ?buf
: Buffer.t
-> f
: ('a
-> t
-> 'a
) -> init
: 'a
-> Lexing.lexbuf
-> 'a
75 (** [scan_fold_sexps ?buf ~f ~init lexbuf] folds over all whitespace
76 separated S-expressions scanned from lex buffer [lexbuf] using
77 function [f], initial state [init], and the optional string buffer
78 [buf] for storing intermediate strings. *)
81 ?buf
: Buffer.t
-> f
: (t
-> 'a
) -> Lexing.lexbuf
-> 'a list
82 (** [scan_sexps_conv ?buf ~f lexbuf] maps all whitespace separated
83 S-expressions scanned from lex buffer [lexbuf] to some list using
84 function [f], and the optional string buffer [buf] for storing
85 intermediate strings. *)
88 (** {6 Type and exception definitions for (partial) parsing} *)
90 module Parse_pos
: sig
91 (** Position information after complete parse *)
92 type t
= Pre_sexp.Parse_pos.t
=
95 mutable text_line
: int; (** Line position in parsed text *)
96 mutable text_char
: int; (** Character position in parsed text *)
97 mutable global_offset
: int; (** Global/logical offset *)
98 mutable buf_pos
: int; (** Read position in string buffer *)
102 ?text_line
: int -> ?text_char
: int ->
103 ?buf_pos
: int -> ?global_offset
: int -> unit -> t
104 (** [create ?text_line ?text_char ?buf_pos ?global_offset ()] @return
105 a parse position with the given parameters.
107 @param text_line default = [1]
108 @param text_char default = [0]
109 @param global_offset default = [0]
110 @param buf_pos default = [0]
113 val with_buf_pos
: t
-> int -> t
114 (** [with_buf_pos t pos] @return a copy of the parse position [t] where
115 [buf_pos] is set to [pos]. *)
118 (** Type of result from calling {!Sexp.parse}. *)
119 type ('a
, 't
) parse_result
= ('a
, 't
) Pre_sexp.parse_result
=
120 | Done
of 't
* Parse_pos.t
(** [Done (t, parse_pos)] finished parsing
121 an S-expression. Current parse position
123 | Cont
of bool * ('a
, 't
) parse_fun
124 (** [Cont (ws_only, parse_fun)] met the end of input before completely
125 parsing an S-expression. The user has to call [parse_fun] to
126 continue parsing the S-expression in another buffer. If [ws_only]
127 is true, only whitespace has been parsed so far (or comments!).
128 NOTE: the continuation may only be called once and will raise
129 [Failure] otherwise! *)
131 (** Type of parsing functions with given offsets and lengths. *)
132 and ('a
, 't
) parse_fun
= pos
: int -> len
: int -> 'a
-> ('a
, 't
) parse_result
134 (** Module for parsing S-expressions annotated with location information *)
135 module Annotated
: sig
136 (** Position information for annotated S-expressions *)
137 type pos
= Pre_sexp.Annotated.pos
= {
143 (** Range information for annotated S-expressions *)
144 type range
= Pre_sexp.Annotated.range
= { start_pos
: pos
; end_pos
: pos
}
146 (** S-expression annotated with location information *)
147 type t
= Pre_sexp.Annotated.t
=
148 | Atom
of range
* Type.t
149 | List
of range
* t list
* Type.t
151 (** Type of conversion results of annotated S-expressions. *)
152 type 'a conv
= [ `Result
of 'a
| `Error
of exn
* t
]
154 (** Exception associated with conversion errors. First argument describes
155 the location, the second the reason. *)
156 exception Conv_exn
of string * exn
158 (** Stack used by annotation parsers *)
159 type stack
= Pre_sexp.Annotated.stack
= {
160 mutable positions
: pos list
;
161 mutable stack
: t list list
;
164 val get_sexp
: t
-> Type.t
165 (** [get_sexp annot_sexp] @return S-expression associated with annotated
166 S-expression [annot_sexp]. *)
168 val get_range
: t
-> range
169 (** [get_range annot_sexp] @return the range associated with annotated
170 S-expression [annot_sexp]. *)
172 val find_sexp
: t
-> Type.t
-> t
option
173 (** [find_sexp annot_sexp sexp] @return [Some res] where [res] is the
174 annotated S-expression that is physically equivalent to [sexp] in
175 [annot_sexp], or [None] if there is no such S-expression. *)
178 (** {6 Annotated (partial) parsing} *)
181 ?parse_pos
: Parse_pos.t
-> ?len
: int -> string
182 -> (string, t
) parse_result
183 (** [parse ?parse_pos ?len str] same as {!parse}, but returns an
184 S-expression annotated with location information. *)
186 val parse_bigstring
:
187 ?parse_pos
: Parse_pos.t
-> ?len
: int -> bigstring
188 -> (bigstring
, t
) parse_result
189 (** [parse_bigstring ?parse_pos ?len str] same as {!parse_bigstring},
190 but returns an S-expression annotated with location information. *)
192 val input_sexp
: ?parse_pos
: Parse_pos.t
-> in_channel
-> t
193 (** [input_sexp ?parse_pos ic] like {!input_sexp}, but returns an
194 annotated S-expression instead. *)
197 ?parse_pos
: Parse_pos.t
-> ?buf
: string -> in_channel
-> t list
198 (** [input_sexps ?parse_pos ?buf ic] like {!input_sexps}, but returns
199 a list of annotated S-expressions. *)
201 val input_rev_sexps
:
202 ?parse_pos
: Parse_pos.t
-> ?buf
: string -> in_channel
-> t list
203 (** [input_sexps ?parse_pos ?buf ic] like {!input_rev_sexps}, but
204 returns a list of annotated S-expressions. *)
207 (** {6 Loading of annotated S-expressions} *)
209 (** NOTE: these functions should only be used if an annotated S-expression
212 val load_sexp
: ?strict
: bool -> ?buf
: string -> string -> t
213 (** [load_sexp ?strict ?buf file] like {!load_sexp}, but returns an
214 annotated S-expression. *)
216 val load_sexps
: ?buf
: string -> string -> t list
217 (** [load_sexps ?buf file] like {!load_sexps}, but returns a list of
218 annotated S-expressions. *)
220 val load_rev_sexps
: ?buf
: string -> string -> t list
221 (** [load_rev_sexps ?buf file] like {!load_rev_sexps}, but returns a
222 list of annotated S-expressions. *)
225 (** {6 String and bigstring conversions} *)
227 val of_string
: string -> t
228 (** [of_string str] same as {!of_string}, but returns an annotated
231 val of_bigstring
: bigstring
-> t
232 (** [of_bigstring bstr] same as {!of_string}, but operates on bigstrings. *)
235 (** Converters using annotations for determining error locations *)
237 val conv
: (Type.t
-> 'a
) -> t
-> 'a conv
238 (** [conv f annot_sexp] converts the S-expression associated with
239 annotated S-expression [annot_sexp] using [f]. @return [`Result
240 res] on success, or [`Error (exn, sub_annot_sexp)] otherwise, where
241 [exn] is the exception associated with the conversion error, and
242 [sub_annot_sexp] is the annotated S-expression on which conversion
245 val get_conv_exn
: file
: string -> exc
: exn
-> t
-> exn
246 (** [get_conv_exn ~file ~exc annot_sexp] @return the exception that
247 would be raised for a given [file] and exception [exc]
248 if conversion had failed on annotated S-expression [annot_sexp].
249 The format of the exception message is "file:line:col" *)
252 (** Type of state maintained during parsing *)
253 type 't parse_state
= 't
Pre_sexp.parse_state
=
256 parse_pos
: Parse_pos.t
; (** Current parse position *)
257 mutable pstack
: 't
; (** Stack of found S-expression lists *)
258 pbuf
: Buffer.t
; (** Current atom buffer *)
261 (** Type of parse errors *)
262 type parse_error
= Pre_sexp.parse_error
=
264 location
: string; (** Function in which the parse failed *)
265 err_msg
: string; (** Reason why parsing failed *)
268 | `Sexp
of t list list parse_state
269 | `Annot
of Annotated.stack parse_state
271 (** State of parser *)
274 (** Exception raised during partial parsing *)
275 exception Parse_error
of parse_error
278 (** {6 Unannotated (partial) parsing} *)
281 ?parse_pos
: Parse_pos.t
-> ?len
: int -> string -> (string, t
) parse_result
282 (** [parse ?parse_pos ?len str] (partially) parses an S-expression in
283 string buffer [str] starting out with position information provided in
284 [parse_pos] and reading at most [len] characters. To parse a single
285 atom that is not delimited by whitespace it is necessary to call this
286 function a second time with the returned continuation, and a dummy
287 buffer that contains whitespace.
289 @param parse_pos default = [Parse_pos.create ()]
290 @param len default = [String.length str - parse_pos.Parse_pos.buf_pos]
293 val parse_bigstring
:
294 ?parse_pos
: Parse_pos.t
-> ?len
: int -> bigstring
295 -> (bigstring
, t
) parse_result
296 (** [parse_bigstring ?parse_pos ?len str] same as {!parse}, but operates on
299 val input_sexp
: ?parse_pos
: Parse_pos.t
-> in_channel
-> t
300 (** [input_sexp ?parse_pos ic] parses an S-expression from input channel
301 [ic] using initial position information in [parse_pos]. NOTE: this
302 function is not as fast on files as {!Sexp.load_sexp}, and is also
303 slightly slower than the scan-functions. But it is guaranteed that
304 [input_sexp] is only going to read data parseable as an S-expression.
305 Thus, subsequent input functions will see the data immediately
308 @param parse_pos default = [Parse_pos.create ()]
312 ?parse_pos
: Parse_pos.t
-> ?buf
: string -> in_channel
-> t list
313 (** [input_sexps ?parse_pos ?buf ic] parses whitespace separated
314 S-expressions from input channel [ic] until EOF is reached. Faster than
317 @param parse_pos default = [Parse_pos.create ()]
320 val input_rev_sexps
:
321 ?parse_pos
: Parse_pos.t
-> ?buf
: string -> in_channel
-> t list
322 (** [input_rev_sexps ?parse_pos ?buf ic] same as {!Sexp.input_sexps},
323 but returns a reversed list of S-expressions, which is slightly more
327 (** {6 Loading of (converted) S-expressions} *)
329 val load_sexp
: ?strict
: bool -> ?buf
: string -> string -> t
330 (** [load_sexp ?strict ?buf file] reads one S-expression from [file] using
331 buffer [buf] for storing intermediate data. Faster than the
334 @raise Parse_error if the S-expression is unparseable.
336 @raise Failure if parsing reached the end of file before one S-expression
339 @raise Failure if [strict] is true and there is more than one
340 S-expression in the file.
342 @param strict default = [true]
345 val load_sexps
: ?buf
: string -> string -> t list
346 (** [load_sexps ?buf file] reads a list of whitespace separated S-expressions
347 from [file] using buffer [buf] for storing intermediate data.
348 Faster than the scan-functions.
350 @raise Parse_error if there is unparseable data in the file.
352 @raise Failure if parsing reached the end of file before the last
353 S-expression could be fully read.
356 val load_rev_sexps
: ?buf
: string -> string -> t list
357 (** [load_rev_sexps ?buf file] same as {!Sexp.load_sexps}, but returns a
358 reversed list of S-expressions, which is slightly more efficient. *)
361 ?strict
: bool -> ?buf
: string -> string -> (t
-> 'a
) -> 'a
Annotated.conv
362 (** [load_sexp_conv ?strict ?buf file f] like {!Sexp.load_sexp}, but
363 performs a conversion on the fly using [f]. Performance is equivalent
364 to executing {!Sexp.load_sexp} and performing conversion when there
365 are no errors. In contrast to the plain S-expression loader, this
366 function not only performs the conversion, it will give exact error
367 ranges for conversion errors.
369 @raise Parse_error if there is unparseable data in the file.
371 @raise Failure if parsing reached the end of file before the last
372 S-expression could be fully read.
375 val load_sexp_conv_exn
:
376 ?strict
: bool -> ?buf
: string -> string -> (t
-> 'a
) -> 'a
377 (** [load_sexp_conv_exn ?strict ?buf file f] like {!load_sexp_conv},
378 but returns the converted value or raises [Of_sexp_error] with exact
379 location information in the case of a conversion error. *)
381 val load_sexps_conv
:
382 ?buf
: string -> string -> (t
-> 'a
) -> 'a
Annotated.conv list
383 (** [load_sexps_conv ?buf file f] like {!Sexp.load_sexps}, but performs
384 a conversion on the fly using [f]. Performance is equivalent to
385 executing {!Sexp.load_sexps} and performing conversion when there
386 are no errors. In contrast to the plain S-expression loader, this
387 function not only performs the conversion, it will give exact error
388 ranges for conversion errors.
390 @raise Parse_error if there is unparseable data in the file.
392 @raise Failure if parsing reached the end of file before the last
393 S-expression could be fully read.
396 val load_sexps_conv_exn
: ?buf
: string -> string -> (t
-> 'a
) -> 'a list
397 (** [load_sexps_conv_exn ?buf file f] like {!load_sexps_conv}, but returns
398 the converted value or raises [Of_sexp_error] with exact location
399 information in the case of a conversion error. *)
402 (** {6 Output of S-expressions to I/O-channels} *)
404 (** NOTE: for performance reasons these output functions may need to
405 allocate large strings to write out huge S-expressions. This may
406 cause problems on 32-bit platforms. If you think that you may need to
407 write huge S-expressions on such platforms, you might want to use the
408 pretty-printers that write to formatters instead (see further below). *)
410 val output_hum
: out_channel
-> t
-> unit
411 (** [output_hum oc sexp] outputs S-expression [sexp] to output channel
412 [oc] in human readable form. *)
414 val output_hum_indent
: int -> out_channel
-> t
-> unit
415 (** [output_hum_indent indent oc sexp] outputs S-expression [sexp]
416 to output channel [oc] in human readable form using indentation level
420 val output_mach
: out_channel
-> t
-> unit
421 (** [output_mach oc sexp] outputs S-expression [sexp] to output channel
422 [oc] in machine readable (i.e. most compact) form. *)
424 val output
: out_channel
-> t
-> unit
425 (** [output oc sexp] same as [output_mach]. *)
428 (** {6 Output of S-expressions to file} *)
430 (** All save-functions write to a temporary file before moving it into
431 place to avoid intermittent garbling of existing files, which may
432 cause problems for other processes that try to read. *)
434 val save_hum
: ?perm
: int -> string -> t
-> unit
435 (** [save_hum ?perm file sexp] outputs S-expression [sexp] to [file] in human
438 @param perm default = umask
441 val save_mach
: ?perm
: int -> string -> t
-> unit
442 (** [save_mach ?perm file sexp] outputs S-expression [sexp] to [file]
443 in machine readable (i.e. most compact) form.
445 @param perm default = umask
448 val save
: ?perm
: int -> string -> t
-> unit
449 (** [save ?perm file sexp] same as {!save_mach}. *)
451 val save_sexps_hum
: ?perm
: int -> string -> t list
-> unit
452 (** [save_sexps_hum ?perm file sexps] outputs S-expression list [sexps] to
453 [file] in human readable form, each sexp being followed by a newline.
455 @param perm default = umask
458 val save_sexps_mach
: ?perm
: int -> string -> t list
-> unit
459 (** [save_sexps_mach ?perm file sexps] outputs S-expression list [sexps] to
460 [file] in machine readable form, each sexp being followed by a
463 @param perm default = umask
466 val save_sexps
: ?perm
: int -> string -> t list
-> unit
467 (** [save_sexps ?perm file sexp] same as {!save_sexps_mach}. *)
470 (** {6 Output of S-expressions to formatters} *)
472 val pp_hum
: formatter
-> t
-> unit
473 (** [pp_hum ppf sexp] outputs S-expression [sexp] to formatter [ppf]
474 in human readable form. *)
476 val pp_hum_indent
: int -> formatter
-> t
-> unit
477 (** [pp_hum_indent n ppf sexp] outputs S-expression [sexp] to formatter
478 [ppf] in human readable form and indentation level [n]. *)
480 val pp_mach
: formatter
-> t
-> unit
481 (** [pp_mach ppf sexp] outputs S-expression [sexp] to formatter [ppf]
482 in machine readable (i.e. most compact) form. *)
484 val pp
: formatter
-> t
-> unit
485 (** [pp ppf sexp] same as [pp_mach]. *)
488 (** {6 String and bigstring conversions} *)
490 (** Module encapsulating the exception raised by string converters when
491 type conversions fail. *)
492 module Of_string_conv_exn
: sig
493 type t
= { exc
: exn
; sexp
: Type.t
; sub_sexp
: Type.t
}
498 val of_string
: string -> t
499 (** [of_string str] converts string [str] to an S-expression. NOTE:
500 trailing whitespace is considered an error, which may be overly
501 strict for some applications. Either strip the string of trailing
502 whitespace first, or, even cheaper, use {!parse} instead. *)
504 val of_string_conv
: string -> (t
-> 'a
) -> 'a
Annotated.conv
505 (** [of_string_conv str conv] like {!of_string}, but performs type conversion
506 with [conv]. @return conversion result. *)
508 val of_string_conv_exn
: string -> (t
-> 'a
) -> 'a
509 (** [of_string_conv_exn str conv] like {!of_string_conv}, but raises
510 {!Of_string_conv_exn.E} if type conversion fails. @return converted
513 val of_bigstring
: bigstring
-> t
514 (** [of_bigstring bstr] same as {!of_string}, but operates on bigstrings. *)
516 val of_bigstring_conv
: bigstring
-> (t
-> 'a
) -> 'a
Annotated.conv
517 (** [of_bigstring_conv bstr conv] like {!of_bigstring}, but performs
518 type conversion with [conv]. @return conversion result. *)
520 val of_bigstring_conv_exn
: bigstring
-> (t
-> 'a
) -> 'a
521 (** [of_bigstring_conv_exn bstr conv] like {!of_bigstring_conv}, but raises
522 {!Of_string_conv_exn.E} if type conversion fails. @return converted
525 val to_string_hum
: ?indent
: int -> t
-> string
526 (** [to_string_hum ?indent sexp] converts S-expression [sexp] to a
527 string in human readable form with indentation level [indent].
529 @param indent default = [!default_indent]
532 val to_string_mach
: t
-> string
533 (** [to_string_mach sexp] converts S-expression [sexp] to a string in
534 machine readable (i.e. most compact) form. *)
536 val to_string
: t
-> string
537 (** [to_string sexp] same as [to_string_mach]. *)
540 (** {6 Buffer conversions} *)
542 val to_buffer_hum
: buf
: Buffer.t
-> ?indent
: int -> t
-> unit
543 (** [to_buffer_hum ~buf ?indent sexp] outputs the S-expression [sexp]
544 converted to a string in human readable form to buffer [buf].
546 @param indent default = [!default_indent]
549 val to_buffer_mach
: buf
: Buffer.t
-> t
-> unit
550 (** [to_buffer_mach ~buf sexp] outputs the S-expression [sexp] converted
551 to a string in machine readable (i.e. most compact) form to buffer [buf].
554 val to_buffer
: buf
: Buffer.t
-> t
-> unit
555 (** [to_buffer ~buf sexp] same as {!to_buffer_mach}. *)
558 (** {6 Utilities for automated type conversions} *)
561 (** [unit] the unit-value as expressed by an S-expression. *)
563 external sexp_of_t
: t
-> t
= "%identity"
564 (** [sexp_of_t sexp] maps S-expressions which are part of a type with
565 automated S-expression conversion to themselves. *)
567 external t_of_sexp
: t
-> t
= "%identity"
568 (** [t_of_sexp sexp] maps S-expressions which are part of a type with
569 automated S-expression conversion to themselves. *)
572 (** {6 Utilities for conversion error handling} *)
574 type found
= [ `Found
| `Pos
of int * found
]
575 (** Type of successful search results. [`Found] means that an
576 S-expression was found at the immediate position, and [`Pos (pos,
577 found)] indicates that it was found at position [pos] within a
578 structure (= S-expression list) where [found] describes recursively
579 where it was found in that structure. *)
581 type search_result
= [ `Not_found
| found
]
582 (** Type of search results. [`Not_found] means that an
583 S-expression was not found within another S-expression. *)
585 val search_physical
: t
-> contained
: t
-> search_result
586 (** [search_physical sexp ~contained] @return the search result
587 indicating whether, and if, where the S-expression [contained]
588 was found within S-expression [sexp]. *)
590 val subst_found
: t
-> subst
: t
-> found
-> t
591 (** [subst_found sexp ~subst found] @return the S-expression that
592 results from substituting [subst] within S-expression [sexp]
593 at the location described by [found]. *)