-module(commonmark@internal@parser@inline). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse_text/1]). -export_type([inline_lexer/0, inline_wrapper/0]). -type inline_lexer() :: {entity, binary(), binary()} | {escaped, binary()} | {word, binary()} | {white_space, binary()} | less_than | greater_than | backtick | tilde | asterisk | underscore | open_bracket | close_bracket | image_start | open_square_bracket | close_square_bracket | single_quote | double_quote | exclamation | soft_line_break | {hard_line_break, binary()}. -type inline_wrapper() :: {lexed_element, inline_lexer()} | {email_autolink, list(inline_wrapper())} | {uri_autolink, list(inline_wrapper())} | {backtick_string, integer()} | {tilde_string, integer()} | {asterisk_string, integer()} | {underscore_string, integer()} | {uri_image, binary(), binary(), gleam@option:option(binary())} | {uri_link, list(inline_wrapper()), binary(), gleam@option:option(binary())} | {emphasis, list(inline_wrapper()), commonmark@ast:emphasis_marker()} | {strong_emphasis, list(inline_wrapper()), commonmark@ast:emphasis_marker()} | {code_span, integer(), list(inline_wrapper())} | {strikethrough, integer(), list(inline_wrapper())}. -spec parse_code_span(integer(), list(inline_wrapper())) -> list(inline_wrapper()). parse_code_span(Size, Previous) -> case gleam@list:split_while( Previous, fun(N) -> N /= {backtick_string, Size} end ) of {_, []} -> [{backtick_string, Size} | Previous]; {Wrapped, [_ | Rest]} -> [{code_span, Size, lists:reverse(Wrapped)} | Rest] end. -spec is_not_less_than(inline_wrapper()) -> boolean(). is_not_less_than(V) -> case V of {lexed_element, less_than} -> false; _ -> true end. -spec parse_strikethrough(integer(), list(inline_wrapper())) -> list(inline_wrapper()). parse_strikethrough(Size, Previous) -> case gleam@list:split_while( Previous, fun(N) -> N /= {tilde_string, Size} end ) of {_, []} -> [{tilde_string, Size} | Previous]; {Wrapped, [_ | Rest]} -> [{strikethrough, Size, lists:reverse(Wrapped)} | Rest] end. -spec parse_emphasis(inline_wrapper(), list(inline_wrapper())) -> {list(inline_wrapper()), list(inline_wrapper())}. parse_emphasis(Final, Previous) -> {Wrapped, Rest} = gleam@list:split_while( Previous, fun(N) -> case {N, Final} of {{asterisk_string, L}, {asterisk_string, R}} -> not (((L > 0) andalso (R > 0)) andalso ((((L + R) rem 3) /= 0) orelse (((L rem 3) =:= 0) andalso ((R rem 3) =:= 0)))); {{underscore_string, L}, {underscore_string, R}} -> not (((L > 0) andalso (R > 0)) andalso ((((L + R) rem 3) /= 0) orelse (((L rem 3) =:= 0) andalso ((R rem 3) =:= 0)))); {_, _} -> true end end ), case {Final, Rest} of {{asterisk_string, R@1}, [{asterisk_string, L@1} | Rest@1]} when (L@1 >= 2) andalso (R@1 >= 2) -> {[{asterisk_string, R@1 - 2}], [{strong_emphasis, lists:reverse(Wrapped), asterisk_emphasis_marker}, {asterisk_string, L@1 - 2} | Rest@1]}; {{asterisk_string, R@2}, [{asterisk_string, L@2} | Rest@2]} -> {[{asterisk_string, R@2 - 1}], [{emphasis, lists:reverse(Wrapped), asterisk_emphasis_marker}, {asterisk_string, L@2 - 1} | Rest@2]}; {{underscore_string, R@3}, [{underscore_string, L@3} | Rest@3]} when (L@3 >= 2) andalso (R@3 >= 2) -> {[{underscore_string, R@3 - 2}], [{strong_emphasis, lists:reverse(Wrapped), underscore_emphasis_marker}, {underscore_string, L@3 - 2} | Rest@3]}; {{underscore_string, R@4}, [{underscore_string, L@4} | Rest@4]} -> {[{underscore_string, R@4 - 1}], [{emphasis, lists:reverse(Wrapped), underscore_emphasis_marker}, {underscore_string, L@4 - 1} | Rest@4]}; {_, _} -> {[], [Final | Previous]} end. -spec is_not_end_of_href(inline_wrapper()) -> boolean(). is_not_end_of_href(V) -> case V of {lexed_element, greater_than} -> false; {lexed_element, soft_line_break} -> false; {lexed_element, {hard_line_break, _}} -> false; _ -> true end. -spec is_not_link_or_image_start(inline_wrapper()) -> boolean(). is_not_link_or_image_start(V) -> case V of {lexed_element, image_start} -> false; {lexed_element, open_square_bracket} -> false; {lexed_element, close_square_bracket} -> false; _ -> true end. -spec trim_left(binary()) -> binary(). trim_left(X) -> case X of <<" "/utf8, X@1/binary>> -> trim_left(X@1); <<"\t"/utf8, X@2/binary>> -> trim_left(X@2); _ -> X end. -spec trim_right(binary()) -> binary(). trim_right(X) -> _pipe = X, _pipe@1 = gleam@string:reverse(_pipe), _pipe@2 = trim_left(_pipe@1), gleam@string:reverse(_pipe@2). -spec do_finalise_plain_text( list(commonmark@ast:inline_node()), list(commonmark@ast:inline_node()), boolean() ) -> list(commonmark@ast:inline_node()). do_finalise_plain_text(Ast, Acc, Trim_ends) -> case {Ast, Acc} of {[], [{plain_text, Y} | Ys]} when Trim_ends -> _pipe = [{plain_text, trim_right(Y)} | Ys], lists:reverse(_pipe); {[], _} -> _pipe@1 = Acc, lists:reverse(_pipe@1); {[{plain_text, <<""/utf8>>} | Xs], _} -> do_finalise_plain_text(Xs, Acc, Trim_ends); {[{strong_emphasis, Content, Marker} | Xs@1], _} -> do_finalise_plain_text( Xs@1, [{strong_emphasis, do_finalise_plain_text(Content, [], false), Marker} | Acc], Trim_ends ); {[{emphasis, Content@1, Marker@1} | Xs@2], _} -> do_finalise_plain_text( Xs@2, [{emphasis, do_finalise_plain_text(Content@1, [], Trim_ends), Marker@1} | Acc], Trim_ends ); {[{strike_through, Content@2} | Xs@3], _} -> do_finalise_plain_text( Xs@3, [{strike_through, do_finalise_plain_text(Content@2, [], Trim_ends)} | Acc], Trim_ends ); {[{plain_text, X} | Xs@4], [{plain_text, Y@1} | Ys@1]} -> do_finalise_plain_text( Xs@4, [{plain_text, <>} | Ys@1], Trim_ends ); {[{plain_text, X@1} | Xs@5], []} when Trim_ends -> do_finalise_plain_text( Xs@5, [{plain_text, trim_left(X@1)} | Acc], Trim_ends ); {[{plain_text, X@1} | Xs@5], [hard_line_break | _]} when Trim_ends -> do_finalise_plain_text( Xs@5, [{plain_text, trim_left(X@1)} | Acc], Trim_ends ); {[{plain_text, X@1} | Xs@5], [soft_line_break | _]} when Trim_ends -> do_finalise_plain_text( Xs@5, [{plain_text, trim_left(X@1)} | Acc], Trim_ends ); {[hard_line_break = X@2 | Xs@6], [{plain_text, Y@2} | Ys@2]} when Trim_ends -> do_finalise_plain_text( Xs@6, [X@2, {plain_text, trim_right(Y@2)} | Ys@2], Trim_ends ); {[soft_line_break = X@2 | Xs@6], [{plain_text, Y@2} | Ys@2]} when Trim_ends -> do_finalise_plain_text( Xs@6, [X@2, {plain_text, trim_right(Y@2)} | Ys@2], Trim_ends ); {[X@3 | Xs@7], _} -> do_finalise_plain_text(Xs@7, [X@3 | Acc], Trim_ends) end. -spec replace_insecure_byte(integer()) -> integer(). replace_insecure_byte(N) -> case gleam@list:contains([0], N) of true -> 16#fffd; false -> N end. -spec translate_numerical_entity({ok, integer()} | {error, nil}, list(binary())) -> {ok, {list(binary()), binary()}} | {error, nil}. translate_numerical_entity(Codepoint, Rest) -> _pipe = Codepoint, _pipe@1 = gleam@result:map(_pipe, fun replace_insecure_byte/1), _pipe@2 = gleam@result:'try'(_pipe@1, fun gleam@string:utf_codepoint/1), gleam@result:map( _pipe@2, fun(Cp) -> {Rest, gleam_stdlib:utf_codepoint_list_to_string([Cp])} end ). -spec match_entity(list(binary())) -> {ok, {list(binary()), binary(), binary()}} | {error, nil}. match_entity(Input) -> _pipe = commonmark@internal@parser@entity:match_html_entity(Input), gleam@result:try_recover( _pipe, fun(_) -> _assert_subject = gleam@regex:from_string( <<"^#([0-9]{1,7});"/utf8>> ), {ok, Dec_entity} = 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/inline"/utf8>>, function => <<"match_entity"/utf8>>, line => 183}) end, _assert_subject@1 = gleam@regex:from_string( <<"^#([xX]([0-9a-fA-F]{1,6}));"/utf8>> ), {ok, Hex_entity} = 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/inline"/utf8>>, function => <<"match_entity"/utf8>>, line => 184}) end, Potential = begin _pipe@1 = gleam@list:take(Input, 9), gleam@string:join(_pipe@1, <<""/utf8>>) end, case {gleam@regex:scan(Dec_entity, Potential), gleam@regex:scan(Hex_entity, Potential)} of {[{match, Full, [{some, N}]}], _} -> _pipe@2 = N, _pipe@3 = gleam@int:parse(_pipe@2), _pipe@4 = translate_numerical_entity( _pipe@3, gleam@list:drop(Input, gleam@string:length(Full)) ), gleam@result:map( _pipe@4, fun(R) -> {erlang:element(1, R), N, erlang:element(2, R)} end ); {_, [{match, Full@1, [{some, M}, {some, N@1}]}]} -> _pipe@5 = N@1, _pipe@6 = gleam@int:base_parse(_pipe@5, 16), _pipe@7 = translate_numerical_entity( _pipe@6, gleam@list:drop(Input, gleam@string:length(Full@1)) ), gleam@result:map( _pipe@7, fun(R@1) -> {erlang:element(1, R@1), M, erlang:element(2, R@1)} end ); {_, _} -> {error, nil} end end ). -spec do_lex_inline_text(list(binary()), list(inline_lexer())) -> list(inline_lexer()). do_lex_inline_text(Input, Acc) -> case Input of [] -> _pipe = Acc, lists:reverse(_pipe); [<<"<"/utf8>> | Xs] -> do_lex_inline_text(Xs, [less_than | Acc]); [<<">"/utf8>> | Xs@1] -> do_lex_inline_text(Xs@1, [greater_than | Acc]); [<<"!"/utf8>>, <<"["/utf8>> | Xs@2] -> do_lex_inline_text(Xs@2, [image_start | Acc]); [<<"["/utf8>> | Xs@3] -> do_lex_inline_text(Xs@3, [open_square_bracket | Acc]); [<<"]"/utf8>> | Xs@4] -> do_lex_inline_text(Xs@4, [close_square_bracket | Acc]); [<<"("/utf8>> | Xs@5] -> do_lex_inline_text(Xs@5, [open_bracket | Acc]); [<<")"/utf8>> | Xs@6] -> do_lex_inline_text(Xs@6, [close_bracket | Acc]); [<<"'"/utf8>> | Xs@7] -> do_lex_inline_text(Xs@7, [single_quote | Acc]); [<<"\""/utf8>> | Xs@8] -> do_lex_inline_text(Xs@8, [double_quote | Acc]); [<<"!"/utf8>> | Xs@9] -> do_lex_inline_text(Xs@9, [exclamation | Acc]); [<<"`"/utf8>> | Xs@10] -> do_lex_inline_text(Xs@10, [backtick | Acc]); [<<"~"/utf8>> | Xs@11] -> do_lex_inline_text(Xs@11, [tilde | Acc]); [<<"_"/utf8>> | Xs@12] -> do_lex_inline_text(Xs@12, [underscore | Acc]); [<<"*"/utf8>> | Xs@13] -> do_lex_inline_text(Xs@13, [asterisk | Acc]); [<<"\\"/utf8>>, <<"\n"/utf8>> | Xs@14] -> do_lex_inline_text( Xs@14, [{hard_line_break, <<"\\\n"/utf8>>} | Acc] ); [<<" "/utf8>>, <<" "/utf8>>, <<"\n"/utf8>> | Xs@15] -> do_lex_inline_text( Xs@15, [{hard_line_break, <<" \n"/utf8>>} | Acc] ); [<<"\n"/utf8>> | Xs@16] -> do_lex_inline_text(Xs@16, [soft_line_break | Acc]); [<<"&"/utf8>> | Xs@17] -> case match_entity(Xs@17) of {ok, {Rest, E, Replacement}} -> do_lex_inline_text(Rest, [{entity, E, Replacement} | Acc]); {error, _} -> case Acc of [{word, T} | Rest@1] -> do_lex_inline_text( Xs@17, [{word, <>} | Rest@1] ); _ -> do_lex_inline_text( Xs@17, [{word, <<"&"/utf8>>} | Acc] ) end end; [<<"\\"/utf8>>, G | Xs@18] -> case gleam@list:contains( [<<"!"/utf8>>, <<"\""/utf8>>, <<"#"/utf8>>, <<"$"/utf8>>, <<"%"/utf8>>, <<"&"/utf8>>, <<"'"/utf8>>, <<"("/utf8>>, <<")"/utf8>>, <<"*"/utf8>>, <<"+"/utf8>>, <<","/utf8>>, <<"-"/utf8>>, <<"."/utf8>>, <<"/"/utf8>>, <<":"/utf8>>, <<";"/utf8>>, <<"<"/utf8>>, <<"="/utf8>>, <<">"/utf8>>, <<"?"/utf8>>, <<"@"/utf8>>, <<"["/utf8>>, <<"]"/utf8>>, <<"\\"/utf8>>, <<"^"/utf8>>, <<"_"/utf8>>, <<"`"/utf8>>, <<"{"/utf8>>, <<"|"/utf8>>, <<"}"/utf8>>, <<"~"/utf8>>], G ) of true -> do_lex_inline_text(Xs@18, [{escaped, G} | Acc]); false -> case Acc of [{word, T@1} | Rest@2] -> do_lex_inline_text( Xs@18, [{word, <<<>/binary, G/binary>>} | Rest@2] ); _ -> do_lex_inline_text( Xs@18, [{word, <<"\\"/utf8, G/binary>>} | Acc] ) end end; [<<" "/utf8>> = W | Xs@19] -> case Acc of [{white_space, Ww} | Rest@3] -> do_lex_inline_text( Xs@19, [{white_space, <>} | Rest@3] ); _ -> do_lex_inline_text(Xs@19, [{white_space, W} | Acc]) end; [<<"\t"/utf8>> = W | Xs@19] -> case Acc of [{white_space, Ww} | Rest@3] -> do_lex_inline_text( Xs@19, [{white_space, <>} | Rest@3] ); _ -> do_lex_inline_text(Xs@19, [{white_space, W} | Acc]) end; [X | Xs@20] -> case Acc of [{word, T@2} | Rest@4] -> do_lex_inline_text( Xs@20, [{word, <>} | Rest@4] ); _ -> do_lex_inline_text(Xs@20, [{word, X} | Acc]) end end. -spec list_to_text(list(inline_wrapper())) -> binary(). list_to_text(Els) -> _pipe = gleam@list:map(Els, fun to_text/1), gleam@string:join(_pipe, <<""/utf8>>). -spec to_text(inline_wrapper()) -> binary(). to_text(El) -> case El of {lexed_element, {word, S}} -> S; {lexed_element, {white_space, S}} -> S; {lexed_element, {escaped, S@1}} -> S@1; {lexed_element, less_than} -> <<"<"/utf8>>; {lexed_element, greater_than} -> <<">"/utf8>>; {lexed_element, backtick} -> <<"`"/utf8>>; {lexed_element, tilde} -> <<"~"/utf8>>; {lexed_element, asterisk} -> <<"*"/utf8>>; {lexed_element, underscore} -> <<"_"/utf8>>; {lexed_element, {hard_line_break, _}} -> <<"\n"/utf8>>; {lexed_element, soft_line_break} -> <<"\n"/utf8>>; {lexed_element, {entity, _, E}} -> E; {lexed_element, open_bracket} -> <<"("/utf8>>; {lexed_element, close_bracket} -> <<")"/utf8>>; {lexed_element, image_start} -> <<"!["/utf8>>; {lexed_element, open_square_bracket} -> <<"["/utf8>>; {lexed_element, close_square_bracket} -> <<"]"/utf8>>; {lexed_element, single_quote} -> <<"'"/utf8>>; {lexed_element, double_quote} -> <<"\""/utf8>>; {lexed_element, exclamation} -> <<"!"/utf8>>; {code_span, _, Contents} -> list_to_text(Contents); {emphasis, Contents, _} -> list_to_text(Contents); {strong_emphasis, Contents, _} -> list_to_text(Contents); {backtick_string, Count} -> gleam@string:repeat(<<"`"/utf8>>, Count); {asterisk_string, Count@1} -> gleam@string:repeat(<<"*"/utf8>>, Count@1); {underscore_string, Count@2} -> gleam@string:repeat(<<"_"/utf8>>, Count@2); {tilde_string, Count@3} -> gleam@string:repeat(<<"~"/utf8>>, Count@3); {strikethrough, _, Content} -> list_to_text(Content); {email_autolink, Ls} -> list_to_text(Ls); {uri_autolink, Ls} -> list_to_text(Ls); {uri_image, Alt, _, _} -> Alt; {uri_link, Content@1, _, _} -> list_to_text(Content@1) end. -spec list_to_string(list(inline_wrapper())) -> binary(). list_to_string(Els) -> _pipe = gleam@list:map(Els, fun to_string/1), gleam@string:join(_pipe, <<""/utf8>>). -spec to_string(inline_wrapper()) -> binary(). to_string(El) -> case El of {lexed_element, {hard_line_break, S}} -> S; {lexed_element, {word, S}} -> S; {lexed_element, {white_space, S}} -> S; {lexed_element, {escaped, S@1}} -> <<"\\"/utf8, S@1/binary>>; {lexed_element, less_than} -> <<"<"/utf8>>; {lexed_element, greater_than} -> <<">"/utf8>>; {lexed_element, backtick} -> <<"`"/utf8>>; {lexed_element, tilde} -> <<"~"/utf8>>; {lexed_element, asterisk} -> <<"*"/utf8>>; {lexed_element, underscore} -> <<"_"/utf8>>; {lexed_element, soft_line_break} -> <<"\n"/utf8>>; {lexed_element, {entity, E, _}} -> <<"&"/utf8, E/binary>>; {lexed_element, open_bracket} -> <<"("/utf8>>; {lexed_element, close_bracket} -> <<")"/utf8>>; {lexed_element, image_start} -> <<"!["/utf8>>; {lexed_element, open_square_bracket} -> <<"["/utf8>>; {lexed_element, close_square_bracket} -> <<"]"/utf8>>; {lexed_element, single_quote} -> <<"'"/utf8>>; {lexed_element, double_quote} -> <<"\""/utf8>>; {lexed_element, exclamation} -> <<"!"/utf8>>; {emphasis, Contents, Marker} -> case Marker of asterisk_emphasis_marker -> <<<<"*"/utf8, (list_to_string(Contents))/binary>>/binary, "*"/utf8>>; underscore_emphasis_marker -> <<<<"_"/utf8, (list_to_string(Contents))/binary>>/binary, "_"/utf8>> end; {strong_emphasis, Contents@1, Marker@1} -> case Marker@1 of asterisk_emphasis_marker -> <<<<"**"/utf8, (list_to_string(Contents@1))/binary>>/binary, "**"/utf8>>; underscore_emphasis_marker -> <<<<"__"/utf8, (list_to_string(Contents@1))/binary>>/binary, "__"/utf8>> end; {backtick_string, Count} -> gleam@string:repeat(<<"`"/utf8>>, Count); {asterisk_string, Count@1} -> gleam@string:repeat(<<"*"/utf8>>, Count@1); {underscore_string, Count@2} -> gleam@string:repeat(<<"_"/utf8>>, Count@2); {code_span, Count@3, Content} -> <<<<(gleam@string:repeat(<<"`"/utf8>>, Count@3))/binary, (list_to_string(Content))/binary>>/binary, (gleam@string:repeat(<<"`"/utf8>>, Count@3))/binary>>; {tilde_string, Count@4} -> gleam@string:repeat(<<"~"/utf8>>, Count@4); {strikethrough, Count@5, Content@1} -> <<<<(gleam@string:repeat(<<"~"/utf8>>, Count@5))/binary, (list_to_string(Content@1))/binary>>/binary, (gleam@string:repeat(<<"~"/utf8>>, Count@5))/binary>>; {email_autolink, Ls} -> <<<<"<"/utf8, (list_to_string(Ls))/binary>>/binary, ">"/utf8>>; {uri_autolink, Ls@1} -> <<<<"<"/utf8, (list_to_string(Ls@1))/binary>>/binary, ">"/utf8>>; {uri_image, Alt, Href, Title} -> Title@1 = begin _pipe = Title, _pipe@1 = gleam@option:map( _pipe, fun(T) -> <<<<" '"/utf8, T/binary>>/binary, "'"/utf8>> end ), gleam@option:unwrap(_pipe@1, <<""/utf8>>) end, <<<<<<<<<<<<"!["/utf8, Alt/binary>>/binary, "](<"/utf8>>/binary, Href/binary>>/binary, ">"/utf8>>/binary, Title@1/binary>>/binary, ")"/utf8>>; {uri_link, Content@2, Href@1, Title@2} -> Title@3 = begin _pipe@2 = Title@2, _pipe@3 = gleam@option:map( _pipe@2, fun(T@1) -> <<<<" '"/utf8, T@1/binary>>/binary, "'"/utf8>> end ), gleam@option:unwrap(_pipe@3, <<""/utf8>>) end, <<<<<<<<<<<<"["/utf8, (list_to_string(Content@2))/binary>>/binary, "](<"/utf8>>/binary, Href@1/binary>>/binary, ">"/utf8>>/binary, Title@3/binary>>/binary, ")"/utf8>> end. -spec parse_autolink(list(inline_wrapper())) -> {ok, inline_wrapper()} | {error, nil}. 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/inline"/utf8>>, function => <<"parse_autolink"/utf8>>, line => 274}) end, _assert_subject@1 = gleam@regex:from_string( <<"^[a-zA-Z][-a-zA-Z+.]{1,31}:[^ \t]+$"/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/inline"/utf8>>, function => <<"parse_autolink"/utf8>>, line => 278}) end, Href_str = list_to_string(Href), case {gleam@regex:check(Email_regex, Href_str), gleam@regex:check(Uri_regex, Href_str)} of {true, _} -> {ok, {email_autolink, Href}}; {_, true} -> {ok, {uri_autolink, Href}}; {false, false} -> {error, nil} end. -spec do_parse_inline_wrappers(list(inline_lexer()), list(inline_wrapper())) -> list(inline_wrapper()). do_parse_inline_wrappers(Lexed, Acc) -> case Lexed of [] -> _pipe = Acc, lists:reverse(_pipe); [greater_than | Ls] -> case gleam@list:split_while(Acc, fun is_not_less_than/1) of {_, []} -> do_parse_inline_wrappers( Ls, [{lexed_element, greater_than} | Acc] ); {To_wrap, [_ | Rest]} -> case parse_autolink( begin _pipe@1 = To_wrap, lists:reverse(_pipe@1) end ) of {ok, Wrapped} -> do_parse_inline_wrappers(Ls, [Wrapped | Rest]); {error, _} -> do_parse_inline_wrappers( Ls, [{lexed_element, greater_than} | Acc] ) end end; [backtick, backtick | Ls@1] -> case Acc of [{backtick_string, Count} | Rest@1] -> do_parse_inline_wrappers( [backtick | Ls@1], [{backtick_string, Count + 1} | Rest@1] ); _ -> do_parse_inline_wrappers( [backtick | Ls@1], [{backtick_string, 1} | Acc] ) end; [backtick | Ls@2] -> Acc@1 = case Acc of [{backtick_string, Count@1} | Rest@2] -> parse_code_span(Count@1 + 1, Rest@2); _ -> parse_code_span(1, Acc) end, do_parse_inline_wrappers(Ls@2, Acc@1); [asterisk, asterisk | Ls@3] -> case Acc of [{asterisk_string, Count@2} | Rest@3] -> do_parse_inline_wrappers( [asterisk | Ls@3], [{asterisk_string, Count@2 + 1} | Rest@3] ); _ -> do_parse_inline_wrappers( [asterisk | Ls@3], [{asterisk_string, 1} | Acc] ) end; [asterisk | Ls@4] -> case Acc of [{asterisk_string, Count@3} | Rest@4] -> do_parse_inline_wrappers( Ls@4, [{asterisk_string, Count@3 + 1} | Rest@4] ); _ -> do_parse_inline_wrappers(Ls@4, [{asterisk_string, 1} | Acc]) end; [underscore, underscore | Ls@5] -> case Acc of [{underscore_string, Count@4} | Rest@5] -> do_parse_inline_wrappers( [underscore | Ls@5], [{underscore_string, Count@4 + 1} | Rest@5] ); _ -> do_parse_inline_wrappers( [underscore | Ls@5], [{underscore_string, 1} | Acc] ) end; [underscore | Ls@6] -> case Acc of [{underscore_string, Count@5} | Rest@6] -> do_parse_inline_wrappers( Ls@6, [{underscore_string, Count@5 + 1} | Rest@6] ); _ -> do_parse_inline_wrappers( Ls@6, [{underscore_string, 1} | Acc] ) end; [tilde, tilde | Ls@7] -> case gleam@list:first(Acc) of {ok, {tilde_string, Count@6}} -> do_parse_inline_wrappers( [tilde | Ls@7], [{tilde_string, Count@6 + 1} | gleam@list:drop(Acc, 1)] ); _ -> do_parse_inline_wrappers( [tilde | Ls@7], [{tilde_string, 1} | Acc] ) end; [tilde | Ls@8] -> {Count@8, Acc@2} = case gleam@list:first(Acc) of {ok, {tilde_string, Count@7}} -> {Count@7 + 1, gleam@list:drop(Acc, 1)}; _ -> {1, Acc} end, do_parse_inline_wrappers(Ls@8, [{tilde_string, Count@8} | Acc@2]); [image_start = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [exclamation = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [single_quote = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [double_quote = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [open_bracket = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [close_bracket = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [open_square_bracket = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [close_square_bracket = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [{entity, _, _} = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [{escaped, _} = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [less_than = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [{hard_line_break, _} = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [soft_line_break = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [{white_space, _} = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]); [{word, _} = V | Ls@9] -> do_parse_inline_wrappers(Ls@9, [{lexed_element, V} | Acc]) end. -spec parse_link_title(list(inline_wrapper()), binary(), list(inline_wrapper())) -> {ok, {inline_wrapper(), list(inline_wrapper())}} | {error, nil}. parse_link_title(Contents, Href, Ls) -> Is_not = fun(X) -> fun(Y) -> X /= Y end end, case Ls of [{lexed_element, single_quote} | Ls@1] -> case gleam@list:split_while( Ls@1, Is_not({lexed_element, single_quote}) ) of {Title, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@2]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title)}}, Ls@2}}; {Title, [_, {lexed_element, close_bracket} | Ls@2]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title)}}, Ls@2}}; _ -> {error, nil} end; [{lexed_element, double_quote} | Ls@3] -> case gleam@list:split_while( Ls@3, Is_not({lexed_element, double_quote}) ) of {Title@1, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@4]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title@1)}}, Ls@4}}; {Title@1, [_, {lexed_element, close_bracket} | Ls@4]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title@1)}}, Ls@4}}; _ -> {error, nil} end; [{lexed_element, open_bracket} | Ls@5] -> case gleam@list:split_while( Ls@5, Is_not({lexed_element, close_bracket}) ) of {Title@2, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@6]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title@2)}}, Ls@6}}; {Title@2, [_, {lexed_element, close_bracket} | Ls@6]} -> {ok, {{uri_link, Contents, Href, {some, list_to_string(Title@2)}}, Ls@6}}; _ -> {error, nil} end; _ -> {error, nil} end. -spec parse_link(list(inline_wrapper()), list(inline_wrapper())) -> {ok, {inline_wrapper(), list(inline_wrapper())}} | {error, nil}. parse_link(Contents, Ls) -> case Ls of [{lexed_element, open_bracket}, {lexed_element, less_than}, {lexed_element, greater_than}, {lexed_element, close_bracket} | Ls@1] -> {ok, {{uri_link, Contents, <<""/utf8>>, none}, Ls@1}}; [{lexed_element, open_bracket}, {lexed_element, close_bracket} | Ls@1] -> {ok, {{uri_link, Contents, <<""/utf8>>, none}, Ls@1}}; [{lexed_element, open_bracket}, {lexed_element, {word, Href}}, {lexed_element, close_bracket} | Ls@2] -> {ok, {{uri_link, Contents, Href, none}, Ls@2}}; [{lexed_element, open_bracket}, {lexed_element, {word, Href@1}}, {lexed_element, {white_space, _}} | Ls@3] -> parse_link_title(Contents, Href@1, Ls@3); [{lexed_element, open_bracket}, {lexed_element, less_than} | Ls@4] -> case gleam@list:split_while(Ls@4, fun is_not_end_of_href/1) of {Href@2, [{lexed_element, greater_than}, {lexed_element, close_bracket} | Ls@5]} -> {ok, {{uri_link, Contents, list_to_string(Href@2), none}, Ls@5}}; {Href@3, [{lexed_element, greater_than}, {lexed_element, {white_space, _}} | Ls@6]} -> parse_link_title(Contents, list_to_string(Href@3), Ls@6); _ -> {error, nil} end; _ -> {error, nil} end. -spec parse_image_title(binary(), binary(), list(inline_wrapper())) -> {ok, {inline_wrapper(), list(inline_wrapper())}} | {error, nil}. parse_image_title(Alt, Href, Ls) -> Is_not = fun(X) -> fun(Y) -> X /= Y end end, case Ls of [{lexed_element, single_quote} | Ls@1] -> case gleam@list:split_while( Ls@1, Is_not({lexed_element, single_quote}) ) of {Title, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@2]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title)}}, Ls@2}}; {Title, [_, {lexed_element, close_bracket} | Ls@2]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title)}}, Ls@2}}; _ -> {error, nil} end; [{lexed_element, double_quote} | Ls@3] -> case gleam@list:split_while( Ls@3, Is_not({lexed_element, double_quote}) ) of {Title@1, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@4]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title@1)}}, Ls@4}}; {Title@1, [_, {lexed_element, close_bracket} | Ls@4]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title@1)}}, Ls@4}}; _ -> {error, nil} end; [{lexed_element, open_bracket} | Ls@5] -> case gleam@list:split_while( Ls@5, Is_not({lexed_element, close_bracket}) ) of {Title@2, [_, {lexed_element, {white_space, _}}, {lexed_element, close_bracket} | Ls@6]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title@2)}}, Ls@6}}; {Title@2, [_, {lexed_element, close_bracket} | Ls@6]} -> {ok, {{uri_image, Alt, Href, {some, list_to_string(Title@2)}}, Ls@6}}; _ -> {error, nil} end; _ -> {error, nil} end. -spec parse_image(binary(), list(inline_wrapper())) -> {ok, {inline_wrapper(), list(inline_wrapper())}} | {error, nil}. parse_image(Alt, Ls) -> case Ls of [{lexed_element, open_bracket}, {lexed_element, less_than}, {lexed_element, greater_than}, {lexed_element, close_bracket} | Ls@1] -> {ok, {{uri_image, Alt, <<""/utf8>>, none}, Ls@1}}; [{lexed_element, open_bracket}, {lexed_element, close_bracket} | Ls@1] -> {ok, {{uri_image, Alt, <<""/utf8>>, none}, Ls@1}}; [{lexed_element, open_bracket}, {lexed_element, {word, Href}}, {lexed_element, close_bracket} | Ls@2] -> {ok, {{uri_image, Alt, Href, none}, Ls@2}}; [{lexed_element, open_bracket}, {lexed_element, {word, Href@1}}, {lexed_element, {white_space, _}} | Ls@3] -> parse_image_title(Alt, Href@1, Ls@3); [{lexed_element, open_bracket}, {lexed_element, less_than} | Ls@4] -> case gleam@list:split_while(Ls@4, fun is_not_end_of_href/1) of {Href@2, [{lexed_element, greater_than}, {lexed_element, close_bracket} | Ls@5]} -> {ok, {{uri_image, Alt, list_to_string(Href@2), none}, Ls@5}}; {Href@3, [{lexed_element, greater_than}, {lexed_element, {white_space, _}} | Ls@6]} -> parse_image_title(Alt, list_to_string(Href@3), Ls@6); _ -> {error, nil} end; _ -> {error, nil} end. -spec do_late_binding(list(inline_wrapper()), list(inline_wrapper())) -> list(inline_wrapper()). do_late_binding(Wrapped, Acc) -> case Wrapped of [] -> _pipe = Acc, lists:reverse(_pipe); [{lexed_element, close_square_bracket} | Ls] -> case gleam@list:split_while(Acc, fun is_not_link_or_image_start/1) of {To_wrap, [{lexed_element, open_square_bracket} | Rest]} -> case parse_link( begin _pipe@1 = To_wrap, lists:reverse(_pipe@1) end, Ls ) of {ok, {Wrapped@1, Ls@1}} -> do_late_binding(Ls@1, [Wrapped@1 | Rest]); {error, _} -> do_late_binding( Ls, [{lexed_element, close_square_bracket} | Acc] ) end; {To_wrap@1, [{lexed_element, image_start} | Rest@1]} -> case parse_image( begin _pipe@2 = To_wrap@1, _pipe@3 = lists:reverse(_pipe@2), list_to_text(_pipe@3) end, Ls ) of {ok, {Wrapped@2, Ls@2}} -> do_late_binding(Ls@2, [Wrapped@2 | Rest@1]); {error, _} -> do_late_binding( Ls, [{lexed_element, close_square_bracket} | Acc] ) end; _ -> do_late_binding( Ls, [{lexed_element, close_square_bracket} | Acc] ) end; [{tilde_string, Count} | Xs] -> case Count =< 2 of true -> do_late_binding(Xs, parse_strikethrough(Count, Acc)); false -> do_late_binding(Xs, [{tilde_string, Count} | Acc]) end; [{asterisk_string, N} = Str | Xs@1] when N > 0 -> {Prefix, Acc@1} = parse_emphasis(Str, Acc), do_late_binding(gleam@list:concat([Prefix, Xs@1]), Acc@1); [{underscore_string, N} = Str | Xs@1] when N > 0 -> {Prefix, Acc@1} = parse_emphasis(Str, Acc), do_late_binding(gleam@list:concat([Prefix, Xs@1]), Acc@1); [X | Xs@2] -> do_late_binding(Xs@2, [X | Acc]) end. -spec do_parse_inline_ast( list(inline_wrapper()), list(commonmark@ast:inline_node()) ) -> list(commonmark@ast:inline_node()). do_parse_inline_ast(Wrapped, Acc) -> case Wrapped of [] -> _pipe = Acc, lists:reverse(_pipe); [{email_autolink, L} | Ws] -> do_parse_inline_ast(Ws, [{email_autolink, list_to_string(L)} | Acc]); [{uri_autolink, L@1} | Ws@1] -> do_parse_inline_ast( Ws@1, [{uri_autolink, list_to_string(L@1)} | Acc] ); [{uri_image, Contents, Href, Title} | Ws@2] -> do_parse_inline_ast(Ws@2, [{image, Contents, Title, Href} | Acc]); [{uri_link, Contents@1, Href@1, Title@1} | Ws@3] -> do_parse_inline_ast( Ws@3, [{link, do_parse_inline_ast(Contents@1, []), Title@1, Href@1} | Acc] ); [{backtick_string, Count} | Ws@4] -> do_parse_inline_ast( Ws@4, [{plain_text, gleam@string:repeat(<<"`"/utf8>>, Count)} | Acc] ); [{code_span, _, Contents@2} | Ws@5] -> _assert_subject = gleam@regex:from_string(<<"^ (.*) $"/utf8>>), {ok, R} = 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/inline"/utf8>>, function => <<"do_parse_inline_ast"/utf8>>, line => 702}) end, C = begin _pipe@1 = Contents@2, _pipe@2 = list_to_string(_pipe@1), gleam@string:replace(_pipe@2, <<"\n"/utf8>>, <<" "/utf8>>) end, case gleam@regex:scan(R, C) of [{match, _, [{some, Span}]}] -> do_parse_inline_ast(Ws@5, [{code_span, Span} | Acc]); _ -> do_parse_inline_ast(Ws@5, [{code_span, C} | Acc]) end; [{tilde_string, Count@1} | Ws@6] -> do_parse_inline_ast( Ws@6, [{plain_text, gleam@string:repeat(<<"~"/utf8>>, Count@1)} | Acc] ); [{strikethrough, _, Contents@3} | Ws@7] -> do_parse_inline_ast( Ws@7, [{strike_through, do_parse_inline_ast(Contents@3, [])} | Acc] ); [{emphasis, Contents@4, Marker} | Ws@8] -> do_parse_inline_ast( Ws@8, [{emphasis, do_parse_inline_ast(Contents@4, []), Marker} | Acc] ); [{strong_emphasis, Contents@5, Marker@1} | Ws@9] -> do_parse_inline_ast( Ws@9, [{strong_emphasis, do_parse_inline_ast(Contents@5, []), Marker@1} | Acc] ); [{asterisk_string, Count@2} | Ws@10] -> do_parse_inline_ast( Ws@10, [{plain_text, gleam@string:repeat(<<"*"/utf8>>, Count@2)} | Acc] ); [{underscore_string, Count@3} | Ws@11] -> do_parse_inline_ast( Ws@11, [{plain_text, gleam@string:repeat(<<"_"/utf8>>, Count@3)} | Acc] ); [{lexed_element, {escaped, S}} | Ws@12] -> do_parse_inline_ast(Ws@12, [{plain_text, S} | Acc]); [{lexed_element, {entity, _, R@1}} | Ws@13] -> do_parse_inline_ast(Ws@13, [{plain_text, R@1} | Acc]); [{lexed_element, soft_line_break} | Ws@14] -> do_parse_inline_ast(Ws@14, [soft_line_break | Acc]); [{lexed_element, {hard_line_break, _}} | Ws@15] -> do_parse_inline_ast(Ws@15, [hard_line_break | Acc]); [{lexed_element, open_bracket} | Ws@16] -> do_parse_inline_ast(Ws@16, [{plain_text, <<"("/utf8>>} | Acc]); [{lexed_element, close_bracket} | Ws@17] -> do_parse_inline_ast(Ws@17, [{plain_text, <<")"/utf8>>} | Acc]); [{lexed_element, image_start} | Ws@18] -> do_parse_inline_ast(Ws@18, [{plain_text, <<"!["/utf8>>} | Acc]); [{lexed_element, open_square_bracket} | Ws@19] -> do_parse_inline_ast(Ws@19, [{plain_text, <<"["/utf8>>} | Acc]); [{lexed_element, close_square_bracket} | Ws@20] -> do_parse_inline_ast(Ws@20, [{plain_text, <<"]"/utf8>>} | Acc]); [{lexed_element, single_quote} | Ws@21] -> do_parse_inline_ast(Ws@21, [{plain_text, <<"'"/utf8>>} | Acc]); [{lexed_element, double_quote} | Ws@22] -> do_parse_inline_ast(Ws@22, [{plain_text, <<"\""/utf8>>} | Acc]); [{lexed_element, exclamation} | Ws@23] -> do_parse_inline_ast(Ws@23, [{plain_text, <<"!"/utf8>>} | Acc]); [{lexed_element, asterisk} | Ws@24] -> do_parse_inline_ast(Ws@24, [{plain_text, <<"*"/utf8>>} | Acc]); [{lexed_element, underscore} | Ws@25] -> do_parse_inline_ast(Ws@25, [{plain_text, <<"_"/utf8>>} | Acc]); [{lexed_element, backtick} | Ws@26] -> do_parse_inline_ast(Ws@26, [{plain_text, <<"`"/utf8>>} | Acc]); [{lexed_element, tilde} | Ws@27] -> do_parse_inline_ast(Ws@27, [{plain_text, <<"~"/utf8>>} | Acc]); [{lexed_element, greater_than} | Ws@28] -> do_parse_inline_ast(Ws@28, [{plain_text, <<">"/utf8>>} | Acc]); [{lexed_element, less_than} | Ws@29] -> do_parse_inline_ast(Ws@29, [{plain_text, <<"<"/utf8>>} | Acc]); [{lexed_element, {white_space, T}} | Ws@30] -> do_parse_inline_ast(Ws@30, [{plain_text, T} | Acc]); [{lexed_element, {word, T@1}} | Ws@31] -> do_parse_inline_ast(Ws@31, [{plain_text, T@1} | Acc]) end. -spec parse_text(binary()) -> list(commonmark@ast:inline_node()). parse_text(Text) -> _pipe = Text, _pipe@1 = gleam@string:to_graphemes(_pipe), _pipe@2 = do_lex_inline_text(_pipe@1, []), _pipe@3 = do_parse_inline_wrappers(_pipe@2, []), _pipe@4 = do_late_binding(_pipe@3, []), _pipe@5 = do_parse_inline_ast(_pipe@4, []), do_finalise_plain_text(_pipe@5, [], true).