diff --git a/src/sexp/CCSexp.ml b/src/sexp/CCSexp.ml index a0c12257..e57695d9 100644 --- a/src/sexp/CCSexp.ml +++ b/src/sexp/CCSexp.ml @@ -231,16 +231,33 @@ module Make(Sexp : SEXP) = struct | E_error (line,col,msg) | CCSexp_lex.Error (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 - let parse_string s : t or_error = - let buf = Lexing.from_string s in - let d = Decoder.of_lexbuf buf in + let dec_next_ (d:Decoder.t) : _ or_error = match Decoder.next d with | End -> Result.Error "unexpected end of file" | Yield x -> Result.Ok x | 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 open Lexing in match file with @@ -251,21 +268,13 @@ module Make(Sexp : SEXP) = struct let buf = Lexing.from_channel ic in set_file_ ?file buf; let d = Decoder.of_lexbuf buf in - match Decoder.next d with - | End -> Result.Error "unexpected end of file" - | Yield x -> Result.Ok x - | Fail e -> Result.Error e + dec_next_ d let parse_chan_list_ ?file ic = let buf = Lexing.from_channel ic in set_file_ ?file buf; let d = Decoder.of_lexbuf buf in - let rec iter acc = match Decoder.next d with - | End -> Result.Ok (List.rev acc) - | Yield x -> iter (x::acc) - | Fail e -> Result.Error e - in - iter [] + Decoder.to_list d let parse_chan ic = parse_chan_ 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")) *) +(*$= & ~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 let sexp_gen = diff --git a/src/sexp/CCSexp_intf.ml b/src/sexp/CCSexp_intf.ml index 20ae28e1..16e4b3c6 100644 --- a/src/sexp/CCSexp_intf.ml +++ b/src/sexp/CCSexp_intf.ml @@ -103,11 +103,19 @@ module type S = sig val next : t -> sexp parse_result (** Parse the next S-expression or return an error if the input isn't 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 val parse_string : string -> t or_error (** 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 (** 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.