-module(commonmark@internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse_text/1, parse_paragraph/1, parse_block_state/1, parse_blocks/1]). -export_type([parser_state/0, block_parse_state/0]). -type parser_state() :: outside_block | {paragraph_builder, list(binary())} | {code_block_builder, binary(), gleam@option:option(binary()), gleam@option:option(binary()), list(binary())}. -opaque block_parse_state() :: {paragraph, list(binary())} | horizontal_break | {heading, integer(), gleam@option:option(list(binary()))} | {code_block, gleam@option:option(binary()), gleam@option:option(binary()), list(binary())}. -spec parse_text(list(binary())) -> list(commonmark@ast:inline_node()). parse_text(Text) -> Len = erlang:length(Text) - 1, _assert_subject = gleam@regex:from_string(<<"( |\\\\)$"/utf8>>), {ok, Hard_break_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_text"/utf8>>, line => 23}) end, _pipe = Text, _pipe@5 = gleam@list:index_map( _pipe, fun(L, I) -> case gleam@regex:check(Hard_break_regex, L) of _ when I =:= Len -> [{text, begin _pipe@1 = L, gleam@string:trim(_pipe@1) end}]; true -> [{text, begin _pipe@2 = L, _pipe@3 = gleam@string:drop_right(_pipe@2, 1), gleam@string:trim(_pipe@3) end}, hard_line_break]; _ -> [{text, begin _pipe@4 = L, gleam@string:trim(_pipe@4) end}, soft_line_break] end end ), gleam@list:concat(_pipe@5). -spec parse_paragraph(list(binary())) -> commonmark@ast:block_node(). parse_paragraph(Lines) -> _pipe = Lines, _pipe@1 = parse_text(_pipe), {paragraph, _pipe@1}. -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 = lists:reverse(_pipe), _pipe@2 = parse_text(_pipe@1), {paragraph, _pipe@2} end]; {code_block, Info, Full_info, Lines@1} -> [{code_block, Info, Full_info, begin _pipe@3 = Lines@1, _pipe@4 = lists:reverse(_pipe@3), gleam@string:join(_pipe@4, <<"\n"/utf8>>) end}]; horizontal_break -> [horizontal_break]; {heading, Level, {some, Contents}} -> [{heading, Level, parse_text(Contents)}]; {heading, Level@1, none} -> [{heading, Level@1, parse_text([])}] end. -spec do_parse_blocks(parser_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 => 62}) 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 => 66}) 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 => 68}) end, _assert_subject@3 = case State of {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 => 70}) 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)} of {{paragraph_builder, Lines@1}, [], _, _, _, _} -> _pipe@1 = [{paragraph, Lines@1} | Acc], lists:reverse(_pipe@1); {{code_block_builder, _, Info, Full_info, Contents}, [<<""/utf8>>], _, _, _, _} -> _pipe@2 = [{code_block, Info, Full_info, [<<""/utf8>> | Contents]} | Acc], lists:reverse(_pipe@2); {{code_block_builder, _, Info, Full_info, Contents}, [], _, _, _, _} -> _pipe@2 = [{code_block, Info, Full_info, [<<""/utf8>> | Contents]} | Acc], lists:reverse(_pipe@2); {outside_block, [], _, _, _, _} -> _pipe@3 = Acc, lists:reverse(_pipe@3); {{paragraph_builder, Bs}, [<<" "/utf8>> | Ls], _, _, _, _} -> do_parse_blocks(outside_block, [{paragraph, Bs} | Acc], Ls); {{paragraph_builder, Bs}, [<<"\\"/utf8>> | Ls], _, _, _, _} -> do_parse_blocks(outside_block, [{paragraph, Bs} | Acc], Ls); {{paragraph_builder, Bs}, [<<""/utf8>> | Ls], _, _, _, _} -> do_parse_blocks(outside_block, [{paragraph, Bs} | 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); {{paragraph_builder, Bs@1}, [_ | Ls@2], _, _, _, [{match, _, [{some, Exit}]}]} -> do_parse_blocks( {code_block_builder, Exit, none, none, []}, [{paragraph, Bs@1} | Acc], Ls@2 ); {{paragraph_builder, Bs@2}, [_ | Ls@3], _, _, _, [{match, _, [{some, Exit@1}, Full_info@1, Info@1]}]} -> do_parse_blocks( {code_block_builder, Exit@1, Info@1, Full_info@1, []}, [{paragraph, Bs@2} | Acc], Ls@3 ); {outside_block, [_ | Ls@4], _, _, _, [{match, _, [{some, Exit@2}]}]} -> do_parse_blocks( {code_block_builder, Exit@2, none, none, []}, Acc, Ls@4 ); {outside_block, [_ | Ls@5], _, _, _, [{match, _, [{some, Exit@3}, Full_info@2, Info@2]}]} -> do_parse_blocks( {code_block_builder, Exit@3, Info@2, Full_info@2, []}, Acc, Ls@5 ); {{code_block_builder, _, Info@3, Full_info@3, Bs@3}, [_ | Ls@6], _, _, _, [{match, _, _}]} -> do_parse_blocks( outside_block, [{code_block, Info@3, Full_info@3, [<<""/utf8>> | Bs@3]} | Acc], Ls@6 ); {{code_block_builder, Break@1, Info@4, Full_info@4, Bs@4}, [L@1 | Ls@7], _, _, _, _} -> do_parse_blocks( {code_block_builder, Break@1, Info@4, Full_info@4, [L@1 | Bs@4]}, Acc, Ls@7 ); {{paragraph_builder, Bs@5}, [_ | Ls@8], _, _, [{match, _, [{some, <<"="/utf8>>}]}], _} -> do_parse_blocks( outside_block, [{heading, 1, {some, lists:reverse(Bs@5)}} | Acc], Ls@8 ); {{paragraph_builder, Bs@6}, [_ | Ls@9], _, _, [{match, _, [{some, <<"-"/utf8>>}]}], _} -> do_parse_blocks( outside_block, [{heading, 2, {some, lists:reverse(Bs@6)}} | Acc], Ls@9 ); {{paragraph_builder, Bs@7}, [_ | Ls@10], true, _, _, _} -> do_parse_blocks( outside_block, [horizontal_break, {paragraph, Bs@7} | Acc], Ls@10 ); {outside_block, [_ | Ls@11], true, _, _, _} -> do_parse_blocks(outside_block, [horizontal_break | Acc], Ls@11); {outside_block, [_ | Ls@12], _, [{match, _, [{some, Heading}]}], _, _} -> do_parse_blocks( outside_block, [{heading, gleam@string:length(Heading), none} | Acc], Ls@12 ); {outside_block, [_ | Ls@13], _, [{match, _, [{some, Heading@1}, {some, Contents@1}]}], _, _} -> do_parse_blocks( outside_block, [{heading, gleam@string:length(Heading@1), {some, [Contents@1]}} | Acc], Ls@13 ); {{paragraph_builder, Bs@8}, [_ | Ls@14], _, [{match, _, [{some, Heading@2}]}], _, _} -> do_parse_blocks( outside_block, [{heading, gleam@string:length(Heading@2), none}, {paragraph, Bs@8} | Acc], Ls@14 ); {{paragraph_builder, Bs@9}, [_ | Ls@15], _, [{match, _, [{some, Heading@3}, {some, Contents@2}]}], _, _} -> do_parse_blocks( outside_block, [{heading, gleam@string:length(Heading@3), {some, [Contents@2]}}, {paragraph, Bs@9} | Acc], Ls@15 ); {outside_block, [Line | Ls@16], _, _, _, _} -> do_parse_blocks({paragraph_builder, [Line]}, Acc, Ls@16); {{paragraph_builder, Bs@10}, [Line@1 | Ls@17], _, _, _, _} -> do_parse_blocks({paragraph_builder, [Line@1 | Bs@10]}, Acc, Ls@17) end. -spec parse_blocks(list(binary())) -> list(block_parse_state()). parse_blocks(Lines) -> do_parse_blocks(outside_block, [], Lines).