mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 03:05:28 -05:00
richer API for sexp (print/parse files)
This commit is contained in:
parent
dd1f331834
commit
8bb6440344
2 changed files with 73 additions and 14 deletions
72
misc/sexp.ml
72
misc/sexp.ml
|
|
@ -84,6 +84,35 @@ let rec print fmt t = match t with
|
|||
Format.pp_print_char fmt ')';
|
||||
Format.close_box ()
|
||||
|
||||
let rec print_noindent fmt t = match t with
|
||||
| Atom s when _must_escape s -> Format.fprintf fmt "\"%s\"" (String.escaped s)
|
||||
| Atom s -> Format.pp_print_string fmt s
|
||||
| List [] -> Format.pp_print_string fmt "()"
|
||||
| List [x] -> Format.fprintf fmt "(%a)" print_noindent x
|
||||
| List l ->
|
||||
Format.pp_print_char fmt '(';
|
||||
List.iteri
|
||||
(fun i t' -> (if i > 0 then Format.pp_print_char fmt ' '; print_noindent fmt t'))
|
||||
l;
|
||||
Format.pp_print_char fmt ')'
|
||||
|
||||
let to_chan oc t =
|
||||
let fmt = Format.formatter_of_out_channel oc in
|
||||
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 filename t = seq_to_file filename (fun k -> k t)
|
||||
|
||||
(** {2 Deserialization (decoding)} *)
|
||||
|
||||
type 'a parse_result = ['a or_error | `End ]
|
||||
|
|
@ -358,13 +387,14 @@ and _push ps e = match ps.ps_stack with
|
|||
ps.ps_stack <- (e :: l) :: tl;
|
||||
_next ps
|
||||
|
||||
let parse_gen g : t ParseGen.t =
|
||||
(* parse from a generator of string slices *)
|
||||
let _parse_gen g : t ParseGen.t =
|
||||
let ps = mk_ps() in
|
||||
let rec next () = match _next ps with
|
||||
| `Await ->
|
||||
begin match g() with
|
||||
| None -> Streaming.reached_end ps.ps_d
|
||||
| Some s -> Streaming.feed ps.ps_d s 0 (String.length s)
|
||||
| Some (s,i,len) -> Streaming.feed ps.ps_d s i len
|
||||
end;
|
||||
next()
|
||||
| `Ok x -> `Ok x
|
||||
|
|
@ -373,6 +403,14 @@ let parse_gen g : t ParseGen.t =
|
|||
in
|
||||
next
|
||||
|
||||
let parse_gen g =
|
||||
_parse_gen
|
||||
(fun () ->
|
||||
match g() with
|
||||
| None -> None
|
||||
| Some s -> Some (s,0,String.length s)
|
||||
)
|
||||
|
||||
(* singleton generator *)
|
||||
let _gen1 x =
|
||||
let first = ref true in
|
||||
|
|
@ -382,16 +420,16 @@ let _gen1 x =
|
|||
let parse_string s =
|
||||
parse_gen (_gen1 s)
|
||||
|
||||
let parse_chan ic =
|
||||
let buf = Buffer.create 512 in
|
||||
let parse_chan ?(bufsize=1024) ic =
|
||||
let buf = String.make bufsize ' ' in
|
||||
let stop = ref false in
|
||||
let gen () =
|
||||
Buffer.clear buf;
|
||||
Buffer.add_channel buf ic 512;
|
||||
if Buffer.length buf = 0
|
||||
then None
|
||||
else Some (Buffer.contents buf)
|
||||
if !stop then None
|
||||
else
|
||||
let n = input ic buf 0 bufsize in
|
||||
if n=0 then (stop:=true; None) else Some (buf,0,n)
|
||||
in
|
||||
parse_gen gen
|
||||
_parse_gen gen
|
||||
|
||||
(** {6 Blocking} *)
|
||||
|
||||
|
|
@ -401,8 +439,18 @@ let parse1_chan ic =
|
|||
let parse1_string s =
|
||||
ParseGen.head (parse_string s)
|
||||
|
||||
let parse_l_chan ic =
|
||||
ParseGen.to_list (parse_chan ic)
|
||||
let parse_l_chan ?bufsize ic =
|
||||
ParseGen.to_list (parse_chan ?bufsize ic)
|
||||
|
||||
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)
|
||||
|
||||
let parse_l_string s =
|
||||
ParseGen.to_list (parse_string s)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,15 @@ val hash : t -> int
|
|||
|
||||
val to_buf : Buffer.t -> t -> unit
|
||||
val to_string : t -> string
|
||||
val to_file : string -> t -> unit
|
||||
val to_chan : out_channel -> t -> unit
|
||||
|
||||
val print : Format.formatter -> t -> unit
|
||||
|
||||
val print_noindent : Format.formatter -> t -> unit
|
||||
|
||||
val seq_to_file : string -> t sequence -> unit
|
||||
|
||||
(** {2 Deserialization (decoding)} *)
|
||||
|
||||
type 'a parse_result = ['a or_error | `End ]
|
||||
|
|
@ -94,7 +101,7 @@ end
|
|||
val parse_string : string -> t ParseGen.t
|
||||
(** Parse a string *)
|
||||
|
||||
val parse_chan : in_channel -> t ParseGen.t
|
||||
val parse_chan : ?bufsize:int -> in_channel -> t ParseGen.t
|
||||
(** Parse a channel *)
|
||||
|
||||
val parse_gen : string gen -> t ParseGen.t
|
||||
|
|
@ -106,7 +113,11 @@ val parse1_chan : in_channel -> t or_error
|
|||
|
||||
val parse1_string : string -> t or_error
|
||||
|
||||
val parse_l_chan : in_channel -> t list or_error
|
||||
val parse_l_chan : ?bufsize:int -> in_channel -> t list or_error
|
||||
(** Parse values from a channel. *)
|
||||
|
||||
val parse_l_file : ?bufsize:int -> string -> t list or_error
|
||||
(** Parse a file *)
|
||||
|
||||
val parse_l_string : string -> t list or_error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue