Skip to main content

src/molt@internal@parser@core.erl

-module(molt@internal@parser@core).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/parser/core.gleam").
-export([new_state/1, peek_first_significant/1, take_ws/1, scan_ws/2, tokenize_value/1, flush_current_table/1, finalize/1, peel_head_block/1, peel_trailing_comment_rev/1]).
-export_type([splitters/0, current_table/0, state/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(false).

-type splitters() :: {splitters,
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter()}.

-type current_table() :: no_table |
    {building,
        molt@types:toml_kind(),
        list(greenwood:element(molt@types:toml_kind())),
        list(greenwood:token(molt@types:toml_kind())),
        list(greenwood:token(molt@types:toml_kind()))}.

-type state() :: {state,
        splitters(),
        list(greenwood:token(molt@types:toml_kind())),
        list(greenwood:token(molt@types:toml_kind())),
        list(greenwood:token(molt@types:toml_kind())),
        list(greenwood:element(molt@types:toml_kind())),
        current_table(),
        {ok, nil} | {error, molt@error:molt_error()}}.

-file("src/molt/internal/parser/core.gleam", 335).
?DOC(false).
-spec new_splitters() -> splitters().
new_splitters() ->
    {splitters,
        splitter:new([<<"\r\n"/utf8>>, <<"\n"/utf8>>, <<"\r"/utf8>>]),
        splitter:new(
            [<<"="/utf8>>,
                <<"."/utf8>>,
                <<" "/utf8>>,
                <<"\t"/utf8>>,
                <<"\""/utf8>>,
                <<"'"/utf8>>,
                <<"["/utf8>>,
                <<"]"/utf8>>,
                <<"#"/utf8>>]
        ),
        splitter:new(
            [<<","/utf8>>,
                <<"["/utf8>>,
                <<"]"/utf8>>,
                <<"{"/utf8>>,
                <<"}"/utf8>>,
                <<"\""/utf8>>,
                <<"'"/utf8>>,
                <<"#"/utf8>>,
                <<" "/utf8>>,
                <<"\t"/utf8>>,
                <<"="/utf8>>]
        ),
        splitter:new([<<"\\"/utf8>>, <<"\""/utf8>>]),
        splitter:new([<<"'"/utf8>>]),
        splitter:new([<<"\"\"\""/utf8>>, <<"\\"/utf8>>]),
        splitter:new([<<"'''"/utf8>>])}.

-file("src/molt/internal/parser/core.gleam", 60).
?DOC(false).
-spec new_state(binary()) -> state().
new_state(Bom) ->
    Bom@1 = case Bom of
        <<"\x{FEFF}"/utf8>> ->
            [greenwood:token(bom, <<"\x{FEFF}"/utf8>>)];

        _ ->
            []
    end,
    {state, new_splitters(), [], [], Bom@1, [], no_table, {ok, nil}}.

-file("src/molt/internal/parser/core.gleam", 77).
?DOC(false).
-spec peek_first_significant(binary()) -> binary().
peek_first_significant(Line) ->
    case Line of
        <<" "/utf8, R/binary>> ->
            peek_first_significant(R);

        <<"\t"/utf8, R/binary>> ->
            peek_first_significant(R);

        _ ->
            Line
    end.

-file("src/molt/internal/parser/core.gleam", 310).
?DOC(false).
-spec do_scan_ws(binary(), list(binary())) -> {binary(), binary()}.
do_scan_ws(Input, Acc) ->
    case {Input, Acc} of
        {<<" "/utf8, Rest/binary>>, _} ->
            do_scan_ws(Rest, [<<" "/utf8>> | Acc]);

        {<<"\t"/utf8, Rest@1/binary>>, _} ->
            do_scan_ws(Rest@1, [<<"\t"/utf8>> | Acc]);

        {_, []} ->
            {<<""/utf8>>, Input};

        {_, _} ->
            {molt@internal@utils:reverse_concat(Acc), Input}
    end.

-file("src/molt/internal/parser/core.gleam", 86).
?DOC(false).
-spec take_ws(binary()) -> {binary(), binary()}.
take_ws(Input) ->
    do_scan_ws(Input, []).

-file("src/molt/internal/parser/core.gleam", 93).
?DOC(false).
-spec scan_ws(binary(), binary()) -> {binary(), binary()}.
scan_ws(First, Rest) ->
    do_scan_ws(Rest, [First]).

-file("src/molt/internal/parser/core.gleam", 99).
?DOC(false).
-spec tokenize_value(binary()) -> greenwood:token(molt@types:toml_kind()).
tokenize_value(Text) ->
    _pipe = molt@internal@classifier:match_type(Text),
    _pipe@1 = gleam@option:map(
        _pipe,
        fun(_capture) -> greenwood:token(_capture, Text) end
    ),
    gleam@option:lazy_unwrap(
        _pipe@1,
        fun() -> greenwood:token(invalid_value, Text) end
    ).

-file("src/molt/internal/parser/core.gleam", 145).
?DOC(false).
-spec prepend_bom(
    greenwood:node_(molt@types:toml_kind()),
    list(greenwood:token(molt@types:toml_kind()))
) -> greenwood:node_(molt@types:toml_kind()).
prepend_bom(Node, Bom) ->
    case Bom of
        [] ->
            Node;

        _ ->
            {Leading@1, Trailing@1} = case erlang:element(4, Node) of
                bare ->
                    {[], []};

                {trivia, Leading, Trailing} ->
                    {Leading, Trailing}
            end,
            {node,
                erlang:element(2, Node),
                erlang:element(3, Node),
                {trivia, lists:append(Bom, Leading@1), Trailing@1}}
    end.

-file("src/molt/internal/parser/core.gleam", 303).
?DOC(false).
-spec reverse_element(greenwood:element(molt@types:toml_kind())) -> greenwood:element(molt@types:toml_kind()).
reverse_element(El) ->
    case El of
        {token_element, _} ->
            El;

        {node_element, N} ->
            {node_element, reverse_tree(N)}
    end.

-file("src/molt/internal/parser/core.gleam", 289).
?DOC(false).
-spec reverse_tree(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
reverse_tree(Node) ->
    Children = begin
        _pipe = erlang:element(3, Node),
        _pipe@1 = lists:reverse(_pipe),
        gleam@list:map(_pipe@1, fun reverse_element/1)
    end,
    Trivia = case erlang:element(4, Node) of
        bare ->
            bare;

        {trivia, L, T} ->
            {trivia, lists:reverse(L), lists:reverse(T)}
    end,
    {node, erlang:element(2, Node), Children, Trivia}.

-file("src/molt/internal/parser/core.gleam", 166).
?DOC(false).
-spec root_node(
    list(greenwood:element(molt@types:toml_kind())),
    list(greenwood:token(molt@types:toml_kind()))
) -> greenwood:node_(molt@types:toml_kind()).
root_node(Children, Leading) ->
    case Leading of
        [] ->
            greenwood:node(root, Children);

        _ ->
            greenwood:node_with_trivia(root, Children, {trivia, Leading, []})
    end.

-file("src/molt/internal/parser/core.gleam", 319).
?DOC(false).
-spec flush_current_table(state()) -> list(greenwood:element(molt@types:toml_kind())).
flush_current_table(State) ->
    case erlang:element(7, State) of
        no_table ->
            erlang:element(6, State);

        {building, Kind, Children, Leading, Trailing} ->
            Trivia = case {Leading, Trailing} of
                {[], []} ->
                    bare;

                {_, _} ->
                    {trivia, Leading, Trailing}
            end,
            [{node_element, greenwood:node_with_trivia(Kind, Children, Trivia)} |
                erlang:element(6, State)]
    end.

-file("src/molt/internal/parser/core.gleam", 105).
?DOC(false).
-spec finalize(state()) -> {ok, greenwood:node_(molt@types:toml_kind())} |
    {error, any()}.
finalize(State) ->
    Doc = flush_current_table(State),
    Node = case {Doc, erlang:element(3, State)} of
        {_, []} ->
            root_node(Doc, erlang:element(4, State));

        {[], Pending} ->
            root_node([], Pending);

        {_, Pending@1} ->
            Postscript = greenwood:node_with_trivia(
                post_script,
                [],
                {trivia, Pending@1, []}
            ),
            root_node(
                [{node_element, Postscript} | Doc],
                erlang:element(4, State)
            )
    end,
    _pipe = Node,
    _pipe@1 = reverse_tree(_pipe),
    _pipe@2 = prepend_bom(_pipe@1, erlang:element(5, State)),
    {ok, _pipe@2}.

-file("src/molt/internal/parser/core.gleam", 248).
?DOC(false).
-spec is_comment_line(list(greenwood:token(molt@types:toml_kind()))) -> boolean().
is_comment_line(Line) ->
    gleam@list:any(Line, fun(T) -> erlang:element(2, T) =:= comment end).

-file("src/molt/internal/parser/core.gleam", 239).
?DOC(false).
-spec split_off_node_block(list(list(greenwood:token(molt@types:toml_kind())))) -> {list(list(greenwood:token(molt@types:toml_kind()))),
    list(list(greenwood:token(molt@types:toml_kind())))}.
split_off_node_block(Lines) ->
    Rev = lists:reverse(Lines),
    Node_rev = gleam@list:take_while(Rev, fun is_comment_line/1),
    Root_rev = gleam@list:drop(Rev, erlang:length(Node_rev)),
    {lists:reverse(Root_rev), lists:reverse(Node_rev)}.

-file("src/molt/internal/parser/core.gleam", 211).
?DOC(false).
-spec do_group_lines(
    list(greenwood:token(molt@types:toml_kind())),
    list(greenwood:token(molt@types:toml_kind())),
    list(list(greenwood:token(molt@types:toml_kind())))
) -> list(list(greenwood:token(molt@types:toml_kind()))).
do_group_lines(Tokens, Current_rev, Acc_rev) ->
    case Tokens of
        [] ->
            case Current_rev of
                [] ->
                    lists:reverse(Acc_rev);

                _ ->
                    lists:reverse([lists:reverse(Current_rev) | Acc_rev])
            end;

        [T | Rest] ->
            Current_rev@1 = [T | Current_rev],
            case erlang:element(2, T) of
                newline ->
                    do_group_lines(
                        Rest,
                        [],
                        [lists:reverse(Current_rev@1) | Acc_rev]
                    );

                _ ->
                    do_group_lines(Rest, Current_rev@1, Acc_rev)
            end
    end.

-file("src/molt/internal/parser/core.gleam", 207).
?DOC(false).
-spec group_lines(list(greenwood:token(molt@types:toml_kind()))) -> list(list(greenwood:token(molt@types:toml_kind()))).
group_lines(Tokens) ->
    do_group_lines(Tokens, [], []).

-file("src/molt/internal/parser/core.gleam", 191).
?DOC(false).
-spec peel_head_block(list(greenwood:token(molt@types:toml_kind()))) -> {list(greenwood:token(molt@types:toml_kind())),
    list(greenwood:token(molt@types:toml_kind()))}.
peel_head_block(Pending_rev) ->
    Lines = group_lines(lists:reverse(Pending_rev)),
    {Root_lines, Node_lines} = split_off_node_block(Lines),
    case gleam@list:any(Root_lines, fun is_comment_line/1) of
        false ->
            {[], Pending_rev};

        true ->
            {lists:reverse(lists:append(Root_lines)),
                lists:reverse(lists:append(Node_lines))}
    end.

-file("src/molt/internal/parser/core.gleam", 261).
?DOC(false).
-spec peel_trailing_comment_rev(list(greenwood:element(molt@types:toml_kind()))) -> {list(greenwood:element(molt@types:toml_kind())),
    list(greenwood:token(molt@types:toml_kind()))}.
peel_trailing_comment_rev(Children_rev) ->
    case Children_rev of
        [{token_element, {token, newline, _}} = Nl,
            {token_element, {token, comment, _} = Comment},
            {token_element, {token, whitespace, _} = Ws} |
            Rest] ->
            {[Nl | Rest], [Comment, Ws]};

        [{token_element, {token, newline, _}} = Nl@1,
            {token_element, {token, comment, _} = Comment@1} |
            Rest@1] ->
            {[Nl@1 | Rest@1], [Comment@1]};

        [{token_element, {token, comment, _} = Comment@2},
            {token_element, {token, whitespace, _} = Ws@1} |
            Rest@2] ->
            {Rest@2, [Comment@2, Ws@1]};

        [{token_element, {token, comment, _} = Comment@3} | Rest@3] ->
            {Rest@3, [Comment@3]};

        _ ->
            {Children_rev, []}
    end.