Skip to main content

src/molt@internal@validate.erl

-module(molt@internal@validate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/validate.gleam").
-export([count/1, enrich/1]).
-export_type([path_entry/0, value_kind/0, pos/0, collector/1, state/1]).

-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 path_entry() :: {explicit_table, molt@types:span()} |
    {explicit_array_of_tables, integer(), molt@types:span()} |
    {header_implicit, molt@types:span()} |
    {dotted_implicit, molt@types:span()} |
    {closed_implicit, molt@types:span()} |
    {explicit_scalar, molt@types:span()} |
    {explicit_inline_table, molt@types:span()} |
    {explicit_inline_array, molt@types:span()}.

-type value_kind() :: scalar_value | inline_table_value | inline_array_value.

-type pos() :: {pos, integer(), integer(), integer()}.

-type collector(INE) :: {collector,
        INE,
        boolean(),
        fun((INE, fun(() -> molt@types:syntax_error())) -> INE)}.

-type state(INF) :: {state,
        collector(INF),
        INF,
        pos(),
        list(binary()),
        list(list(binary())),
        gleam@dict:dict(list(binary()), path_entry()),
        gleam@dict:dict(list(binary()), integer()),
        integer()}.

-file("src/molt/internal/validate.gleam", 292).
?DOC(false).
-spec pop_path(state(IOD)) -> state(IOD).
pop_path(State) ->
    case erlang:element(6, State) of
        [Parent | Rest] ->
            {state,
                erlang:element(2, State),
                erlang:element(3, State),
                erlang:element(4, State),
                Parent,
                Rest,
                erlang:element(7, State),
                erlang:element(8, State),
                erlang:element(9, State)};

        [] ->
            State
    end.

-file("src/molt/internal/validate.gleam", 272).
?DOC(false).
-spec exit_node(state(INV), greenwood:node_(molt@types:toml_kind())) -> state(INV).
exit_node(State, Node) ->
    gleam@bool:guard(
        erlang:element(2, Node) =:= root,
        State,
        fun() ->
            gleam@bool:guard(
                erlang:element(2, Node) =:= error,
                {state,
                    erlang:element(2, State),
                    erlang:element(3, State),
                    erlang:element(4, State),
                    erlang:element(5, State),
                    erlang:element(6, State),
                    erlang:element(7, State),
                    erlang:element(8, State),
                    erlang:element(9, State) - 1},
                fun() ->
                    State@1 = case erlang:element(2, Node) of
                        array ->
                            {state,
                                erlang:element(2, State),
                                erlang:element(3, State),
                                erlang:element(4, State),
                                erlang:element(5, State),
                                erlang:element(6, State),
                                erlang:element(7, State),
                                erlang:element(8, State),
                                erlang:element(9, State) - 1};

                        inline_table ->
                            {state,
                                erlang:element(2, State),
                                erlang:element(3, State),
                                erlang:element(4, State),
                                erlang:element(5, State),
                                erlang:element(6, State),
                                erlang:element(7, State),
                                erlang:element(8, State),
                                erlang:element(9, State) - 1};

                        _ ->
                            State
                    end,
                    pop_path(State@1)
                end
            )
        end
    ).

-file("src/molt/internal/validate.gleam", 288).
?DOC(false).
-spec push_path(state(INZ), list(binary())) -> state(INZ).
push_path(State, New_path) ->
    {state,
        erlang:element(2, State),
        erlang:element(3, State),
        erlang:element(4, State),
        New_path,
        [erlang:element(5, State) | erlang:element(6, State)],
        erlang:element(7, State),
        erlang:element(8, State),
        erlang:element(9, State)}.

-file("src/molt/internal/validate.gleam", 388).
?DOC(false).
-spec pos_span(pos()) -> molt@types:span().
pos_span(Pos) ->
    {span,
        erlang:element(2, Pos),
        erlang:element(3, Pos),
        erlang:element(4, Pos)}.

-file("src/molt/internal/validate.gleam", 380).
?DOC(false).
-spec make_error(state(any()), molt@types:syntax_error_kind(), list(binary())) -> molt@types:syntax_error().
make_error(State, Kind, Path) ->
    {syntax_error, Kind, Path, pos_span(erlang:element(4, State))}.

-file("src/molt/internal/validate.gleam", 190).
?DOC(false).
-spec emit(state(INO), fun(() -> molt@types:syntax_error())) -> state(INO).
emit(State, Build) ->
    {state,
        erlang:element(2, State),
        (erlang:element(4, erlang:element(2, State)))(
            erlang:element(3, State),
            Build
        ),
        erlang:element(4, State),
        erlang:element(5, State),
        erlang:element(6, State),
        erlang:element(7, State),
        erlang:element(8, State),
        erlang:element(9, State)}.

-file("src/molt/internal/validate.gleam", 724).
?DOC(false).
-spec push_error(state(IQS), molt@types:syntax_error_kind(), list(binary())) -> state(IQS).
push_error(State, Kind, Path) ->
    emit(State, fun() -> make_error(State, Kind, Path) end).

-file("src/molt/internal/validate.gleam", 1039).
?DOC(false).
-spec do_inline_commas_ok(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> boolean().
do_inline_commas_ok(Children, Seen_entry) ->
    case Children of
        [] ->
            true;

        [{token_element, {token, left_brace, _}} | Rest] ->
            do_inline_commas_ok(Rest, false);

        [{token_element, {token, right_brace, _}} | Rest@1] ->
            do_inline_commas_ok(Rest@1, false);

        [{token_element, {token, comma, _}} | Rest@2] ->
            case Seen_entry of
                true ->
                    do_inline_commas_ok(Rest@2, false);

                false ->
                    false
            end;

        [{token_element, {token, whitespace, _}} | Rest@3] ->
            do_inline_commas_ok(Rest@3, Seen_entry);

        [{token_element, {token, newline, _}} | Rest@3] ->
            do_inline_commas_ok(Rest@3, Seen_entry);

        [{token_element, {token, comment, _}} | Rest@3] ->
            do_inline_commas_ok(Rest@3, Seen_entry);

        [_ | Rest@4] ->
            do_inline_commas_ok(Rest@4, true)
    end.

-file("src/molt/internal/validate.gleam", 1035).
?DOC(false).
-spec inline_table_commas_ok(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
inline_table_commas_ok(Children) ->
    do_inline_commas_ok(Children, false).

-file("src/molt/internal/validate.gleam", 1066).
?DOC(false).
-spec do_inline_bare_ok(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> boolean().
do_inline_bare_ok(Children, After_eq) ->
    case Children of
        [] ->
            true;

        [{token_element, {token, equals, _}} | Rest] ->
            do_inline_bare_ok(Rest, true);

        [{token_element, {token, comma, _}} | Rest@1] ->
            do_inline_bare_ok(Rest@1, false);

        [{token_element, {token, invalid_value, _}} | _] ->
            false;

        [{token_element, {token, invalid_basic_string, _}} | _] ->
            false;

        [{token_element, {token, invalid_literal_string, _}} | _] ->
            false;

        [{token_element, {token, invalid_multiline_basic_string, _}} | _] ->
            false;

        [{token_element, {token, invalid_multiline_literal_string, _}} | _] ->
            false;

        [{token_element, {token, bare_key, _}} | _] when After_eq ->
            false;

        [_ | Rest@2] ->
            do_inline_bare_ok(Rest@2, After_eq)
    end.

-file("src/molt/internal/validate.gleam", 1062).
?DOC(false).
-spec inline_table_bare_values_ok(
    list(greenwood:element(molt@types:toml_kind()))
) -> boolean().
inline_table_bare_values_ok(Children) ->
    do_inline_bare_ok(Children, false).

-file("src/molt/internal/validate.gleam", 392).
?DOC(false).
-spec entry_span(path_entry()) -> molt@types:span().
entry_span(Entry) ->
    case Entry of
        {explicit_table, Span} ->
            Span;

        {explicit_array_of_tables, _, Span@1} ->
            Span@1;

        {header_implicit, Span@2} ->
            Span@2;

        {dotted_implicit, Span@3} ->
            Span@3;

        {closed_implicit, Span@4} ->
            Span@4;

        {explicit_scalar, Span@5} ->
            Span@5;

        {explicit_inline_table, Span@6} ->
            Span@6;

        {explicit_inline_array, Span@7} ->
            Span@7
    end.

-file("src/molt/internal/validate.gleam", 674).
?DOC(false).
-spec value_kind_entry(value_kind(), pos()) -> path_entry().
value_kind_entry(Value_kind, Pos) ->
    Span = pos_span(Pos),
    case Value_kind of
        scalar_value ->
            {explicit_scalar, Span};

        inline_table_value ->
            {explicit_inline_table, Span};

        inline_array_value ->
            {explicit_inline_array, Span}
    end.

-file("src/molt/internal/validate.gleam", 1230).
?DOC(false).
-spec last_or_empty(list(binary())) -> binary().
last_or_empty(L) ->
    _pipe = gleam@list:last(L),
    gleam@result:unwrap(_pipe, <<""/utf8>>).

-file("src/molt/internal/validate.gleam", 1222).
?DOC(false).
-spec list_init(list(binary())) -> list(binary()).
list_init(L) ->
    case L of
        [] ->
            [];

        [_] ->
            [];

        _ ->
            gleam@list:take(L, erlang:length(L) - 1)
    end.

-file("src/molt/internal/validate.gleam", 686).
?DOC(false).
-spec emit_descent_error(
    state(IQJ),
    list(binary()),
    fun((binary()) -> molt@types:syntax_error_kind())
) -> state(IQJ).
emit_descent_error(State, Prefix, Kind_with_key) ->
    Key = last_or_empty(Prefix),
    Parent = list_init(Prefix),
    emit(State, fun() -> make_error(State, Kind_with_key(Key), Parent) end).

-file("src/molt/internal/validate.gleam", 619).
?DOC(false).
-spec register_dotted_implicit_parents(state(IQD), list(list(binary()))) -> state(IQD).
register_dotted_implicit_parents(State, Parent_paths) ->
    Span = pos_span(erlang:element(4, State)),
    gleam@list:fold(
        Parent_paths,
        State,
        fun(State@1, Prefix) ->
            case gleam_stdlib:map_get(erlang:element(7, State@1), Prefix) of
                {error, nil} ->
                    {state,
                        erlang:element(2, State@1),
                        erlang:element(3, State@1),
                        erlang:element(4, State@1),
                        erlang:element(5, State@1),
                        erlang:element(6, State@1),
                        gleam@dict:insert(
                            erlang:element(7, State@1),
                            Prefix,
                            {dotted_implicit, Span}
                        ),
                        erlang:element(8, State@1),
                        erlang:element(9, State@1)};

                {ok, {dotted_implicit, _}} ->
                    State@1;

                {ok, {explicit_scalar, Original}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key) -> {key_is_scalar, Key, Original} end
                    );

                {ok, {explicit_inline_table, Original@1}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key@1) ->
                            {key_is_inline_table, Key@1, Original@1}
                        end
                    );

                {ok, {explicit_inline_array, Original@2}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key@2) -> {key_is_array, Key@2, Original@2} end
                    );

                {ok, Entry} ->
                    Original@3 = entry_span(Entry),
                    emit(
                        State@1,
                        fun() ->
                            make_error(
                                State@1,
                                {duplicate_table, Original@3},
                                Prefix
                            )
                        end
                    )
            end
        end
    ).

-file("src/molt/internal/validate.gleam", 558).
?DOC(false).
-spec register_kv_path(state(IPU), list(binary()), list(binary()), value_kind()) -> state(IPU).
register_kv_path(State, Table_path, Segments, Value_kind) ->
    Full_path = lists:append(Table_path, Segments),
    Table_len = erlang:length(Table_path),
    Dotted_prefixes = gleam@list:drop(
        molt@internal@utils:all_prefixes(Full_path),
        Table_len
    ),
    State@1 = register_dotted_implicit_parents(State, Dotted_prefixes),
    Key = last_or_empty(Segments),
    Entry = value_kind_entry(Value_kind, erlang:element(4, State@1)),
    case gleam_stdlib:map_get(erlang:element(7, State@1), Full_path) of
        {error, nil} ->
            {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                gleam@dict:insert(erlang:element(7, State@1), Full_path, Entry),
                erlang:element(8, State@1),
                erlang:element(9, State@1)};

        {ok, Existing} ->
            Original = entry_span(Existing),
            State@2 = {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                gleam@dict:insert(erlang:element(7, State@1), Full_path, Entry),
                erlang:element(8, State@1),
                erlang:element(9, State@1)},
            emit(
                State@2,
                fun() ->
                    make_error(
                        State@2,
                        {duplicate_key, Key, Original},
                        Table_path
                    )
                end
            )
    end.

-file("src/molt/internal/validate.gleam", 128).
?DOC(false).
-spec enrich_collector() -> collector(list(molt@types:syntax_error())).
enrich_collector() ->
    {collector, [], true, fun(Errors, Build) -> [Build() | Errors] end}.

-file("src/molt/internal/validate.gleam", 1212).
?DOC(false).
-spec skip_inline_value(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
skip_inline_value(Children) ->
    case molt@internal@cst@elements:skip_all_trivia(Children) of
        [] ->
            [];

        [{node_element, _} | Rest] ->
            Rest;

        [{token_element, _} | Rest@1] ->
            Rest@1
    end.

-file("src/molt/internal/validate.gleam", 1202).
?DOC(false).
-spec skip_to_equals_value(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
skip_to_equals_value(Children) ->
    case Children of
        [] ->
            [];

        [{token_element, {token, equals, _}} | Rest] ->
            Rest;

        [_ | Rest@1] ->
            skip_to_equals_value(Rest@1)
    end.

-file("src/molt/internal/validate.gleam", 1154).
?DOC(false).
-spec take_inline_key_segments(
    list(greenwood:element(molt@types:toml_kind())),
    list(binary())
) -> {list(binary()), list(greenwood:element(molt@types:toml_kind()))}.
take_inline_key_segments(Children, Acc) ->
    case molt@internal@cst@elements:skip_all_trivia(Children) of
        [] ->
            {lists:reverse(Acc), []};

        [{token_element, {token, equals, _}} | _] = Rest ->
            {lists:reverse(Acc), Rest};

        [{token_element, {token, bare_key, Text}} | Rest@1] ->
            Segs = begin
                _pipe = gleam@string:split(Text, <<"."/utf8>>),
                gleam@list:filter(_pipe, fun(S) -> S /= <<""/utf8>> end)
            end,
            take_inline_key_segments(
                Rest@1,
                lists:append(lists:reverse(Segs), Acc)
            );

        [{token_element, {token, integer, Text@1}} | Rest@2] ->
            take_inline_key_segments(Rest@2, [Text@1 | Acc]);

        [{token_element, {token, basic_string, Text@2}} | Rest@3] ->
            take_inline_key_segments(
                Rest@3,
                [molt@internal@utils:unescape_basic_string(Text@2) | Acc]
            );

        [{token_element, {token, literal_string, Text@3}} | Rest@4] ->
            take_inline_key_segments(Rest@4, [Text@3 | Acc]);

        [{token_element, {token, dot, _}} | Rest@5] ->
            take_inline_key_segments(Rest@5, Acc);

        [_ | Rest@6] ->
            take_inline_key_segments(Rest@6, Acc)
    end.

-file("src/molt/internal/validate.gleam", 1177).
?DOC(false).
-spec take_inline_key_segments_from_kv(
    list(greenwood:element(molt@types:toml_kind())),
    list(binary())
) -> list(binary()).
take_inline_key_segments_from_kv(Children, Acc) ->
    case Children of
        [] ->
            lists:reverse(Acc);

        [{token_element, {token, equals, _}} | _] ->
            lists:reverse(Acc);

        [{token_element, {token, whitespace, _}} | Rest] ->
            take_inline_key_segments_from_kv(Rest, Acc);

        [{token_element, {token, dot, _}} | Rest] ->
            take_inline_key_segments_from_kv(Rest, Acc);

        [{token_element, {token, bare_key, Text}} | Rest@1] ->
            take_inline_key_segments_from_kv(Rest@1, [Text | Acc]);

        [{token_element, {token, integer, Text@1}} | Rest@2] ->
            take_inline_key_segments_from_kv(Rest@2, [Text@1 | Acc]);

        [{token_element, {token, basic_string, Text@2}} | Rest@3] ->
            take_inline_key_segments_from_kv(
                Rest@3,
                [molt@internal@utils:unescape_basic_string(Text@2) | Acc]
            );

        [{token_element, {token, literal_string, Text@3}} | Rest@4] ->
            take_inline_key_segments_from_kv(Rest@4, [Text@3 | Acc]);

        [_ | Rest@5] ->
            take_inline_key_segments_from_kv(Rest@5, Acc)
    end.

-file("src/molt/internal/validate.gleam", 1125).
?DOC(false).
-spec extract_inline_key_paths(
    list(greenwood:element(molt@types:toml_kind())),
    list(list(binary()))
) -> list(list(binary())).
extract_inline_key_paths(Children, Acc) ->
    case molt@internal@cst@elements:skip_all_trivia(Children) of
        [] ->
            lists:reverse(Acc);

        [{token_element, {token, left_brace, _}} | Rest] ->
            extract_inline_key_paths(Rest, Acc);

        [{token_element, {token, right_brace, _}} | _] ->
            lists:reverse(Acc);

        [{token_element, {token, comma, _}} | Rest@1] ->
            extract_inline_key_paths(Rest@1, Acc);

        [{node_element, N} | Rest@2] when erlang:element(2, N) =:= key_value ->
            case take_inline_key_segments_from_kv(erlang:element(3, N), []) of
                [] ->
                    extract_inline_key_paths(Rest@2, Acc);

                Segments ->
                    extract_inline_key_paths(Rest@2, [Segments | Acc])
            end;

        Rest@3 ->
            {Segments@1, After_key} = take_inline_key_segments(Rest@3, []),
            After_eq = skip_to_equals_value(After_key),
            After_value = skip_inline_value(After_eq),
            case Segments@1 of
                [] ->
                    extract_inline_key_paths(After_value, Acc);

                _ ->
                    extract_inline_key_paths(After_value, [Segments@1 | Acc])
            end
    end.

-file("src/molt/internal/validate.gleam", 1088).
?DOC(false).
-spec inline_table_first_duplicate_key(
    list(greenwood:element(molt@types:toml_kind()))
) -> gleam@option:option(binary()).
inline_table_first_duplicate_key(Children) ->
    Key_paths = extract_inline_key_paths(Children, []),
    State = {state,
        enrich_collector(),
        [],
        {pos, 0, 0, 0},
        [],
        [],
        maps:new(),
        maps:new(),
        0},
    State@2 = gleam@list:fold(
        Key_paths,
        State,
        fun(State@1, Segments) ->
            register_kv_path(State@1, [], Segments, scalar_value)
        end
    ),
    _pipe = lists:reverse(erlang:element(3, State@2)),
    _pipe@1 = gleam@list:find_map(
        _pipe,
        fun(Err) -> case erlang:element(2, Err) of
                {duplicate_key, Key, _} ->
                    {ok, Key};

                {key_is_scalar, Key, _} ->
                    {ok, Key};

                {key_is_inline_table, Key, _} ->
                    {ok, Key};

                {key_is_array, Key, _} ->
                    {ok, Key};

                _ ->
                    {error, nil}
            end end
    ),
    gleam@option:from_result(_pipe@1).

-file("src/molt/internal/validate.gleam", 1026).
?DOC(false).
-spec inline_table_is_closed(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
inline_table_is_closed(Children) ->
    gleam@list:any(Children, fun(El) -> case El of
                {token_element, {token, right_brace, _}} ->
                    true;

                _ ->
                    false
            end end).

-file("src/molt/internal/validate.gleam", 770).
?DOC(false).
-spec check_inline_table_syntax(
    state(IRG),
    greenwood:node_(molt@types:toml_kind()),
    list(binary())
) -> state(IRG).
check_inline_table_syntax(State, Node, Path) ->
    State@1 = case inline_table_is_closed(erlang:element(3, Node)) of
        true ->
            State;

        false ->
            push_error(State, unterminated_inline_table, Path)
    end,
    State@2 = case inline_table_first_duplicate_key(erlang:element(3, Node)) of
        none ->
            State@1;

        {some, Key} ->
            push_error(State@1, {duplicate_key_in_inline_table, Key}, Path)
    end,
    State@3 = case inline_table_bare_values_ok(erlang:element(3, Node)) of
        true ->
            State@2;

        false ->
            push_error(State@2, invalid_bare_value_in_inline_table, Path)
    end,
    case inline_table_commas_ok(erlang:element(3, Node)) of
        true ->
            State@3;

        false ->
            push_error(State@3, misplaced_inline_table_separator, Path)
    end.

-file("src/molt/internal/validate.gleam", 1011).
?DOC(false).
-spec do_element_value_count(
    list(greenwood:element(molt@types:toml_kind())),
    integer()
) -> boolean().
do_element_value_count(Children, Count) ->
    case Children of
        [] ->
            Count =:= 1;

        [{token_element, {token, whitespace, _}} | Rest] ->
            do_element_value_count(Rest, Count);

        [{token_element, {token, newline, _}} | Rest] ->
            do_element_value_count(Rest, Count);

        [{token_element, {token, comment, _}} | Rest] ->
            do_element_value_count(Rest, Count);

        [{token_element, {token, comma, _}} | Rest] ->
            do_element_value_count(Rest, Count);

        [_ | Rest@1] ->
            do_element_value_count(Rest@1, Count + 1)
    end.

-file("src/molt/internal/validate.gleam", 1007).
?DOC(false).
-spec element_has_single_value(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
element_has_single_value(Children) ->
    do_element_value_count(Children, 0).

-file("src/molt/internal/validate.gleam", 990).
?DOC(false).
-spec do_array_seps_ok(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
do_array_seps_ok(Children) ->
    case Children of
        [] ->
            true;

        [{token_element, {token, right_bracket, _}} | _] ->
            true;

        [{token_element, {token, left_bracket, _}} | Rest] ->
            do_array_seps_ok(Rest);

        [{token_element, {token, whitespace, _}} | Rest@1] ->
            do_array_seps_ok(Rest@1);

        [{token_element, {token, newline, _}} | Rest@1] ->
            do_array_seps_ok(Rest@1);

        [{token_element, {token, comment, _}} | Rest@1] ->
            do_array_seps_ok(Rest@1);

        [{node_element, N} | Rest@2] when erlang:element(2, N) =:= array_element ->
            gleam@bool:guard(
                not element_has_single_value(erlang:element(3, N)),
                false,
                fun() -> do_array_seps_ok(Rest@2) end
            );

        [{token_element, {token, comma, _}} | _] ->
            false;

        [_ | _] ->
            false
    end.

-file("src/molt/internal/validate.gleam", 986).
?DOC(false).
-spec array_separators_ok(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
array_separators_ok(Children) ->
    do_array_seps_ok(Children).

-file("src/molt/internal/validate.gleam", 977).
?DOC(false).
-spec array_is_closed(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
array_is_closed(Children) ->
    gleam@list:any(Children, fun(El) -> case El of
                {token_element, {token, right_bracket, _}} ->
                    true;

                _ ->
                    false
            end end).

-file("src/molt/internal/validate.gleam", 753).
?DOC(false).
-spec check_array_syntax(
    state(IRB),
    greenwood:node_(molt@types:toml_kind()),
    list(binary())
) -> state(IRB).
check_array_syntax(State, Node, Path) ->
    State@1 = case array_is_closed(erlang:element(3, Node)) of
        true ->
            State;

        false ->
            push_error(State, unterminated_array, Path)
    end,
    gleam@bool:guard(
        array_separators_ok(erlang:element(3, Node)),
        State@1,
        fun() -> push_error(State@1, misplaced_array_separator, Path) end
    ).

-file("src/molt/internal/validate.gleam", 865).
?DOC(false).
-spec do_has_single_value(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> boolean().
do_has_single_value(Children, Saw_value) ->
    case Children of
        [] ->
            true;

        [{token_element, {token, whitespace, _}} | Rest] ->
            do_has_single_value(Rest, Saw_value);

        [{token_element, {token, newline, _}} | Rest] ->
            do_has_single_value(Rest, Saw_value);

        [{token_element, {token, comment, _}} | Rest] ->
            do_has_single_value(Rest, Saw_value);

        [{token_element, {token, comma, _}} | Rest] ->
            do_has_single_value(Rest, Saw_value);

        [_ | Rest@1] ->
            gleam@bool:guard(
                Saw_value,
                false,
                fun() -> do_has_single_value(Rest@1, true) end
            )
    end.

-file("src/molt/internal/validate.gleam", 861).
?DOC(false).
-spec has_single_value(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
has_single_value(Value_tokens) ->
    do_has_single_value(Value_tokens, false).

-file("src/molt/internal/validate.gleam", 852).
?DOC(false).
-spec has_extra_equals(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
has_extra_equals(Value_tokens) ->
    gleam@list:any(Value_tokens, fun(El) -> case El of
                {token_element, {token, equals, _}} ->
                    true;

                _ ->
                    false
            end end).

-file("src/molt/internal/validate.gleam", 840).
?DOC(false).
-spec has_value(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
has_value(Value_tokens) ->
    gleam@list:any(Value_tokens, fun(El) -> case El of
                {token_element, {token, whitespace, _}} ->
                    false;

                {token_element, {token, newline, _}} ->
                    false;

                {token_element, {token, comment, _}} ->
                    false;

                {token_element, {token, equals, _}} ->
                    false;

                _ ->
                    true
            end end).

-file("src/molt/internal/validate.gleam", 800).
?DOC(false).
-spec do_check_key_tokens_ok(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> boolean().
do_check_key_tokens_ok(Children, Seen_key) ->
    case Children of
        [] ->
            Seen_key;

        [{token_element, {token, equals, _}} | _] ->
            Seen_key;

        [{token_element, {token, whitespace, _}} | Rest] ->
            do_check_key_tokens_ok(Rest, Seen_key);

        [{token_element, {token, dot, _}} | Rest@1] ->
            case Seen_key of
                true ->
                    do_check_key_tokens_ok(Rest@1, false);

                false ->
                    false
            end;

        [{token_element, {token, bare_key, Text}} | Rest@2] ->
            case Seen_key of
                true ->
                    false;

                false ->
                    case molt@internal@utils:is_bare_key(Text) of
                        true ->
                            do_check_key_tokens_ok(Rest@2, true);

                        false ->
                            false
                    end
            end;

        [{token_element, {token, integer, _}} | Rest@3] ->
            case Seen_key of
                true ->
                    false;

                false ->
                    do_check_key_tokens_ok(Rest@3, true)
            end;

        [{token_element, {token, basic_string, _}} | Rest@3] ->
            case Seen_key of
                true ->
                    false;

                false ->
                    do_check_key_tokens_ok(Rest@3, true)
            end;

        [{token_element, {token, literal_string, _}} | Rest@3] ->
            case Seen_key of
                true ->
                    false;

                false ->
                    do_check_key_tokens_ok(Rest@3, true)
            end;

        [{node_element, N} | Rest@4] when erlang:element(2, N) =:= key ->
            case check_key_tokens_ok(N) of
                true ->
                    do_check_key_tokens_ok(Rest@4, true);

                false ->
                    false
            end;

        _ ->
            false
    end.

-file("src/molt/internal/validate.gleam", 796).
?DOC(false).
-spec check_key_tokens_ok(greenwood:node_(molt@types:toml_kind())) -> boolean().
check_key_tokens_ok(Kv) ->
    do_check_key_tokens_ok(erlang:element(3, Kv), false).

-file("src/molt/internal/validate.gleam", 698).
?DOC(false).
-spec check_kv_syntax(
    state(IQN),
    greenwood:node_(molt@types:toml_kind()),
    list(binary())
) -> state(IQN).
check_kv_syntax(State, Node, Path) ->
    State@1 = case check_key_tokens_ok(Node) of
        true ->
            State;

        false ->
            push_error(State, invalid_key_syntax, Path)
    end,
    Value_tokens = molt@internal@cst@elements:value_tokens(
        erlang:element(3, Node)
    ),
    State@2 = case has_value(Value_tokens) of
        true ->
            State@1;

        false ->
            push_error(State@1, missing_value, Path)
    end,
    State@3 = case has_extra_equals(Value_tokens) of
        false ->
            State@2;

        true ->
            push_error(State@2, extra_equals, Path)
    end,
    case has_single_value(Value_tokens) of
        true ->
            State@3;

        false ->
            push_error(State@3, multiple_values, Path)
    end.

-file("src/molt/internal/validate.gleam", 661).
?DOC(false).
-spec kv_value_kind(greenwood:node_(molt@types:toml_kind())) -> value_kind().
kv_value_kind(Kv) ->
    Value_tokens = molt@internal@cst@elements:value_tokens(
        erlang:element(3, Kv)
    ),
    case molt@internal@cst@elements:find_first_value(Value_tokens) of
        {some, {node_element, N}} ->
            case erlang:element(2, N) of
                inline_table ->
                    inline_table_value;

                array ->
                    inline_array_value;

                _ ->
                    scalar_value
            end;

        _ ->
            scalar_value
    end.

-file("src/molt/internal/validate.gleam", 538).
?DOC(false).
-spec register_kv(
    state(IPP),
    list(binary()),
    greenwood:node_(molt@types:toml_kind())
) -> state(IPP).
register_kv(State, Table_path, Kv) ->
    case molt@internal@cst@elements:key_path(erlang:element(3, Kv)) of
        none ->
            emit(
                State,
                fun() -> make_error(State, invalid_key_syntax, Table_path) end
            );

        {some, Segments} ->
            register_kv_path(State, Table_path, Segments, kv_value_kind(Kv))
    end.

-file("src/molt/internal/validate.gleam", 967).
?DOC(false).
-spec only_trailing_trivia(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
only_trailing_trivia(Children) ->
    case Children of
        [] ->
            true;

        [{token_element, {token, newline, _}} | _] ->
            true;

        [{token_element, {token, whitespace, _}} | Rest] ->
            only_trailing_trivia(Rest);

        [{token_element, {token, comment, _}} | Rest] ->
            only_trailing_trivia(Rest);

        _ ->
            false
    end.

-file("src/molt/internal/validate.gleam", 908).
?DOC(false).
-spec consume_brackets_ok(
    list(greenwood:element(molt@types:toml_kind())),
    integer(),
    molt@types:toml_kind()
) -> {ok, list(greenwood:element(molt@types:toml_kind()))} | {error, nil}.
consume_brackets_ok(Children, Count, Bracket) ->
    gleam@bool:guard(Count =:= 0, {ok, Children}, fun() -> case Children of
                [{token_element, {token, K, _}} | Children@1] when K =:= Bracket ->
                    consume_brackets_ok(Children@1, Count - 1, Bracket);

                _ ->
                    {error, nil}
            end end).

-file("src/molt/internal/validate.gleam", 940).
?DOC(false).
-spec do_check_header_keys_ok(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> boolean().
do_check_header_keys_ok(Tokens, Seen_key) ->
    case Tokens of
        [] ->
            Seen_key;

        [{token_element, {token, whitespace, _}} | Rest] ->
            do_check_header_keys_ok(Rest, Seen_key);

        [{token_element, {token, dot, _}} | Rest@1] ->
            gleam@bool:guard(
                not Seen_key,
                false,
                fun() -> do_check_header_keys_ok(Rest@1, false) end
            );

        [{token_element, {token, bare_key, Text}} | Rest@2] ->
            gleam@bool:guard(
                Seen_key,
                false,
                fun() ->
                    gleam@bool:guard(
                        not molt@internal@utils:is_bare_key(Text),
                        false,
                        fun() -> do_check_header_keys_ok(Rest@2, true) end
                    )
                end
            );

        [{token_element, {token, basic_string, _}} | Rest@3] ->
            gleam@bool:guard(
                Seen_key,
                false,
                fun() -> do_check_header_keys_ok(Rest@3, true) end
            );

        [{token_element, {token, literal_string, _}} | Rest@3] ->
            gleam@bool:guard(
                Seen_key,
                false,
                fun() -> do_check_header_keys_ok(Rest@3, true) end
            );

        [{token_element, {token, integer, _}} | Rest@3] ->
            gleam@bool:guard(
                Seen_key,
                false,
                fun() -> do_check_header_keys_ok(Rest@3, true) end
            );

        _ ->
            false
    end.

-file("src/molt/internal/validate.gleam", 936).
?DOC(false).
-spec check_header_key_tokens_ok(
    list(greenwood:element(molt@types:toml_kind()))
) -> boolean().
check_header_key_tokens_ok(Tokens) ->
    do_check_header_keys_ok(Tokens, false).

-file("src/molt/internal/validate.gleam", 922).
?DOC(false).
-spec take_until_right_bracket(
    list(greenwood:element(molt@types:toml_kind())),
    list(greenwood:element(molt@types:toml_kind()))
) -> {list(greenwood:element(molt@types:toml_kind())),
    list(greenwood:element(molt@types:toml_kind()))}.
take_until_right_bracket(Children, Acc) ->
    case Children of
        [] ->
            {lists:reverse(Acc), []};

        [{token_element, {token, right_bracket, _}} | _] ->
            {lists:reverse(Acc), Children};

        [El | Rest] ->
            take_until_right_bracket(Rest, [El | Acc])
    end.

-file("src/molt/internal/validate.gleam", 883).
?DOC(false).
-spec check_table_bracket_shape_ok(
    list(greenwood:element(molt@types:toml_kind())),
    integer()
) -> boolean().
check_table_bracket_shape_ok(Children, Expected) ->
    Children@1 = molt@internal@cst@elements:skip_trivia(Children),
    case consume_brackets_ok(Children@1, Expected, left_bracket) of
        {error, nil} ->
            false;

        {ok, Rest} ->
            {Key_tokens, Children@2} = take_until_right_bracket(Rest, []),
            gleam@bool:guard(
                not check_header_key_tokens_ok(Key_tokens),
                false,
                fun() ->
                    _pipe = consume_brackets_ok(
                        Children@2,
                        Expected,
                        right_bracket
                    ),
                    _pipe@1 = gleam@result:map(
                        _pipe,
                        fun only_trailing_trivia/1
                    ),
                    gleam@result:unwrap(_pipe@1, false)
                end
            )
    end.

-file("src/molt/internal/validate.gleam", 732).
?DOC(false).
-spec check_table_header_syntax(
    state(IQW),
    greenwood:node_(molt@types:toml_kind()),
    list(binary())
) -> state(IQW).
check_table_header_syntax(State, Node, Path) ->
    gleam@bool:lazy_guard(
        Path =:= [],
        fun() -> push_error(State, empty_table_header, Path) end,
        fun() ->
            Expected = case erlang:element(2, Node) of
                array_of_tables ->
                    2;

                _ ->
                    1
            end,
            gleam@bool:guard(
                check_table_bracket_shape_ok(erlang:element(3, Node), Expected),
                State,
                fun() -> push_error(State, malformed_table_header, Path) end
            )
        end
    ).

-file("src/molt/internal/validate.gleam", 437).
?DOC(false).
-spec do_scope_path(
    state(any()),
    list(binary()),
    list(binary()),
    list(binary()),
    boolean()
) -> list(binary()).
do_scope_path(State, Remaining, Raw_current, Scoped_current, Scope_terminal) ->
    case Remaining of
        [] ->
            Scoped_current;

        [Segment | Rest] ->
            Raw_prefix = lists:append(Raw_current, [Segment]),
            Scoped_prefix = lists:append(Scoped_current, [Segment]),
            Scope_here = Scope_terminal orelse (Rest /= []),
            case {Scope_here,
                gleam_stdlib:map_get(erlang:element(8, State), Raw_prefix)} of
                {true, {ok, Instance}} ->
                    do_scope_path(
                        State,
                        Rest,
                        Raw_prefix,
                        lists:append(
                            Scoped_prefix,
                            [erlang:integer_to_binary(Instance)]
                        ),
                        Scope_terminal
                    );

                {_, _} ->
                    do_scope_path(
                        State,
                        Rest,
                        Raw_prefix,
                        Scoped_prefix,
                        Scope_terminal
                    )
            end
    end.

-file("src/molt/internal/validate.gleam", 417).
?DOC(false).
-spec scope_path(state(any()), list(binary())) -> list(binary()).
scope_path(State, Path) ->
    do_scope_path(State, Path, [], [], true).

-file("src/molt/internal/validate.gleam", 589).
?DOC(false).
-spec register_header_implicit_parents(state(IPZ), list(binary())) -> state(IPZ).
register_header_implicit_parents(State, Path) ->
    Parent_paths = molt@internal@utils:all_prefixes(Path),
    Span = pos_span(erlang:element(4, State)),
    gleam@list:fold(
        Parent_paths,
        State,
        fun(State@1, Prefix) ->
            case gleam_stdlib:map_get(erlang:element(7, State@1), Prefix) of
                {error, nil} ->
                    {state,
                        erlang:element(2, State@1),
                        erlang:element(3, State@1),
                        erlang:element(4, State@1),
                        erlang:element(5, State@1),
                        erlang:element(6, State@1),
                        gleam@dict:insert(
                            erlang:element(7, State@1),
                            Prefix,
                            {header_implicit, Span}
                        ),
                        erlang:element(8, State@1),
                        erlang:element(9, State@1)};

                {ok, {explicit_scalar, Original}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key) -> {key_is_scalar, Key, Original} end
                    );

                {ok, {explicit_inline_table, Original@1}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key@1) ->
                            {key_is_inline_table, Key@1, Original@1}
                        end
                    );

                {ok, {explicit_inline_array, Original@2}} ->
                    emit_descent_error(
                        State@1,
                        Prefix,
                        fun(Key@2) -> {key_is_array, Key@2, Original@2} end
                    );

                {ok, _} ->
                    State@1
            end
        end
    ).

-file("src/molt/internal/validate.gleam", 427).
?DOC(false).
-spec scope_header_path(state(any()), list(binary())) -> list(binary()).
scope_header_path(State, Path) ->
    do_scope_path(State, Path, [], [], false).

-file("src/molt/internal/validate.gleam", 496).
?DOC(false).
-spec register_array_of_tables(state(IPL), list(binary())) -> state(IPL).
register_array_of_tables(State, Raw_path) ->
    Span = pos_span(erlang:element(4, State)),
    Scoped = scope_header_path(State, Raw_path),
    State@1 = register_header_implicit_parents(State, Scoped),
    Count = begin
        _pipe = gleam_stdlib:map_get(erlang:element(8, State@1), Raw_path),
        gleam@result:unwrap(_pipe, -1)
    end
    + 1,
    State@2 = {state,
        erlang:element(2, State@1),
        erlang:element(3, State@1),
        erlang:element(4, State@1),
        erlang:element(5, State@1),
        erlang:element(6, State@1),
        erlang:element(7, State@1),
        gleam@dict:insert(erlang:element(8, State@1), Raw_path, Count),
        erlang:element(9, State@1)},
    case gleam_stdlib:map_get(erlang:element(7, State@2), Scoped) of
        {error, nil} ->
            {state,
                erlang:element(2, State@2),
                erlang:element(3, State@2),
                erlang:element(4, State@2),
                erlang:element(5, State@2),
                erlang:element(6, State@2),
                gleam@dict:insert(
                    erlang:element(7, State@2),
                    Scoped,
                    {explicit_array_of_tables, Count, Span}
                ),
                erlang:element(8, State@2),
                erlang:element(9, State@2)};

        {ok, {explicit_array_of_tables, _, _}} ->
            {state,
                erlang:element(2, State@2),
                erlang:element(3, State@2),
                erlang:element(4, State@2),
                erlang:element(5, State@2),
                erlang:element(6, State@2),
                gleam@dict:insert(
                    erlang:element(7, State@2),
                    Scoped,
                    {explicit_array_of_tables, Count, Span}
                ),
                erlang:element(8, State@2),
                erlang:element(9, State@2)};

        {ok, Entry} ->
            Original = entry_span(Entry),
            State@3 = {state,
                erlang:element(2, State@2),
                erlang:element(3, State@2),
                erlang:element(4, State@2),
                erlang:element(5, State@2),
                erlang:element(6, State@2),
                gleam@dict:insert(
                    erlang:element(7, State@2),
                    Scoped,
                    {explicit_array_of_tables, Count, Span}
                ),
                erlang:element(8, State@2),
                erlang:element(9, State@2)},
            emit(
                State@3,
                fun() ->
                    make_error(State@3, {duplicate_table, Original}, Scoped)
                end
            )
    end.

-file("src/molt/internal/validate.gleam", 405).
?DOC(false).
-spec freeze_dotted(state(IOQ)) -> state(IOQ).
freeze_dotted(State) ->
    {state,
        erlang:element(2, State),
        erlang:element(3, State),
        erlang:element(4, State),
        erlang:element(5, State),
        erlang:element(6, State),
        gleam@dict:map_values(erlang:element(7, State), fun(_, V) -> case V of
                    {dotted_implicit, Span} ->
                        {closed_implicit, Span};

                    _ ->
                        V
                end end),
        erlang:element(8, State),
        erlang:element(9, State)}.

-file("src/molt/internal/validate.gleam", 473).
?DOC(false).
-spec register_table(state(IPH), list(binary())) -> state(IPH).
register_table(State, Path) ->
    Span = pos_span(erlang:element(4, State)),
    State@1 = register_header_implicit_parents(State, Path),
    case gleam_stdlib:map_get(erlang:element(7, State@1), Path) of
        {error, nil} ->
            {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                gleam@dict:insert(
                    erlang:element(7, State@1),
                    Path,
                    {explicit_table, Span}
                ),
                erlang:element(8, State@1),
                erlang:element(9, State@1)};

        {ok, {header_implicit, _}} ->
            {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                gleam@dict:insert(
                    erlang:element(7, State@1),
                    Path,
                    {explicit_table, Span}
                ),
                erlang:element(8, State@1),
                erlang:element(9, State@1)};

        {ok, Entry} ->
            Original = entry_span(Entry),
            State@2 = {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                gleam@dict:insert(
                    erlang:element(7, State@1),
                    Path,
                    {explicit_table, Span}
                ),
                erlang:element(8, State@1),
                erlang:element(9, State@1)},
            emit(
                State@2,
                fun() ->
                    make_error(State@2, {duplicate_table, Original}, Path)
                end
            )
    end.

-file("src/molt/internal/validate.gleam", 194).
?DOC(false).
-spec enter_node(state(INR), greenwood:node_(molt@types:toml_kind())) -> state(INR).
enter_node(State, Node) ->
    case erlang:element(2, Node) of
        root ->
            State;

        error ->
            State@1 = emit(
                State,
                fun() ->
                    make_error(
                        State,
                        unparsable_content,
                        erlang:element(5, State)
                    )
                end
            ),
            {state,
                erlang:element(2, State@1),
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                erlang:element(6, State@1),
                erlang:element(7, State@1),
                erlang:element(8, State@1),
                erlang:element(9, State@1) + 1};

        table ->
            Table_path = molt@internal@cst@elements:extract_key_segments(
                erlang:element(3, Node)
            ),
            State@2 = freeze_dotted(State),
            Scoped = scope_header_path(State@2, Table_path),
            State@3 = push_path(State@2, Scoped),
            _pipe = register_table(State@3, Scoped),
            check_table_header_syntax(_pipe, Node, Table_path);

        array_of_tables ->
            Table_path@1 = molt@internal@cst@elements:extract_key_segments(
                erlang:element(3, Node)
            ),
            State@4 = begin
                _pipe@1 = freeze_dotted(State),
                register_array_of_tables(_pipe@1, Table_path@1)
            end,
            Instance = begin
                _pipe@2 = gleam_stdlib:map_get(
                    erlang:element(8, State@4),
                    Table_path@1
                ),
                gleam@result:unwrap(_pipe@2, 1)
            end
            - 1,
            Last = last_or_empty(Table_path@1),
            Scoped_parent = scope_path(State@4, list_init(Table_path@1)),
            Scoped_path = lists:append(
                Scoped_parent,
                [Last, erlang:integer_to_binary(Instance)]
            ),
            _pipe@3 = push_path(State@4, Scoped_path),
            check_table_header_syntax(_pipe@3, Node, Table_path@1);

        key_value ->
            State@5 = case erlang:element(9, State) of
                0 ->
                    register_kv(State, erlang:element(5, State), Node);

                _ ->
                    State
            end,
            Kv_path = lists:append(
                erlang:element(5, State@5),
                begin
                    _pipe@4 = molt@internal@cst@elements:key_path(
                        erlang:element(3, Node)
                    ),
                    gleam@option:unwrap(_pipe@4, [])
                end
            ),
            _pipe@5 = push_path(State@5, Kv_path),
            check_kv_syntax(_pipe@5, Node, Kv_path);

        array ->
            State@6 = {state,
                erlang:element(2, State),
                erlang:element(3, State),
                erlang:element(4, State),
                erlang:element(5, State),
                erlang:element(6, State),
                erlang:element(7, State),
                erlang:element(8, State),
                erlang:element(9, State) + 1},
            State@7 = push_path(State@6, erlang:element(5, State@6)),
            check_array_syntax(State@7, Node, erlang:element(5, State@7));

        inline_table ->
            State@8 = {state,
                erlang:element(2, State),
                erlang:element(3, State),
                erlang:element(4, State),
                erlang:element(5, State),
                erlang:element(6, State),
                erlang:element(7, State),
                erlang:element(8, State),
                erlang:element(9, State) + 1},
            State@9 = push_path(State@8, erlang:element(5, State@8)),
            check_inline_table_syntax(State@9, Node, erlang:element(5, State@9));

        _ ->
            push_path(State, erlang:element(5, State))
    end.

-file("src/molt/internal/validate.gleam", 361).
?DOC(false).
-spec count_newlines(binary(), integer(), integer()) -> {integer(), integer()}.
count_newlines(Text, Line, Col) ->
    case Text of
        <<""/utf8>> ->
            {Line, Col};

        <<"\r\n"/utf8, Rest/binary>> ->
            count_newlines(Rest, Line + 1, 1);

        <<"\n"/utf8, Rest/binary>> ->
            count_newlines(Rest, Line + 1, 1);

        _ ->
            case gleam_stdlib:string_pop_grapheme(Text) of
                {ok, {_, Rest@1}} ->
                    count_newlines(Rest@1, Line, Col + 1);

                {error, nil} ->
                    {Line, Col}
            end
    end.

-file("src/molt/internal/validate.gleam", 324).
?DOC(false).
-spec advance_text(state(IOK), binary(), molt@types:toml_kind()) -> state(IOK).
advance_text(State, Text, Kind) ->
    {pos, Line, Col, Offset} = erlang:element(4, State),
    Text@1 = case Kind of
        equals ->
            <<"="/utf8>>;

        dot ->
            <<"."/utf8>>;

        comma ->
            <<","/utf8>>;

        left_bracket ->
            <<"["/utf8>>;

        right_bracket ->
            <<"]"/utf8>>;

        left_brace ->
            <<"{"/utf8>>;

        right_brace ->
            <<"}"/utf8>>;

        basic_string ->
            <<<<"\""/utf8, Text/binary>>/binary, "\""/utf8>>;

        literal_string ->
            <<<<"'"/utf8, Text/binary>>/binary, "'"/utf8>>;

        multiline_basic_string ->
            <<<<"\"\"\""/utf8, Text/binary>>/binary, "\"\"\""/utf8>>;

        multiline_basic_string_nl ->
            <<<<"\"\"\"\n"/utf8, Text/binary>>/binary, "\"\"\""/utf8>>;

        multiline_literal_string ->
            <<<<"'''"/utf8, Text/binary>>/binary, "'''"/utf8>>;

        multiline_literal_string_nl ->
            <<<<"'''\n"/utf8, Text/binary>>/binary, "'''"/utf8>>;

        _ ->
            Text
    end,
    Len = erlang:byte_size(Text@1),
    {New_line, New_col} = count_newlines(Text@1, Line, Col),
    {state,
        erlang:element(2, State),
        erlang:element(3, State),
        {pos, New_line, New_col, Offset + Len},
        erlang:element(5, State),
        erlang:element(6, State),
        erlang:element(7, State),
        erlang:element(8, State),
        erlang:element(9, State)}.

-file("src/molt/internal/validate.gleam", 299).
?DOC(false).
-spec advance_token(state(IOG), greenwood:token(molt@types:toml_kind())) -> state(IOG).
advance_token(State, Token) ->
    State@1 = case erlang:element(2, Token) of
        invalid_value ->
            emit(
                State,
                fun() ->
                    make_error(State, {bad_value, erlang:element(3, Token)}, [])
                end
            );

        invalid_basic_string ->
            emit(State, fun() -> make_error(State, unterminated_string, []) end);

        invalid_literal_string ->
            emit(State, fun() -> make_error(State, unterminated_string, []) end);

        invalid_multiline_basic_string ->
            emit(
                State,
                fun() ->
                    make_error(State, unterminated_multiline_string, [])
                end
            );

        invalid_multiline_literal_string ->
            emit(
                State,
                fun() ->
                    make_error(State, unterminated_multiline_string, [])
                end
            );

        _ ->
            State
    end,
    case erlang:element(3, erlang:element(2, State@1)) of
        true ->
            advance_text(
                State@1,
                erlang:element(3, Token),
                erlang:element(2, Token)
            );

        false ->
            State@1
    end.

-file("src/molt/internal/validate.gleam", 137).
?DOC(false).
-spec walk(greenwood:node_(molt@types:toml_kind()), collector(INM)) -> INM.
walk(Tree, Collector) ->
    case molt@internal@cst@elements:is_toml(erlang:element(3, Tree)) of
        false ->
            (erlang:element(4, Collector))(
                erlang:element(2, Collector),
                fun() ->
                    {syntax_error, no_valid_toml_structure, [], {span, 1, 1, 0}}
                end
            );

        true ->
            State = {state,
                Collector,
                erlang:element(2, Collector),
                {pos, 1, 1, 0},
                [],
                [],
                maps:new(),
                maps:new(),
                0},
            Tree@1 = molt@internal@cst@elements:inline_trailing_trivia(Tree),
            State@5 = begin
                _pipe = greenwood:visitor(),
                _pipe@1 = greenwood:on_trivia(
                    _pipe,
                    fun(State@1, Tok) ->
                        {continue, advance_token(State@1, Tok)}
                    end
                ),
                _pipe@2 = greenwood:on_token(
                    _pipe@1,
                    fun(State@2, Tok@1) ->
                        {continue, advance_token(State@2, Tok@1)}
                    end
                ),
                _pipe@3 = greenwood:on_enter_node(
                    _pipe@2,
                    fun(State@3, Node) ->
                        {continue, enter_node(State@3, Node)}
                    end
                ),
                _pipe@4 = greenwood:on_exit_node(
                    _pipe@3,
                    fun(State@4, Node@1) ->
                        {continue, exit_node(State@4, Node@1)}
                    end
                ),
                greenwood:traverse(Tree@1, State, _pipe@4)
            end,
            erlang:element(3, State@5)
    end.

-file("src/molt/internal/validate.gleam", 107).
?DOC(false).
-spec count(greenwood:node_(molt@types:toml_kind())) -> integer().
count(Tree) ->
    walk(Tree, {collector, 0, false, fun(N, _) -> N + 1 end}).

-file("src/molt/internal/validate.gleam", 120).
?DOC(false).
-spec enrich(greenwood:node_(molt@types:toml_kind())) -> list(molt@types:syntax_error()).
enrich(Tree) ->
    _pipe = walk(Tree, enrich_collector()),
    lists:reverse(_pipe).