Skip to main content

src/william.erl

-module(william).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/william.gleam").
-export([new/0, tokenise/2, to_highlight/1, highlight/1, to_ansi/1, to_html/1, to_source/1, ignore_whitespace/1, ignore_comments/1]).
-export_type([highlight_token/0, highlight_context/0, token/0, base/0, string_delimiter/0, mode/0, container/0, lexer/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.

-type highlight_token() :: {highlight_error, binary()} |
    {highlight_key, binary()} |
    {highlight_table, binary()} |
    {highlight_string, binary()} |
    {highlight_number, binary()} |
    {highlight_date_time, binary()} |
    {highlight_literal, binary()} |
    {highlight_operator, binary()} |
    {highlight_punctuation, binary()} |
    {highlight_comment, binary()} |
    {highlight_whitespace, binary()}.

-type highlight_context() :: normal | table_header.

-type token() :: {end_of_line, binary()} |
    {whitespace, binary()} |
    {comment, binary()} |
    {bare_key, binary()} |
    {string, string_delimiter(), binary()} |
    {boolean, binary()} |
    {integer, base(), binary()} |
    {float, binary()} |
    {date_time, binary()} |
    equal |
    dot |
    comma |
    open_table |
    close_table |
    open_array_table |
    close_array_table |
    open_bracket |
    close_bracket |
    open_brace |
    close_brace |
    {unexpected, binary()} |
    {invalid_number, binary()} |
    {unterminated_string, string_delimiter(), binary()}.

-type base() :: binary | octal | decimal | hexadecimal.

-type string_delimiter() :: basic_string |
    literal_string |
    multiline_basic_string |
    multiline_literal_string.

-type mode() :: key_mode | value_mode | after_value_mode | table_mode.

-type container() :: array_container | inline_table_container.

-opaque lexer() :: {lexer,
        boolean(),
        boolean(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter(),
        splitter:splitter()}.

-file("src/william.gleam", 325).
?DOC(
    " Create a new Lexer with default settings.\n"
    "\n"
    " Lexers can be cached and reused to parse many source files efficiently.\n"
).
-spec new() -> lexer().
new() ->
    {lexer,
        false,
        false,
        splitter:new([<<"\r\n"/utf8>>, <<"\n"/utf8>>, <<"\r"/utf8>>]),
        splitter:new(
            [<<"\r\n"/utf8>>,
                <<"\n"/utf8>>,
                <<"\r"/utf8>>,
                <<" "/utf8>>,
                <<"\t"/utf8>>,
                <<"#"/utf8>>,
                <<","/utf8>>,
                <<"]"/utf8>>,
                <<"}"/utf8>>,
                <<"["/utf8>>,
                <<"{"/utf8>>,
                <<"="/utf8>>,
                <<"\""/utf8>>,
                <<"'"/utf8>>]
        ),
        splitter:new(
            [<<"\r\n"/utf8>>,
                <<"\n"/utf8>>,
                <<"\r"/utf8>>,
                <<" "/utf8>>,
                <<"\t"/utf8>>,
                <<"#"/utf8>>,
                <<","/utf8>>,
                <<"]"/utf8>>,
                <<"}"/utf8>>]
        ),
        splitter:new(
            [<<"\r\n"/utf8>>,
                <<"\n"/utf8>>,
                <<"\r"/utf8>>,
                <<"\\"/utf8>>,
                <<"\""/utf8>>]
        ),
        splitter:new(
            [<<"\r\n"/utf8>>, <<"\n"/utf8>>, <<"\r"/utf8>>, <<"'"/utf8>>]
        ),
        splitter:new(
            [<<"\"\"\"\"\""/utf8>>,
                <<"\"\"\"\""/utf8>>,
                <<"\"\"\""/utf8>>,
                <<"\\"/utf8>>]
        ),
        splitter:new([<<"'''''"/utf8>>, <<"''''"/utf8>>, <<"'''"/utf8>>])}.

-file("src/william.gleam", 594).
-spec emit(lexer(), token(), list(token())) -> list(token()).
emit(Lexer, Token, Acc) ->
    case Token of
        {whitespace, _} ->
            case erlang:element(2, Lexer) of
                true ->
                    Acc;

                false ->
                    [Token | Acc]
            end;

        {end_of_line, _} ->
            case erlang:element(2, Lexer) of
                true ->
                    Acc;

                false ->
                    [Token | Acc]
            end;

        {comment, _} ->
            case erlang:element(3, Lexer) of
                true ->
                    Acc;

                false ->
                    [Token | Acc]
            end;

        _ ->
            [Token | Acc]
    end.

-file("src/william.gleam", 784).
-spec unexpected(lexer(), binary(), binary()) -> {token(), binary()}.
unexpected(Lexer, Input, Acc) ->
    {Unexpected, Rest} = splitter_ffi:split_before(
        erlang:element(6, Lexer),
        Input
    ),
    {{unexpected, <<Acc/binary, Unexpected/binary>>}, Rest}.

-file("src/william.gleam", 1311).
-spec invalid_number(lexer(), binary(), binary()) -> {token(), binary()}.
invalid_number(Lexer, Input, Acc) ->
    {Unexpected, Rest} = splitter_ffi:split_before(
        erlang:element(5, Lexer),
        Input
    ),
    {{invalid_number, <<Acc/binary, Unexpected/binary>>}, Rest}.

-file("src/william.gleam", 1320).
-spec is_value_terminator(binary()) -> boolean().
is_value_terminator(Input) ->
    case Input of
        <<""/utf8>> ->
            true;

        <<" "/utf8, _/binary>> ->
            true;

        <<"\t"/utf8, _/binary>> ->
            true;

        <<"\r\n"/utf8, _/binary>> ->
            true;

        <<"\n"/utf8, _/binary>> ->
            true;

        <<"\r"/utf8, _/binary>> ->
            true;

        <<"#"/utf8, _/binary>> ->
            true;

        <<","/utf8, _/binary>> ->
            true;

        <<"]"/utf8, _/binary>> ->
            true;

        <<"}"/utf8, _/binary>> ->
            true;

        _ ->
            false
    end.

-file("src/william.gleam", 1299).
-spec number_end(lexer(), binary(), binary(), fun((binary()) -> token())) -> {token(),
    binary()}.
number_end(Lexer, Input, Acc, Token) ->
    case is_value_terminator(Input) of
        true ->
            {Token(Acc), Input};

        false ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1283).
-spec take_digit(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
take_digit(Input) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            {ok, {<<"0"/utf8>>, Rest}};

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

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

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

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

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

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

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

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

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

        _ ->
            {error, nil}
    end.

-file("src/william.gleam", 1272).
-spec take_two_digits(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
take_two_digits(Input) ->
    case take_digit(Input) of
        {ok, {First, Rest}} ->
            case take_digit(Rest) of
                {ok, {Second, Rest@1}} ->
                    {ok, {<<First/binary, Second/binary>>, Rest@1}};

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

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

-file("src/william.gleam", 1260).
-spec offset(lexer(), binary(), binary()) -> {token(), binary()}.
offset(Lexer, Input, Acc) ->
    case take_two_digits(Input) of
        {ok, {Hour, <<":"/utf8, Rest/binary>>}} ->
            case take_two_digits(Rest) of
                {ok, {Minute, Rest@1}} ->
                    number_end(
                        Lexer,
                        Rest@1,
                        <<<<<<Acc/binary, Hour/binary>>/binary, ":"/utf8>>/binary,
                            Minute/binary>>,
                        fun(Field@0) -> {date_time, Field@0} end
                    );

                _ ->
                    invalid_number(Lexer, Input, Acc)
            end;

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1245).
-spec date_time_end(lexer(), binary(), binary(), boolean()) -> {token(),
    binary()}.
date_time_end(Lexer, Input, Acc, Allow_offset) ->
    case Input of
        <<"Z"/utf8, Rest/binary>> when Allow_offset ->
            number_end(
                Lexer,
                Rest,
                <<Acc/binary, "Z"/utf8>>,
                fun(Field@0) -> {date_time, Field@0} end
            );

        <<"z"/utf8, Rest@1/binary>> when Allow_offset ->
            number_end(
                Lexer,
                Rest@1,
                <<Acc/binary, "z"/utf8>>,
                fun(Field@0) -> {date_time, Field@0} end
            );

        <<"+"/utf8, Rest@2/binary>> when Allow_offset ->
            offset(Lexer, Rest@2, <<Acc/binary, "+"/utf8>>);

        <<"-"/utf8, Rest@3/binary>> when Allow_offset ->
            offset(Lexer, Rest@3, <<Acc/binary, "-"/utf8>>);

        _ ->
            number_end(
                Lexer,
                Input,
                Acc,
                fun(Field@0) -> {date_time, Field@0} end
            )
    end.

-file("src/william.gleam", 1224).
-spec fraction_digits(lexer(), binary(), binary(), boolean()) -> {token(),
    binary()}.
fraction_digits(Lexer, Input, Acc, Allow_offset) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            fraction_digits(Lexer, Rest, <<Acc/binary, "0"/utf8>>, Allow_offset);

        <<"1"/utf8, Rest@1/binary>> ->
            fraction_digits(
                Lexer,
                Rest@1,
                <<Acc/binary, "1"/utf8>>,
                Allow_offset
            );

        <<"2"/utf8, Rest@2/binary>> ->
            fraction_digits(
                Lexer,
                Rest@2,
                <<Acc/binary, "2"/utf8>>,
                Allow_offset
            );

        <<"3"/utf8, Rest@3/binary>> ->
            fraction_digits(
                Lexer,
                Rest@3,
                <<Acc/binary, "3"/utf8>>,
                Allow_offset
            );

        <<"4"/utf8, Rest@4/binary>> ->
            fraction_digits(
                Lexer,
                Rest@4,
                <<Acc/binary, "4"/utf8>>,
                Allow_offset
            );

        <<"5"/utf8, Rest@5/binary>> ->
            fraction_digits(
                Lexer,
                Rest@5,
                <<Acc/binary, "5"/utf8>>,
                Allow_offset
            );

        <<"6"/utf8, Rest@6/binary>> ->
            fraction_digits(
                Lexer,
                Rest@6,
                <<Acc/binary, "6"/utf8>>,
                Allow_offset
            );

        <<"7"/utf8, Rest@7/binary>> ->
            fraction_digits(
                Lexer,
                Rest@7,
                <<Acc/binary, "7"/utf8>>,
                Allow_offset
            );

        <<"8"/utf8, Rest@8/binary>> ->
            fraction_digits(
                Lexer,
                Rest@8,
                <<Acc/binary, "8"/utf8>>,
                Allow_offset
            );

        <<"9"/utf8, Rest@9/binary>> ->
            fraction_digits(
                Lexer,
                Rest@9,
                <<Acc/binary, "9"/utf8>>,
                Allow_offset
            );

        _ ->
            date_time_end(Lexer, Input, Acc, Allow_offset)
    end.

-file("src/william.gleam", 1203).
-spec fraction(lexer(), binary(), binary(), boolean()) -> {token(), binary()}.
fraction(Lexer, Input, Acc, Allow_offset) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            fraction_digits(Lexer, Rest, <<Acc/binary, "0"/utf8>>, Allow_offset);

        <<"1"/utf8, Rest@1/binary>> ->
            fraction_digits(
                Lexer,
                Rest@1,
                <<Acc/binary, "1"/utf8>>,
                Allow_offset
            );

        <<"2"/utf8, Rest@2/binary>> ->
            fraction_digits(
                Lexer,
                Rest@2,
                <<Acc/binary, "2"/utf8>>,
                Allow_offset
            );

        <<"3"/utf8, Rest@3/binary>> ->
            fraction_digits(
                Lexer,
                Rest@3,
                <<Acc/binary, "3"/utf8>>,
                Allow_offset
            );

        <<"4"/utf8, Rest@4/binary>> ->
            fraction_digits(
                Lexer,
                Rest@4,
                <<Acc/binary, "4"/utf8>>,
                Allow_offset
            );

        <<"5"/utf8, Rest@5/binary>> ->
            fraction_digits(
                Lexer,
                Rest@5,
                <<Acc/binary, "5"/utf8>>,
                Allow_offset
            );

        <<"6"/utf8, Rest@6/binary>> ->
            fraction_digits(
                Lexer,
                Rest@6,
                <<Acc/binary, "6"/utf8>>,
                Allow_offset
            );

        <<"7"/utf8, Rest@7/binary>> ->
            fraction_digits(
                Lexer,
                Rest@7,
                <<Acc/binary, "7"/utf8>>,
                Allow_offset
            );

        <<"8"/utf8, Rest@8/binary>> ->
            fraction_digits(
                Lexer,
                Rest@8,
                <<Acc/binary, "8"/utf8>>,
                Allow_offset
            );

        <<"9"/utf8, Rest@9/binary>> ->
            fraction_digits(
                Lexer,
                Rest@9,
                <<Acc/binary, "9"/utf8>>,
                Allow_offset
            );

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1188).
-spec time_seconds(lexer(), binary(), binary(), boolean()) -> {token(),
    binary()}.
time_seconds(Lexer, Input, Acc, Allow_offset) ->
    case take_two_digits(Input) of
        {ok, {Second, <<"."/utf8, Rest/binary>>}} ->
            fraction(
                Lexer,
                Rest,
                <<<<Acc/binary, Second/binary>>/binary, "."/utf8>>,
                Allow_offset
            );

        {ok, {Second@1, Rest@1}} ->
            date_time_end(
                Lexer,
                Rest@1,
                <<Acc/binary, Second@1/binary>>,
                Allow_offset
            );

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1170).
-spec time_minutes(lexer(), binary(), binary(), boolean()) -> {token(),
    binary()}.
time_minutes(Lexer, Input, Acc, Allow_offset) ->
    case take_two_digits(Input) of
        {ok, {Minute, Rest}} ->
            Acc@1 = <<Acc/binary, Minute/binary>>,
            case Rest of
                <<":"/utf8, Rest@1/binary>> ->
                    time_seconds(
                        Lexer,
                        Rest@1,
                        <<Acc@1/binary, ":"/utf8>>,
                        Allow_offset
                    );

                _ ->
                    date_time_end(Lexer, Rest, Acc@1, Allow_offset)
            end;

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1162).
-spec date_time(lexer(), binary(), binary()) -> {token(), binary()}.
date_time(Lexer, Input, Acc) ->
    case take_two_digits(Input) of
        {ok, {Hour, <<":"/utf8, Rest/binary>>}} ->
            time_minutes(
                Lexer,
                Rest,
                <<<<Acc/binary, Hour/binary>>/binary, ":"/utf8>>,
                true
            );

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1148).
-spec date_tail(lexer(), binary(), binary()) -> {token(), binary()}.
date_tail(Lexer, Input, Acc) ->
    case Input of
        <<"T"/utf8, Rest/binary>> ->
            date_time(Lexer, Rest, <<Acc/binary, "T"/utf8>>);

        <<"t"/utf8, Rest@1/binary>> ->
            date_time(Lexer, Rest@1, <<Acc/binary, "t"/utf8>>);

        <<" "/utf8, Rest@2/binary>> ->
            case take_two_digits(Rest@2) of
                {ok, {Hour, <<":"/utf8, Rest@3/binary>>}} ->
                    time_minutes(
                        Lexer,
                        Rest@3,
                        <<<<<<Acc/binary, " "/utf8>>/binary, Hour/binary>>/binary,
                            ":"/utf8>>,
                        true
                    );

                _ ->
                    number_end(
                        Lexer,
                        Input,
                        Acc,
                        fun(Field@0) -> {date_time, Field@0} end
                    )
            end;

        _ ->
            number_end(
                Lexer,
                Input,
                Acc,
                fun(Field@0) -> {date_time, Field@0} end
            )
    end.

-file("src/william.gleam", 1137).
-spec date(lexer(), binary(), binary()) -> {token(), binary()}.
date(Lexer, Input, Acc) ->
    case take_two_digits(Input) of
        {ok, {Month, <<"-"/utf8, Rest/binary>>}} ->
            case take_two_digits(Rest) of
                {ok, {Day, Rest@1}} ->
                    date_tail(
                        Lexer,
                        Rest@1,
                        <<<<<<Acc/binary, Month/binary>>/binary, "-"/utf8>>/binary,
                            Day/binary>>
                    );

                _ ->
                    invalid_number(Lexer, Input, Acc)
            end;

        _ ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 1111).
-spec exponent(lexer(), binary(), binary()) -> {token(), binary()}.
exponent(Lexer, Input, Acc) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            exponent(Lexer, Rest, <<Acc/binary, "0"/utf8>>);

        <<"1"/utf8, Rest@1/binary>> ->
            exponent(Lexer, Rest@1, <<Acc/binary, "1"/utf8>>);

        <<"2"/utf8, Rest@2/binary>> ->
            exponent(Lexer, Rest@2, <<Acc/binary, "2"/utf8>>);

        <<"3"/utf8, Rest@3/binary>> ->
            exponent(Lexer, Rest@3, <<Acc/binary, "3"/utf8>>);

        <<"4"/utf8, Rest@4/binary>> ->
            exponent(Lexer, Rest@4, <<Acc/binary, "4"/utf8>>);

        <<"5"/utf8, Rest@5/binary>> ->
            exponent(Lexer, Rest@5, <<Acc/binary, "5"/utf8>>);

        <<"6"/utf8, Rest@6/binary>> ->
            exponent(Lexer, Rest@6, <<Acc/binary, "6"/utf8>>);

        <<"7"/utf8, Rest@7/binary>> ->
            exponent(Lexer, Rest@7, <<Acc/binary, "7"/utf8>>);

        <<"8"/utf8, Rest@8/binary>> ->
            exponent(Lexer, Rest@8, <<Acc/binary, "8"/utf8>>);

        <<"9"/utf8, Rest@9/binary>> ->
            exponent(Lexer, Rest@9, <<Acc/binary, "9"/utf8>>);

        <<"_0"/utf8, Rest@10/binary>> ->
            exponent(Lexer, Rest@10, <<Acc/binary, "_0"/utf8>>);

        <<"_1"/utf8, Rest@11/binary>> ->
            exponent(Lexer, Rest@11, <<Acc/binary, "_1"/utf8>>);

        <<"_2"/utf8, Rest@12/binary>> ->
            exponent(Lexer, Rest@12, <<Acc/binary, "_2"/utf8>>);

        <<"_3"/utf8, Rest@13/binary>> ->
            exponent(Lexer, Rest@13, <<Acc/binary, "_3"/utf8>>);

        <<"_4"/utf8, Rest@14/binary>> ->
            exponent(Lexer, Rest@14, <<Acc/binary, "_4"/utf8>>);

        <<"_5"/utf8, Rest@15/binary>> ->
            exponent(Lexer, Rest@15, <<Acc/binary, "_5"/utf8>>);

        <<"_6"/utf8, Rest@16/binary>> ->
            exponent(Lexer, Rest@16, <<Acc/binary, "_6"/utf8>>);

        <<"_7"/utf8, Rest@17/binary>> ->
            exponent(Lexer, Rest@17, <<Acc/binary, "_7"/utf8>>);

        <<"_8"/utf8, Rest@18/binary>> ->
            exponent(Lexer, Rest@18, <<Acc/binary, "_8"/utf8>>);

        <<"_9"/utf8, Rest@19/binary>> ->
            exponent(Lexer, Rest@19, <<Acc/binary, "_9"/utf8>>);

        _ ->
            number_end(Lexer, Input, Acc, fun(Field@0) -> {float, Field@0} end)
    end.

-file("src/william.gleam", 1089).
-spec exponent_start(lexer(), binary(), binary(), binary(), binary()) -> {token(),
    binary()}.
exponent_start(Lexer, Before_marker, Input, Acc, Marker) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            exponent(
                Lexer,
                Rest,
                <<<<Acc/binary, Marker/binary>>/binary, "0"/utf8>>
            );

        <<"1"/utf8, Rest@1/binary>> ->
            exponent(
                Lexer,
                Rest@1,
                <<<<Acc/binary, Marker/binary>>/binary, "1"/utf8>>
            );

        <<"2"/utf8, Rest@2/binary>> ->
            exponent(
                Lexer,
                Rest@2,
                <<<<Acc/binary, Marker/binary>>/binary, "2"/utf8>>
            );

        <<"3"/utf8, Rest@3/binary>> ->
            exponent(
                Lexer,
                Rest@3,
                <<<<Acc/binary, Marker/binary>>/binary, "3"/utf8>>
            );

        <<"4"/utf8, Rest@4/binary>> ->
            exponent(
                Lexer,
                Rest@4,
                <<<<Acc/binary, Marker/binary>>/binary, "4"/utf8>>
            );

        <<"5"/utf8, Rest@5/binary>> ->
            exponent(
                Lexer,
                Rest@5,
                <<<<Acc/binary, Marker/binary>>/binary, "5"/utf8>>
            );

        <<"6"/utf8, Rest@6/binary>> ->
            exponent(
                Lexer,
                Rest@6,
                <<<<Acc/binary, Marker/binary>>/binary, "6"/utf8>>
            );

        <<"7"/utf8, Rest@7/binary>> ->
            exponent(
                Lexer,
                Rest@7,
                <<<<Acc/binary, Marker/binary>>/binary, "7"/utf8>>
            );

        <<"8"/utf8, Rest@8/binary>> ->
            exponent(
                Lexer,
                Rest@8,
                <<<<Acc/binary, Marker/binary>>/binary, "8"/utf8>>
            );

        <<"9"/utf8, Rest@9/binary>> ->
            exponent(
                Lexer,
                Rest@9,
                <<<<Acc/binary, Marker/binary>>/binary, "9"/utf8>>
            );

        _ ->
            invalid_number(Lexer, Before_marker, Acc)
    end.

-file("src/william.gleam", 1057).
-spec float(lexer(), binary(), binary()) -> {token(), binary()}.
float(Lexer, Input, Acc) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            float(Lexer, Rest, <<Acc/binary, "0"/utf8>>);

        <<"1"/utf8, Rest@1/binary>> ->
            float(Lexer, Rest@1, <<Acc/binary, "1"/utf8>>);

        <<"2"/utf8, Rest@2/binary>> ->
            float(Lexer, Rest@2, <<Acc/binary, "2"/utf8>>);

        <<"3"/utf8, Rest@3/binary>> ->
            float(Lexer, Rest@3, <<Acc/binary, "3"/utf8>>);

        <<"4"/utf8, Rest@4/binary>> ->
            float(Lexer, Rest@4, <<Acc/binary, "4"/utf8>>);

        <<"5"/utf8, Rest@5/binary>> ->
            float(Lexer, Rest@5, <<Acc/binary, "5"/utf8>>);

        <<"6"/utf8, Rest@6/binary>> ->
            float(Lexer, Rest@6, <<Acc/binary, "6"/utf8>>);

        <<"7"/utf8, Rest@7/binary>> ->
            float(Lexer, Rest@7, <<Acc/binary, "7"/utf8>>);

        <<"8"/utf8, Rest@8/binary>> ->
            float(Lexer, Rest@8, <<Acc/binary, "8"/utf8>>);

        <<"9"/utf8, Rest@9/binary>> ->
            float(Lexer, Rest@9, <<Acc/binary, "9"/utf8>>);

        <<"_0"/utf8, Rest@10/binary>> ->
            float(Lexer, Rest@10, <<Acc/binary, "_0"/utf8>>);

        <<"_1"/utf8, Rest@11/binary>> ->
            float(Lexer, Rest@11, <<Acc/binary, "_1"/utf8>>);

        <<"_2"/utf8, Rest@12/binary>> ->
            float(Lexer, Rest@12, <<Acc/binary, "_2"/utf8>>);

        <<"_3"/utf8, Rest@13/binary>> ->
            float(Lexer, Rest@13, <<Acc/binary, "_3"/utf8>>);

        <<"_4"/utf8, Rest@14/binary>> ->
            float(Lexer, Rest@14, <<Acc/binary, "_4"/utf8>>);

        <<"_5"/utf8, Rest@15/binary>> ->
            float(Lexer, Rest@15, <<Acc/binary, "_5"/utf8>>);

        <<"_6"/utf8, Rest@16/binary>> ->
            float(Lexer, Rest@16, <<Acc/binary, "_6"/utf8>>);

        <<"_7"/utf8, Rest@17/binary>> ->
            float(Lexer, Rest@17, <<Acc/binary, "_7"/utf8>>);

        <<"_8"/utf8, Rest@18/binary>> ->
            float(Lexer, Rest@18, <<Acc/binary, "_8"/utf8>>);

        <<"_9"/utf8, Rest@19/binary>> ->
            float(Lexer, Rest@19, <<Acc/binary, "_9"/utf8>>);

        <<"e+"/utf8, Rest@20/binary>> ->
            exponent_start(Lexer, Input, Rest@20, Acc, <<"e+"/utf8>>);

        <<"e-"/utf8, Rest@21/binary>> ->
            exponent_start(Lexer, Input, Rest@21, Acc, <<"e-"/utf8>>);

        <<"e"/utf8, Rest@22/binary>> ->
            exponent_start(Lexer, Input, Rest@22, Acc, <<"e"/utf8>>);

        <<"E+"/utf8, Rest@23/binary>> ->
            exponent_start(Lexer, Input, Rest@23, Acc, <<"E+"/utf8>>);

        <<"E-"/utf8, Rest@24/binary>> ->
            exponent_start(Lexer, Input, Rest@24, Acc, <<"E-"/utf8>>);

        <<"E"/utf8, Rest@25/binary>> ->
            exponent_start(Lexer, Input, Rest@25, Acc, <<"E"/utf8>>);

        _ ->
            number_end(Lexer, Input, Acc, fun(Field@0) -> {float, Field@0} end)
    end.

-file("src/william.gleam", 1003).
-spec decimal(lexer(), binary(), binary(), integer(), boolean()) -> {token(),
    binary()}.
decimal(Lexer, Input, Acc, Digits, Date_time) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            decimal(
                Lexer,
                Rest,
                <<Acc/binary, "0"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"1"/utf8, Rest@1/binary>> ->
            decimal(
                Lexer,
                Rest@1,
                <<Acc/binary, "1"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"2"/utf8, Rest@2/binary>> ->
            decimal(
                Lexer,
                Rest@2,
                <<Acc/binary, "2"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"3"/utf8, Rest@3/binary>> ->
            decimal(
                Lexer,
                Rest@3,
                <<Acc/binary, "3"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"4"/utf8, Rest@4/binary>> ->
            decimal(
                Lexer,
                Rest@4,
                <<Acc/binary, "4"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"5"/utf8, Rest@5/binary>> ->
            decimal(
                Lexer,
                Rest@5,
                <<Acc/binary, "5"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"6"/utf8, Rest@6/binary>> ->
            decimal(
                Lexer,
                Rest@6,
                <<Acc/binary, "6"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"7"/utf8, Rest@7/binary>> ->
            decimal(
                Lexer,
                Rest@7,
                <<Acc/binary, "7"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"8"/utf8, Rest@8/binary>> ->
            decimal(
                Lexer,
                Rest@8,
                <<Acc/binary, "8"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"9"/utf8, Rest@9/binary>> ->
            decimal(
                Lexer,
                Rest@9,
                <<Acc/binary, "9"/utf8>>,
                Digits + 1,
                Date_time
            );

        <<"_0"/utf8, Rest@10/binary>> ->
            decimal(
                Lexer,
                Rest@10,
                <<Acc/binary, "_0"/utf8>>,
                Digits + 1,
                false
            );

        <<"_1"/utf8, Rest@11/binary>> ->
            decimal(
                Lexer,
                Rest@11,
                <<Acc/binary, "_1"/utf8>>,
                Digits + 1,
                false
            );

        <<"_2"/utf8, Rest@12/binary>> ->
            decimal(
                Lexer,
                Rest@12,
                <<Acc/binary, "_2"/utf8>>,
                Digits + 1,
                false
            );

        <<"_3"/utf8, Rest@13/binary>> ->
            decimal(
                Lexer,
                Rest@13,
                <<Acc/binary, "_3"/utf8>>,
                Digits + 1,
                false
            );

        <<"_4"/utf8, Rest@14/binary>> ->
            decimal(
                Lexer,
                Rest@14,
                <<Acc/binary, "_4"/utf8>>,
                Digits + 1,
                false
            );

        <<"_5"/utf8, Rest@15/binary>> ->
            decimal(
                Lexer,
                Rest@15,
                <<Acc/binary, "_5"/utf8>>,
                Digits + 1,
                false
            );

        <<"_6"/utf8, Rest@16/binary>> ->
            decimal(
                Lexer,
                Rest@16,
                <<Acc/binary, "_6"/utf8>>,
                Digits + 1,
                false
            );

        <<"_7"/utf8, Rest@17/binary>> ->
            decimal(
                Lexer,
                Rest@17,
                <<Acc/binary, "_7"/utf8>>,
                Digits + 1,
                false
            );

        <<"_8"/utf8, Rest@18/binary>> ->
            decimal(
                Lexer,
                Rest@18,
                <<Acc/binary, "_8"/utf8>>,
                Digits + 1,
                false
            );

        <<"_9"/utf8, Rest@19/binary>> ->
            decimal(
                Lexer,
                Rest@19,
                <<Acc/binary, "_9"/utf8>>,
                Digits + 1,
                false
            );

        <<".0"/utf8, Rest@20/binary>> ->
            float(Lexer, Rest@20, <<Acc/binary, ".0"/utf8>>);

        <<".1"/utf8, Rest@21/binary>> ->
            float(Lexer, Rest@21, <<Acc/binary, ".1"/utf8>>);

        <<".2"/utf8, Rest@22/binary>> ->
            float(Lexer, Rest@22, <<Acc/binary, ".2"/utf8>>);

        <<".3"/utf8, Rest@23/binary>> ->
            float(Lexer, Rest@23, <<Acc/binary, ".3"/utf8>>);

        <<".4"/utf8, Rest@24/binary>> ->
            float(Lexer, Rest@24, <<Acc/binary, ".4"/utf8>>);

        <<".5"/utf8, Rest@25/binary>> ->
            float(Lexer, Rest@25, <<Acc/binary, ".5"/utf8>>);

        <<".6"/utf8, Rest@26/binary>> ->
            float(Lexer, Rest@26, <<Acc/binary, ".6"/utf8>>);

        <<".7"/utf8, Rest@27/binary>> ->
            float(Lexer, Rest@27, <<Acc/binary, ".7"/utf8>>);

        <<".8"/utf8, Rest@28/binary>> ->
            float(Lexer, Rest@28, <<Acc/binary, ".8"/utf8>>);

        <<".9"/utf8, Rest@29/binary>> ->
            float(Lexer, Rest@29, <<Acc/binary, ".9"/utf8>>);

        <<"e+"/utf8, Rest@30/binary>> ->
            exponent_start(Lexer, Input, Rest@30, Acc, <<"e+"/utf8>>);

        <<"e-"/utf8, Rest@31/binary>> ->
            exponent_start(Lexer, Input, Rest@31, Acc, <<"e-"/utf8>>);

        <<"e"/utf8, Rest@32/binary>> ->
            exponent_start(Lexer, Input, Rest@32, Acc, <<"e"/utf8>>);

        <<"E+"/utf8, Rest@33/binary>> ->
            exponent_start(Lexer, Input, Rest@33, Acc, <<"E+"/utf8>>);

        <<"E-"/utf8, Rest@34/binary>> ->
            exponent_start(Lexer, Input, Rest@34, Acc, <<"E-"/utf8>>);

        <<"E"/utf8, Rest@35/binary>> ->
            exponent_start(Lexer, Input, Rest@35, Acc, <<"E"/utf8>>);

        <<":"/utf8, Rest@36/binary>> when Date_time andalso (Digits =:= 2) ->
            time_minutes(Lexer, Rest@36, <<Acc/binary, ":"/utf8>>, false);

        <<"-"/utf8, Rest@37/binary>> when Date_time andalso (Digits =:= 4) ->
            date(Lexer, Rest@37, <<Acc/binary, "-"/utf8>>);

        _ ->
            To_token = fun(Value) -> {integer, decimal, Value} end,
            number_end(Lexer, Input, Acc, To_token)
    end.

-file("src/william.gleam", 987).
-spec based_integer_end(lexer(), binary(), binary(), base(), boolean()) -> {token(),
    binary()}.
based_integer_end(Lexer, Input, Acc, Base, Last_was_underscore) ->
    case Last_was_underscore of
        false ->
            To_token = fun(Value) -> {integer, Base, Value} end,
            number_end(Lexer, Input, Acc, To_token);

        true ->
            invalid_number(Lexer, Input, Acc)
    end.

-file("src/william.gleam", 950).
-spec hexadecimal(lexer(), binary(), binary(), boolean()) -> {token(), binary()}.
hexadecimal(Lexer, Input, Acc, Last_was_underscore) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            hexadecimal(Lexer, Rest, <<Acc/binary, "0"/utf8>>, false);

        <<"1"/utf8, Rest@1/binary>> ->
            hexadecimal(Lexer, Rest@1, <<Acc/binary, "1"/utf8>>, false);

        <<"2"/utf8, Rest@2/binary>> ->
            hexadecimal(Lexer, Rest@2, <<Acc/binary, "2"/utf8>>, false);

        <<"3"/utf8, Rest@3/binary>> ->
            hexadecimal(Lexer, Rest@3, <<Acc/binary, "3"/utf8>>, false);

        <<"4"/utf8, Rest@4/binary>> ->
            hexadecimal(Lexer, Rest@4, <<Acc/binary, "4"/utf8>>, false);

        <<"5"/utf8, Rest@5/binary>> ->
            hexadecimal(Lexer, Rest@5, <<Acc/binary, "5"/utf8>>, false);

        <<"6"/utf8, Rest@6/binary>> ->
            hexadecimal(Lexer, Rest@6, <<Acc/binary, "6"/utf8>>, false);

        <<"7"/utf8, Rest@7/binary>> ->
            hexadecimal(Lexer, Rest@7, <<Acc/binary, "7"/utf8>>, false);

        <<"8"/utf8, Rest@8/binary>> ->
            hexadecimal(Lexer, Rest@8, <<Acc/binary, "8"/utf8>>, false);

        <<"9"/utf8, Rest@9/binary>> ->
            hexadecimal(Lexer, Rest@9, <<Acc/binary, "9"/utf8>>, false);

        <<"A"/utf8, Rest@10/binary>> ->
            hexadecimal(Lexer, Rest@10, <<Acc/binary, "A"/utf8>>, false);

        <<"B"/utf8, Rest@11/binary>> ->
            hexadecimal(Lexer, Rest@11, <<Acc/binary, "B"/utf8>>, false);

        <<"C"/utf8, Rest@12/binary>> ->
            hexadecimal(Lexer, Rest@12, <<Acc/binary, "C"/utf8>>, false);

        <<"D"/utf8, Rest@13/binary>> ->
            hexadecimal(Lexer, Rest@13, <<Acc/binary, "D"/utf8>>, false);

        <<"E"/utf8, Rest@14/binary>> ->
            hexadecimal(Lexer, Rest@14, <<Acc/binary, "E"/utf8>>, false);

        <<"F"/utf8, Rest@15/binary>> ->
            hexadecimal(Lexer, Rest@15, <<Acc/binary, "F"/utf8>>, false);

        <<"a"/utf8, Rest@16/binary>> ->
            hexadecimal(Lexer, Rest@16, <<Acc/binary, "a"/utf8>>, false);

        <<"b"/utf8, Rest@17/binary>> ->
            hexadecimal(Lexer, Rest@17, <<Acc/binary, "b"/utf8>>, false);

        <<"c"/utf8, Rest@18/binary>> ->
            hexadecimal(Lexer, Rest@18, <<Acc/binary, "c"/utf8>>, false);

        <<"d"/utf8, Rest@19/binary>> ->
            hexadecimal(Lexer, Rest@19, <<Acc/binary, "d"/utf8>>, false);

        <<"e"/utf8, Rest@20/binary>> ->
            hexadecimal(Lexer, Rest@20, <<Acc/binary, "e"/utf8>>, false);

        <<"f"/utf8, Rest@21/binary>> ->
            hexadecimal(Lexer, Rest@21, <<Acc/binary, "f"/utf8>>, false);

        <<"_"/utf8, Rest@22/binary>> when not Last_was_underscore ->
            Acc@1 = <<Acc/binary, "_"/utf8>>,
            hexadecimal(Lexer, Rest@22, Acc@1, true);

        _ ->
            based_integer_end(
                Lexer,
                Input,
                Acc,
                hexadecimal,
                Last_was_underscore
            )
    end.

-file("src/william.gleam", 927).
-spec octal(lexer(), binary(), binary(), boolean()) -> {token(), binary()}.
octal(Lexer, Input, Acc, Last_was_underscore) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            octal(Lexer, Rest, <<Acc/binary, "0"/utf8>>, false);

        <<"1"/utf8, Rest@1/binary>> ->
            octal(Lexer, Rest@1, <<Acc/binary, "1"/utf8>>, false);

        <<"2"/utf8, Rest@2/binary>> ->
            octal(Lexer, Rest@2, <<Acc/binary, "2"/utf8>>, false);

        <<"3"/utf8, Rest@3/binary>> ->
            octal(Lexer, Rest@3, <<Acc/binary, "3"/utf8>>, false);

        <<"4"/utf8, Rest@4/binary>> ->
            octal(Lexer, Rest@4, <<Acc/binary, "4"/utf8>>, false);

        <<"5"/utf8, Rest@5/binary>> ->
            octal(Lexer, Rest@5, <<Acc/binary, "5"/utf8>>, false);

        <<"6"/utf8, Rest@6/binary>> ->
            octal(Lexer, Rest@6, <<Acc/binary, "6"/utf8>>, false);

        <<"7"/utf8, Rest@7/binary>> ->
            octal(Lexer, Rest@7, <<Acc/binary, "7"/utf8>>, false);

        <<"_"/utf8, Rest@8/binary>> when not Last_was_underscore ->
            Acc@1 = <<Acc/binary, "_"/utf8>>,
            octal(Lexer, Rest@8, Acc@1, true);

        _ ->
            based_integer_end(Lexer, Input, Acc, octal, Last_was_underscore)
    end.

-file("src/william.gleam", 910).
-spec binary(lexer(), binary(), binary(), boolean()) -> {token(), binary()}.
binary(Lexer, Input, Acc, Last_was_underscore) ->
    case Input of
        <<"0"/utf8, Rest/binary>> ->
            binary(Lexer, Rest, <<Acc/binary, "0"/utf8>>, false);

        <<"1"/utf8, Rest@1/binary>> ->
            binary(Lexer, Rest@1, <<Acc/binary, "1"/utf8>>, false);

        <<"_"/utf8, Rest@2/binary>> when not Last_was_underscore ->
            Acc@1 = <<Acc/binary, "_"/utf8>>,
            binary(Lexer, Rest@2, Acc@1, true);

        _ ->
            based_integer_end(Lexer, Input, Acc, binary, Last_was_underscore)
    end.

-file("src/william.gleam", 772).
-spec literal_or_unexpected(lexer(), binary(), token(), binary()) -> {token(),
    binary()}.
literal_or_unexpected(Lexer, Rest, Token, Original) ->
    case is_value_terminator(Rest) of
        true ->
            {Token, Rest};

        false ->
            unexpected(Lexer, Original, <<""/utf8>>)
    end.

-file("src/william.gleam", 731).
-spec value(lexer(), binary()) -> {token(), binary()}.
value(Lexer, Input) ->
    case Input of
        <<"true"/utf8, Rest/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest,
                {boolean, <<"true"/utf8>>},
                Input
            );

        <<"false"/utf8, Rest@1/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest@1,
                {boolean, <<"false"/utf8>>},
                Input
            );

        <<"inf"/utf8, Rest@2/binary>> ->
            literal_or_unexpected(Lexer, Rest@2, {float, <<"inf"/utf8>>}, Input);

        <<"+inf"/utf8, Rest@3/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest@3,
                {float, <<"+inf"/utf8>>},
                Input
            );

        <<"-inf"/utf8, Rest@4/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest@4,
                {float, <<"-inf"/utf8>>},
                Input
            );

        <<"nan"/utf8, Rest@5/binary>> ->
            literal_or_unexpected(Lexer, Rest@5, {float, <<"nan"/utf8>>}, Input);

        <<"+nan"/utf8, Rest@6/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest@6,
                {float, <<"+nan"/utf8>>},
                Input
            );

        <<"-nan"/utf8, Rest@7/binary>> ->
            literal_or_unexpected(
                Lexer,
                Rest@7,
                {float, <<"-nan"/utf8>>},
                Input
            );

        <<"+0b"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"+0o"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"+0x"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"-0b"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"-0o"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"-0x"/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"+"/utf8, Rest@8/binary>> ->
            case take_digit(Rest@8) of
                {ok, {Digit, Rest@9}} ->
                    decimal(Lexer, Rest@9, <<"+"/utf8, Digit/binary>>, 1, false);

                {error, _} ->
                    invalid_number(Lexer, Rest@8, <<"+"/utf8>>)
            end;

        <<"-"/utf8, Rest@10/binary>> ->
            case take_digit(Rest@10) of
                {ok, {Digit@1, Rest@11}} ->
                    decimal(
                        Lexer,
                        Rest@11,
                        <<"-"/utf8, Digit@1/binary>>,
                        1,
                        false
                    );

                {error, _} ->
                    invalid_number(Lexer, Rest@10, <<"-"/utf8>>)
            end;

        <<"."/utf8, _/binary>> ->
            invalid_number(Lexer, Input, <<""/utf8>>);

        <<"0b"/utf8, Rest@12/binary>> ->
            binary(Lexer, Rest@12, <<"0b"/utf8>>, true);

        <<"0o"/utf8, Rest@13/binary>> ->
            octal(Lexer, Rest@13, <<"0o"/utf8>>, true);

        <<"0x"/utf8, Rest@14/binary>> ->
            hexadecimal(Lexer, Rest@14, <<"0x"/utf8>>, true);

        <<"0"/utf8, Rest@15/binary>> ->
            decimal(Lexer, Rest@15, <<"0"/utf8>>, 1, true);

        <<"1"/utf8, Rest@16/binary>> ->
            decimal(Lexer, Rest@16, <<"1"/utf8>>, 1, true);

        <<"2"/utf8, Rest@17/binary>> ->
            decimal(Lexer, Rest@17, <<"2"/utf8>>, 1, true);

        <<"3"/utf8, Rest@18/binary>> ->
            decimal(Lexer, Rest@18, <<"3"/utf8>>, 1, true);

        <<"4"/utf8, Rest@19/binary>> ->
            decimal(Lexer, Rest@19, <<"4"/utf8>>, 1, true);

        <<"5"/utf8, Rest@20/binary>> ->
            decimal(Lexer, Rest@20, <<"5"/utf8>>, 1, true);

        <<"6"/utf8, Rest@21/binary>> ->
            decimal(Lexer, Rest@21, <<"6"/utf8>>, 1, true);

        <<"7"/utf8, Rest@22/binary>> ->
            decimal(Lexer, Rest@22, <<"7"/utf8>>, 1, true);

        <<"8"/utf8, Rest@23/binary>> ->
            decimal(Lexer, Rest@23, <<"8"/utf8>>, 1, true);

        <<"9"/utf8, Rest@24/binary>> ->
            decimal(Lexer, Rest@24, <<"9"/utf8>>, 1, true);

        _ ->
            unexpected(Lexer, Input, <<""/utf8>>)
    end.

-file("src/william.gleam", 661).
-spec bare_key(binary(), binary()) -> {binary(), binary()}.
bare_key(Input, Acc) ->
    case Input of
        <<"A"/utf8, Rest/binary>> ->
            bare_key(Rest, <<Acc/binary, "A"/utf8>>);

        <<"B"/utf8, Rest@1/binary>> ->
            bare_key(Rest@1, <<Acc/binary, "B"/utf8>>);

        <<"C"/utf8, Rest@2/binary>> ->
            bare_key(Rest@2, <<Acc/binary, "C"/utf8>>);

        <<"D"/utf8, Rest@3/binary>> ->
            bare_key(Rest@3, <<Acc/binary, "D"/utf8>>);

        <<"E"/utf8, Rest@4/binary>> ->
            bare_key(Rest@4, <<Acc/binary, "E"/utf8>>);

        <<"F"/utf8, Rest@5/binary>> ->
            bare_key(Rest@5, <<Acc/binary, "F"/utf8>>);

        <<"G"/utf8, Rest@6/binary>> ->
            bare_key(Rest@6, <<Acc/binary, "G"/utf8>>);

        <<"H"/utf8, Rest@7/binary>> ->
            bare_key(Rest@7, <<Acc/binary, "H"/utf8>>);

        <<"I"/utf8, Rest@8/binary>> ->
            bare_key(Rest@8, <<Acc/binary, "I"/utf8>>);

        <<"J"/utf8, Rest@9/binary>> ->
            bare_key(Rest@9, <<Acc/binary, "J"/utf8>>);

        <<"K"/utf8, Rest@10/binary>> ->
            bare_key(Rest@10, <<Acc/binary, "K"/utf8>>);

        <<"L"/utf8, Rest@11/binary>> ->
            bare_key(Rest@11, <<Acc/binary, "L"/utf8>>);

        <<"M"/utf8, Rest@12/binary>> ->
            bare_key(Rest@12, <<Acc/binary, "M"/utf8>>);

        <<"N"/utf8, Rest@13/binary>> ->
            bare_key(Rest@13, <<Acc/binary, "N"/utf8>>);

        <<"O"/utf8, Rest@14/binary>> ->
            bare_key(Rest@14, <<Acc/binary, "O"/utf8>>);

        <<"P"/utf8, Rest@15/binary>> ->
            bare_key(Rest@15, <<Acc/binary, "P"/utf8>>);

        <<"Q"/utf8, Rest@16/binary>> ->
            bare_key(Rest@16, <<Acc/binary, "Q"/utf8>>);

        <<"R"/utf8, Rest@17/binary>> ->
            bare_key(Rest@17, <<Acc/binary, "R"/utf8>>);

        <<"S"/utf8, Rest@18/binary>> ->
            bare_key(Rest@18, <<Acc/binary, "S"/utf8>>);

        <<"T"/utf8, Rest@19/binary>> ->
            bare_key(Rest@19, <<Acc/binary, "T"/utf8>>);

        <<"U"/utf8, Rest@20/binary>> ->
            bare_key(Rest@20, <<Acc/binary, "U"/utf8>>);

        <<"V"/utf8, Rest@21/binary>> ->
            bare_key(Rest@21, <<Acc/binary, "V"/utf8>>);

        <<"W"/utf8, Rest@22/binary>> ->
            bare_key(Rest@22, <<Acc/binary, "W"/utf8>>);

        <<"X"/utf8, Rest@23/binary>> ->
            bare_key(Rest@23, <<Acc/binary, "X"/utf8>>);

        <<"Y"/utf8, Rest@24/binary>> ->
            bare_key(Rest@24, <<Acc/binary, "Y"/utf8>>);

        <<"Z"/utf8, Rest@25/binary>> ->
            bare_key(Rest@25, <<Acc/binary, "Z"/utf8>>);

        <<"a"/utf8, Rest@26/binary>> ->
            bare_key(Rest@26, <<Acc/binary, "a"/utf8>>);

        <<"b"/utf8, Rest@27/binary>> ->
            bare_key(Rest@27, <<Acc/binary, "b"/utf8>>);

        <<"c"/utf8, Rest@28/binary>> ->
            bare_key(Rest@28, <<Acc/binary, "c"/utf8>>);

        <<"d"/utf8, Rest@29/binary>> ->
            bare_key(Rest@29, <<Acc/binary, "d"/utf8>>);

        <<"e"/utf8, Rest@30/binary>> ->
            bare_key(Rest@30, <<Acc/binary, "e"/utf8>>);

        <<"f"/utf8, Rest@31/binary>> ->
            bare_key(Rest@31, <<Acc/binary, "f"/utf8>>);

        <<"g"/utf8, Rest@32/binary>> ->
            bare_key(Rest@32, <<Acc/binary, "g"/utf8>>);

        <<"h"/utf8, Rest@33/binary>> ->
            bare_key(Rest@33, <<Acc/binary, "h"/utf8>>);

        <<"i"/utf8, Rest@34/binary>> ->
            bare_key(Rest@34, <<Acc/binary, "i"/utf8>>);

        <<"j"/utf8, Rest@35/binary>> ->
            bare_key(Rest@35, <<Acc/binary, "j"/utf8>>);

        <<"k"/utf8, Rest@36/binary>> ->
            bare_key(Rest@36, <<Acc/binary, "k"/utf8>>);

        <<"l"/utf8, Rest@37/binary>> ->
            bare_key(Rest@37, <<Acc/binary, "l"/utf8>>);

        <<"m"/utf8, Rest@38/binary>> ->
            bare_key(Rest@38, <<Acc/binary, "m"/utf8>>);

        <<"n"/utf8, Rest@39/binary>> ->
            bare_key(Rest@39, <<Acc/binary, "n"/utf8>>);

        <<"o"/utf8, Rest@40/binary>> ->
            bare_key(Rest@40, <<Acc/binary, "o"/utf8>>);

        <<"p"/utf8, Rest@41/binary>> ->
            bare_key(Rest@41, <<Acc/binary, "p"/utf8>>);

        <<"q"/utf8, Rest@42/binary>> ->
            bare_key(Rest@42, <<Acc/binary, "q"/utf8>>);

        <<"r"/utf8, Rest@43/binary>> ->
            bare_key(Rest@43, <<Acc/binary, "r"/utf8>>);

        <<"s"/utf8, Rest@44/binary>> ->
            bare_key(Rest@44, <<Acc/binary, "s"/utf8>>);

        <<"t"/utf8, Rest@45/binary>> ->
            bare_key(Rest@45, <<Acc/binary, "t"/utf8>>);

        <<"u"/utf8, Rest@46/binary>> ->
            bare_key(Rest@46, <<Acc/binary, "u"/utf8>>);

        <<"v"/utf8, Rest@47/binary>> ->
            bare_key(Rest@47, <<Acc/binary, "v"/utf8>>);

        <<"w"/utf8, Rest@48/binary>> ->
            bare_key(Rest@48, <<Acc/binary, "w"/utf8>>);

        <<"x"/utf8, Rest@49/binary>> ->
            bare_key(Rest@49, <<Acc/binary, "x"/utf8>>);

        <<"y"/utf8, Rest@50/binary>> ->
            bare_key(Rest@50, <<Acc/binary, "y"/utf8>>);

        <<"z"/utf8, Rest@51/binary>> ->
            bare_key(Rest@51, <<Acc/binary, "z"/utf8>>);

        <<"0"/utf8, Rest@52/binary>> ->
            bare_key(Rest@52, <<Acc/binary, "0"/utf8>>);

        <<"1"/utf8, Rest@53/binary>> ->
            bare_key(Rest@53, <<Acc/binary, "1"/utf8>>);

        <<"2"/utf8, Rest@54/binary>> ->
            bare_key(Rest@54, <<Acc/binary, "2"/utf8>>);

        <<"3"/utf8, Rest@55/binary>> ->
            bare_key(Rest@55, <<Acc/binary, "3"/utf8>>);

        <<"4"/utf8, Rest@56/binary>> ->
            bare_key(Rest@56, <<Acc/binary, "4"/utf8>>);

        <<"5"/utf8, Rest@57/binary>> ->
            bare_key(Rest@57, <<Acc/binary, "5"/utf8>>);

        <<"6"/utf8, Rest@58/binary>> ->
            bare_key(Rest@58, <<Acc/binary, "6"/utf8>>);

        <<"7"/utf8, Rest@59/binary>> ->
            bare_key(Rest@59, <<Acc/binary, "7"/utf8>>);

        <<"8"/utf8, Rest@60/binary>> ->
            bare_key(Rest@60, <<Acc/binary, "8"/utf8>>);

        <<"9"/utf8, Rest@61/binary>> ->
            bare_key(Rest@61, <<Acc/binary, "9"/utf8>>);

        <<"-"/utf8, Rest@62/binary>> ->
            bare_key(Rest@62, <<Acc/binary, "-"/utf8>>);

        <<"_"/utf8, Rest@63/binary>> ->
            bare_key(Rest@63, <<Acc/binary, "_"/utf8>>);

        _ ->
            {Acc, Input}
    end.

-file("src/william.gleam", 619).
-spec mode_after_string(mode()) -> mode().
mode_after_string(Mode) ->
    case Mode of
        value_mode ->
            after_value_mode;

        _ ->
            Mode
    end.

-file("src/william.gleam", 829).
-spec literal_string(lexer(), binary(), binary()) -> {token(), binary()}.
literal_string(Lexer, Input, Acc) ->
    {Before, Delimiter, Rest} = splitter_ffi:split(
        erlang:element(8, Lexer),
        Input
    ),
    case Delimiter of
        <<"'"/utf8>> ->
            {{string, literal_string, <<Acc/binary, Before/binary>>}, Rest};

        <<"\r\n"/utf8>> ->
            {{unterminated_string,
                    literal_string,
                    <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<"\n"/utf8>> ->
            {{unterminated_string,
                    literal_string,
                    <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<"\r"/utf8>> ->
            {{unterminated_string,
                    literal_string,
                    <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<""/utf8>> ->
            {{unterminated_string,
                    literal_string,
                    <<Acc/binary, Before/binary>>},
                <<""/utf8>>};

        _ ->
            {{unterminated_string,
                    literal_string,
                    <<<<Acc/binary, Before/binary>>/binary, Delimiter/binary>>},
                Rest}
    end.

-file("src/william.gleam", 891).
-spec multiline_literal_string(lexer(), binary(), binary()) -> {token(),
    binary()}.
multiline_literal_string(Lexer, Input, Acc) ->
    {Before, Delimiter, Rest} = splitter_ffi:split(
        erlang:element(10, Lexer),
        Input
    ),
    case Delimiter of
        <<"'''''"/utf8>> ->
            {{string,
                    multiline_literal_string,
                    <<<<Acc/binary, Before/binary>>/binary, "''"/utf8>>},
                Rest};

        <<"''''"/utf8>> ->
            {{string,
                    multiline_literal_string,
                    <<<<Acc/binary, Before/binary>>/binary, "'"/utf8>>},
                Rest};

        <<"'''"/utf8>> ->
            {{string, multiline_literal_string, <<Acc/binary, Before/binary>>},
                Rest};

        <<""/utf8>> ->
            {{unterminated_string,
                    multiline_literal_string,
                    <<Acc/binary, Before/binary>>},
                <<""/utf8>>};

        _ ->
            {{unterminated_string,
                    multiline_literal_string,
                    <<<<Acc/binary, Before/binary>>/binary, Delimiter/binary>>},
                Rest}
    end.

-file("src/william.gleam", 803).
-spec basic_string_escape(lexer(), binary(), binary()) -> {token(), binary()}.
basic_string_escape(Lexer, Input, Acc) ->
    case Input of
        <<""/utf8>> ->
            {{unterminated_string, basic_string, Acc}, <<""/utf8>>};

        <<"\r\n"/utf8, _/binary>> ->
            {{unterminated_string, basic_string, Acc}, Input};

        <<"\n"/utf8, _/binary>> ->
            {{unterminated_string, basic_string, Acc}, Input};

        <<"\r"/utf8, _/binary>> ->
            {{unterminated_string, basic_string, Acc}, Input};

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

        <<"\\"/utf8, Rest@1/binary>> ->
            basic_string(Lexer, Rest@1, <<Acc/binary, "\\"/utf8>>);

        _ ->
            {Escaped, Delimiter, Rest@2} = splitter_ffi:split(
                erlang:element(7, Lexer),
                Input
            ),
            case {Escaped, Delimiter} of
                {<<""/utf8>>, <<""/utf8>>} ->
                    {{unterminated_string, basic_string, Acc}, <<""/utf8>>};

                {_, <<""/utf8>>} ->
                    {{unterminated_string,
                            basic_string,
                            <<Acc/binary, Escaped/binary>>},
                        <<""/utf8>>};

                {<<""/utf8>>, _} ->
                    basic_string(
                        Lexer,
                        Rest@2,
                        <<Acc/binary, Delimiter/binary>>
                    );

                {_, _} ->
                    basic_string(
                        Lexer,
                        <<Delimiter/binary, Rest@2/binary>>,
                        <<Acc/binary, Escaped/binary>>
                    )
            end
    end.

-file("src/william.gleam", 789).
-spec basic_string(lexer(), binary(), binary()) -> {token(), binary()}.
basic_string(Lexer, Input, Acc) ->
    {Before, Delimiter, Rest} = splitter_ffi:split(
        erlang:element(7, Lexer),
        Input
    ),
    case Delimiter of
        <<"\""/utf8>> ->
            {{string, basic_string, <<Acc/binary, Before/binary>>}, Rest};

        <<"\r\n"/utf8>> ->
            {{unterminated_string, basic_string, <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<"\n"/utf8>> ->
            {{unterminated_string, basic_string, <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<"\r"/utf8>> ->
            {{unterminated_string, basic_string, <<Acc/binary, Before/binary>>},
                <<Delimiter/binary, Rest/binary>>};

        <<"\\"/utf8>> ->
            basic_string_escape(
                Lexer,
                Rest,
                <<<<Acc/binary, Before/binary>>/binary, "\\"/utf8>>
            );

        <<""/utf8>> ->
            {{unterminated_string, basic_string, <<Acc/binary, Before/binary>>},
                <<""/utf8>>};

        _ ->
            {{unterminated_string,
                    basic_string,
                    <<<<Acc/binary, Before/binary>>/binary, Delimiter/binary>>},
                Rest}
    end.

-file("src/william.gleam", 869).
-spec multiline_basic_string_escape(lexer(), binary(), binary()) -> {token(),
    binary()}.
multiline_basic_string_escape(Lexer, Input, Acc) ->
    case Input of
        <<""/utf8>> ->
            {{unterminated_string, multiline_basic_string, Acc}, <<""/utf8>>};

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

        <<"\\"/utf8, Rest@1/binary>> ->
            multiline_basic_string(Lexer, Rest@1, <<Acc/binary, "\\"/utf8>>);

        _ ->
            {Escaped, Delimiter, Rest@2} = splitter_ffi:split(
                erlang:element(9, Lexer),
                Input
            ),
            case {Escaped, Delimiter} of
                {<<""/utf8>>, <<""/utf8>>} ->
                    {{unterminated_string, multiline_basic_string, Acc},
                        <<""/utf8>>};

                {_, <<""/utf8>>} ->
                    {{unterminated_string,
                            multiline_basic_string,
                            <<Acc/binary, Escaped/binary>>},
                        <<""/utf8>>};

                {<<""/utf8>>, _} ->
                    multiline_basic_string(
                        Lexer,
                        Rest@2,
                        <<Acc/binary, Delimiter/binary>>
                    );

                {_, _} ->
                    multiline_basic_string(
                        Lexer,
                        <<Delimiter/binary, Rest@2/binary>>,
                        <<Acc/binary, Escaped/binary>>
                    )
            end
    end.

-file("src/william.gleam", 846).
-spec multiline_basic_string(lexer(), binary(), binary()) -> {token(), binary()}.
multiline_basic_string(Lexer, Input, Acc) ->
    {Before, Delimiter, Rest} = splitter_ffi:split(
        erlang:element(9, Lexer),
        Input
    ),
    case Delimiter of
        <<"\"\"\"\"\""/utf8>> ->
            {{string,
                    multiline_basic_string,
                    <<<<Acc/binary, Before/binary>>/binary, "\"\""/utf8>>},
                Rest};

        <<"\"\"\"\""/utf8>> ->
            {{string,
                    multiline_basic_string,
                    <<<<Acc/binary, Before/binary>>/binary, "\""/utf8>>},
                Rest};

        <<"\"\"\""/utf8>> ->
            {{string, multiline_basic_string, <<Acc/binary, Before/binary>>},
                Rest};

        <<"\\"/utf8>> ->
            multiline_basic_string_escape(
                Lexer,
                Rest,
                <<<<Acc/binary, Before/binary>>/binary, "\\"/utf8>>
            );

        <<""/utf8>> ->
            {{unterminated_string,
                    multiline_basic_string,
                    <<Acc/binary, Before/binary>>},
                <<""/utf8>>};

        _ ->
            {{unterminated_string,
                    multiline_basic_string,
                    <<<<Acc/binary, Before/binary>>/binary, Delimiter/binary>>},
                Rest}
    end.

-file("src/william.gleam", 640).
-spec mode_after_comma(list(container())) -> mode().
mode_after_comma(Containers) ->
    case Containers of
        [inline_table_container | _] ->
            key_mode;

        [array_container | _] ->
            value_mode;

        [] ->
            value_mode
    end.

-file("src/william.gleam", 633).
-spec close_inline_table(list(container())) -> list(container()).
close_inline_table(Containers) ->
    case Containers of
        [inline_table_container | Containers@1] ->
            Containers@1;

        _ ->
            Containers
    end.

-file("src/william.gleam", 626).
-spec close_array(list(container())) -> list(container()).
close_array(Containers) ->
    case Containers of
        [array_container | Containers@1] ->
            Containers@1;

        _ ->
            Containers
    end.

-file("src/william.gleam", 656).
-spec comment(lexer(), binary()) -> {token(), binary()}.
comment(Lexer, Input) ->
    {Body, Rest} = splitter_ffi:split_before(erlang:element(4, Lexer), Input),
    {{comment, <<"#"/utf8, Body/binary>>}, Rest}.

-file("src/william.gleam", 648).
-spec whitespace(binary(), binary()) -> {token(), binary()}.
whitespace(Input, Acc) ->
    case Input of
        <<" "/utf8, Rest/binary>> ->
            whitespace(Rest, <<Acc/binary, " "/utf8>>);

        <<"\t"/utf8, Rest@1/binary>> ->
            whitespace(Rest@1, <<Acc/binary, "\t"/utf8>>);

        _ ->
            {{whitespace, Acc}, Input}
    end.

-file("src/william.gleam", 612).
-spec reset_mode_after_newline(mode(), list(container())) -> mode().
reset_mode_after_newline(Mode, Containers) ->
    case Containers of
        [] ->
            key_mode;

        _ ->
            Mode
    end.

-file("src/william.gleam", 584).
-spec unexpected_token(lexer(), binary(), list(token()), list(container())) -> list(token()).
unexpected_token(Lexer, Input, Acc, Containers) ->
    {Token, Rest} = unexpected(Lexer, Input, <<""/utf8>>),
    start(
        Lexer,
        Rest,
        emit(Lexer, Token, Acc),
        after_value_mode,
        Containers,
        false
    ).

-file("src/william.gleam", 574).
-spec value_token(lexer(), binary(), list(token()), list(container())) -> list(token()).
value_token(Lexer, Input, Acc, Containers) ->
    {Token, Rest} = value(Lexer, Input),
    start(
        Lexer,
        Rest,
        emit(Lexer, Token, Acc),
        after_value_mode,
        Containers,
        false
    ).

-file("src/william.gleam", 557).
-spec key_token(lexer(), binary(), list(token()), mode(), list(container())) -> list(token()).
key_token(Lexer, Input, Acc, Mode, Containers) ->
    {Key, Rest} = bare_key(Input, <<""/utf8>>),
    case Key of
        <<""/utf8>> ->
            unexpected_token(Lexer, Input, Acc, Containers);

        _ ->
            Acc@1 = emit(Lexer, {bare_key, Key}, Acc),
            start(Lexer, Rest, Acc@1, Mode, Containers, false)
    end.

-file("src/william.gleam", 380).
-spec start(
    lexer(),
    binary(),
    list(token()),
    mode(),
    list(container()),
    boolean()
) -> list(token()).
start(Lexer, Input, Acc, Mode, Containers, At_line_start) ->
    case Input of
        <<""/utf8>> ->
            lists:reverse(Acc);

        <<"\r\n"/utf8, Rest/binary>> ->
            Acc@1 = emit(Lexer, {end_of_line, <<"\r\n"/utf8>>}, Acc),
            Mode@1 = reset_mode_after_newline(Mode, Containers),
            start(Lexer, Rest, Acc@1, Mode@1, Containers, true);

        <<"\n"/utf8, Rest@1/binary>> ->
            Acc@2 = emit(Lexer, {end_of_line, <<"\n"/utf8>>}, Acc),
            Mode@2 = reset_mode_after_newline(Mode, Containers),
            start(Lexer, Rest@1, Acc@2, Mode@2, Containers, true);

        <<"\r"/utf8, Rest@2/binary>> ->
            Acc@3 = emit(Lexer, {end_of_line, <<"\r"/utf8>>}, Acc),
            Mode@3 = reset_mode_after_newline(Mode, Containers),
            start(Lexer, Rest@2, Acc@3, Mode@3, Containers, true);

        <<" "/utf8, Rest@3/binary>> ->
            {Token, Rest@4} = whitespace(Rest@3, <<" "/utf8>>),
            Acc@4 = emit(Lexer, Token, Acc),
            start(Lexer, Rest@4, Acc@4, Mode, Containers, At_line_start);

        <<"\t"/utf8, Rest@5/binary>> ->
            {Token@1, Rest@6} = whitespace(Rest@5, <<"\t"/utf8>>),
            Acc@5 = emit(Lexer, Token@1, Acc),
            start(Lexer, Rest@6, Acc@5, Mode, Containers, At_line_start);

        <<"#"/utf8, Rest@7/binary>> ->
            {Token@2, Rest@8} = comment(Lexer, Rest@7),
            Acc@6 = emit(Lexer, Token@2, Acc),
            start(Lexer, Rest@8, Acc@6, Mode, Containers, At_line_start);

        <<"[["/utf8, Rest@9/binary>> ->
            case {At_line_start, Containers} of
                {true, []} ->
                    Acc@7 = emit(Lexer, open_array_table, Acc),
                    start(Lexer, Rest@9, Acc@7, table_mode, Containers, false);

                {_, _} ->
                    Acc@8 = emit(Lexer, open_bracket, Acc),
                    Input@1 = <<"["/utf8, Rest@9/binary>>,
                    Containers@1 = [array_container | Containers],
                    start(
                        Lexer,
                        Input@1,
                        Acc@8,
                        value_mode,
                        Containers@1,
                        false
                    )
            end;

        <<"["/utf8, Rest@10/binary>> ->
            case {At_line_start, Containers} of
                {true, []} ->
                    Acc@9 = emit(Lexer, open_table, Acc),
                    start(Lexer, Rest@10, Acc@9, table_mode, Containers, false);

                {_, _} ->
                    Acc@10 = emit(Lexer, open_bracket, Acc),
                    Containers@2 = [array_container | Containers],
                    start(
                        Lexer,
                        Rest@10,
                        Acc@10,
                        value_mode,
                        Containers@2,
                        false
                    )
            end;

        <<"]]"/utf8, Rest@11/binary>> ->
            case Mode of
                table_mode ->
                    Acc@11 = emit(Lexer, close_array_table, Acc),
                    start(
                        Lexer,
                        Rest@11,
                        Acc@11,
                        after_value_mode,
                        Containers,
                        false
                    );

                _ ->
                    Acc@12 = emit(Lexer, close_bracket, Acc),
                    Acc@13 = emit(Lexer, close_bracket, Acc@12),
                    Containers@3 = close_array(close_array(Containers)),
                    start(
                        Lexer,
                        Rest@11,
                        Acc@13,
                        after_value_mode,
                        Containers@3,
                        false
                    )
            end;

        <<"]"/utf8, Rest@12/binary>> ->
            case Mode of
                table_mode ->
                    Acc@14 = emit(Lexer, close_table, Acc),
                    start(
                        Lexer,
                        Rest@12,
                        Acc@14,
                        after_value_mode,
                        Containers,
                        false
                    );

                _ ->
                    Acc@15 = emit(Lexer, close_bracket, Acc),
                    Containers@4 = close_array(Containers),
                    start(
                        Lexer,
                        Rest@12,
                        Acc@15,
                        after_value_mode,
                        Containers@4,
                        false
                    )
            end;

        <<"{"/utf8, Rest@13/binary>> ->
            Acc@16 = emit(Lexer, open_brace, Acc),
            Containers@5 = [inline_table_container | Containers],
            start(Lexer, Rest@13, Acc@16, key_mode, Containers@5, false);

        <<"}"/utf8, Rest@14/binary>> ->
            Acc@17 = emit(Lexer, close_brace, Acc),
            Containers@6 = close_inline_table(Containers),
            start(Lexer, Rest@14, Acc@17, after_value_mode, Containers@6, false);

        <<","/utf8, Rest@15/binary>> ->
            Acc@18 = emit(Lexer, comma, Acc),
            start(
                Lexer,
                Rest@15,
                Acc@18,
                mode_after_comma(Containers),
                Containers,
                false
            );

        <<"="/utf8, Rest@16/binary>> ->
            Acc@19 = emit(Lexer, equal, Acc),
            start(Lexer, Rest@16, Acc@19, value_mode, Containers, false);

        <<"."/utf8, Rest@17/binary>> ->
            case Mode of
                key_mode ->
                    Acc@20 = emit(Lexer, dot, Acc),
                    start(Lexer, Rest@17, Acc@20, Mode, Containers, false);

                table_mode ->
                    Acc@20 = emit(Lexer, dot, Acc),
                    start(Lexer, Rest@17, Acc@20, Mode, Containers, false);

                value_mode ->
                    value_token(Lexer, Input, Acc, Containers);

                after_value_mode ->
                    unexpected_token(Lexer, Input, Acc, Containers)
            end;

        <<"\"\"\""/utf8, Rest@18/binary>> ->
            {Token@3, Rest@19} = multiline_basic_string(
                Lexer,
                Rest@18,
                <<""/utf8>>
            ),
            Mode@4 = mode_after_string(Mode),
            start(
                Lexer,
                Rest@19,
                emit(Lexer, Token@3, Acc),
                Mode@4,
                Containers,
                false
            );

        <<"\""/utf8, Rest@20/binary>> ->
            {Token@4, Rest@21} = basic_string(Lexer, Rest@20, <<""/utf8>>),
            Mode@5 = mode_after_string(Mode),
            start(
                Lexer,
                Rest@21,
                emit(Lexer, Token@4, Acc),
                Mode@5,
                Containers,
                false
            );

        <<"'''"/utf8, Rest@22/binary>> ->
            {Token@5, Rest@23} = multiline_literal_string(
                Lexer,
                Rest@22,
                <<""/utf8>>
            ),
            Mode@6 = mode_after_string(Mode),
            start(
                Lexer,
                Rest@23,
                emit(Lexer, Token@5, Acc),
                Mode@6,
                Containers,
                false
            );

        <<"'"/utf8, Rest@24/binary>> ->
            {Token@6, Rest@25} = literal_string(Lexer, Rest@24, <<""/utf8>>),
            Mode@7 = mode_after_string(Mode),
            start(
                Lexer,
                Rest@25,
                emit(Lexer, Token@6, Acc),
                Mode@7,
                Containers,
                false
            );

        _ ->
            case Mode of
                key_mode ->
                    key_token(Lexer, Input, Acc, Mode, Containers);

                table_mode ->
                    key_token(Lexer, Input, Acc, Mode, Containers);

                value_mode ->
                    value_token(Lexer, Input, Acc, Containers);

                after_value_mode ->
                    unexpected_token(Lexer, Input, Acc, Containers)
            end
    end.

-file("src/william.gleam", 370).
?DOC(" Parse TOML source code into a list of lexer tokens.\n").
-spec tokenise(lexer(), binary()) -> list(token()).
tokenise(Lexer, Input) ->
    case Input of
        <<"\x{FEFF}"/utf8, Rest/binary>> ->
            Acc = emit(Lexer, {whitespace, <<"\x{FEFF}"/utf8>>}, []),
            start(Lexer, Rest, Acc, key_mode, [], true);

        _ ->
            start(Lexer, Input, [], key_mode, [], true)
    end.

-file("src/william.gleam", 1328).
-spec string_delimiter(string_delimiter()) -> binary().
string_delimiter(Delimiter) ->
    case Delimiter of
        basic_string ->
            <<"\""/utf8>>;

        literal_string ->
            <<"'"/utf8>>;

        multiline_basic_string ->
            <<"\"\"\""/utf8>>;

        multiline_literal_string ->
            <<"'''"/utf8>>
    end.

-file("src/william.gleam", 176).
-spec highlight_normal_token(token()) -> highlight_token().
highlight_normal_token(Token) ->
    case Token of
        {bare_key, Name} ->
            {highlight_key, Name};

        {boolean, Value} ->
            {highlight_literal, Value};

        close_array_table ->
            {highlight_punctuation, <<"]]"/utf8>>};

        close_brace ->
            {highlight_punctuation, <<"}"/utf8>>};

        close_bracket ->
            {highlight_punctuation, <<"]"/utf8>>};

        close_table ->
            {highlight_punctuation, <<"]"/utf8>>};

        comma ->
            {highlight_punctuation, <<","/utf8>>};

        {comment, Str} ->
            {highlight_comment, Str};

        {date_time, Value@1} ->
            {highlight_date_time, Value@1};

        dot ->
            {highlight_operator, <<"."/utf8>>};

        {end_of_line, Str@1} ->
            {highlight_whitespace, Str@1};

        equal ->
            {highlight_operator, <<"="/utf8>>};

        {float, Value@2} ->
            {highlight_number, Value@2};

        {integer, _, Value@3} ->
            {highlight_number, Value@3};

        {invalid_number, Str@2} ->
            {highlight_error, Str@2};

        open_array_table ->
            {highlight_punctuation, <<"[["/utf8>>};

        open_brace ->
            {highlight_punctuation, <<"{"/utf8>>};

        open_bracket ->
            {highlight_punctuation, <<"["/utf8>>};

        open_table ->
            {highlight_punctuation, <<"["/utf8>>};

        {string, Delimiter, Value@4} ->
            {highlight_string,
                <<<<(string_delimiter(Delimiter))/binary, Value@4/binary>>/binary,
                    (string_delimiter(Delimiter))/binary>>};

        {unexpected, Str@3} ->
            {highlight_error, Str@3};

        {unterminated_string, Delimiter@1, Value@5} ->
            {highlight_error,
                <<(string_delimiter(Delimiter@1))/binary, Value@5/binary>>};

        {whitespace, Str@4} ->
            {highlight_whitespace, Str@4}
    end.

-file("src/william.gleam", 42).
-spec highlight_loop(
    list(token()),
    highlight_context(),
    list(highlight_token())
) -> list(highlight_token()).
highlight_loop(Tokens, Context, Acc) ->
    case {Context, Tokens} of
        {_, []} ->
            Acc;

        {_, [open_table | Tokens@1]} ->
            highlight_loop(
                Tokens@1,
                table_header,
                [{highlight_punctuation, <<"["/utf8>>} | Acc]
            );

        {_, [open_array_table | Tokens@2]} ->
            highlight_loop(
                Tokens@2,
                table_header,
                [{highlight_punctuation, <<"[["/utf8>>} | Acc]
            );

        {table_header, [close_table | Tokens@3]} ->
            highlight_loop(
                Tokens@3,
                normal,
                [{highlight_punctuation, <<"]"/utf8>>} | Acc]
            );

        {table_header, [close_array_table | Tokens@4]} ->
            highlight_loop(
                Tokens@4,
                normal,
                [{highlight_punctuation, <<"]]"/utf8>>} | Acc]
            );

        {table_header, [{bare_key, Name} | Tokens@5]} ->
            highlight_loop(
                Tokens@5,
                table_header,
                [{highlight_table, Name} | Acc]
            );

        {table_header, [{string, Delimiter, Value} | Tokens@6]} ->
            Delim = string_delimiter(Delimiter),
            Table = {highlight_table,
                <<<<Delim/binary, Value/binary>>/binary, Delim/binary>>},
            highlight_loop(Tokens@6, table_header, [Table | Acc]);

        {normal, [{string, Delimiter@1, Value@1}, equal | Tokens@7]} ->
            Delim@1 = string_delimiter(Delimiter@1),
            Key = {highlight_key,
                <<<<Delim@1/binary, Value@1/binary>>/binary, Delim@1/binary>>},
            highlight_loop([equal | Tokens@7], normal, [Key | Acc]);

        {normal,
            [{string, Delimiter@2, Value@2}, {whitespace, Ws}, equal | Tokens@8]} ->
            Delim@2 = string_delimiter(Delimiter@2),
            Key@1 = {highlight_key,
                <<<<Delim@2/binary, Value@2/binary>>/binary, Delim@2/binary>>},
            highlight_loop(
                [{whitespace, Ws}, equal | Tokens@8],
                normal,
                [Key@1 | Acc]
            );

        {normal, [{string, Delimiter@3, Value@3}, dot | Tokens@9]} ->
            Delim@3 = string_delimiter(Delimiter@3),
            Key@2 = {highlight_key,
                <<<<Delim@3/binary, Value@3/binary>>/binary, Delim@3/binary>>},
            highlight_loop([dot | Tokens@9], normal, [Key@2 | Acc]);

        {normal,
            [{string, Delimiter@4, Value@4},
                {whitespace, Ws@1},
                dot |
                Tokens@10]} ->
            Delim@4 = string_delimiter(Delimiter@4),
            Key@3 = {highlight_key,
                <<<<Delim@4/binary, Value@4/binary>>/binary, Delim@4/binary>>},
            highlight_loop(
                [{whitespace, Ws@1}, dot | Tokens@10],
                normal,
                [Key@3 | Acc]
            );

        {_, [Token | Tokens@11]} ->
            highlight_loop(
                Tokens@11,
                Context,
                [highlight_normal_token(Token) | Acc]
            )
    end.

-file("src/william.gleam", 36).
?DOC(" Convert a list of lexer tokens into a list of `HighlightToken`.\n").
-spec to_highlight(list(token())) -> list(highlight_token()).
to_highlight(Tokens) ->
    Tokens@1 = highlight_loop(Tokens, normal, []),
    lists:reverse(Tokens@1).

-file("src/william.gleam", 31).
?DOC(
    " Parse TOML source code into a list of `HighlightToken` using default\n"
    " settings.\n"
    "\n"
    " The resulting token list can be highlighted by using functions like\n"
    " `to_ansi`, `to_html`, or by pattern matching on it yourself.\n"
).
-spec highlight(binary()) -> list(highlight_token()).
highlight(Source) ->
    to_highlight(tokenise(new(), Source)).

-file("src/william.gleam", 96).
?DOC(
    " Format a list of `HighlightToken` into ANSI highlighting for display in a\n"
    " terminal.\n"
).
-spec to_ansi(list(highlight_token())) -> binary().
to_ansi(Tokens) ->
    gleam@list:fold(
        Tokens,
        <<""/utf8>>,
        fun(Acc, Token) ->
            Highlighted = case Token of
                {highlight_comment, Str} ->
                    gleam_community@ansi:italic(gleam_community@ansi:gray(Str));

                {highlight_date_time, Str@1} ->
                    gleam_community@ansi:blue(Str@1);

                {highlight_error, Str@2} ->
                    gleam_community@ansi:bg_bright_red(
                        gleam_community@ansi:white(Str@2)
                    );

                {highlight_key, Str@3} ->
                    gleam_community@ansi:yellow(Str@3);

                {highlight_literal, Str@4} ->
                    gleam_community@ansi:green(Str@4);

                {highlight_number, Str@5} ->
                    gleam_community@ansi:green(Str@5);

                {highlight_operator, Str@6} ->
                    gleam_community@ansi:magenta(Str@6);

                {highlight_punctuation, Str@7} ->
                    Str@7;

                {highlight_string, Str@8} ->
                    gleam_community@ansi:green(Str@8);

                {highlight_table, Str@9} ->
                    gleam_community@ansi:cyan(Str@9);

                {highlight_whitespace, Str@10} ->
                    Str@10
            end,
            <<Acc/binary, Highlighted/binary>>
        end
    ).

-file("src/william.gleam", 208).
-spec span(binary(), binary()) -> binary().
span(Class, Text) ->
    <<<<<<<<"<span class=\""/utf8, Class/binary>>/binary, "\">"/utf8>>/binary,
            (houdini:escape(Text))/binary>>/binary,
        "</span>"/utf8>>.

-file("src/william.gleam", 156).
?DOC(
    " Format a list of `HighlightToken` as HTML.\n"
    "\n"
    " Each non-whitespace token is wrapped inside a `<span>` tag with a class\n"
    " indicating the type.\n"
    "\n"
    " Class names are based on [`contour`](https://hexdocs.pm/contour):\n"
    "\n"
    " | Token       | CSS class      |\n"
    " | ----------- | -------------- |\n"
    " | Comment     | hl-comment     |\n"
    " | Date/time   | hl-function    |\n"
    " | Error       | hl-error       |\n"
    " | Key         | hl-attribute   |\n"
    " | Literal     | hl-literal     |\n"
    " | Number      | hl-number      |\n"
    " | Operator    | hl-operator    |\n"
    " | Punctuation | hl-punctuation |\n"
    " | String      | hl-string      |\n"
    " | Table name  | hl-module      |\n"
    " | Whitespace  | no class       |\n"
    "\n"
    " Place the output within\n"
    " `<pre><code class=\"language-toml\">...</code></pre>` and add styling for\n"
    " these CSS classes to get highlighting on your website. Here's some CSS you\n"
    " could use:\n"
    "\n"
    " ```css\n"
    " pre code {\n"
    "   .hl-comment     { color: #d4d4d4; font-style: italic }\n"
    "   .hl-function    { color: #9ce7ff }\n"
    "   .hl-attribute   { color: #ffd596 }\n"
    "   .hl-operator    { color: #ffaff3 }\n"
    "   .hl-string      { color: #c8ffa7 }\n"
    "   .hl-number      { color: #c8ffa7 }\n"
    "   .hl-literal     { color: #c8ffa7 }\n"
    "   .hl-module      { color: #ffddfa }\n"
    "   .hl-punctuation { color: inherit }\n"
    "   .hl-error       { background: red; color: white }\n"
    " }\n"
    " ```\n"
).
-spec to_html(list(highlight_token())) -> binary().
to_html(Tokens) ->
    gleam@list:fold(
        Tokens,
        <<""/utf8>>,
        fun(Acc, Token) ->
            Highlighted = case Token of
                {highlight_comment, Str} ->
                    span(<<"hl-comment"/utf8>>, Str);

                {highlight_date_time, Str@1} ->
                    span(<<"hl-function"/utf8>>, Str@1);

                {highlight_error, Str@2} ->
                    span(<<"hl-error"/utf8>>, Str@2);

                {highlight_key, Str@3} ->
                    span(<<"hl-attribute"/utf8>>, Str@3);

                {highlight_literal, Str@4} ->
                    span(<<"hl-literal"/utf8>>, Str@4);

                {highlight_number, Str@5} ->
                    span(<<"hl-number"/utf8>>, Str@5);

                {highlight_operator, Str@6} ->
                    span(<<"hl-operator"/utf8>>, Str@6);

                {highlight_punctuation, Str@7} ->
                    span(<<"hl-punctuation"/utf8>>, Str@7);

                {highlight_string, Str@8} ->
                    span(<<"hl-string"/utf8>>, Str@8);

                {highlight_table, Str@9} ->
                    span(<<"hl-module"/utf8>>, Str@9);

                {highlight_whitespace, Str@10} ->
                    Str@10
            end,
            <<Acc/binary, Highlighted/binary>>
        end
    ).

-file("src/william.gleam", 218).
-spec token_source(token()) -> binary().
token_source(Token) ->
    case Token of
        {bare_key, Name} ->
            Name;

        {boolean, Value} ->
            Value;

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

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

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

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

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

        {comment, Str} ->
            Str;

        {date_time, Value@1} ->
            Value@1;

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

        {end_of_line, Str@1} ->
            Str@1;

        equal ->
            <<"="/utf8>>;

        {float, Value@2} ->
            Value@2;

        {integer, _, Value@3} ->
            Value@3;

        {invalid_number, Str@2} ->
            Str@2;

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

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

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

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

        {string, Delimiter, Value@4} ->
            <<<<(string_delimiter(Delimiter))/binary, Value@4/binary>>/binary,
                (string_delimiter(Delimiter))/binary>>;

        {unexpected, Str@3} ->
            Str@3;

        {unterminated_string, Delimiter@1, Value@5} ->
            <<(string_delimiter(Delimiter@1))/binary, Value@5/binary>>;

        {whitespace, Str@4} ->
            Str@4
    end.

-file("src/william.gleam", 213).
?DOC(" Convert a list of tokens back into their source representation.\n").
-spec to_source(list(token())) -> binary().
to_source(Tokens) ->
    gleam@list:fold(
        Tokens,
        <<""/utf8>>,
        fun(Acc, Token) -> <<Acc/binary, (token_source(Token))/binary>> end
    ).

-file("src/william.gleam", 360).
?DOC(" Skip whitespace and end-of-line tokens in the resulting token list.\n").
-spec ignore_whitespace(lexer()) -> lexer().
ignore_whitespace(Lexer) ->
    {lexer,
        true,
        erlang:element(3, Lexer),
        erlang:element(4, Lexer),
        erlang:element(5, Lexer),
        erlang:element(6, Lexer),
        erlang:element(7, Lexer),
        erlang:element(8, Lexer),
        erlang:element(9, Lexer),
        erlang:element(10, Lexer)}.

-file("src/william.gleam", 365).
?DOC(" Skip comment tokens in the resulting token list.\n").
-spec ignore_comments(lexer()) -> lexer().
ignore_comments(Lexer) ->
    {lexer,
        erlang:element(2, Lexer),
        true,
        erlang:element(4, Lexer),
        erlang:element(5, Lexer),
        erlang:element(6, Lexer),
        erlang:element(7, Lexer),
        erlang:element(8, Lexer),
        erlang:element(9, Lexer),
        erlang:element(10, Lexer)}.