changed the Sexp api (renamed parsing/printing functions)

This commit is contained in:
Simon Cruanes 2014-09-17 23:42:59 +02:00
parent daf06196c0
commit 9ca56d8046
3 changed files with 125 additions and 69 deletions

View file

@ -3,7 +3,7 @@
let () =
if Array.length Sys.argv <> 2 then failwith "usage: id_sexp file";
let f = Sys.argv.(1) in
let s = Sexp.parse_l_file f in
let s = Sexp.L.of_file f in
match s with
| `Ok l ->
List.iter

View file

@ -33,14 +33,35 @@ type t =
| Atom of string
| List of t list
let eq a b = a = b
let equal a b = a = b
let compare a b = Pervasives.compare a b
let hash a = Hashtbl.hash a
let _with_in filename f =
let ic = open_in filename in
try
let x = f ic in
close_in ic;
x
with e ->
close_in ic;
`Error (Printexc.to_string e)
let _with_out filename f =
let oc = open_out filename in
try
let x = f oc in
close_out oc;
x
with e ->
close_out oc;
raise e
(** {2 Serialization (encoding)} *)
(* shall we escape the string because of one of its chars? *)
let _must_escape s =
try
for i = 0 to String.length s - 1 do
@ -101,17 +122,13 @@ let to_chan oc t =
print fmt t;
Format.pp_print_flush fmt ()
let seq_to_file filename seq =
let oc = open_out filename in
try
seq
(fun t -> to_chan oc t; output_char oc '\n');
close_out oc
with e ->
close_out oc;
raise e
let to_file_seq filename seq =
_with_out filename
(fun oc ->
seq (fun t -> to_chan oc t; output_char oc '\n')
)
let to_file filename t = seq_to_file filename (fun k -> k t)
let to_file filename t = to_file_seq filename (fun k -> k t)
(** {2 Deserialization (decoding)} *)
@ -472,51 +489,66 @@ let parse_chan ?bufsize ic =
(** {6 Blocking} *)
let parse1_chan ic =
let of_chan ic =
ParseGen.head (parse_chan ic)
let parse1_string s =
let of_string s =
ParseGen.head (parse_string s)
let parse_l_chan ?bufsize ic =
ParseGen.to_list (parse_chan ?bufsize ic)
let of_file f =
_with_in f of_chan
let parse_l_file ?bufsize filename =
let ic = open_in filename in
try
let l = parse_l_chan ?bufsize ic in
close_in ic;
l
with e ->
close_in ic;
`Error (Printexc.to_string e)
module L = struct
let to_buf b l =
List.iter (to_buf b) l
let parse_l_string s =
ParseGen.to_list (parse_string s)
let to_string l =
let b = Buffer.create 32 in
to_buf b l;
Buffer.contents b
let parse_l_gen g =
ParseGen.to_list (parse_gen g)
let to_chan oc l =
let fmt = Format.formatter_of_out_channel oc in
List.iter (Format.fprintf fmt "%a@." print) l;
Format.pp_print_flush fmt ()
exception OhNoes of string
exception StopNaow
let to_file filename l =
_with_out filename (fun oc -> to_chan oc l)
let parse_l_seq seq =
let src = Source.Manual.make () in
let ps = mk_ps (Source.Manual.to_src src) in
let l = ref [] in
(* read as many expressions as possible *)
let rec _nexts () = match _next ps with
| `Ok x -> l := x :: !l; _nexts ()
| `Error e -> raise (OhNoes e)
| `End -> raise StopNaow
| `Await -> ()
in
try
seq
(fun s -> Source.Manual.feed src s 0 (String.length s); _nexts ());
Source.Manual.reached_end src;
_nexts ();
`Ok (List.rev !l)
with
| OhNoes msg -> `Error msg
| StopNaow -> `Ok (List.rev !l)
let of_chan ?bufsize ic =
ParseGen.to_list (parse_chan ?bufsize ic)
let of_file ?bufsize filename =
_with_in filename
(fun ic -> of_chan ?bufsize ic)
let of_string s =
ParseGen.to_list (parse_string s)
let of_gen g =
ParseGen.to_list (parse_gen g)
exception OhNoes of string
exception StopNaow
let of_seq seq =
let src = Source.Manual.make () in
let ps = mk_ps (Source.Manual.to_src src) in
let l = ref [] in
(* read as many expressions as possible *)
let rec _nexts () = match _next ps with
| `Ok x -> l := x :: !l; _nexts ()
| `Error e -> raise (OhNoes e)
| `End -> raise StopNaow
| `Await -> ()
in
try
seq
(fun s -> Source.Manual.feed src s 0 (String.length s); _nexts ());
Source.Manual.reached_end src;
_nexts ();
`Ok (List.rev !l)
with
| OhNoes msg -> `Error msg
| StopNaow -> `Ok (List.rev !l)
end

View file

@ -23,7 +23,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
(** {1 Simple S-expression parsing/printing} *)
(** {1 Simple and efficient S-expression parsing/printing}
@since NEXT_RELEASE *)
type 'a or_error = [ `Ok of 'a | `Error of string ]
type 'a sequence = ('a -> unit) -> unit
@ -35,15 +37,21 @@ type t =
| Atom of string
| List of t list
val eq : t -> t -> bool
val equal : t -> t -> bool
val compare : t -> t -> int
val hash : t -> int
(** {2 Serialization (encoding)} *)
val to_buf : Buffer.t -> t -> unit
val to_string : t -> string
val to_file : string -> t -> unit
val to_file_seq : string -> t sequence -> unit
(** Print the given sequence of expressions to a file *)
val to_chan : out_channel -> t -> unit
val print : Format.formatter -> t -> unit
@ -52,16 +60,12 @@ val print : Format.formatter -> t -> unit
val print_noindent : Format.formatter -> t -> unit
(** Raw, direct printing as compact as possible *)
val seq_to_file : string -> t sequence -> unit
(** Print the given sequence of expressions to a file *)
(** {2 Deserialization (decoding)} *)
type 'a parse_result = ['a or_error | `End ]
type 'a partial_result = [ 'a parse_result | `Await ]
(** {6 Streaming Parsing} *)
(** {6 Source of characters} *)
module Source : sig
type individual_char =
| NC_yield of char
@ -105,6 +109,8 @@ module Source : sig
val of_gen : string gen -> t
end
(** {6 Streaming Lexer}
splits the input into opening parenthesis, closing ones, and atoms *)
module Lexer : sig
type t
(** A streaming lexer, that parses atomic chunks of S-expressions (atoms
@ -148,7 +154,8 @@ module ParseGen : sig
val take : int -> 'a t -> 'a t
end
(** {6 Stream Parser} *)
(** {6 Stream Parser}
Returns a lazy stream of S-expressions. *)
val parse_string : string -> t ParseGen.t
(** Parse a string *)
@ -159,20 +166,37 @@ val parse_chan : ?bufsize:int -> in_channel -> t ParseGen.t
val parse_gen : string gen -> t ParseGen.t
(** Parse chunks of string *)
(** {6 Blocking} *)
(** {6 Blocking API}
Parse one S-expression from some source. *)
val parse1_chan : in_channel -> t or_error
val of_chan : in_channel -> t or_error
(** Parse a S-expression from the given channel. Can read more data than
necessary, so don't use this if you need finer-grained control (e.g.
to read something else {b after} the S-exp) *)
val parse1_string : string -> t or_error
val of_string : string -> t or_error
val parse_l_chan : ?bufsize:int -> in_channel -> t list or_error
(** Parse values from a channel. *)
val of_file : string -> t or_error
(** Open the file and read a S-exp from it *)
val parse_l_file : ?bufsize:int -> string -> t list or_error
(** Parse a file *)
(** {6 Lists of S-exps} *)
val parse_l_string : string -> t list or_error
module L : sig
val to_buf : Buffer.t -> t list -> unit
val parse_l_gen : string gen -> t list or_error
val to_string : t list -> string
val parse_l_seq : string sequence -> t list or_error
val to_file : string -> t list -> unit
val to_chan : out_channel -> t list -> unit
val of_chan : ?bufsize:int -> in_channel -> t list or_error
val of_file : ?bufsize:int -> string -> t list or_error
val of_string : string -> t list or_error
val of_gen : string gen -> t list or_error
val of_seq : string sequence -> t list or_error
end