Skip to main content

src/tomlet@parser.erl

-module(tomlet@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/tomlet/parser.gleam").
-export([date_repr_is_valid/1, time_repr_is_valid/1, datetime_repr_is_valid/1, parse/2]).
-export_type([parse_error/0, expected_token_kind/0, version/0, assembly_state/0, strip_state/0, strip_step/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 parse_error() :: {unexpected, binary(), expected_token_kind(), integer()} |
    {key_already_in_use, list(binary()), integer()}.

-type expected_token_kind() :: expected_value |
    expected_key |
    expected_table_header |
    expected_syntax.

-type version() :: toml10 | toml11.

-type assembly_state() :: {assembly_state,
        list(binary()),
        list(list(binary())),
        list(list(binary())),
        list(list(binary())),
        list(list(binary())),
        list(list(binary()))}.

-type strip_state() :: strip_normal |
    strip_basic |
    strip_literal |
    strip_multi_basic |
    strip_multi_literal.

-type strip_step() :: {strip_step, list(binary()), strip_state(), binary()}.

-file("src/tomlet/parser.gleam", 139).
?DOC(false).
-spec token_src(william:token()) -> binary().
token_src(Token) ->
    william:to_source([Token]).

-file("src/tomlet/parser.gleam", 917).
?DOC(false).
-spec dotted_table_paths_loop(
    list(binary()),
    list(binary()),
    list(binary()),
    list(list(binary()))
) -> list(list(binary())).
dotted_table_paths_loop(Key, Prefix, Active_table, Acc) ->
    case Key of
        [] ->
            Acc;

        [_] ->
            Acc;

        [Segment | Rest] ->
            Next_prefix = lists:append(Prefix, [Segment]),
            Next_acc = case erlang:length(Next_prefix) > erlang:length(
                Active_table
            ) of
                true ->
                    [Next_prefix | Acc];

                false ->
                    Acc
            end,
            dotted_table_paths_loop(Rest, Next_prefix, Active_table, Next_acc)
    end.

-file("src/tomlet/parser.gleam", 910).
?DOC(false).
-spec dotted_table_paths(list(binary()), list(binary())) -> list(list(binary())).
dotted_table_paths(Active_table, Key) ->
    dotted_table_paths_loop(Key, [], Active_table, []).

-file("src/tomlet/parser.gleam", 937).
?DOC(false).
-spec add_paths(list(list(binary())), list(list(binary()))) -> list(list(binary())).
add_paths(Paths, Existing) ->
    case Paths of
        [] ->
            Existing;

        [Path | Rest] ->
            case gleam@list:contains(Existing, Path) of
                true ->
                    add_paths(Rest, Existing);

                false ->
                    add_paths(Rest, [Path | Existing])
            end
    end.

-file("src/tomlet/parser.gleam", 902).
?DOC(false).
-spec add_dotted_table_paths(
    list(list(binary())),
    list(binary()),
    list(binary())
) -> list(list(binary())).
add_dotted_table_paths(Existing, Active_table, Key) ->
    add_paths(dotted_table_paths(Active_table, Key), Existing).

-file("src/tomlet/parser.gleam", 886).
?DOC(false).
-spec dotted_key_extends_table(
    list(list(binary())),
    list(binary()),
    list(binary())
) -> boolean().
dotted_key_extends_table(Table_paths, Active_table, Key) ->
    case Table_paths of
        [] ->
            false;

        [Table | Rest] ->
            (tomlet@key:starts_with(Key, Table) andalso not tomlet@key:starts_with(
                Active_table,
                Table
            ))
            orelse dotted_key_extends_table(Rest, Active_table, Key)
    end.

-file("src/tomlet/parser.gleam", 876).
?DOC(false).
-spec dotted_key_extends_defined_table(
    list(list(binary())),
    list(list(binary())),
    list(binary()),
    list(binary())
) -> boolean().
dotted_key_extends_defined_table(
    Explicit_tables,
    Array_tables,
    Active_table,
    Key
) ->
    dotted_key_extends_table(Explicit_tables, Active_table, Key) orelse dotted_key_extends_table(
        Array_tables,
        Active_table,
        Key
    ).

-file("src/tomlet/parser.gleam", 814).
?DOC(false).
-spec key_path_conflicts(list(list(binary())), list(binary())) -> boolean().
key_path_conflicts(Seen, Key) ->
    case Seen of
        [] ->
            false;

        [Existing | Rest] ->
            (tomlet@key:starts_with(Existing, Key) orelse tomlet@key:starts_with(
                Key,
                Existing
            ))
            orelse key_path_conflicts(Rest, Key)
    end.

-file("src/tomlet/parser.gleam", 432).
?DOC(false).
-spec apply_key_value_state(assembly_state(), tomlet@ast:key(), integer()) -> {ok,
        assembly_state()} |
    {error, parse_error()}.
apply_key_value_state(State, Key, Key_offset) ->
    Full_key = lists:append(
        erlang:element(2, State),
        tomlet@key:to_strings(Key)
    ),
    case key_path_conflicts(erlang:element(3, State), Full_key) orelse dotted_key_extends_defined_table(
        erlang:element(4, State),
        erlang:element(5, State),
        erlang:element(2, State),
        Full_key
    ) of
        true ->
            {error, {key_already_in_use, Full_key, Key_offset}};

        false ->
            {ok,
                {assembly_state,
                    erlang:element(2, State),
                    [Full_key | erlang:element(3, State)],
                    erlang:element(4, State),
                    erlang:element(5, State),
                    erlang:element(6, State),
                    add_dotted_table_paths(
                        erlang:element(7, State),
                        erlang:element(2, State),
                        Full_key
                    )}}
    end.

-file("src/tomlet/parser.gleam", 348).
?DOC(false).
-spec scan_trailing(list(tomlet@lexer:spanned()), binary()) -> {ok,
        {binary(), list(tomlet@lexer:spanned())}} |
    {error, parse_error()}.
scan_trailing(Spans, Acc) ->
    case Spans of
        [] ->
            {ok, {Acc, []}};

        [{spanned, {whitespace, Text}, _} | Rest] ->
            scan_trailing(Rest, <<Acc/binary, Text/binary>>);

        [{spanned, {comment, Text@1}, _} | Rest@1] ->
            scan_trailing(Rest@1, <<Acc/binary, Text@1/binary>>);

        [{spanned, {end_of_line, _}, _} | Rest@2] ->
            {ok, {Acc, Rest@2}};

        [{spanned, Token, Offset} | _] ->
            {error, {unexpected, token_src(Token), expected_syntax, Offset}}
    end.

-file("src/tomlet/parser.gleam", 1693).
?DOC(false).
-spec based_int_result({ok, integer()} | {error, nil}, binary(), integer()) -> {ok,
        tomlet@ast:value()} |
    {error, parse_error()}.
based_int_result(Result, Source_text, Offset) ->
    case Result of
        {ok, Value} ->
            {ok, {int, Value, Source_text}};

        {error, nil} ->
            {error, {unexpected, Source_text, expected_value, Offset}}
    end.

-file("src/tomlet/parser.gleam", 1731).
?DOC(false).
-spec based_digit_value(binary()) -> {ok, integer()} | {error, nil}.
based_digit_value(Char) ->
    case Char of
        <<"0"/utf8>> ->
            {ok, 0};

        <<"1"/utf8>> ->
            {ok, 1};

        <<"2"/utf8>> ->
            {ok, 2};

        <<"3"/utf8>> ->
            {ok, 3};

        <<"4"/utf8>> ->
            {ok, 4};

        <<"5"/utf8>> ->
            {ok, 5};

        <<"6"/utf8>> ->
            {ok, 6};

        <<"7"/utf8>> ->
            {ok, 7};

        <<"8"/utf8>> ->
            {ok, 8};

        <<"9"/utf8>> ->
            {ok, 9};

        <<"a"/utf8>> ->
            {ok, 10};

        <<"A"/utf8>> ->
            {ok, 10};

        <<"b"/utf8>> ->
            {ok, 11};

        <<"B"/utf8>> ->
            {ok, 11};

        <<"c"/utf8>> ->
            {ok, 12};

        <<"C"/utf8>> ->
            {ok, 12};

        <<"d"/utf8>> ->
            {ok, 13};

        <<"D"/utf8>> ->
            {ok, 13};

        <<"e"/utf8>> ->
            {ok, 14};

        <<"E"/utf8>> ->
            {ok, 14};

        <<"f"/utf8>> ->
            {ok, 15};

        <<"F"/utf8>> ->
            {ok, 15};

        _ ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 1712).
?DOC(false).
-spec parse_based_int_digits_loop(list(binary()), integer(), integer()) -> {ok,
        integer()} |
    {error, nil}.
parse_based_int_digits_loop(Chars, Base, Acc) ->
    case Chars of
        [] ->
            {ok, Acc};

        [Char | Rest] ->
            case based_digit_value(Char) of
                {ok, Value} ->
                    case Value < Base of
                        true ->
                            parse_based_int_digits_loop(
                                Rest,
                                Base,
                                (Acc * Base) + Value
                            );

                        false ->
                            {error, nil}
                    end;

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

-file("src/tomlet/parser.gleam", 1704).
?DOC(false).
-spec parse_based_int_digits(binary(), integer(), integer()) -> {ok, integer()} |
    {error, nil}.
parse_based_int_digits(Text, Base, Acc) ->
    parse_based_int_digits_loop(gleam@string:to_graphemes(Text), Base, Acc).

-file("src/tomlet/parser.gleam", 1668).
?DOC(false).
-spec parse_based_int_value(binary(), binary(), integer()) -> {ok,
        tomlet@ast:value()} |
    {error, parse_error()}.
parse_based_int_value(Normalized, Source_text, Offset) ->
    case gleam_stdlib:string_starts_with(Normalized, <<"0x"/utf8>>) of
        true ->
            _pipe = parse_based_int_digits(
                gleam@string:drop_start(Normalized, 2),
                16,
                0
            ),
            based_int_result(_pipe, Source_text, Offset);

        false ->
            case gleam_stdlib:string_starts_with(Normalized, <<"0o"/utf8>>) of
                true ->
                    _pipe@1 = parse_based_int_digits(
                        gleam@string:drop_start(Normalized, 2),
                        8,
                        0
                    ),
                    based_int_result(_pipe@1, Source_text, Offset);

                false ->
                    case gleam_stdlib:string_starts_with(
                        Normalized,
                        <<"0b"/utf8>>
                    ) of
                        true ->
                            _pipe@2 = parse_based_int_digits(
                                gleam@string:drop_start(Normalized, 2),
                                2,
                                0
                            ),
                            based_int_result(_pipe@2, Source_text, Offset);

                        false ->
                            {error,
                                {unexpected,
                                    Source_text,
                                    expected_value,
                                    Offset}}
                    end
            end
    end.

-file("src/tomlet/parser.gleam", 2158).
?DOC(false).
-spec char_is_digit(binary()) -> boolean().
char_is_digit(Char) ->
    case Char of
        <<"0"/utf8>> ->
            true;

        <<"1"/utf8>> ->
            true;

        <<"2"/utf8>> ->
            true;

        <<"3"/utf8>> ->
            true;

        <<"4"/utf8>> ->
            true;

        <<"5"/utf8>> ->
            true;

        <<"6"/utf8>> ->
            true;

        <<"7"/utf8>> ->
            true;

        <<"8"/utf8>> ->
            true;

        <<"9"/utf8>> ->
            true;

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 1904).
?DOC(false).
-spec separated_digits_loop(
    list(binary()),
    fun((binary()) -> boolean()),
    boolean(),
    boolean()
) -> boolean().
separated_digits_loop(
    Chars,
    Is_valid_digit,
    Seen_digit,
    Previous_was_underscore
) ->
    case Chars of
        [] ->
            Seen_digit andalso not Previous_was_underscore;

        [<<"_"/utf8>> | Rest] ->
            case Seen_digit andalso not Previous_was_underscore of
                true ->
                    separated_digits_loop(
                        Rest,
                        Is_valid_digit,
                        Seen_digit,
                        true
                    );

                false ->
                    false
            end;

        [Char | Rest@1] ->
            case Is_valid_digit(Char) of
                true ->
                    separated_digits_loop(Rest@1, Is_valid_digit, true, false);

                false ->
                    false
            end
    end.

-file("src/tomlet/parser.gleam", 1897).
?DOC(false).
-spec separated_digits_are_valid(list(binary()), fun((binary()) -> boolean())) -> boolean().
separated_digits_are_valid(Chars, Is_valid_digit) ->
    separated_digits_loop(Chars, Is_valid_digit, false, false).

-file("src/tomlet/parser.gleam", 1872).
?DOC(false).
-spec decimal_digits_are_valid(binary()) -> boolean().
decimal_digits_are_valid(Text) ->
    gleam@bool:guard(
        not separated_digits_are_valid(
            gleam@string:to_graphemes(Text),
            fun char_is_digit/1
        ),
        false,
        fun() -> case gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>) of
                <<""/utf8>> ->
                    false;

                Digits ->
                    Has_leading_zero = (string:length(Digits) > 1) andalso gleam_stdlib:string_starts_with(
                        Digits,
                        <<"0"/utf8>>
                    ),
                    not Has_leading_zero
            end end
    ).

-file("src/tomlet/parser.gleam", 2187).
?DOC(false).
-spec is_bin_digit_string(binary()) -> boolean().
is_bin_digit_string(Char) ->
    (Char =:= <<"0"/utf8>>) orelse (Char =:= <<"1"/utf8>>).

-file("src/tomlet/parser.gleam", 1887).
?DOC(false).
-spec based_digits_are_valid(binary(), fun((binary()) -> boolean())) -> boolean().
based_digits_are_valid(Text, Is_valid_digit) ->
    case gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>) of
        <<""/utf8>> ->
            false;

        _ ->
            separated_digits_are_valid(
                gleam@string:to_graphemes(Text),
                Is_valid_digit
            )
    end.

-file("src/tomlet/parser.gleam", 2180).
?DOC(false).
-spec is_oct_digit_string(binary()) -> boolean().
is_oct_digit_string(Char) ->
    case Char of
        <<"0"/utf8>> ->
            true;

        <<"1"/utf8>> ->
            true;

        <<"2"/utf8>> ->
            true;

        <<"3"/utf8>> ->
            true;

        <<"4"/utf8>> ->
            true;

        <<"5"/utf8>> ->
            true;

        <<"6"/utf8>> ->
            true;

        <<"7"/utf8>> ->
            true;

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 2165).
?DOC(false).
-spec char_is_hex_digit(binary()) -> boolean().
char_is_hex_digit(Char) ->
    char_is_digit(Char) orelse (case Char of
        <<"a"/utf8>> ->
            true;

        <<"b"/utf8>> ->
            true;

        <<"c"/utf8>> ->
            true;

        <<"d"/utf8>> ->
            true;

        <<"e"/utf8>> ->
            true;

        <<"f"/utf8>> ->
            true;

        <<"A"/utf8>> ->
            true;

        <<"B"/utf8>> ->
            true;

        <<"C"/utf8>> ->
            true;

        <<"D"/utf8>> ->
            true;

        <<"E"/utf8>> ->
            true;

        <<"F"/utf8>> ->
            true;

        _ ->
            false
    end).

-file("src/tomlet/parser.gleam", 2176).
?DOC(false).
-spec is_hex_digit_string(binary()) -> boolean().
is_hex_digit_string(Char) ->
    char_is_hex_digit(Char).

-file("src/tomlet/parser.gleam", 2152).
?DOC(false).
-spec drop_sign(binary()) -> binary().
drop_sign(Text) ->
    Has_sign = gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) orelse gleam_stdlib:string_starts_with(
        Text,
        <<"-"/utf8>>
    ),
    gleam@bool:guard(
        not Has_sign,
        Text,
        fun() -> gleam@string:drop_start(Text, 1) end
    ).

-file("src/tomlet/parser.gleam", 1840).
?DOC(false).
-spec int_repr_is_valid(binary()) -> boolean().
int_repr_is_valid(Text) ->
    Has_sign = gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) orelse gleam_stdlib:string_starts_with(
        Text,
        <<"-"/utf8>>
    ),
    Unsigned = drop_sign(Text),
    case gleam_stdlib:string_starts_with(Unsigned, <<"0x"/utf8>>) of
        true ->
            not Has_sign andalso based_digits_are_valid(
                gleam@string:drop_start(Unsigned, 2),
                fun is_hex_digit_string/1
            );

        false ->
            case gleam_stdlib:string_starts_with(Unsigned, <<"0o"/utf8>>) of
                true ->
                    not Has_sign andalso based_digits_are_valid(
                        gleam@string:drop_start(Unsigned, 2),
                        fun is_oct_digit_string/1
                    );

                false ->
                    case gleam_stdlib:string_starts_with(
                        Unsigned,
                        <<"0b"/utf8>>
                    ) of
                        true ->
                            not Has_sign andalso based_digits_are_valid(
                                gleam@string:drop_start(Unsigned, 2),
                                fun is_bin_digit_string/1
                            );

                        false ->
                            decimal_digits_are_valid(Unsigned)
                    end
            end
    end.

-file("src/tomlet/parser.gleam", 1656).
?DOC(false).
-spec parse_int_value(binary(), integer()) -> {ok, tomlet@ast:value()} |
    {error, parse_error()}.
parse_int_value(Text, Offset) ->
    Normalized = gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>),
    case int_repr_is_valid(Text) of
        true ->
            case gleam_stdlib:parse_int(Normalized) of
                {ok, Value} ->
                    {ok, {int, Value, Text}};

                {error, nil} ->
                    parse_based_int_value(Normalized, Text, Offset)
            end;

        false ->
            {error, {unexpected, Text, expected_value, Offset}}
    end.

-file("src/tomlet/parser.gleam", 2137).
?DOC(false).
-spec is_leap_year(integer()) -> boolean().
is_leap_year(Year) ->
    ((Year rem 4) =:= 0) andalso (((Year rem 100) /= 0) orelse ((Year rem 400)
    =:= 0)).

-file("src/tomlet/parser.gleam", 2124).
?DOC(false).
-spec days_in_month(integer(), integer()) -> integer().
days_in_month(Year, Month) ->
    case Month of
        1 ->
            31;

        3 ->
            31;

        5 ->
            31;

        7 ->
            31;

        8 ->
            31;

        10 ->
            31;

        12 ->
            31;

        4 ->
            30;

        6 ->
            30;

        9 ->
            30;

        11 ->
            30;

        2 ->
            case is_leap_year(Year) of
                true ->
                    29;

                false ->
                    28
            end;

        _ ->
            0
    end.

-file("src/tomlet/parser.gleam", 2141).
?DOC(false).
-spec two_digits_in_range(binary(), integer(), integer()) -> boolean().
two_digits_in_range(Text, Minimum, Maximum) ->
    Has_two_digits = (string:length(Text) =:= 2) andalso separated_digits_are_valid(
        gleam@string:to_graphemes(Text),
        fun char_is_digit/1
    ),
    gleam@bool:guard(
        not Has_two_digits,
        false,
        fun() -> case gleam_stdlib:parse_int(Text) of
                {ok, Value} ->
                    (Value >= Minimum) andalso (Value =< Maximum);

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

-file("src/tomlet/parser.gleam", 2105).
?DOC(false).
-spec date_parts_are_valid(binary()) -> boolean().
date_parts_are_valid(Text) ->
    Year = gleam@string:slice(Text, 0, 4),
    Month = gleam@string:slice(Text, 5, 2),
    Day = gleam@string:slice(Text, 8, 2),
    case (separated_digits_are_valid(
        gleam@string:to_graphemes(Year),
        fun char_is_digit/1
    )
    andalso two_digits_in_range(Month, 1, 12))
    andalso two_digits_in_range(Day, 1, 31) of
        true ->
            case {gleam_stdlib:parse_int(Year),
                gleam_stdlib:parse_int(Month),
                gleam_stdlib:parse_int(Day)} of
                {{ok, Year_number}, {ok, Month_number}, {ok, Day_number}} ->
                    Day_number =< days_in_month(Year_number, Month_number);

                {_, _, _} ->
                    false
            end;

        false ->
            false
    end.

-file("src/tomlet/parser.gleam", 1964).
?DOC(false).
-spec date_repr_is_valid(binary()) -> boolean().
date_repr_is_valid(Text) ->
    Has_date_shape = ((string:length(Text) =:= 10) andalso (gleam@string:slice(
        Text,
        4,
        1
    )
    =:= <<"-"/utf8>>))
    andalso (gleam@string:slice(Text, 7, 1) =:= <<"-"/utf8>>),
    gleam@bool:guard(
        not Has_date_shape,
        false,
        fun() -> date_parts_are_valid(Text) end
    ).

-file("src/tomlet/parser.gleam", 2043).
?DOC(false).
-spec hour_minute_repr_is_valid(binary()) -> boolean().
hour_minute_repr_is_valid(Text) ->
    (((string:length(Text) =:= 5) andalso (gleam@string:slice(Text, 2, 1) =:= <<":"/utf8>>))
    andalso two_digits_in_range(gleam@string:slice(Text, 0, 2), 0, 23))
    andalso two_digits_in_range(gleam@string:slice(Text, 3, 2), 0, 59).

-file("src/tomlet/parser.gleam", 2091).
?DOC(false).
-spec fraction_is_valid(binary()) -> boolean().
fraction_is_valid(Text) ->
    case Text of
        <<""/utf8>> ->
            true;

        _ ->
            case gleam_stdlib:string_starts_with(Text, <<"."/utf8>>) of
                true ->
                    Digits = gleam@string:drop_start(Text, 1),
                    separated_digits_are_valid(
                        gleam@string:to_graphemes(Digits),
                        fun char_is_digit/1
                    );

                false ->
                    false
            end
    end.

-file("src/tomlet/parser.gleam", 2075).
?DOC(false).
-spec time_repr_is_valid(binary()) -> boolean().
time_repr_is_valid(Text) ->
    Has_time_shape = ((string:length(Text) >= 8) andalso (gleam@string:slice(
        Text,
        2,
        1
    )
    =:= <<":"/utf8>>))
    andalso (gleam@string:slice(Text, 5, 1) =:= <<":"/utf8>>),
    gleam@bool:guard(
        not Has_time_shape,
        false,
        fun() ->
            Hour = gleam@string:slice(Text, 0, 2),
            Minute = gleam@string:slice(Text, 3, 2),
            Seconds = gleam@string:slice(Text, 6, 2),
            Fraction = gleam@string:drop_start(Text, 8),
            ((two_digits_in_range(Hour, 0, 23) andalso two_digits_in_range(
                Minute,
                0,
                59
            ))
            andalso two_digits_in_range(Seconds, 0, 59))
            andalso fraction_is_valid(Fraction)
        end
    ).

-file("src/tomlet/parser.gleam", 2034).
?DOC(false).
-spec time_repr_is_valid_versioned(binary(), version()) -> boolean().
time_repr_is_valid_versioned(Text, Version) ->
    case Version of
        toml10 ->
            time_repr_is_valid(Text);

        toml11 ->
            time_repr_is_valid(Text) orelse hour_minute_repr_is_valid(Text)
    end.

-file("src/tomlet/parser.gleam", 2064).
?DOC(false).
-spec offset_repr_is_valid(binary()) -> boolean().
offset_repr_is_valid(Text) ->
    Has_offset_shape = ((string:length(Text) =:= 6) andalso (gleam_stdlib:string_starts_with(
        Text,
        <<"+"/utf8>>
    )
    orelse gleam_stdlib:string_starts_with(Text, <<"-"/utf8>>)))
    andalso (gleam@string:slice(Text, 3, 1) =:= <<":"/utf8>>),
    gleam@bool:guard(
        not Has_offset_shape,
        false,
        fun() ->
            Hour = gleam@string:slice(Text, 1, 2),
            Minute = gleam@string:slice(Text, 4, 2),
            two_digits_in_range(Hour, 0, 23) andalso two_digits_in_range(
                Minute,
                0,
                59
            )
        end
    ).

-file("src/tomlet/parser.gleam", 2050).
?DOC(false).
-spec find_offset_separator(list(binary()), binary()) -> {ok,
        {binary(), binary()}} |
    {error, nil}.
find_offset_separator(Chars, Before) ->
    case Chars of
        [] ->
            {error, nil};

        [Char | Rest] ->
            case (Char =:= <<"+"/utf8>>) orelse (Char =:= <<"-"/utf8>>) of
                true ->
                    {ok,
                        {Before,
                            <<Char/binary,
                                (gleam@string:join(Rest, <<""/utf8>>))/binary>>}};

                false ->
                    find_offset_separator(Rest, <<Before/binary, Char/binary>>)
            end
    end.

-file("src/tomlet/parser.gleam", 2021).
?DOC(false).
-spec time_offset_repr_is_valid_versioned(binary(), version()) -> boolean().
time_offset_repr_is_valid_versioned(Text, Version) ->
    case gleam_stdlib:string_ends_with(Text, <<"Z"/utf8>>) orelse gleam_stdlib:string_ends_with(
        Text,
        <<"z"/utf8>>
    ) of
        true ->
            time_repr_is_valid_versioned(
                gleam@string:drop_end(Text, 1),
                Version
            );

        false ->
            case find_offset_separator(
                gleam@string:to_graphemes(Text),
                <<""/utf8>>
            ) of
                {ok, {Time, Offset}} ->
                    time_repr_is_valid_versioned(Time, Version) andalso offset_repr_is_valid(
                        Offset
                    );

                {error, nil} ->
                    time_repr_is_valid_versioned(Text, Version)
            end
    end.

-file("src/tomlet/parser.gleam", 1975).
?DOC(false).
-spec split_datetime(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
split_datetime(Text) ->
    case gleam@string:split_once(Text, <<"T"/utf8>>) of
        {ok, Parts} ->
            {ok, Parts};

        {error, nil} ->
            case gleam@string:split_once(Text, <<"t"/utf8>>) of
                {ok, Parts@1} ->
                    {ok, Parts@1};

                {error, nil} ->
                    gleam@string:split_once(Text, <<" "/utf8>>)
            end
    end.

-file("src/tomlet/parser.gleam", 1994).
?DOC(false).
-spec time_offset_repr_is_valid(binary()) -> boolean().
time_offset_repr_is_valid(Text) ->
    case gleam_stdlib:string_ends_with(Text, <<"Z"/utf8>>) orelse gleam_stdlib:string_ends_with(
        Text,
        <<"z"/utf8>>
    ) of
        true ->
            time_repr_is_valid(gleam@string:drop_end(Text, 1));

        false ->
            case find_offset_separator(
                gleam@string:to_graphemes(Text),
                <<""/utf8>>
            ) of
                {ok, {Time, Offset}} ->
                    time_repr_is_valid(Time) andalso offset_repr_is_valid(
                        Offset
                    );

                {error, nil} ->
                    time_repr_is_valid(Text)
            end
    end.

-file("src/tomlet/parser.gleam", 1986).
?DOC(false).
-spec datetime_repr_is_valid(binary()) -> boolean().
datetime_repr_is_valid(Text) ->
    case split_datetime(Text) of
        {ok, {Date, Time_offset}} ->
            date_repr_is_valid(Date) andalso time_offset_repr_is_valid(
                Time_offset
            );

        {error, nil} ->
            false
    end.

-file("src/tomlet/parser.gleam", 2008).
?DOC(false).
-spec datetime_repr_is_valid_versioned(binary(), version()) -> boolean().
datetime_repr_is_valid_versioned(Text, Version) ->
    case Version of
        toml10 ->
            datetime_repr_is_valid(Text);

        toml11 ->
            case split_datetime(Text) of
                {ok, {Date, Time_offset}} ->
                    date_repr_is_valid(Date) andalso time_offset_repr_is_valid_versioned(
                        Time_offset,
                        Version
                    );

                {error, nil} ->
                    false
            end
    end.

-file("src/tomlet/parser.gleam", 1640).
?DOC(false).
-spec parse_date_like_value(binary(), version()) -> {ok, tomlet@ast:value()} |
    {error, nil}.
parse_date_like_value(Text, Version) ->
    gleam@bool:guard(
        datetime_repr_is_valid_versioned(Text, Version),
        {ok, {date_time, Text}},
        fun() ->
            gleam@bool:guard(
                time_repr_is_valid_versioned(Text, Version),
                {ok, {time, Text}},
                fun() ->
                    gleam@bool:guard(
                        date_repr_is_valid(Text),
                        {ok, {date, Text}},
                        fun() -> {error, nil} end
                    )
                end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 1632).
?DOC(false).
-spec parse_signed_exponent(binary()) -> {ok, integer()} | {error, nil}.
parse_signed_exponent(Text) ->
    Without_plus = case gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) of
        true ->
            gleam@string:drop_start(Text, 1);

        false ->
            Text
    end,
    gleam_stdlib:parse_int(Without_plus).

-file("src/tomlet/parser.gleam", 1621).
?DOC(false).
-spec parse_number_part_as_float(binary()) -> {ok, float()} | {error, nil}.
parse_number_part_as_float(Text) ->
    case gleam_stdlib:parse_float(Text) of
        {ok, Value} ->
            {ok, Value};

        {error, nil} ->
            case gleam_stdlib:parse_int(Text) of
                {ok, Value@1} ->
                    {ok, erlang:float(Value@1)};

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

-file("src/tomlet/parser.gleam", 1609).
?DOC(false).
-spec parse_exponent_float_parts({binary(), binary()}) -> {ok, float()} |
    {error, nil}.
parse_exponent_float_parts(Parts) ->
    {Mantissa, Exponent} = Parts,
    case {parse_number_part_as_float(Mantissa), parse_signed_exponent(Exponent)} of
        {{ok, Mantissa_value}, {ok, Exponent_value}} ->
            case gleam@float:power(10.0, erlang:float(Exponent_value)) of
                {ok, Scale} ->
                    {ok, Mantissa_value * Scale};

                {error, nil} ->
                    {error, nil}
            end;

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

-file("src/tomlet/parser.gleam", 1598).
?DOC(false).
-spec parse_exponent_float(binary()) -> {ok, float()} | {error, nil}.
parse_exponent_float(Text) ->
    case gleam@string:split_once(Text, <<"e"/utf8>>) of
        {ok, Parts} ->
            parse_exponent_float_parts(Parts);

        {error, nil} ->
            case gleam@string:split_once(Text, <<"E"/utf8>>) of
                {ok, Parts@1} ->
                    parse_exponent_float_parts(Parts@1);

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

-file("src/tomlet/parser.gleam", 1591).
?DOC(false).
-spec parse_toml_float(binary()) -> {ok, float()} | {error, nil}.
parse_toml_float(Text) ->
    case gleam_stdlib:parse_float(Text) of
        {ok, Value} ->
            {ok, Value};

        {error, nil} ->
            parse_exponent_float(Text)
    end.

-file("src/tomlet/parser.gleam", 1576).
?DOC(false).
-spec parse_special_float_value(binary(), binary()) -> {ok, tomlet@ast:value()} |
    {error, nil}.
parse_special_float_value(Normalized, Source_text) ->
    case Normalized of
        <<"inf"/utf8>> ->
            {ok, {special_float, positive_infinity, Source_text}};

        <<"+inf"/utf8>> ->
            {ok, {special_float, positive_infinity, Source_text}};

        <<"-inf"/utf8>> ->
            {ok, {special_float, negative_infinity, Source_text}};

        <<"nan"/utf8>> ->
            {ok, {special_float, not_a_number, Source_text}};

        <<"+nan"/utf8>> ->
            {ok, {special_float, not_a_number, Source_text}};

        <<"-nan"/utf8>> ->
            {ok, {special_float, not_a_number, Source_text}};

        _ ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 1945).
?DOC(false).
-spec mantissa_repr_is_valid(binary()) -> boolean().
mantissa_repr_is_valid(Text) ->
    case gleam@string:split_once(Text, <<"."/utf8>>) of
        {ok, {Whole, Fraction}} ->
            decimal_digits_are_valid(Whole) andalso separated_digits_are_valid(
                gleam@string:to_graphemes(Fraction),
                fun char_is_digit/1
            );

        {error, nil} ->
            decimal_digits_are_valid(Text)
    end.

-file("src/tomlet/parser.gleam", 1957).
?DOC(false).
-spec exponent_repr_is_valid(binary()) -> boolean().
exponent_repr_is_valid(Text) ->
    separated_digits_are_valid(
        gleam@string:to_graphemes(drop_sign(Text)),
        fun char_is_digit/1
    ).

-file("src/tomlet/parser.gleam", 1925).
?DOC(false).
-spec float_repr_is_valid(binary()) -> boolean().
float_repr_is_valid(Text) ->
    case Text of
        <<"inf"/utf8>> ->
            true;

        <<"+inf"/utf8>> ->
            true;

        <<"-inf"/utf8>> ->
            true;

        <<"nan"/utf8>> ->
            true;

        <<"+nan"/utf8>> ->
            true;

        <<"-nan"/utf8>> ->
            true;

        _ ->
            Unsigned = drop_sign(Text),
            case gleam@string:split_once(Unsigned, <<"e"/utf8>>) of
                {ok, {Mantissa, Exponent}} ->
                    mantissa_repr_is_valid(Mantissa) andalso exponent_repr_is_valid(
                        Exponent
                    );

                {error, nil} ->
                    case gleam@string:split_once(Unsigned, <<"E"/utf8>>) of
                        {ok, {Mantissa@1, Exponent@1}} ->
                            mantissa_repr_is_valid(Mantissa@1) andalso exponent_repr_is_valid(
                                Exponent@1
                            );

                        {error, nil} ->
                            mantissa_repr_is_valid(Unsigned)
                    end
            end
    end.

-file("src/tomlet/parser.gleam", 1547).
?DOC(false).
-spec parse_float_value(binary()) -> {ok, tomlet@ast:value()} | {error, nil}.
parse_float_value(Text) ->
    Normalized = gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>),
    case float_repr_is_valid(Text) andalso ((((((((gleam_stdlib:contains_string(
        Normalized,
        <<"."/utf8>>
    )
    orelse gleam_stdlib:contains_string(Normalized, <<"e"/utf8>>))
    orelse gleam_stdlib:contains_string(Normalized, <<"E"/utf8>>))
    orelse (Normalized =:= <<"inf"/utf8>>))
    orelse (Normalized =:= <<"+inf"/utf8>>))
    orelse (Normalized =:= <<"-inf"/utf8>>))
    orelse (Normalized =:= <<"nan"/utf8>>))
    orelse (Normalized =:= <<"+nan"/utf8>>))
    orelse (Normalized =:= <<"-nan"/utf8>>)) of
        true ->
            case parse_special_float_value(Normalized, Text) of
                {ok, Value} ->
                    {ok, Value};

                {error, nil} ->
                    case parse_toml_float(Normalized) of
                        {ok, Value@1} ->
                            {ok, {float, Value@1, Text}};

                        {error, _} ->
                            {error, nil}
                    end
            end;

        false ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 1539).
?DOC(false).
-spec parse_bool_value(binary()) -> {ok, tomlet@ast:value()} | {error, nil}.
parse_bool_value(Text) ->
    case Text of
        <<"true"/utf8>> ->
            {ok, {bool, true, Text}};

        <<"false"/utf8>> ->
            {ok, {bool, false, Text}};

        _ ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 2191).
?DOC(false).
-spec char_is_disallowed_control(binary()) -> boolean().
char_is_disallowed_control(Char) ->
    case Char of
        <<"\x{0000}"/utf8>> ->
            true;

        <<"\x{0001}"/utf8>> ->
            true;

        <<"\x{0002}"/utf8>> ->
            true;

        <<"\x{0003}"/utf8>> ->
            true;

        <<"\x{0004}"/utf8>> ->
            true;

        <<"\x{0005}"/utf8>> ->
            true;

        <<"\x{0006}"/utf8>> ->
            true;

        <<"\x{0007}"/utf8>> ->
            true;

        <<"\x{0008}"/utf8>> ->
            true;

        <<"\x{000B}"/utf8>> ->
            true;

        <<"\x{000C}"/utf8>> ->
            true;

        <<"\r"/utf8>> ->
            true;

        <<"\x{000E}"/utf8>> ->
            true;

        <<"\x{000F}"/utf8>> ->
            true;

        <<"\x{0010}"/utf8>> ->
            true;

        <<"\x{0011}"/utf8>> ->
            true;

        <<"\x{0012}"/utf8>> ->
            true;

        <<"\x{0013}"/utf8>> ->
            true;

        <<"\x{0014}"/utf8>> ->
            true;

        <<"\x{0015}"/utf8>> ->
            true;

        <<"\x{0016}"/utf8>> ->
            true;

        <<"\x{0017}"/utf8>> ->
            true;

        <<"\x{0018}"/utf8>> ->
            true;

        <<"\x{0019}"/utf8>> ->
            true;

        <<"\x{001A}"/utf8>> ->
            true;

        <<"\x{001B}"/utf8>> ->
            true;

        <<"\x{001C}"/utf8>> ->
            true;

        <<"\x{001D}"/utf8>> ->
            true;

        <<"\x{001E}"/utf8>> ->
            true;

        <<"\x{001F}"/utf8>> ->
            true;

        <<"\x{007F}"/utf8>> ->
            true;

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 1440).
?DOC(false).
-spec literal_string_chars_are_valid(list(binary())) -> boolean().
literal_string_chars_are_valid(Chars) ->
    case Chars of
        [] ->
            true;

        [<<"'"/utf8>> | _] ->
            false;

        [<<"\n"/utf8>> | _] ->
            false;

        [Char | Rest] ->
            case char_is_disallowed_control(Char) of
                true ->
                    false;

                false ->
                    literal_string_chars_are_valid(Rest)
            end
    end.

-file("src/tomlet/parser.gleam", 1436).
?DOC(false).
-spec literal_string_content_is_valid(binary()) -> boolean().
literal_string_content_is_valid(Text) ->
    literal_string_chars_are_valid(gleam@string:to_graphemes(Text)).

-file("src/tomlet/parser.gleam", 1420).
?DOC(false).
-spec parse_literal_string(binary()) -> {ok, tomlet@ast:value()} | {error, nil}.
parse_literal_string(Text) ->
    Is_delimited = gleam_stdlib:string_starts_with(Text, <<"'"/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"'"/utf8>>
    ),
    gleam@bool:guard(
        not Is_delimited,
        {error, nil},
        fun() ->
            Inner = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            gleam@bool:guard(
                not literal_string_content_is_valid(Inner),
                {error, nil},
                fun() -> {ok, {string, Inner, literal_string, Text}} end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 2283).
?DOC(false).
-spec hex_to_int(list(binary()), integer()) -> {ok, integer()} | {error, nil}.
hex_to_int(Chars, Acc) ->
    case Chars of
        [] ->
            {ok, Acc};

        [Char | Rest] ->
            case based_digit_value(Char) of
                {ok, Value} ->
                    hex_to_int(Rest, (Acc * 16) + Value);

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

-file("src/tomlet/parser.gleam", 1829).
?DOC(false).
-spec unicode_escape_scalar_is_valid(binary()) -> boolean().
unicode_escape_scalar_is_valid(Escape) ->
    case hex_to_int(gleam@string:to_graphemes(Escape), 0) of
        {ok, Value} ->
            case gleam@string:utf_codepoint(Value) of
                {ok, _} ->
                    true;

                {error, nil} ->
                    false
            end;

        {error, nil} ->
            false
    end.

-file("src/tomlet/parser.gleam", 2294).
?DOC(false).
-spec take_chars(list(binary()), integer(), binary()) -> {binary(),
    list(binary())}.
take_chars(Chars, Count, Acc) ->
    case {Count, Chars} of
        {0, _} ->
            {Acc, Chars};

        {_, [Char | Rest]} ->
            take_chars(Rest, Count - 1, <<Acc/binary, Char/binary>>);

        {_, []} ->
            {Acc, []}
    end.

-file("src/tomlet/parser.gleam", 1815).
?DOC(false).
-spec unicode_escape_is_valid_for(
    fun((list(binary())) -> boolean()),
    list(binary()),
    integer()
) -> boolean().
unicode_escape_is_valid_for(Validate_remaining, Chars, Count) ->
    {Escape, Remaining} = take_chars(Chars, Count, <<""/utf8>>),
    case (string:length(Escape) =:= Count) andalso unicode_escape_scalar_is_valid(
        Escape
    ) of
        true ->
            Validate_remaining(Remaining);

        false ->
            false
    end.

-file("src/tomlet/parser.gleam", 1789).
?DOC(false).
-spec hex_escape_is_valid_for(
    fun((list(binary())) -> boolean()),
    list(binary())
) -> boolean().
hex_escape_is_valid_for(Validate_remaining, Chars) ->
    case Chars of
        [High, Low | Rest] ->
            case is_hex_digit_string(High) andalso is_hex_digit_string(Low) of
                true ->
                    Validate_remaining(Rest);

                false ->
                    false
            end;

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 1803).
?DOC(false).
-spec unicode_escape_is_valid(list(binary()), integer(), version()) -> boolean().
unicode_escape_is_valid(Chars, Count, Version) ->
    unicode_escape_is_valid_for(
        fun(Remaining) -> basic_string_chars_are_valid(Remaining, Version) end,
        Chars,
        Count
    ).

-file("src/tomlet/parser.gleam", 1757).
?DOC(false).
-spec basic_string_chars_are_valid(list(binary()), version()) -> boolean().
basic_string_chars_are_valid(Chars, Version) ->
    case Chars of
        [] ->
            true;

        [<<"\\"/utf8>>] ->
            false;

        [<<"\\"/utf8>>, <<"e"/utf8>> | Rest] when Version =:= toml11 ->
            basic_string_chars_are_valid(Rest, Version);

        [<<"\\"/utf8>>, <<"x"/utf8>> | Rest@1] when Version =:= toml11 ->
            hex_escape_is_valid_for(
                fun(Remaining) ->
                    basic_string_chars_are_valid(Remaining, Version)
                end,
                Rest@1
            );

        [<<"\\"/utf8>>, Escaped | Rest@2] ->
            case Escaped of
                <<"b"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"t"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"n"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"f"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"r"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"\""/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"\\"/utf8>> ->
                    basic_string_chars_are_valid(Rest@2, Version);

                <<"u"/utf8>> ->
                    unicode_escape_is_valid(Rest@2, 4, Version);

                <<"U"/utf8>> ->
                    unicode_escape_is_valid(Rest@2, 8, Version);

                _ ->
                    false
            end;

        [<<"\n"/utf8>> | _] ->
            false;

        [<<"\""/utf8>> | _] ->
            false;

        [Char | Rest@3] ->
            case char_is_disallowed_control(Char) of
                true ->
                    false;

                false ->
                    basic_string_chars_are_valid(Rest@3, Version)
            end
    end.

-file("src/tomlet/parser.gleam", 1753).
?DOC(false).
-spec basic_string_content_is_valid(binary(), version()) -> boolean().
basic_string_content_is_valid(Text, Version) ->
    basic_string_chars_are_valid(gleam@string:to_graphemes(Text), Version).

-file("src/tomlet/parser.gleam", 1401).
?DOC(false).
-spec parse_basic_string(binary(), version()) -> {ok, tomlet@ast:value()} |
    {error, nil}.
parse_basic_string(Text, Version) ->
    Is_delimited = gleam_stdlib:string_starts_with(Text, <<"\""/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"\""/utf8>>
    ),
    gleam@bool:guard(
        not Is_delimited,
        {error, nil},
        fun() ->
            Inner = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            gleam@bool:guard(
                not basic_string_content_is_valid(Inner, Version),
                {error, nil},
                fun() -> {ok, {string, Inner, basic_string, Text}} end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 1527).
?DOC(false).
-spec multiline_literal_string_chars_are_valid(list(binary())) -> boolean().
multiline_literal_string_chars_are_valid(Chars) ->
    case Chars of
        [] ->
            true;

        [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | _] ->
            false;

        [Char | Rest] ->
            case char_is_disallowed_control(Char) of
                true ->
                    false;

                false ->
                    multiline_literal_string_chars_are_valid(Rest)
            end
    end.

-file("src/tomlet/parser.gleam", 1523).
?DOC(false).
-spec multiline_literal_string_content_is_valid(binary()) -> boolean().
multiline_literal_string_content_is_valid(Text) ->
    multiline_literal_string_chars_are_valid(gleam@string:to_graphemes(Text)).

-file("src/tomlet/parser.gleam", 1386).
?DOC(false).
-spec parse_multiline_literal_string(binary()) -> {ok, tomlet@ast:value()} |
    {error, nil}.
parse_multiline_literal_string(Text) ->
    Is_delimited = gleam_stdlib:string_starts_with(Text, <<"'''"/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"'''"/utf8>>
    ),
    gleam@bool:guard(
        not Is_delimited,
        {error, nil},
        fun() ->
            Inner = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 3),
                gleam@string:drop_end(_pipe@1, 3)
            end,
            Content_valid = (Text /= <<"'''"/utf8>>) andalso multiline_literal_string_content_is_valid(
                Inner
            ),
            gleam@bool:guard(
                not Content_valid,
                {error, nil},
                fun() -> {ok, {string, Inner, multi_literal_string, Text}} end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 1508).
?DOC(false).
-spec multiline_basic_line_ending_escape_is_valid(list(binary()), version()) -> boolean().
multiline_basic_line_ending_escape_is_valid(Chars, Version) ->
    case Chars of
        [] ->
            false;

        [<<" "/utf8>> | Rest] ->
            multiline_basic_line_ending_escape_is_valid(Rest, Version);

        [<<"\t"/utf8>> | Rest@1] ->
            multiline_basic_line_ending_escape_is_valid(Rest@1, Version);

        [<<"\n"/utf8>> | Rest@2] ->
            multiline_basic_string_chars_are_valid(Rest@2, Version);

        [<<"\r"/utf8>>, <<"\n"/utf8>> | Rest@3] ->
            multiline_basic_string_chars_are_valid(Rest@3, Version);

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 1482).
?DOC(false).
-spec multiline_basic_escape_is_valid(list(binary()), version()) -> boolean().
multiline_basic_escape_is_valid(Chars, Version) ->
    Continue = fun(Rest) ->
        multiline_basic_string_chars_are_valid(Rest, Version)
    end,
    case Chars of
        [] ->
            false;

        [<<"\n"/utf8>> | Rest@1] ->
            Continue(Rest@1);

        [<<"\r"/utf8>>, <<"\n"/utf8>> | Rest@2] ->
            Continue(Rest@2);

        [<<" "/utf8>> | Rest@3] ->
            multiline_basic_line_ending_escape_is_valid(Rest@3, Version);

        [<<"\t"/utf8>> | Rest@4] ->
            multiline_basic_line_ending_escape_is_valid(Rest@4, Version);

        [<<"e"/utf8>> | Rest@5] when Version =:= toml11 ->
            Continue(Rest@5);

        [<<"x"/utf8>> | Rest@6] when Version =:= toml11 ->
            hex_escape_is_valid_for(Continue, Rest@6);

        [Escaped | Rest@7] ->
            case Escaped of
                <<"b"/utf8>> ->
                    Continue(Rest@7);

                <<"t"/utf8>> ->
                    Continue(Rest@7);

                <<"n"/utf8>> ->
                    Continue(Rest@7);

                <<"f"/utf8>> ->
                    Continue(Rest@7);

                <<"r"/utf8>> ->
                    Continue(Rest@7);

                <<"\""/utf8>> ->
                    Continue(Rest@7);

                <<"\\"/utf8>> ->
                    Continue(Rest@7);

                <<"u"/utf8>> ->
                    unicode_escape_is_valid_for(Continue, Rest@7, 4);

                <<"U"/utf8>> ->
                    unicode_escape_is_valid_for(Continue, Rest@7, 8);

                _ ->
                    false
            end
    end.

-file("src/tomlet/parser.gleam", 1465).
?DOC(false).
-spec multiline_basic_string_chars_are_valid(list(binary()), version()) -> boolean().
multiline_basic_string_chars_are_valid(Chars, Version) ->
    case Chars of
        [] ->
            true;

        [<<"\\"/utf8>>] ->
            false;

        [<<"\\"/utf8>> | Rest] ->
            multiline_basic_escape_is_valid(Rest, Version);

        [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | _] ->
            false;

        [Char | Rest@1] ->
            case char_is_disallowed_control(Char) of
                true ->
                    false;

                false ->
                    multiline_basic_string_chars_are_valid(Rest@1, Version)
            end
    end.

-file("src/tomlet/parser.gleam", 1458).
?DOC(false).
-spec multiline_basic_string_content_is_valid(binary(), version()) -> boolean().
multiline_basic_string_content_is_valid(Text, Version) ->
    multiline_basic_string_chars_are_valid(
        gleam@string:to_graphemes(Text),
        Version
    ).

-file("src/tomlet/parser.gleam", 1368).
?DOC(false).
-spec parse_multiline_basic_string(binary(), version()) -> {ok,
        tomlet@ast:value()} |
    {error, nil}.
parse_multiline_basic_string(Text, Version) ->
    Is_delimited = gleam_stdlib:string_starts_with(Text, <<"\"\"\""/utf8>>)
    andalso gleam_stdlib:string_ends_with(Text, <<"\"\"\""/utf8>>),
    gleam@bool:guard(
        not Is_delimited,
        {error, nil},
        fun() ->
            Inner = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 3),
                gleam@string:drop_end(_pipe@1, 3)
            end,
            Content_valid = (Text /= <<"\"\"\""/utf8>>) andalso multiline_basic_string_content_is_valid(
                Inner,
                Version
            ),
            gleam@bool:guard(
                not Content_valid,
                {error, nil},
                fun() -> {ok, {string, Inner, multi_basic_string, Text}} end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 966).
?DOC(false).
-spec parse_scalar_value(binary(), integer(), version()) -> {ok,
        tomlet@ast:value()} |
    {error, parse_error()}.
parse_scalar_value(Text, Offset, Version) ->
    Parsers = [fun(Text@1) -> parse_multiline_basic_string(Text@1, Version) end,
        fun parse_multiline_literal_string/1,
        fun(Text@2) -> parse_basic_string(Text@2, Version) end,
        fun parse_literal_string/1,
        fun parse_bool_value/1,
        fun parse_float_value/1,
        fun(Text@3) -> parse_date_like_value(Text@3, Version) end],
    case gleam@list:find_map(Parsers, fun(Parse) -> Parse(Text) end) of
        {ok, Value} ->
            {ok, Value};

        {error, nil} ->
            parse_int_value(Text, Offset)
    end.

-file("src/tomlet/parser.gleam", 1305).
?DOC(false).
-spec strip_state_step(list(binary()), strip_state(), boolean()) -> strip_step().
strip_state_step(Chars, State, Close_single_line_on_newline) ->
    case {State, Chars} of
        {_, []} ->
            {strip_step, [], State, <<""/utf8>>};

        {strip_normal, [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | Rest]} ->
            {strip_step, Rest, strip_multi_basic, <<"\"\"\""/utf8>>};

        {strip_normal, [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | Rest@1]} ->
            {strip_step, Rest@1, strip_multi_literal, <<"'''"/utf8>>};

        {strip_normal, [<<"\""/utf8>> | Rest@2]} ->
            {strip_step, Rest@2, strip_basic, <<"\""/utf8>>};

        {strip_normal, [<<"'"/utf8>> | Rest@3]} ->
            {strip_step, Rest@3, strip_literal, <<"'"/utf8>>};

        {strip_normal, [Char | Rest@4]} ->
            {strip_step, Rest@4, strip_normal, Char};

        {strip_basic, [<<"\\"/utf8>>, Escaped | Rest@5]} ->
            {strip_step, Rest@5, strip_basic, <<"\\"/utf8, Escaped/binary>>};

        {strip_basic, [<<"\""/utf8>> | Rest@6]} ->
            {strip_step, Rest@6, strip_normal, <<"\""/utf8>>};

        {strip_basic, [<<"\n"/utf8>> | Rest@7]} when Close_single_line_on_newline ->
            {strip_step, Rest@7, strip_normal, <<"\n"/utf8>>};

        {strip_basic, [Char@1 | Rest@8]} ->
            {strip_step, Rest@8, strip_basic, Char@1};

        {strip_literal, [<<"'"/utf8>> | Rest@9]} ->
            {strip_step, Rest@9, strip_normal, <<"'"/utf8>>};

        {strip_literal, [<<"\n"/utf8>> | Rest@10]} when Close_single_line_on_newline ->
            {strip_step, Rest@10, strip_normal, <<"\n"/utf8>>};

        {strip_literal, [Char@2 | Rest@11]} ->
            {strip_step, Rest@11, strip_literal, Char@2};

        {strip_multi_basic, [<<"\\"/utf8>>, Escaped@1 | Rest@12]} ->
            {strip_step,
                Rest@12,
                strip_multi_basic,
                <<"\\"/utf8, Escaped@1/binary>>};

        {strip_multi_basic,
            [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | Rest@13]} ->
            {strip_step, Rest@13, strip_normal, <<"\"\"\""/utf8>>};

        {strip_multi_basic, [Char@3 | Rest@14]} ->
            {strip_step, Rest@14, strip_multi_basic, Char@3};

        {strip_multi_literal,
            [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | Rest@15]} ->
            {strip_step, Rest@15, strip_normal, <<"'''"/utf8>>};

        {strip_multi_literal, [Char@4 | Rest@16]} ->
            {strip_step, Rest@16, strip_multi_literal, Char@4}
    end.

-file("src/tomlet/parser.gleam", 1079).
?DOC(false).
-spec trim_start_byte_offset(binary()) -> integer().
trim_start_byte_offset(Text) ->
    erlang:byte_size(Text) - erlang:byte_size(gleam@string:trim_start(Text)).

-file("src/tomlet/parser.gleam", 997).
?DOC(false).
-spec split_top_level_commas_loop(
    list(binary()),
    integer(),
    strip_state(),
    binary(),
    integer(),
    list({binary(), integer()})
) -> list({binary(), integer()}).
split_top_level_commas_loop(Chars, Depth, State, Current, Current_start, Parts) ->
    case {State, Chars} of
        {_, []} ->
            lists:reverse(
                [{gleam@string:trim(Current),
                        Current_start + trim_start_byte_offset(Current)} |
                    Parts]
            );

        {strip_normal, [<<","/utf8>> | Rest]} when Depth =:= 0 ->
            split_top_level_commas_loop(
                Rest,
                Depth,
                strip_normal,
                <<""/utf8>>,
                (Current_start + erlang:byte_size(Current)) + 1,
                [{gleam@string:trim(Current),
                        Current_start + trim_start_byte_offset(Current)} |
                    Parts]
            );

        {strip_normal, [<<"["/utf8>> | Rest@1]} ->
            split_top_level_commas_loop(
                Rest@1,
                Depth + 1,
                strip_normal,
                <<Current/binary, "["/utf8>>,
                Current_start,
                Parts
            );

        {strip_normal, [<<"{"/utf8>> | Rest@2]} ->
            split_top_level_commas_loop(
                Rest@2,
                Depth + 1,
                strip_normal,
                <<Current/binary, "{"/utf8>>,
                Current_start,
                Parts
            );

        {strip_normal, [<<"]"/utf8>> | Rest@3]} ->
            split_top_level_commas_loop(
                Rest@3,
                Depth - 1,
                strip_normal,
                <<Current/binary, "]"/utf8>>,
                Current_start,
                Parts
            );

        {strip_normal, [<<"}"/utf8>> | Rest@4]} ->
            split_top_level_commas_loop(
                Rest@4,
                Depth - 1,
                strip_normal,
                <<Current/binary, "}"/utf8>>,
                Current_start,
                Parts
            );

        {_, _} ->
            {strip_step, Rest@5, Next_state, Consumed} = strip_state_step(
                Chars,
                State,
                false
            ),
            split_top_level_commas_loop(
                Rest@5,
                Depth,
                Next_state,
                <<Current/binary, Consumed/binary>>,
                Current_start,
                Parts
            )
    end.

-file("src/tomlet/parser.gleam", 986).
?DOC(false).
-spec split_top_level_commas(binary()) -> list({binary(), integer()}).
split_top_level_commas(Text) ->
    split_top_level_commas_loop(
        gleam@string:to_graphemes(Text),
        0,
        strip_normal,
        <<""/utf8>>,
        0,
        []
    ).

-file("src/tomlet/parser.gleam", 1346).
?DOC(false).
-spec strip_inline_comments_loop(list(binary()), strip_state(), binary()) -> binary().
strip_inline_comments_loop(Chars, State, Acc) ->
    case {State, Chars} of
        {_, []} ->
            Acc;

        {strip_normal, [<<"#"/utf8>> | Rest]} ->
            strip_inline_comments_loop(
                gleam@list:drop_while(
                    Rest,
                    fun(Char) -> Char /= <<"\n"/utf8>> end
                ),
                strip_normal,
                Acc
            );

        {_, _} ->
            {strip_step, Rest@1, Next_state, Consumed} = strip_state_step(
                Chars,
                State,
                true
            ),
            strip_inline_comments_loop(
                Rest@1,
                Next_state,
                <<Acc/binary, Consumed/binary>>
            )
    end.

-file("src/tomlet/parser.gleam", 1289).
?DOC(false).
-spec strip_inline_comments_by_line(binary()) -> binary().
strip_inline_comments_by_line(Text) ->
    strip_inline_comments_loop(
        gleam@string:to_graphemes(Text),
        strip_normal,
        <<""/utf8>>
    ).

-file("src/tomlet/parser.gleam", 2272).
?DOC(false).
-spec unicode_escape_to_string(binary()) -> binary().
unicode_escape_to_string(Escape) ->
    case hex_to_int(gleam@string:to_graphemes(Escape), 0) of
        {ok, Value} ->
            case gleam@string:utf_codepoint(Value) of
                {ok, Codepoint} ->
                    gleam_stdlib:utf_codepoint_list_to_string([Codepoint]);

                {error, nil} ->
                    <<<<"\\u{"/utf8, Escape/binary>>/binary, "}"/utf8>>
            end;

        {error, nil} ->
            <<<<"\\u{"/utf8, Escape/binary>>/binary, "}"/utf8>>
    end.

-file("src/tomlet/parser.gleam", 2232).
?DOC(false).
-spec basic_key_value_loop(list(binary()), binary()) -> binary().
basic_key_value_loop(Chars, Acc) ->
    case Chars of
        [] ->
            Acc;

        [<<"\\"/utf8>>, Escaped | Rest] ->
            case Escaped of
                <<"b"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\x{0008}"/utf8>>);

                <<"t"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\t"/utf8>>);

                <<"n"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\n"/utf8>>);

                <<"f"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\x{000C}"/utf8>>);

                <<"r"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\r"/utf8>>);

                <<"\""/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\""/utf8>>);

                <<"\\"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\\"/utf8>>);

                <<"e"/utf8>> ->
                    basic_key_value_loop(Rest, <<Acc/binary, "\x{001B}"/utf8>>);

                <<"x"/utf8>> ->
                    {Escape, Remaining} = take_chars(Rest, 2, <<""/utf8>>),
                    basic_key_value_loop(
                        Remaining,
                        <<Acc/binary,
                            (unicode_escape_to_string(Escape))/binary>>
                    );

                <<"u"/utf8>> ->
                    {Escape@1, Remaining@1} = take_chars(Rest, 4, <<""/utf8>>),
                    basic_key_value_loop(
                        Remaining@1,
                        <<Acc/binary,
                            (unicode_escape_to_string(Escape@1))/binary>>
                    );

                <<"U"/utf8>> ->
                    {Escape@2, Remaining@2} = take_chars(Rest, 8, <<""/utf8>>),
                    basic_key_value_loop(
                        Remaining@2,
                        <<Acc/binary,
                            (unicode_escape_to_string(Escape@2))/binary>>
                    );

                _ ->
                    basic_key_value_loop(
                        Rest,
                        <<<<Acc/binary, "\\"/utf8>>/binary, Escaped/binary>>
                    )
            end;

        [Char | Rest@1] ->
            basic_key_value_loop(Rest@1, <<Acc/binary, Char/binary>>)
    end.

-file("src/tomlet/parser.gleam", 2228).
?DOC(false).
-spec basic_key_value(binary()) -> binary().
basic_key_value(Text) ->
    basic_key_value_loop(gleam@string:to_graphemes(Text), <<""/utf8>>).

-file("src/tomlet/parser.gleam", 1453).
?DOC(false).
-spec string_is_multiline_delimited(binary()) -> boolean().
string_is_multiline_delimited(Text) ->
    (gleam_stdlib:string_starts_with(Text, <<"\"\"\""/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"\"\"\""/utf8>>
    ))
    orelse (gleam_stdlib:string_starts_with(Text, <<"'''"/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"'''"/utf8>>
    )).

-file("src/tomlet/parser.gleam", 749).
?DOC(false).
-spec parse_key_segment(binary(), version()) -> {ok, tomlet@ast:key_segment()} |
    {error, nil}.
parse_key_segment(Segment, Version) ->
    Trimmed = gleam@string:trim(Segment),
    gleam@bool:guard(
        Trimmed =:= <<""/utf8>>,
        {error, nil},
        fun() ->
            gleam@bool:guard(
                string_is_multiline_delimited(Trimmed),
                {error, nil},
                fun() ->
                    case (gleam_stdlib:string_starts_with(
                        Trimmed,
                        <<"\""/utf8>>
                    )
                    andalso gleam_stdlib:string_ends_with(
                        Trimmed,
                        <<"\""/utf8>>
                    ))
                    andalso (string:length(Trimmed) > 1) of
                        true ->
                            Inner = begin
                                _pipe = Trimmed,
                                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                                gleam@string:drop_end(_pipe@1, 1)
                            end,
                            case basic_string_content_is_valid(Inner, Version) of
                                true ->
                                    {ok,
                                        {quoted_key_segment,
                                            basic_key_value(Inner),
                                            Trimmed}};

                                false ->
                                    {error, nil}
                            end;

                        false ->
                            case (gleam_stdlib:string_starts_with(
                                Trimmed,
                                <<"'"/utf8>>
                            )
                            andalso gleam_stdlib:string_ends_with(
                                Trimmed,
                                <<"'"/utf8>>
                            ))
                            andalso (string:length(Trimmed) > 1) of
                                true ->
                                    {ok,
                                        {quoted_key_segment,
                                            begin
                                                _pipe@2 = Trimmed,
                                                _pipe@3 = gleam@string:drop_start(
                                                    _pipe@2,
                                                    1
                                                ),
                                                gleam@string:drop_end(
                                                    _pipe@3,
                                                    1
                                                )
                                            end,
                                            Trimmed}};

                                false ->
                                    case (((gleam_stdlib:string_starts_with(
                                        Trimmed,
                                        <<"\""/utf8>>
                                    )
                                    orelse gleam_stdlib:string_ends_with(
                                        Trimmed,
                                        <<"\""/utf8>>
                                    ))
                                    orelse gleam_stdlib:string_starts_with(
                                        Trimmed,
                                        <<"'"/utf8>>
                                    ))
                                    orelse gleam_stdlib:string_ends_with(
                                        Trimmed,
                                        <<"'"/utf8>>
                                    ))
                                    orelse not tomlet@key:is_bare_key(Trimmed) of
                                        true ->
                                            {error, nil};

                                        false ->
                                            {ok, {bare_key_segment, Trimmed}}
                                    end
                            end
                    end
                end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 568).
?DOC(false).
-spec split_key_segments_loop(
    list(binary()),
    binary(),
    list(binary()),
    boolean(),
    boolean()
) -> list(binary()).
split_key_segments_loop(Chars, Current, Segments, In_basic, In_literal) ->
    case Chars of
        [] ->
            lists:reverse([Current | Segments]);

        [<<"\\"/utf8>>, Escaped | Rest] ->
            case In_basic of
                true ->
                    split_key_segments_loop(
                        Rest,
                        <<<<Current/binary, "\\"/utf8>>/binary, Escaped/binary>>,
                        Segments,
                        In_basic,
                        In_literal
                    );

                false ->
                    split_key_segments_loop(
                        Rest,
                        <<Current/binary, "\\"/utf8>>,
                        Segments,
                        In_basic,
                        In_literal
                    )
            end;

        [<<"."/utf8>> | Rest@1] ->
            case In_basic orelse In_literal of
                true ->
                    split_key_segments_loop(
                        Rest@1,
                        <<Current/binary, "."/utf8>>,
                        Segments,
                        In_basic,
                        In_literal
                    );

                false ->
                    split_key_segments_loop(
                        Rest@1,
                        <<""/utf8>>,
                        [Current | Segments],
                        In_basic,
                        In_literal
                    )
            end;

        [<<"\""/utf8>> | Rest@2] ->
            case In_literal of
                true ->
                    split_key_segments_loop(
                        Rest@2,
                        <<Current/binary, "\""/utf8>>,
                        Segments,
                        In_basic,
                        In_literal
                    );

                false ->
                    split_key_segments_loop(
                        Rest@2,
                        <<Current/binary, "\""/utf8>>,
                        Segments,
                        not In_basic,
                        In_literal
                    )
            end;

        [<<"'"/utf8>> | Rest@3] ->
            case In_basic of
                true ->
                    split_key_segments_loop(
                        Rest@3,
                        <<Current/binary, "'"/utf8>>,
                        Segments,
                        In_basic,
                        In_literal
                    );

                false ->
                    split_key_segments_loop(
                        Rest@3,
                        <<Current/binary, "'"/utf8>>,
                        Segments,
                        In_basic,
                        not In_literal
                    )
            end;

        [Char | Rest@4] ->
            split_key_segments_loop(
                Rest@4,
                <<Current/binary, Char/binary>>,
                Segments,
                In_basic,
                In_literal
            )
    end.

-file("src/tomlet/parser.gleam", 564).
?DOC(false).
-spec split_key_segments_text(binary()) -> list(binary()).
split_key_segments_text(Text) ->
    split_key_segments_loop(
        gleam@string:to_graphemes(Text),
        <<""/utf8>>,
        [],
        false,
        false
    ).

-file("src/tomlet/parser.gleam", 554).
?DOC(false).
-spec parse_key(binary(), version()) -> {ok, tomlet@ast:key()} | {error, nil}.
parse_key(Text, Version) ->
    _pipe = split_key_segments_text(Text),
    _pipe@1 = gleam@list:try_map(
        _pipe,
        fun(Segment) -> parse_key_segment(Segment, Version) end
    ),
    gleam@result:map(_pipe@1, fun(Field@0) -> {key, Field@0} end).

-file("src/tomlet/parser.gleam", 744).
?DOC(false).
-spec bool_pick(boolean(), binary(), binary()) -> binary().
bool_pick(Condition, Yes, No) ->
    gleam@bool:guard(Condition, Yes, fun() -> No end).

-file("src/tomlet/parser.gleam", 664).
?DOC(false).
-spec split_key_value_loop(
    list(binary()),
    binary(),
    binary(),
    boolean(),
    boolean(),
    boolean()
) -> {ok, {binary(), binary()}} | {error, nil}.
split_key_value_loop(Chars, Key, Value, In_basic, In_literal, Found) ->
    case Chars of
        [] ->
            case Found of
                true ->
                    {ok, {Key, Value}};

                false ->
                    {error, nil}
            end;

        [Char | Rest] ->
            case {Char, Found, In_basic, In_literal} of
                {<<"\\"/utf8>>, _, true, false} ->
                    case Rest of
                        [] ->
                            split_key_value_loop(
                                Rest,
                                Key,
                                Value,
                                In_basic,
                                In_literal,
                                Found
                            );

                        [Escaped | After_escape] ->
                            split_key_value_loop(
                                After_escape,
                                <<Key/binary,
                                    (bool_pick(
                                        not Found,
                                        <<"\\"/utf8, Escaped/binary>>,
                                        <<""/utf8>>
                                    ))/binary>>,
                                <<Value/binary,
                                    (bool_pick(
                                        Found,
                                        <<"\\"/utf8, Escaped/binary>>,
                                        <<""/utf8>>
                                    ))/binary>>,
                                In_basic,
                                In_literal,
                                Found
                            )
                    end;

                {<<"="/utf8>>, false, false, false} ->
                    split_key_value_loop(
                        Rest,
                        Key,
                        Value,
                        In_basic,
                        In_literal,
                        true
                    );

                {<<"\""/utf8>>, _, _, false} ->
                    split_key_value_loop(
                        Rest,
                        <<Key/binary,
                            (bool_pick(not Found, <<"\""/utf8>>, <<""/utf8>>))/binary>>,
                        <<Value/binary,
                            (bool_pick(Found, <<"\""/utf8>>, <<""/utf8>>))/binary>>,
                        not In_basic,
                        In_literal,
                        Found
                    );

                {<<"'"/utf8>>, _, false, _} ->
                    split_key_value_loop(
                        Rest,
                        <<Key/binary,
                            (bool_pick(not Found, <<"'"/utf8>>, <<""/utf8>>))/binary>>,
                        <<Value/binary,
                            (bool_pick(Found, <<"'"/utf8>>, <<""/utf8>>))/binary>>,
                        In_basic,
                        not In_literal,
                        Found
                    );

                {_, false, _, _} ->
                    split_key_value_loop(
                        Rest,
                        <<Key/binary, Char/binary>>,
                        Value,
                        In_basic,
                        In_literal,
                        Found
                    );

                {_, true, _, _} ->
                    split_key_value_loop(
                        Rest,
                        Key,
                        <<Value/binary, Char/binary>>,
                        In_basic,
                        In_literal,
                        Found
                    )
            end
    end.

-file("src/tomlet/parser.gleam", 560).
?DOC(false).
-spec split_key_value(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
split_key_value(Line) ->
    split_key_value_loop(
        gleam@string:to_graphemes(Line),
        <<""/utf8>>,
        <<""/utf8>>,
        false,
        false,
        false
    ).

-file("src/tomlet/parser.gleam", 1196).
?DOC(false).
-spec inline_table_newlines_are_valid_loop(
    list(binary()),
    integer(),
    strip_state()
) -> boolean().
inline_table_newlines_are_valid_loop(Chars, Depth, State) ->
    case {State, Chars} of
        {_, []} ->
            true;

        {strip_normal, [<<"\n"/utf8>> | Rest]} ->
            case Depth > 0 of
                true ->
                    inline_table_newlines_are_valid_loop(
                        Rest,
                        Depth,
                        strip_normal
                    );

                false ->
                    false
            end;

        {strip_normal, [<<"["/utf8>> | Rest@1]} ->
            inline_table_newlines_are_valid_loop(
                Rest@1,
                Depth + 1,
                strip_normal
            );

        {strip_normal, [<<"{"/utf8>> | Rest@2]} ->
            inline_table_newlines_are_valid_loop(
                Rest@2,
                Depth + 1,
                strip_normal
            );

        {strip_normal, [<<"]"/utf8>> | Rest@3]} ->
            inline_table_newlines_are_valid_loop(
                Rest@3,
                Depth - 1,
                strip_normal
            );

        {strip_normal, [<<"}"/utf8>> | Rest@4]} ->
            inline_table_newlines_are_valid_loop(
                Rest@4,
                Depth - 1,
                strip_normal
            );

        {_, _} ->
            {strip_step, Rest@5, Next_state, _} = strip_state_step(
                Chars,
                State,
                false
            ),
            inline_table_newlines_are_valid_loop(Rest@5, Depth, Next_state)
    end.

-file("src/tomlet/parser.gleam", 1184).
?DOC(false).
-spec inline_table_newlines_are_valid(binary(), version()) -> boolean().
inline_table_newlines_are_valid(Text, Version) ->
    case Version of
        toml11 ->
            true;

        toml10 ->
            inline_table_newlines_are_valid_loop(
                gleam@string:to_graphemes(Text),
                0,
                strip_normal
            )
    end.

-file("src/tomlet/parser.gleam", 1225).
?DOC(false).
-spec parse_inline_entries(
    list({binary(), integer()}),
    integer(),
    list(list(binary())),
    version()
) -> {ok, list(tomlet@ast:inline_table_entry())} | {error, parse_error()}.
parse_inline_entries(Parts, Body_offset, Seen, Version) ->
    case Parts of
        [] ->
            {ok, []};

        [{Part, Part_offset} | Rest] ->
            Entry_offset = Body_offset + Part_offset,
            case gleam@string:trim(Part) of
                <<""/utf8>> ->
                    case {Version, Rest} of
                        {toml11, []} ->
                            {ok, []};

                        {_, _} ->
                            {error,
                                {unexpected,
                                    <<""/utf8>>,
                                    expected_syntax,
                                    Entry_offset}}
                    end;

                _ ->
                    gleam@result:'try'(
                        gleam@result:replace_error(
                            split_key_value(Part),
                            {unexpected, Part, expected_syntax, Entry_offset}
                        ),
                        fun(_use0) ->
                            {Raw_key, Raw_value} = _use0,
                            gleam@result:'try'(
                                gleam@result:replace_error(
                                    parse_key(
                                        gleam@string:trim(Raw_key),
                                        Version
                                    ),
                                    {unexpected,
                                        Part,
                                        expected_key,
                                        Entry_offset}
                                ),
                                fun(Key) ->
                                    Key_path = tomlet@key:to_strings(Key),
                                    gleam@bool:guard(
                                        key_path_conflicts(Seen, Key_path),
                                        {error,
                                            {unexpected,
                                                Part,
                                                expected_syntax,
                                                Entry_offset}},
                                        fun() ->
                                            gleam@result:'try'(
                                                parse_value(
                                                    gleam@string:trim(
                                                        strip_inline_comments_by_line(
                                                            Raw_value
                                                        )
                                                    ),
                                                    ((Entry_offset + erlang:byte_size(
                                                        Raw_key
                                                    ))
                                                    + 1)
                                                    + trim_start_byte_offset(
                                                        Raw_value
                                                    ),
                                                    Version
                                                ),
                                                fun(Value) ->
                                                    gleam@result:'try'(
                                                        parse_inline_entries(
                                                            Rest,
                                                            Body_offset,
                                                            [Key_path | Seen],
                                                            Version
                                                        ),
                                                        fun(Entries) ->
                                                            {ok,
                                                                [{inline_table_entry,
                                                                        {trivia,
                                                                            <<""/utf8>>},
                                                                        Key,
                                                                        Value,
                                                                        {trivia,
                                                                            <<""/utf8>>}} |
                                                                    Entries]}
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
            end
    end.

-file("src/tomlet/parser.gleam", 1146).
?DOC(false).
-spec parse_inline_table_value(binary(), integer(), version()) -> {ok,
        tomlet@ast:value()} |
    {error, parse_error()}.
parse_inline_table_value(Text, Offset, Version) ->
    Is_inline_table = gleam_stdlib:string_starts_with(Text, <<"{"/utf8>>)
    andalso gleam_stdlib:string_ends_with(Text, <<"}"/utf8>>),
    gleam@bool:guard(
        not Is_inline_table,
        {error, {unexpected, Text, expected_syntax, Offset}},
        fun() ->
            Body = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            Clean_body = strip_inline_comments_by_line(Body),
            gleam@bool:guard(
                not inline_table_newlines_are_valid(Body, Version),
                {error, {unexpected, Text, expected_syntax, Offset}},
                fun() -> case gleam@string:trim(Clean_body) of
                        <<""/utf8>> ->
                            {ok, {inline_table, [], Text}};

                        _ ->
                            case parse_inline_entries(
                                split_top_level_commas(Clean_body),
                                Offset + 1,
                                [],
                                Version
                            ) of
                                {ok, Entries} ->
                                    {ok, {inline_table, Entries, Text}};

                                {error, Error} ->
                                    {error, Error}
                            end
                    end end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 1115).
?DOC(false).
-spec parse_array_items(list({binary(), integer()}), integer(), version()) -> {ok,
        list(tomlet@ast:array_item())} |
    {error, parse_error()}.
parse_array_items(Parts, Body_offset, Version) ->
    case Parts of
        [] ->
            {ok, []};

        [{Part, Part_offset} | Rest] ->
            case gleam@string:trim(strip_inline_comments_by_line(Part)) of
                <<""/utf8>> ->
                    case Rest of
                        [] ->
                            {ok, []};

                        _ ->
                            {error,
                                {unexpected,
                                    <<""/utf8>>,
                                    expected_value,
                                    Body_offset + Part_offset}}
                    end;

                Clean_part ->
                    case parse_value(
                        Clean_part,
                        Body_offset + Part_offset,
                        Version
                    ) of
                        {ok, Value} ->
                            case parse_array_items(Rest, Body_offset, Version) of
                                {ok, Items} ->
                                    {ok,
                                        [{array_item,
                                                {trivia, <<""/utf8>>},
                                                Value,
                                                {trivia, <<""/utf8>>}} |
                                            Items]};

                                {error, Error} ->
                                    {error, Error}
                            end;

                        {error, Error@1} ->
                            {error, Error@1}
                    end
            end
    end.

-file("src/tomlet/parser.gleam", 1083).
?DOC(false).
-spec parse_array_value(binary(), integer(), version()) -> {ok,
        tomlet@ast:value()} |
    {error, parse_error()}.
parse_array_value(Text, Offset, Version) ->
    Is_array = gleam_stdlib:string_starts_with(Text, <<"["/utf8>>) andalso gleam_stdlib:string_ends_with(
        Text,
        <<"]"/utf8>>
    ),
    gleam@bool:guard(
        not Is_array,
        {error, {unexpected, Text, expected_syntax, Offset}},
        fun() ->
            Body = begin
                _pipe = Text,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            Clean_body = strip_inline_comments_by_line(Body),
            case gleam@string:trim(Clean_body) of
                <<""/utf8>> ->
                    {ok, {array, [], Text}};

                _ ->
                    case parse_array_items(
                        split_top_level_commas(Clean_body),
                        Offset + 1,
                        Version
                    ) of
                        {ok, Items} ->
                            {ok, {array, Items, Text}};

                        {error, Error} ->
                            {error, Error}
                    end
            end
        end
    ).

-file("src/tomlet/parser.gleam", 951).
?DOC(false).
-spec parse_value(binary(), integer(), version()) -> {ok, tomlet@ast:value()} |
    {error, parse_error()}.
parse_value(Text, Offset, Version) ->
    case gleam_stdlib:string_starts_with(Text, <<"["/utf8>>) of
        true ->
            parse_array_value(Text, Offset, Version);

        false ->
            case gleam_stdlib:string_starts_with(Text, <<"{"/utf8>>) of
                true ->
                    parse_inline_table_value(Text, Offset, Version);

                false ->
                    parse_scalar_value(Text, Offset, Version)
            end
    end.

-file("src/tomlet/parser.gleam", 310).
?DOC(false).
-spec spans_source(list(tomlet@lexer:spanned())) -> binary().
spans_source(Spans) ->
    _pipe = Spans,
    _pipe@1 = gleam@list:map(
        _pipe,
        fun(Span) ->
            {spanned, Token, _} = Span,
            Token
        end
    ),
    william:to_source(_pipe@1).

-file("src/tomlet/parser.gleam", 298).
?DOC(false).
-spec finish_value(
    list(tomlet@lexer:spanned()),
    integer(),
    list(tomlet@lexer:spanned()),
    version()
) -> {ok, {tomlet@ast:value(), binary(), list(tomlet@lexer:spanned())}} |
    {error, parse_error()}.
finish_value(Span, Offset, Rest, Version) ->
    Source = spans_source(Span),
    gleam@result:'try'(
        parse_value(Source, Offset, Version),
        fun(Value) ->
            gleam@result:map(
                scan_trailing(Rest, <<""/utf8>>),
                fun(_use0) ->
                    {Trailing, After} = _use0,
                    {Value, Trailing, After}
                end
            )
        end
    ).

-file("src/tomlet/parser.gleam", 322).
?DOC(false).
-spec balanced_span(
    list(tomlet@lexer:spanned()),
    integer(),
    list(tomlet@lexer:spanned())
) -> {list(tomlet@lexer:spanned()), list(tomlet@lexer:spanned())}.
balanced_span(Spans, Depth, Acc) ->
    case Spans of
        [] ->
            {lists:reverse(Acc), []};

        [Span | Rest] ->
            {spanned, Token, _} = Span,
            Next_depth = case Token of
                open_bracket ->
                    Depth + 1;

                open_brace ->
                    Depth + 1;

                close_bracket ->
                    Depth - 1;

                close_brace ->
                    Depth - 1;

                _ ->
                    Depth
            end,
            Acc@1 = [Span | Acc],
            case Next_depth =:= 0 of
                true ->
                    {lists:reverse(Acc@1), Rest};

                false ->
                    balanced_span(Rest, Next_depth, Acc@1)
            end
    end.

-file("src/tomlet/parser.gleam", 143).
?DOC(false).
-spec take_whitespace(list(tomlet@lexer:spanned()), binary()) -> {binary(),
    list(tomlet@lexer:spanned())}.
take_whitespace(Spans, Acc) ->
    case Spans of
        [{spanned, {whitespace, Text}, _} | Rest] ->
            take_whitespace(Rest, <<Acc/binary, Text/binary>>);

        _ ->
            {Acc, Spans}
    end.

-file("src/tomlet/parser.gleam", 264).
?DOC(false).
-spec parse_value_tokens(list(tomlet@lexer:spanned()), integer(), version()) -> {ok,
        {tomlet@ast:value(), binary(), list(tomlet@lexer:spanned())}} |
    {error, parse_error()}.
parse_value_tokens(Spans, Equal_offset, Version) ->
    {_, Spans@1} = take_whitespace(Spans, <<""/utf8>>),
    case Spans@1 of
        [{spanned, open_bracket, Offset} | _] ->
            {Span, Rest} = balanced_span(Spans@1, 0, []),
            finish_value(Span, Offset, Rest, Version);

        [{spanned, open_brace, Offset@1} | _] ->
            {Span@1, Rest@1} = balanced_span(Spans@1, 0, []),
            finish_value(Span@1, Offset@1, Rest@1, Version);

        [{spanned, {end_of_line, _}, Offset@2} | _] ->
            gleam@result:map(
                parse_value(<<""/utf8>>, Offset@2, Version),
                fun(Value) -> {Value, <<""/utf8>>, Spans@1} end
            );

        [{spanned, {comment, _}, Offset@2} | _] ->
            gleam@result:map(
                parse_value(<<""/utf8>>, Offset@2, Version),
                fun(Value) -> {Value, <<""/utf8>>, Spans@1} end
            );

        [] ->
            gleam@result:map(
                parse_value(<<""/utf8>>, Equal_offset + 1, Version),
                fun(Value@1) -> {Value@1, <<""/utf8>>, []} end
            );

        [{spanned, Token, Offset@3} | Rest@2] ->
            gleam@result:'try'(
                parse_value(token_src(Token), Offset@3, Version),
                fun(Value@2) ->
                    gleam@result:map(
                        scan_trailing(Rest@2, <<""/utf8>>),
                        fun(_use0) ->
                            {Trailing, After} = _use0,
                            {Value@2, Trailing, After}
                        end
                    )
                end
            )
    end.

-file("src/tomlet/parser.gleam", 204).
?DOC(false).
-spec key_segment_from_string(william:string_delimiter(), binary(), version()) -> {ok,
        tomlet@ast:key_segment()} |
    {error, nil}.
key_segment_from_string(Delimiter, Value, Version) ->
    case Delimiter of
        basic_string ->
            case basic_string_content_is_valid(Value, Version) of
                true ->
                    {ok,
                        {quoted_key_segment,
                            basic_key_value(Value),
                            <<<<"\""/utf8, Value/binary>>/binary, "\""/utf8>>}};

                false ->
                    {error, nil}
            end;

        literal_string ->
            {ok,
                {quoted_key_segment,
                    Value,
                    <<<<"'"/utf8, Value/binary>>/binary, "'"/utf8>>}};

        multiline_basic_string ->
            {error, nil};

        multiline_literal_string ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 164).
?DOC(false).
-spec collect_segments(
    list(tomlet@lexer:spanned()),
    boolean(),
    list(tomlet@ast:key_segment()),
    version()
) -> {ok, {list(tomlet@ast:key_segment()), list(tomlet@lexer:spanned())}} |
    {error, parse_error()}.
collect_segments(Spans, Expect_segment, Acc, Version) ->
    {_, Spans@1} = take_whitespace(Spans, <<""/utf8>>),
    case Spans@1 of
        [{spanned, {bare_key, Name}, _} | Rest] when Expect_segment ->
            collect_segments(
                Rest,
                false,
                [{bare_key_segment, Name} | Acc],
                Version
            );

        [{spanned, {string, Delimiter, Value}, Offset} | Rest@1] when Expect_segment ->
            case key_segment_from_string(Delimiter, Value, Version) of
                {ok, Segment} ->
                    collect_segments(Rest@1, false, [Segment | Acc], Version);

                {error, nil} ->
                    {error,
                        {unexpected,
                            token_src({string, Delimiter, Value}),
                            expected_key,
                            Offset}}
            end;

        [{spanned, dot, _} | Rest@2] when not Expect_segment ->
            collect_segments(Rest@2, true, Acc, Version);

        _ ->
            case Expect_segment of
                true ->
                    case Spans@1 of
                        [{spanned, Token, Offset@1} | _] ->
                            {error,
                                {unexpected,
                                    token_src(Token),
                                    expected_key,
                                    Offset@1}};

                        [] ->
                            {error, {unexpected, <<""/utf8>>, expected_key, 0}}
                    end;

                false ->
                    {ok, {lists:reverse(Acc), Spans@1}}
            end
    end.

-file("src/tomlet/parser.gleam", 807).
?DOC(false).
-spec remove_keys_under_table(list(list(binary())), list(binary())) -> list(list(binary())).
remove_keys_under_table(Seen, Table_key) ->
    gleam@list:filter(
        Seen,
        fun(Key) -> not tomlet@key:starts_with(Key, Table_key) end
    ).

-file("src/tomlet/parser.gleam", 862).
?DOC(false).
-spec array_table_parent_already_implied(
    tomlet@ast:header(),
    list(list(binary())),
    list(list(binary())),
    list(binary())
) -> boolean().
array_table_parent_already_implied(
    Header,
    Array_tables,
    Array_table_parents,
    Key
) ->
    case Header of
        {header, _, array_of_tables_header, _} ->
            gleam@list:contains(Array_table_parents, Key) andalso not gleam@list:contains(
                Array_tables,
                Key
            );

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 849).
?DOC(false).
-spec table_kind_already_defined(
    tomlet@ast:header(),
    list(list(binary())),
    list(list(binary())),
    list(binary())
) -> boolean().
table_kind_already_defined(Header, Explicit_tables, Array_tables, Key) ->
    case Header of
        {header, _, standard_table, _} ->
            gleam@list:contains(Array_tables, Key);

        {header, _, array_of_tables_header, _} ->
            gleam@list:contains(Explicit_tables, Key)
    end.

-file("src/tomlet/parser.gleam", 837).
?DOC(false).
-spec standard_table_already_defined(
    tomlet@ast:header(),
    list(list(binary())),
    list(binary())
) -> boolean().
standard_table_already_defined(Header, Explicit_tables, Key) ->
    case Header of
        {header, _, standard_table, _} ->
            gleam@list:contains(Explicit_tables, Key);

        _ ->
            false
    end.

-file("src/tomlet/parser.gleam", 824).
?DOC(false).
-spec key_path_conflicts_for_table_header(list(list(binary())), list(binary())) -> boolean().
key_path_conflicts_for_table_header(Seen, Key) ->
    case Seen of
        [] ->
            false;

        [Existing | Rest] ->
            ((Existing =:= Key) orelse tomlet@key:starts_with(Key, Existing))
            orelse key_path_conflicts_for_table_header(Rest, Key)
    end.

-file("src/tomlet/parser.gleam", 802).
?DOC(false).
-spec header_key(tomlet@ast:header()) -> list(binary()).
header_key(Header) ->
    {header, Key, _, _} = Header,
    tomlet@key:to_strings(Key).

-file("src/tomlet/parser.gleam", 463).
?DOC(false).
-spec apply_header_state(assembly_state(), tomlet@ast:header(), integer()) -> {ok,
        assembly_state()} |
    {error, parse_error()}.
apply_header_state(State, Header, Open_offset) ->
    Table_key = header_key(Header),
    case (((key_path_conflicts_for_table_header(
        erlang:element(3, State),
        Table_key
    )
    orelse gleam@list:contains(erlang:element(7, State), Table_key))
    orelse standard_table_already_defined(
        Header,
        erlang:element(4, State),
        Table_key
    ))
    orelse table_kind_already_defined(
        Header,
        erlang:element(4, State),
        erlang:element(5, State),
        Table_key
    ))
    orelse array_table_parent_already_implied(
        Header,
        erlang:element(5, State),
        erlang:element(6, State),
        Table_key
    ) of
        true ->
            {error, {key_already_in_use, Table_key, Open_offset}};

        false ->
            Is_array = case Header of
                {header, _, array_of_tables_header, _} ->
                    true;

                _ ->
                    false
            end,
            Next_seen = case Is_array of
                true ->
                    remove_keys_under_table(erlang:element(3, State), Table_key);

                false ->
                    erlang:element(3, State)
            end,
            Next_explicit = case Header of
                {header, _, standard_table, _} ->
                    [Table_key | erlang:element(4, State)];

                {header, _, array_of_tables_header, _} ->
                    remove_keys_under_table(erlang:element(4, State), Table_key)
            end,
            Next_dotted = case Is_array of
                true ->
                    remove_keys_under_table(erlang:element(7, State), Table_key);

                false ->
                    erlang:element(7, State)
            end,
            Next_arrays = case Is_array of
                true ->
                    [Table_key | erlang:element(5, State)];

                false ->
                    erlang:element(5, State)
            end,
            Next_parents = case Is_array of
                true ->
                    add_paths(
                        dotted_table_paths([], Table_key),
                        erlang:element(6, State)
                    );

                false ->
                    erlang:element(6, State)
            end,
            {ok,
                {assembly_state,
                    Table_key,
                    Next_seen,
                    Next_explicit,
                    Next_arrays,
                    Next_parents,
                    Next_dotted}}
    end.

-file("src/tomlet/parser.gleam", 416).
?DOC(false).
-spec scan_header_trailing(list(tomlet@lexer:spanned()), integer()) -> {ok,
        list(tomlet@lexer:spanned())} |
    {error, parse_error()}.
scan_header_trailing(Spans, Open_offset) ->
    case Spans of
        [] ->
            {ok, []};

        [{spanned, {whitespace, _}, _} | Rest] ->
            scan_header_trailing(Rest, Open_offset);

        [{spanned, {comment, _}, _} | Rest@1] ->
            scan_header_trailing(Rest@1, Open_offset);

        [{spanned, {end_of_line, _}, _} | Rest@2] ->
            {ok, Rest@2};

        [{spanned, _, _} | _] ->
            {error,
                {unexpected, <<""/utf8>>, expected_table_header, Open_offset}}
    end.

-file("src/tomlet/parser.gleam", 407).
?DOC(false).
-spec after_key_is_close_array_table(list(tomlet@lexer:spanned())) -> {ok,
        list(tomlet@lexer:spanned())} |
    {error, nil}.
after_key_is_close_array_table(Spans) ->
    case Spans of
        [{spanned, close_array_table, _} | Rest] ->
            {ok, Rest};

        _ ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 398).
?DOC(false).
-spec after_key_is_close_table(list(tomlet@lexer:spanned())) -> {ok,
        list(tomlet@lexer:spanned())} |
    {error, nil}.
after_key_is_close_table(Spans) ->
    case Spans of
        [{spanned, close_table, _} | Rest] ->
            {ok, Rest};

        _ ->
            {error, nil}
    end.

-file("src/tomlet/parser.gleam", 154).
?DOC(false).
-spec drop_one_eol(list(tomlet@lexer:spanned())) -> list(tomlet@lexer:spanned()).
drop_one_eol(Spans) ->
    case Spans of
        [{spanned, {end_of_line, _}, _} | Rest] ->
            Rest;

        _ ->
            Spans
    end.

-file("src/tomlet/parser.gleam", 223).
?DOC(false).
-spec parse_key_value_tokens(
    list(tomlet@lexer:spanned()),
    integer(),
    assembly_state(),
    list(tomlet@ast:entry()),
    version()
) -> {ok, tomlet@ast:table()} | {error, parse_error()}.
parse_key_value_tokens(Spans, Key_offset, State, Entries, Version) ->
    gleam@result:'try'(
        collect_segments(Spans, true, [], Version),
        fun(_use0) ->
            {Segments, After_key} = _use0,
            case After_key of
                [{spanned, equal, Equal_offset} | After_equal] ->
                    Key = {key, Segments},
                    gleam@result:'try'(
                        parse_value_tokens(After_equal, Equal_offset, Version),
                        fun(_use0@1) ->
                            {Value, Trailing, Rest} = _use0@1,
                            Entry = {key_value,
                                {trivia, <<""/utf8>>},
                                Key,
                                Value,
                                {trivia, <<Trailing/binary, "\n"/utf8>>}},
                            gleam@result:'try'(
                                apply_key_value_state(State, Key, Key_offset),
                                fun(Next_state) ->
                                    assemble_loop(
                                        Rest,
                                        Next_state,
                                        [Entry | Entries],
                                        Version
                                    )
                                end
                            )
                        end
                    );

                [{spanned, Token, Offset} | _] ->
                    {error,
                        {unexpected, token_src(Token), expected_syntax, Offset}};

                [] ->
                    {error,
                        {unexpected, <<""/utf8>>, expected_syntax, Key_offset}}
            end
        end
    ).

-file("src/tomlet/parser.gleam", 364).
?DOC(false).
-spec parse_header_tokens(
    list(tomlet@lexer:spanned()),
    tomlet@ast:header_kind(),
    integer(),
    assembly_state(),
    list(tomlet@ast:entry()),
    version()
) -> {ok, tomlet@ast:table()} | {error, parse_error()}.
parse_header_tokens(Spans, Kind, Open_offset, State, Entries, Version) ->
    gleam@result:'try'(
        collect_segments(Spans, true, [], Version),
        fun(_use0) ->
            {Segments, After_key} = _use0,
            Closer = case Kind of
                standard_table ->
                    after_key_is_close_table(After_key);

                array_of_tables_header ->
                    after_key_is_close_array_table(After_key)
            end,
            case Closer of
                {ok, After_close} ->
                    gleam@result:'try'(
                        scan_header_trailing(After_close, Open_offset),
                        fun(Rest) ->
                            Header = {header,
                                {key, Segments},
                                Kind,
                                {trivia, <<""/utf8>>}},
                            Entry = {table_header, Header},
                            gleam@result:'try'(
                                apply_header_state(State, Header, Open_offset),
                                fun(Next_state) ->
                                    assemble_loop(
                                        Rest,
                                        Next_state,
                                        [Entry | Entries],
                                        Version
                                    )
                                end
                            )
                        end
                    );

                {error, nil} ->
                    {error,
                        {unexpected,
                            <<""/utf8>>,
                            expected_table_header,
                            Open_offset}}
            end
        end
    ).

-file("src/tomlet/parser.gleam", 80).
?DOC(false).
-spec assemble_loop(
    list(tomlet@lexer:spanned()),
    assembly_state(),
    list(tomlet@ast:entry()),
    version()
) -> {ok, tomlet@ast:table()} | {error, parse_error()}.
assemble_loop(Spans, State, Entries, Version) ->
    {Leading_ws, Rest} = take_whitespace(Spans, <<""/utf8>>),
    case Rest of
        [] ->
            case Leading_ws of
                <<""/utf8>> ->
                    {ok, {table, lists:reverse(Entries), none}};

                _ ->
                    {ok, {table, lists:reverse([blank_line | Entries]), none}}
            end;

        [{spanned, {end_of_line, _}, _} | Tail] ->
            assemble_loop(Tail, State, [blank_line | Entries], Version);

        [{spanned, {comment, Text}, _} | Tail@1] ->
            assemble_loop(
                drop_one_eol(Tail@1),
                State,
                [{comment, <<Leading_ws/binary, Text/binary>>} | Entries],
                Version
            );

        [{spanned, open_table, Offset} | Tail@2] ->
            parse_header_tokens(
                Tail@2,
                standard_table,
                Offset,
                State,
                Entries,
                Version
            );

        [{spanned, open_array_table, Offset@1} | Tail@3] ->
            parse_header_tokens(
                Tail@3,
                array_of_tables_header,
                Offset@1,
                State,
                Entries,
                Version
            );

        [{spanned, {bare_key, _}, Offset@2} | _] ->
            parse_key_value_tokens(Rest, Offset@2, State, Entries, Version);

        [{spanned, {string, _, _}, Offset@2} | _] ->
            parse_key_value_tokens(Rest, Offset@2, State, Entries, Version);

        [{spanned, Token, Offset@3} | _] ->
            {error, {unexpected, token_src(Token), expected_syntax, Offset@3}}
    end.

-file("src/tomlet/parser.gleam", 61).
?DOC(false).
-spec assemble(list(tomlet@lexer:spanned()), version()) -> {ok,
        tomlet@ast:table()} |
    {error, parse_error()}.
assemble(Spans, Version) ->
    assemble_loop(Spans, {assembly_state, [], [], [], [], [], []}, [], Version).

-file("src/tomlet/parser.gleam", 536).
?DOC(false).
-spec first_disallowed_control_offset_loop(list(binary()), integer()) -> {ok,
        integer()} |
    {error, nil}.
first_disallowed_control_offset_loop(Chars, Offset) ->
    case Chars of
        [] ->
            {error, nil};

        [Char | Rest] ->
            case char_is_disallowed_control(Char) of
                true ->
                    {ok, Offset};

                false ->
                    first_disallowed_control_offset_loop(
                        Rest,
                        Offset + erlang:byte_size(Char)
                    )
            end
    end.

-file("src/tomlet/parser.gleam", 532).
?DOC(false).
-spec first_disallowed_control_offset(binary()) -> {ok, integer()} |
    {error, nil}.
first_disallowed_control_offset(Input) ->
    first_disallowed_control_offset_loop(gleam@string:to_graphemes(Input), 0).

-file("src/tomlet/parser.gleam", 40).
?DOC(false).
-spec parse(binary(), version()) -> {ok, tomlet@ast:table()} |
    {error, parse_error()}.
parse(Input, Version) ->
    case first_disallowed_control_offset(Input) of
        {ok, Offset} ->
            {error, {unexpected, <<""/utf8>>, expected_syntax, Offset}};

        {error, nil} ->
            assemble(tomlet@lexer:lex(Input), Version)
    end.