let read ?start ?(fmt=default_fmt) r =
let {allow_sharp_comments;
allow_semicolon_comments;
allow_empty_lines;
comments_only_at_top;
max_line_length;
alphabet} = fmt
in
let error_string s = Some (Or_error.error_string s) in
let item0s = read0 r
?start
~allow_sharp_comments
~allow_semicolon_comments
~allow_empty_lines
?max_line_length
?alphabet
in
match read_header ~allow_empty_lines item0s with
| Error _ as e -> e
| Ok header ->
let rec f description partial_seqs : item Or_error.t option =
match Stream.peek item0s with
| Some (Ok (`Comment _)) -> begin
if comments_only_at_top then
error_string "comments_only_at_top = true but got comment later"
else (
Stream.junk item0s;
f description partial_seqs
)
end
| Some (Ok `Empty_line) -> begin
if allow_empty_lines then (
Stream.junk item0s;
f description partial_seqs
)
else
error_string "allow_empty_lines = false but got empty line"
end
| Some (Ok (`Description x)) -> begin
match description,partial_seqs with
| None, [] -> (
Stream.junk item0s;
f (Some x) []
)
| None, _::_ ->
assert false
| Some _, [] ->
error_string "previous description line not followed by sequence"
| Some description, partial_seqs ->
Some (Ok {
description;
sequence = partial_seqs |> List.rev |> String.concat ~sep:"";
})
end
| Some (Ok (`Partial_sequence x)) -> begin
match description,partial_seqs with
| None, _ ->
error_string "sequence not preceded by description line"
| Some _, partial_seqs -> (
Stream.junk item0s;
f description (x::partial_seqs)
)
end
| Some (Error _ as e) -> begin
Stream.junk item0s;
Some e
end
| None -> begin
match description,partial_seqs with
| None, [] -> None
| None, _::_ ->
assert false
| Some _, [] ->
error_string
"description line not followed by sequence, reached end-of-file"
| Some description, partial_seqs ->
Some (Ok {
description;
sequence = partial_seqs |> List.rev |> String.concat ~sep:"";
})
end
in
Ok (header, Stream.from (fun _ -> f None []))