feat(sexp): expose parse_string_list and the list decoder

This commit is contained in:
Simon Cruanes 2019-12-10 15:50:18 -06:00
parent 08f333ffa8
commit 0ef454c6dc
2 changed files with 38 additions and 13 deletions

View file

@ -231,16 +231,33 @@ module Make(Sexp : SEXP) = struct
| E_error (line,col,msg) | E_error (line,col,msg)
| CCSexp_lex.Error (line,col,msg) -> | CCSexp_lex.Error (line,col,msg) ->
Fail (Printf.sprintf "parse error at %d:%d: %s" line col msg) Fail (Printf.sprintf "parse error at %d:%d: %s" line col msg)
let to_list (d:t) : _ or_error =
let rec iter acc = match next d with
| End -> Result.Ok (List.rev acc)
| Yield x -> iter (x::acc)
| Fail e -> Result.Error e
in
try iter []
with e -> Error (Printexc.to_string e)
end end
let parse_string s : t or_error = let dec_next_ (d:Decoder.t) : _ or_error =
let buf = Lexing.from_string s in
let d = Decoder.of_lexbuf buf in
match Decoder.next d with match Decoder.next d with
| End -> Result.Error "unexpected end of file" | End -> Result.Error "unexpected end of file"
| Yield x -> Result.Ok x | Yield x -> Result.Ok x
| Fail s -> Result.Error s | Fail s -> Result.Error s
let parse_string s : t or_error =
let buf = Lexing.from_string s in
let d = Decoder.of_lexbuf buf in
dec_next_ d
let parse_string_list s : t list or_error =
let buf = Lexing.from_string s in
let d = Decoder.of_lexbuf buf in
Decoder.to_list d
let set_file_ ?file buf = let set_file_ ?file buf =
let open Lexing in let open Lexing in
match file with match file with
@ -251,21 +268,13 @@ module Make(Sexp : SEXP) = struct
let buf = Lexing.from_channel ic in let buf = Lexing.from_channel ic in
set_file_ ?file buf; set_file_ ?file buf;
let d = Decoder.of_lexbuf buf in let d = Decoder.of_lexbuf buf in
match Decoder.next d with dec_next_ d
| End -> Result.Error "unexpected end of file"
| Yield x -> Result.Ok x
| Fail e -> Result.Error e
let parse_chan_list_ ?file ic = let parse_chan_list_ ?file ic =
let buf = Lexing.from_channel ic in let buf = Lexing.from_channel ic in
set_file_ ?file buf; set_file_ ?file buf;
let d = Decoder.of_lexbuf buf in let d = Decoder.of_lexbuf buf in
let rec iter acc = match Decoder.next d with Decoder.to_list d
| End -> Result.Ok (List.rev acc)
| Yield x -> iter (x::acc)
| Fail e -> Result.Error e
in
iter []
let parse_chan ic = parse_chan_ ic let parse_chan ic = parse_chan_ ic
let parse_chan_list ic = parse_chan_list_ ic let parse_chan_list ic = parse_chan_list_ ic
@ -340,6 +349,14 @@ include (Make(struct
(parse_string "#; (a b) 1") (Result.Ok (`Atom "1")) (parse_string "#; (a b) 1") (Result.Ok (`Atom "1"))
*) *)
(*$= & ~printer:(function Result.Ok x -> String.concat ";" @@ List.map to_string x | Result.Error e -> "error " ^ e)
(parse_string_list "(a b)(c)") (Result.Ok [`List [`Atom "a"; `Atom "b"]; `List [`Atom "c"]])
(parse_string_list " ") (Result.Ok [])
(parse_string_list "(a\n ;coucou\n b)") (Result.Ok [`List [`Atom "a"; `Atom "b"]])
(parse_string_list "#; (a b) (c d) e ") (Result.Ok [`List [`Atom "c"; `Atom "d"]; `Atom "e"])
(parse_string_list "#; (a b) 1") (Result.Ok [`Atom "1"])
*)
(*$inject (*$inject
let sexp_gen = let sexp_gen =

View file

@ -103,11 +103,19 @@ module type S = sig
val next : t -> sexp parse_result val next : t -> sexp parse_result
(** Parse the next S-expression or return an error if the input isn't (** Parse the next S-expression or return an error if the input isn't
long enough or isn't a proper S-expression. *) long enough or isn't a proper S-expression. *)
val to_list : t -> sexp list or_error
(** Read all the values from this decoder.
@since NEXT_RELEASE *)
end end
val parse_string : string -> t or_error val parse_string : string -> t or_error
(** Parse a string. *) (** Parse a string. *)
val parse_string_list : string -> t list or_error
(** Parse a string into a list of S-exprs.
@since NEXT_RELEASE *)
val parse_chan : in_channel -> t or_error val parse_chan : in_channel -> t or_error
(** Parse a S-expression from the given channel. Can read more data than (** 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. necessary, so don't use this if you need finer-grained control (e.g.