Current section
Files
Jump to
Current section
Files
src/commonmark@internal@parser.erl
-module(commonmark@internal@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([trim_indent/2, parse_text/1, parse_block_state/1, parse_blocks/1]).
-export_type([block_state/0, inline_state/0, block_parse_state/0]).
-type block_state() :: outside_block |
{paragraph_builder, list(binary())} |
{fenced_code_block_builder,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
list(binary()),
integer()} |
{indented_code_block_builder, list(binary())}.
-type inline_state() :: {text_accumulator, list(binary())} |
{autolink_accumulator, list(binary())}.
-opaque block_parse_state() :: {paragraph, binary()} |
horizontal_break |
{heading, integer(), gleam@option:option(binary())} |
{code_block,
gleam@option:option(binary()),
gleam@option:option(binary()),
binary()}.
-spec do_trim_indent(binary(), integer(), integer()) -> binary().
do_trim_indent(Line, N, Removed) ->
case Line of
_ when Removed >= N ->
Line;
<<" "/utf8, Rest/binary>> ->
do_trim_indent(Rest, N, Removed + 1);
<<"\t"/utf8, Rest@1/binary>> ->
Next_tab_stop = Removed + (4 - (Removed rem 4)),
do_trim_indent(Rest@1, N, Removed + Next_tab_stop);
_ ->
Line
end.
-spec trim_indent(binary(), integer()) -> binary().
trim_indent(Line, N) ->
do_trim_indent(Line, N, 0).
-spec determine_indent(gleam@option:option(binary())) -> integer().
determine_indent(Indent) ->
case Indent of
none ->
0;
{some, S} ->
gleam@string:length(S)
end.
-spec parse_autolink(binary()) -> commonmark@ast:inline_node().
parse_autolink(Href) ->
_assert_subject = gleam@regex:from_string(
<<"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"/utf8>>
),
{ok, Email_regex} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"parse_autolink"/utf8>>,
line => 63})
end,
_assert_subject@1 = gleam@regex:from_string(
<<"^[a-zA-Z][-a-zA-Z+.]{1,31}:"/utf8>>
),
{ok, Uri_regex} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"parse_autolink"/utf8>>,
line => 67})
end,
case {gleam@regex:check(Email_regex, Href),
gleam@regex:check(Uri_regex, Href)} of
{true, _} ->
{email_autolink, Href};
{_, true} ->
{uri_autolink, Href};
{false, false} ->
{text, <<<<"<"/utf8, Href/binary>>/binary, ">"/utf8>>}
end.
-spec do_parse_text(
list(binary()),
inline_state(),
list(commonmark@ast:inline_node())
) -> list(commonmark@ast:inline_node()).
do_parse_text(Text, State, Acc) ->
case {State, Text} of
{{autolink_accumulator, Ts}, []} ->
[{text,
begin
_pipe = [<<"<"/utf8>> | lists:reverse(Ts)],
gleam@string:join(_pipe, <<""/utf8>>)
end} |
Acc];
{{text_accumulator, Ts@1}, []} ->
_pipe@4 = [{text,
begin
_pipe@1 = Ts@1,
_pipe@2 = lists:reverse(_pipe@1),
_pipe@3 = gleam@string:join(_pipe@2, <<""/utf8>>),
gleam@string:trim(_pipe@3)
end} |
Acc],
lists:reverse(_pipe@4);
{{text_accumulator, Ts@2},
[<<" "/utf8>>, <<" "/utf8>>, <<"\n"/utf8>> | Gs]} ->
do_parse_text(
Gs,
{text_accumulator, []},
[hard_line_break,
{text,
begin
_pipe@5 = Ts@2,
_pipe@6 = lists:reverse(_pipe@5),
_pipe@7 = gleam@string:join(_pipe@6, <<""/utf8>>),
gleam@string:trim(_pipe@7)
end} |
Acc]
);
{{text_accumulator, Ts@2}, [<<"\\"/utf8>>, <<"\n"/utf8>> | Gs]} ->
do_parse_text(
Gs,
{text_accumulator, []},
[hard_line_break,
{text,
begin
_pipe@5 = Ts@2,
_pipe@6 = lists:reverse(_pipe@5),
_pipe@7 = gleam@string:join(_pipe@6, <<""/utf8>>),
gleam@string:trim(_pipe@7)
end} |
Acc]
);
{{autolink_accumulator, Ts@3},
[<<" "/utf8>>, <<" "/utf8>>, <<"\n"/utf8>> | Gs@1]} ->
do_parse_text(
Gs@1,
{text_accumulator, []},
[hard_line_break,
{text,
begin
_pipe@8 = lists:reverse([<<"<"/utf8>> | Ts@3]),
gleam@string:join(_pipe@8, <<""/utf8>>)
end} |
Acc]
);
{{autolink_accumulator, Ts@3}, [<<"\\"/utf8>>, <<"\n"/utf8>> | Gs@1]} ->
do_parse_text(
Gs@1,
{text_accumulator, []},
[hard_line_break,
{text,
begin
_pipe@8 = lists:reverse([<<"<"/utf8>> | Ts@3]),
gleam@string:join(_pipe@8, <<""/utf8>>)
end} |
Acc]
);
{{text_accumulator, Ts@4}, [<<"\n"/utf8>> | Gs@2]} ->
do_parse_text(
Gs@2,
{text_accumulator, []},
[soft_line_break,
{text,
begin
_pipe@9 = Ts@4,
_pipe@10 = lists:reverse(_pipe@9),
_pipe@11 = gleam@string:join(_pipe@10, <<""/utf8>>),
gleam@string:trim(_pipe@11)
end} |
Acc]
);
{{autolink_accumulator, Ts@5}, [<<"\n"/utf8>> | Gs@3]} ->
do_parse_text(
Gs@3,
{text_accumulator, []},
[soft_line_break,
{text,
begin
_pipe@12 = lists:reverse([<<"<"/utf8>> | Ts@5]),
gleam@string:join(_pipe@12, <<""/utf8>>)
end} |
Acc]
);
{{text_accumulator, Ts@6}, [<<"<"/utf8>> | Gs@4]} ->
do_parse_text(
Gs@4,
{autolink_accumulator, []},
[{text,
begin
_pipe@13 = Ts@6,
_pipe@14 = lists:reverse(_pipe@13),
gleam@string:join(_pipe@14, <<""/utf8>>)
end} |
Acc]
);
{{autolink_accumulator, Ts@7}, [<<"\t"/utf8>> = Space | Gs@5]} ->
do_parse_text(
Gs@5,
{text_accumulator, [Space | lists:append(Ts@7, [<<"<"/utf8>>])]},
Acc
);
{{autolink_accumulator, Ts@7}, [<<" "/utf8>> = Space | Gs@5]} ->
do_parse_text(
Gs@5,
{text_accumulator, [Space | lists:append(Ts@7, [<<"<"/utf8>>])]},
Acc
);
{{autolink_accumulator, Ts@8}, [<<">"/utf8>> | Gs@6]} ->
do_parse_text(
Gs@6,
{text_accumulator, []},
[parse_autolink(
begin
_pipe@15 = Ts@8,
_pipe@16 = lists:reverse(_pipe@15),
gleam@string:join(_pipe@16, <<""/utf8>>)
end
) |
Acc]
);
{{autolink_accumulator, Ts@9}, [G | Gs@7]} ->
do_parse_text(Gs@7, {autolink_accumulator, [G | Ts@9]}, Acc);
{{text_accumulator, Ts@10}, [G@1 | Gs@8]} ->
do_parse_text(Gs@8, {text_accumulator, [G@1 | Ts@10]}, Acc)
end.
-spec parse_text(binary()) -> list(commonmark@ast:inline_node()).
parse_text(Text) ->
_pipe = Text,
_pipe@1 = gleam@string:to_graphemes(_pipe),
do_parse_text(_pipe@1, {text_accumulator, []}, []).
-spec parse_block_state(block_parse_state()) -> list(commonmark@ast:block_node()).
parse_block_state(State) ->
case State of
{paragraph, Lines} ->
[begin
_pipe = Lines,
_pipe@1 = parse_text(_pipe),
{paragraph, _pipe@1}
end];
{code_block, Info, Full_info, Lines@1} ->
[{code_block, Info, Full_info, Lines@1}];
horizontal_break ->
[horizontal_break];
{heading, Level, {some, Contents}} ->
[{heading, Level, parse_text(Contents)}];
{heading, Level@1, none} ->
[{heading, Level@1, []}]
end.
-spec do_parse_blocks(block_state(), list(block_parse_state()), list(binary())) -> list(block_parse_state()).
do_parse_blocks(State, Acc, Lines) ->
_assert_subject = gleam@regex:from_string(
<<"^ {0,3}(?:\\*[* \t]*\\*[* \t]*\\*|-[- \t]*-[- \t]*-|_[_ \t]*_[_ \t]*_)[ \t]*$"/utf8>>
),
{ok, Hr_regex} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"do_parse_blocks"/utf8>>,
line => 157})
end,
_assert_subject@1 = gleam@regex:from_string(
<<"^ {0,3}(#{1,6})([ \t]+.*?)?(?:(?<=[ \t])#*)?[ \t]*$"/utf8>>
),
{ok, Atx_header_regex} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"do_parse_blocks"/utf8>>,
line => 161})
end,
_assert_subject@2 = gleam@regex:from_string(
<<"^ {0,3}([-=])+[ \t]*$"/utf8>>
),
{ok, Setext_header_regex} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"do_parse_blocks"/utf8>>,
line => 163})
end,
_assert_subject@3 = case State of
{fenced_code_block_builder, Break, _, _, _, _} ->
gleam@regex:from_string(
<<<<"^ {0,3}"/utf8, Break/binary>>/binary, "+[ \t]*$"/utf8>>
);
_ ->
gleam@regex:from_string(
<<"^( {0,3})([~`]{3,})[ \t]*(([^\\s]+).*?)?[ \t]*$"/utf8>>
)
end,
{ok, Fenced_code_regex} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"do_parse_blocks"/utf8>>,
line => 165})
end,
_assert_subject@4 = gleam@regex:from_string(
<<<<"^"/utf8, "(?: {0,3}\t| )"/utf8>>/binary, "|^[ \t]*$"/utf8>>
),
{ok, Valid_indented_code_regex} = case _assert_subject@4 of
{ok, _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@4,
module => <<"commonmark/internal/parser"/utf8>>,
function => <<"do_parse_blocks"/utf8>>,
line => 170})
end,
L = begin
_pipe = gleam@list:first(Lines),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
case {State,
Lines,
gleam@regex:check(Hr_regex, L),
gleam@regex:scan(Atx_header_regex, L),
gleam@regex:scan(Setext_header_regex, L),
gleam@regex:scan(Fenced_code_regex, L),
gleam@regex:check(Valid_indented_code_regex, L)} of
{{paragraph_builder, Lines@1}, [], _, _, _, _, _} ->
_pipe@2 = [{paragraph,
begin
_pipe@1 = Lines@1,
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end} |
Acc],
lists:reverse(_pipe@2);
{{indented_code_block_builder, Lines@2}, [], _, _, _, _, _} ->
_pipe@8 = [{code_block,
none,
none,
begin
_pipe@5 = [<<""/utf8>> |
begin
_pipe@3 = Lines@2,
_pipe@4 = gleam@list:map(
_pipe@3,
fun(_capture) ->
trim_indent(_capture, 4)
end
),
gleam@list:drop_while(
_pipe@4,
fun(N) -> N =:= <<""/utf8>> end
)
end],
_pipe@6 = lists:reverse(_pipe@5),
_pipe@7 = gleam@list:drop_while(
_pipe@6,
fun(N@1) -> N@1 =:= <<""/utf8>> end
),
gleam@string:join(_pipe@7, <<"\n"/utf8>>)
end} |
Acc],
lists:reverse(_pipe@8);
{{fenced_code_block_builder, _, Info, Full_info, Contents, Indent},
[<<""/utf8>>],
_,
_,
_,
_,
_} ->
_pipe@12 = [{code_block,
Info,
Full_info,
begin
_pipe@9 = [<<""/utf8>> | Contents],
_pipe@10 = gleam@list:map(
_pipe@9,
fun(_capture@1) ->
trim_indent(_capture@1, Indent)
end
),
_pipe@11 = lists:reverse(_pipe@10),
gleam@string:join(_pipe@11, <<"\n"/utf8>>)
end} |
Acc],
lists:reverse(_pipe@12);
{{fenced_code_block_builder, _, Info, Full_info, Contents, Indent},
[],
_,
_,
_,
_,
_} ->
_pipe@12 = [{code_block,
Info,
Full_info,
begin
_pipe@9 = [<<""/utf8>> | Contents],
_pipe@10 = gleam@list:map(
_pipe@9,
fun(_capture@1) ->
trim_indent(_capture@1, Indent)
end
),
_pipe@11 = lists:reverse(_pipe@10),
gleam@string:join(_pipe@11, <<"\n"/utf8>>)
end} |
Acc],
lists:reverse(_pipe@12);
{outside_block, [], _, _, _, _, _} ->
_pipe@13 = Acc,
lists:reverse(_pipe@13);
{{paragraph_builder, Bs}, [<<" "/utf8>> | Ls], _, _, _, _, _} ->
do_parse_blocks(
outside_block,
[{paragraph,
begin
_pipe@14 = lists:reverse(Bs),
gleam@string:join(_pipe@14, <<"\n"/utf8>>)
end} |
Acc],
Ls
);
{{paragraph_builder, Bs}, [<<"\\"/utf8>> | Ls], _, _, _, _, _} ->
do_parse_blocks(
outside_block,
[{paragraph,
begin
_pipe@14 = lists:reverse(Bs),
gleam@string:join(_pipe@14, <<"\n"/utf8>>)
end} |
Acc],
Ls
);
{{paragraph_builder, Bs}, [<<""/utf8>> | Ls], _, _, _, _, _} ->
do_parse_blocks(
outside_block,
[{paragraph,
begin
_pipe@14 = lists:reverse(Bs),
gleam@string:join(_pipe@14, <<"\n"/utf8>>)
end} |
Acc],
Ls
);
{outside_block, [<<" "/utf8>> | Ls@1], _, _, _, _, _} ->
do_parse_blocks(outside_block, Acc, Ls@1);
{outside_block, [<<"\\"/utf8>> | Ls@1], _, _, _, _, _} ->
do_parse_blocks(outside_block, Acc, Ls@1);
{outside_block, [<<""/utf8>> | Ls@1], _, _, _, _, _} ->
do_parse_blocks(outside_block, Acc, Ls@1);
{outside_block, [L@1 | Ls@2], _, _, _, _, true} ->
do_parse_blocks({indented_code_block_builder, [L@1]}, Acc, Ls@2);
{{indented_code_block_builder, Bs@1}, [L@2], _, _, _, _, true} ->
do_parse_blocks(
{indented_code_block_builder, [L@2 | Bs@1]},
Acc,
[]
);
{{indented_code_block_builder, Bs@2}, [L@3 | Ls@3], _, _, _, _, true} ->
do_parse_blocks(
{indented_code_block_builder, [L@3 | Bs@2]},
Acc,
Ls@3
);
{{indented_code_block_builder, Bs@3}, Ls@4, _, _, _, _, false} ->
do_parse_blocks(
outside_block,
[{code_block,
none,
none,
begin
_pipe@17 = [<<""/utf8>> |
begin
_pipe@15 = Bs@3,
_pipe@16 = gleam@list:map(
_pipe@15,
fun(_capture@2) ->
trim_indent(_capture@2, 4)
end
),
gleam@list:drop_while(
_pipe@16,
fun(N@2) -> N@2 =:= <<""/utf8>> end
)
end],
_pipe@18 = lists:reverse(_pipe@17),
_pipe@19 = gleam@list:drop_while(
_pipe@18,
fun(N@3) -> N@3 =:= <<""/utf8>> end
),
gleam@string:join(_pipe@19, <<"\n"/utf8>>)
end} |
Acc],
Ls@4
);
{{paragraph_builder, Bs@4},
[_ | Ls@5],
_,
_,
_,
[{match, _, [Indent@1, {some, Exit}]}],
_} ->
do_parse_blocks(
{fenced_code_block_builder,
Exit,
none,
none,
[],
determine_indent(Indent@1)},
[{paragraph,
begin
_pipe@20 = lists:reverse(Bs@4),
gleam@string:join(_pipe@20, <<"\n"/utf8>>)
end} |
Acc],
Ls@5
);
{{paragraph_builder, Bs@5},
[_ | Ls@6],
_,
_,
_,
[{match, _, [Indent@2, {some, Exit@1}, Full_info@1, Info@1]}],
_} ->
do_parse_blocks(
{fenced_code_block_builder,
Exit@1,
Info@1,
Full_info@1,
[],
determine_indent(Indent@2)},
[{paragraph,
begin
_pipe@21 = lists:reverse(Bs@5),
gleam@string:join(_pipe@21, <<"\n"/utf8>>)
end} |
Acc],
Ls@6
);
{outside_block,
[_ | Ls@7],
_,
_,
_,
[{match, _, [Indent@3, {some, Exit@2}]}],
_} ->
do_parse_blocks(
{fenced_code_block_builder,
Exit@2,
none,
none,
[],
determine_indent(Indent@3)},
Acc,
Ls@7
);
{outside_block,
[_ | Ls@8],
_,
_,
_,
[{match, _, [Indent@4, {some, Exit@3}, Full_info@2, Info@2]}],
_} ->
do_parse_blocks(
{fenced_code_block_builder,
Exit@3,
Info@2,
Full_info@2,
[],
determine_indent(Indent@4)},
Acc,
Ls@8
);
{{fenced_code_block_builder, _, Info@3, Full_info@3, Bs@6, Indent@5},
[_ | Ls@9],
_,
_,
_,
[{match, _, _}],
_} ->
do_parse_blocks(
outside_block,
[{code_block,
Info@3,
Full_info@3,
begin
_pipe@23 = lists:reverse(
[<<""/utf8>> |
begin
_pipe@22 = Bs@6,
gleam@list:map(
_pipe@22,
fun(_capture@3) ->
trim_indent(
_capture@3,
Indent@5
)
end
)
end]
),
gleam@string:join(_pipe@23, <<"\n"/utf8>>)
end} |
Acc],
Ls@9
);
{{fenced_code_block_builder,
Break@1,
Info@4,
Full_info@4,
Bs@7,
Indent@6},
[L@4 | Ls@10],
_,
_,
_,
_,
_} ->
do_parse_blocks(
{fenced_code_block_builder,
Break@1,
Info@4,
Full_info@4,
[L@4 | Bs@7],
Indent@6},
Acc,
Ls@10
);
{{paragraph_builder, Bs@8},
[_ | Ls@11],
_,
_,
[{match, _, [{some, <<"="/utf8>>}]}],
_,
_} ->
do_parse_blocks(
outside_block,
[{heading,
1,
{some,
begin
_pipe@24 = lists:reverse(Bs@8),
gleam@string:join(_pipe@24, <<"\n"/utf8>>)
end}} |
Acc],
Ls@11
);
{{paragraph_builder, Bs@9},
[_ | Ls@12],
_,
_,
[{match, _, [{some, <<"-"/utf8>>}]}],
_,
_} ->
do_parse_blocks(
outside_block,
[{heading,
2,
{some,
begin
_pipe@25 = lists:reverse(Bs@9),
gleam@string:join(_pipe@25, <<"\n"/utf8>>)
end}} |
Acc],
Ls@12
);
{{paragraph_builder, Bs@10}, [_ | Ls@13], true, _, _, _, _} ->
do_parse_blocks(
outside_block,
[horizontal_break,
{paragraph,
begin
_pipe@26 = lists:reverse(Bs@10),
gleam@string:join(_pipe@26, <<"\n"/utf8>>)
end} |
Acc],
Ls@13
);
{outside_block, [_ | Ls@14], true, _, _, _, _} ->
do_parse_blocks(outside_block, [horizontal_break | Acc], Ls@14);
{outside_block,
[_ | Ls@15],
_,
[{match, _, [{some, Heading}]}],
_,
_,
_} ->
do_parse_blocks(
outside_block,
[{heading, gleam@string:length(Heading), none} | Acc],
Ls@15
);
{outside_block,
[_ | Ls@16],
_,
[{match, _, [{some, Heading@1}, {some, Contents@1}]}],
_,
_,
_} ->
do_parse_blocks(
outside_block,
[{heading, gleam@string:length(Heading@1), {some, Contents@1}} |
Acc],
Ls@16
);
{{paragraph_builder, Bs@11},
[_ | Ls@17],
_,
[{match, _, [{some, Heading@2}]}],
_,
_,
_} ->
do_parse_blocks(
outside_block,
[{heading, gleam@string:length(Heading@2), none},
{paragraph,
begin
_pipe@27 = lists:reverse(Bs@11),
gleam@string:join(_pipe@27, <<"\n"/utf8>>)
end} |
Acc],
Ls@17
);
{{paragraph_builder, Bs@12},
[_ | Ls@18],
_,
[{match, _, [{some, Heading@3}, {some, Contents@2}]}],
_,
_,
_} ->
do_parse_blocks(
outside_block,
[{heading, gleam@string:length(Heading@3), {some, Contents@2}},
{paragraph,
begin
_pipe@28 = lists:reverse(Bs@12),
gleam@string:join(_pipe@28, <<"\n"/utf8>>)
end} |
Acc],
Ls@18
);
{outside_block, [Line | Ls@19], _, _, _, _, _} ->
do_parse_blocks({paragraph_builder, [Line]}, Acc, Ls@19);
{{paragraph_builder, Bs@13}, [Line@1 | Ls@20], _, _, _, _, _} ->
do_parse_blocks({paragraph_builder, [Line@1 | Bs@13]}, Acc, Ls@20)
end.
-spec parse_blocks(list(binary())) -> list(block_parse_state()).
parse_blocks(Lines) ->
do_parse_blocks(outside_block, [], Lines).