let of_stream stream =
let get_content parse_first parse empty extended (s, pos) =
let rec loop acc =
try
let str = Stream.next stream in
(match parse (str, 0) with
| Parsed (r, _) -> loop (r::acc)
| Failed when extended ->
(match Stream.peek stream with
| Some next_str ->
(match (block_modifier (next_str, 0)) with
| Parsed _ -> List.rev acc
| Failed -> (loop (empty::acc)))
| None -> List.rev acc)
| Failed -> List.rev acc)
with Stream.Failure -> List.rev acc in
match parse_first (s, pos) with
| Parsed (first, _) -> Parsed (loop [first], (s, pos))
| Failed -> Failed in
let get_lines extended (s, pos) =
let parse_line = line in
let parse_first_line = line in
get_content parse_first_line parse_line [] extended (s, pos) in
let get_strings extended (s, pos) =
let parse_string (s, pos) =
match s with
| "" -> Failed
| _ -> Parsed (s, (s, (String.length s))) in
let parse_first_string (s, first) =
let s = String.slice ~first s in
parse_string (s, first) in
get_content parse_first_string parse_string "" extended (s, pos) in
let celloptions =
let option =
(p_char '_' >>> return `Head) |||
(tableoption >>= fun x -> return (`Topt x)) |||
(p_char '\\' >>> p_int >>= fun x -> return (`Colspan x)) |||
(p_char '/' >>> p_int >>= fun x -> return (`Rowspan x)) in
let add (celltype, topts, ((colspan, rowspan) as cellspan)) = function
| `Head -> (Head, topts, cellspan)
| `Topt x -> (celltype, add_tableoption topts x, cellspan)
| `Colspan x -> (celltype, topts, (Some x, rowspan))
| `Rowspan x -> (celltype, topts, (colspan, Some x)) in
p_plusf option add default_celloptions in
let element c prev_level =
let bullet = p_many p_whitespace >>> c in
bullet >>>
p_upto_timesf prev_level
(p_many p_whitespace >>> c)
(fun l _ -> succ l) 1 >>= fun lvl ->
p_plus p_whitespace >>>
line >>= fun line ->
return (lvl, line) in
let get_element c prev_level x =
match Stream.peek stream with
| Some s ->
(element c prev_level >>= fun e ->
return (Stream.junk stream; e)) (s, 0)
| None -> Failed in
let get_elements c =
element (p_char c) 0 >>= fun ((f_e_lvl, _) as first_element) ->
p_manyf_arg
(fun (prev_lvl, elements) -> get_element (p_char c) prev_lvl)
(fun (_, acc) (lvl, line) -> lvl, (lvl, line)::acc)
(f_e_lvl, [first_element]) >>= fun (_, rev_elements) ->
return (List.rev (rev_elements)) in
let row peeks =
let peeks = ref peeks in
let get_cell =
let continue_cell x =
let rec loop acc cell_peeks x =
match peekn stream (!peeks + cell_peeks) with
| None -> Failed
| Some s ->
(collect
~what:all_phrases
~ended_with:(end_of_phrase |||
dont_jump (
p_many p_punct >>>
p_char '|' >>> return ()))
~from:0
~until:(
(p_char '|' >>> return true) |||
(p_end >>> return false)
) >>= function
| line, true ->
return (peeks := !peeks + (succ cell_peeks); List.rev (line::acc))
| line, false ->
loop (line::acc) (succ cell_peeks)
) (s, 0) in
loop [] 0 x in
p_opt default_celloptions (
celloptions >>= fun copts ->
p_str ". " >>>
return copts) >>= fun copts ->
(
(p_char '|' >>> return (empty_line, true)) |||
(current_pos >>= fun beg_of_line ->
collect
~what:all_phrases
~ended_with:(end_of_phrase |||
dont_jump (p_many p_punct >>> p_char '|' >>> return ()))
~from:beg_of_line
~until:(
(p_char '|' >>> return true) |||
(p_end >>> return false)
))
) >>= function
| first_line, true -> return (copts, [first_line])
| first_line, false -> continue_cell >>= fun lines ->
return (copts, first_line::lines) in
p_many p_whitespace >>>
p_opt default_tableoptions (
tableoptions_plus >>= fun topts ->
p_char '.' >>>
p_plus p_whitespace >>>
return topts) >>= fun topts ->
p_char '|' >>>
get_cell >>= fun first_cell ->
p_manyf_ends_with
get_cell
(fun acc x -> x :: acc)
[first_cell]
p_end >>= fun rev_cells ->
return (njunk stream !peeks; (topts, List.rev rev_cells)) in
let get_extra_rows =
p_seq
(fun _ ->
match Stream.peek stream with
| None -> Failed
| Some s -> row 1 (s, 0)) in
let get_rows =
row 0 >>= fun first_row ->
get_extra_rows >>= fun extra_rows ->
return (first_row::extra_rows) in
let get_block s =
(
(block_modifier >>= function
| `Textblock (bm, opts, extended) ->
let lines f = get_lines extended >>= fun r -> return (f r) in
let strings f = get_strings extended >>= fun r -> return (f r) in
(match bm with
| `Header lvl -> lines (fun x -> Header (lvl, (opts, x)))
| `Blockquote -> lines (fun x -> Blockquote (opts, x))
| `Footnote n -> lines (fun x -> Footnote (n, (opts, x)))
| `Blockcode -> strings (fun x -> Blockcode (opts, x))
| `Pre -> strings (fun x -> Pre (opts, x))
| `Blocknott -> strings (fun x -> Blocknott (opts, x))
| `Paragraph -> lines (fun x -> Paragraph (opts, x)))
| `Table topts ->
(get_extra_rows >>= function
| [] -> fail
| rows -> return (Table (topts, rows)))
) ||| (
get_rows >>= fun rows ->
return (Table (default_tableoptions, rows))
) ||| (
get_elements '*' >>= fun el -> return (Bulllist el)
) ||| (
get_elements '#' >>= fun el -> return (Numlist el)
) ||| (
get_lines false >>= fun lines ->
return (Paragraph (default_options, lines))
)
) (s, 0) >> function
| Parsed (r, _) -> r
| Failed -> assert false in
let rec next_block () =
try
match Stream.next stream with
| "" -> next_block ()
| fstr -> Some (get_block fstr)
with Stream.Failure -> None in
Stream.from (fun _ -> next_block ())