let rec parse str : Biblio.set =
let valid_and_parse_entry sexp =
match sexp with
| Sx.Atom s -> fail_atom s
| Sx.List l ->
let field_sexp_list =
Ls.map l
~f:(function
| Sx.Atom s -> fail_atom s
| Sx.List l -> l) in
parse_entry field_sexp_list
in
let whitespace_regexp =
Pcre.regexp ~flags:[ `MULTILINE ] "[ \t\n\r]*" in
let is_white s = Pcre.pmatch ~rex:whitespace_regexp s in
let string_abstract pos max_len s =
if lei max_len ((Str.length s) - pos) then
(Str.sub s pos max_len) ^ " [...]"
else
(Str.sub s pos ((Str.length s) - pos))
in
let pos = ref None in
let res = ref [] in
let terminate = ref false in
let the_end = Str.length str in
while not !terminate do
try
match Sx.parse ?parse_pos:!pos str with
| Sx.Cont (state, _) ->
let cur_pos =
match !pos with | None -> 0 | Some p -> p.Sx.Parse_pos.buf_pos in
if is_white (Str.sub str cur_pos (the_end - cur_pos)) && state then
terminate := true
else
let msg =
sprintf "Parsing Error (sexplib, unfinished s-expression?) for string: \"%s\""
(string_abstract cur_pos 80 str) in
raise (Parse_error msg)
| Sx.Done (sx, parse_pos) ->
pos := Some parse_pos;
let id, entry = valid_and_parse_entry sx in
res := entry :: !res;
with
| Sx.Parse_error _ ->
let cur_pos, cur_line =
match !pos with
| None -> 0, 0 | Some p -> p.Sx.Parse_pos.buf_pos, p.Sx.Parse_pos.text_line in
let msg =
sprintf "Parse Error: XXX line: %d, pos: %d, sexp: \"%s\""
cur_line cur_pos (string_abstract cur_pos 80 str)
in
raise (Parse_error msg)
done;
Ls.rev !res