-module(glexer).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).

-export([new/1, take_content/3, next/1, iterator/1, lex/1]).
-export_type([position/0, lexer/0, number_lexer_mode/0]).

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

-opaque lexer() :: {lexer, binary(), integer()}.

-type number_lexer_mode() :: lex_int | lex_float | lex_float_exponent.

-spec new(binary()) -> lexer().
new(Source) ->
    {lexer, Source, 0}.

-spec consume_whitespace(lexer()) -> {lexer(), boolean()}.
consume_whitespace(Lexer) ->
    case erlang:element(2, Lexer) of
        <<""/utf8>> ->
            {Lexer, true};

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

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

        <<" "/utf8, Rest/binary>> ->
            consume_whitespace({lexer, Rest, erlang:element(3, Lexer) + 1});

        <<"\t"/utf8, Rest@1/binary>> ->
            consume_whitespace({lexer, Rest@1, erlang:element(3, Lexer) + 1});

        _ ->
            {Lexer, false}
    end.

-spec byte_size(binary()) -> integer().
byte_size(String) ->
    erlang:byte_size(<<String/binary>>).

-spec comment(binary(), integer(), integer(), glexer@token:token()) -> {lexer(),
    {glexer@token:token(), position()}}.
comment(Src, Start, Size, Token) ->
    case Src of
        <<"\n"/utf8, _/binary>> ->
            {{lexer, Src, Start + Size}, {Token, {position, Start}}};

        <<"\r\n"/utf8, _/binary>> ->
            {{lexer, Src, Start + Size}, {Token, {position, Start}}};

        _ ->
            case gleam@string:pop_grapheme(Src) of
                {error, _} ->
                    {{lexer, Src, Start + Size}, {Token, {position, Start}}};

                {ok, {Char, Rest}} ->
                    comment(Rest, Start, Size + byte_size(Char), Token)
            end
    end.

-spec take_content(binary(), binary(), fun((binary()) -> boolean())) -> {binary(),
    binary()}.
take_content(Source, Content, Predicate) ->
    case gleam@string:pop_grapheme(Source) of
        {error, _} ->
            {Content, <<""/utf8>>};

        {ok, {Grapheme, Rest}} ->
            case Predicate(Grapheme) of
                true ->
                    take_content(
                        Rest,
                        <<Content/binary, Grapheme/binary>>,
                        Predicate
                    );

                false ->
                    {Content, Source}
            end
    end.

-spec advance(lexer(), binary(), integer()) -> lexer().
advance(Lexer, Source, Offset) ->
    {lexer, Source, erlang:element(3, Lexer) + Offset}.

-spec token(lexer(), glexer@token:token()) -> {glexer@token:token(), position()}.
token(Lexer, Token) ->
    {Token, {position, erlang:element(3, Lexer)}}.

-spec doc_comment(binary(), integer(), integer(), binary()) -> {lexer(),
    {glexer@token:token(), position()}}.
doc_comment(Src, Start, Size, Content) ->
    case Src of
        <<"\n"/utf8, _/binary>> ->
            {{lexer, Src, Start + Size},
                {{comment_doc, Content}, {position, Start}}};

        <<"\r\n"/utf8, _/binary>> ->
            {{lexer, Src, Start + Size},
                {{comment_doc, Content}, {position, Start}}};

        _ ->
            case gleam@string:pop_grapheme(Src) of
                {error, _} ->
                    {{lexer, Src, Start + Size},
                        {{comment_doc, Content}, {position, Start}}};

                {ok, {Char, Rest}} ->
                    Size@1 = Size + byte_size(Char),
                    doc_comment(
                        Rest,
                        Start,
                        Size@1,
                        <<Content/binary, Char/binary>>
                    )
            end
    end.

-spec lex_string(binary(), binary(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
lex_string(Input, Content, Start) ->
    case Input of
        <<"\""/utf8, Rest/binary>> ->
            Lexer = {lexer, Rest, (Start + byte_size(Content)) + 2},
            {Lexer, {{string, Content}, {position, Start}}};

        <<"\\"/utf8, Rest@1/binary>> ->
            case gleam@string:pop_grapheme(Rest@1) of
                {error, _} ->
                    lex_string(Rest@1, <<Content/binary, "\\"/utf8>>, Start);

                {ok, {G, Rest@2}} ->
                    lex_string(
                        Rest@2,
                        <<<<Content/binary, "\\"/utf8>>/binary, G/binary>>,
                        Start
                    )
            end;

        _ ->
            case gleam@string:pop_grapheme(Input) of
                {ok, {G@1, Rest@3}} ->
                    lex_string(Rest@3, <<Content/binary, G@1/binary>>, Start);

                {error, _} ->
                    Lexer@1 = {lexer,
                        <<""/utf8>>,
                        (Start + byte_size(Content)) + 1},
                    {Lexer@1,
                        {{unterminated_string, Content}, {position, Start}}}
            end
    end.

-spec lex_number(binary(), binary(), number_lexer_mode(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
lex_number(Input, Content, Mode, Start) ->
    case Input of
        <<"."/utf8, Rest/binary>> when Mode =:= lex_int ->
            lex_number(Rest, <<Content/binary, "."/utf8>>, lex_float, Start);

        <<"e-"/utf8, Rest@1/binary>> when Mode =:= lex_float ->
            lex_number(
                Rest@1,
                <<Content/binary, "e-"/utf8>>,
                lex_float_exponent,
                Start
            );

        <<"e"/utf8, Rest@2/binary>> when Mode =:= lex_float ->
            lex_number(
                Rest@2,
                <<Content/binary, "e"/utf8>>,
                lex_float_exponent,
                Start
            );

        <<"_"/utf8, Source/binary>> ->
            lex_number(Source, <<Content/binary, "_"/utf8>>, Mode, Start);

        <<"0"/utf8, Source@1/binary>> ->
            lex_number(Source@1, <<Content/binary, "0"/utf8>>, Mode, Start);

        <<"1"/utf8, Source@2/binary>> ->
            lex_number(Source@2, <<Content/binary, "1"/utf8>>, Mode, Start);

        <<"2"/utf8, Source@3/binary>> ->
            lex_number(Source@3, <<Content/binary, "2"/utf8>>, Mode, Start);

        <<"3"/utf8, Source@4/binary>> ->
            lex_number(Source@4, <<Content/binary, "3"/utf8>>, Mode, Start);

        <<"4"/utf8, Source@5/binary>> ->
            lex_number(Source@5, <<Content/binary, "4"/utf8>>, Mode, Start);

        <<"5"/utf8, Source@6/binary>> ->
            lex_number(Source@6, <<Content/binary, "5"/utf8>>, Mode, Start);

        <<"6"/utf8, Source@7/binary>> ->
            lex_number(Source@7, <<Content/binary, "6"/utf8>>, Mode, Start);

        <<"7"/utf8, Source@8/binary>> ->
            lex_number(Source@8, <<Content/binary, "7"/utf8>>, Mode, Start);

        <<"8"/utf8, Source@9/binary>> ->
            lex_number(Source@9, <<Content/binary, "8"/utf8>>, Mode, Start);

        <<"9"/utf8, Source@10/binary>> ->
            lex_number(Source@10, <<Content/binary, "9"/utf8>>, Mode, Start);

        Source@11 ->
            Lexer = {lexer, Source@11, Start + byte_size(Content)},
            Token = case Mode of
                lex_int ->
                    {int, Content};

                lex_float ->
                    {float, Content};

                lex_float_exponent ->
                    {float, Content}
            end,
            {Lexer, {Token, {position, Start}}}
    end.

-spec lex_binary(binary(), binary(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
lex_binary(Source, Content, Start) ->
    case Source of
        <<"_"/utf8, Source@1/binary>> ->
            lex_binary(Source@1, <<Content/binary, "_"/utf8>>, Start);

        <<"0"/utf8, Source@2/binary>> ->
            lex_binary(Source@2, <<Content/binary, "0"/utf8>>, Start);

        <<"1"/utf8, Source@3/binary>> ->
            lex_binary(Source@3, <<Content/binary, "1"/utf8>>, Start);

        Source@4 ->
            Lexer = {lexer, Source@4, Start + byte_size(Content)},
            {Lexer, {{int, Content}, {position, Start}}}
    end.

-spec lex_octal(binary(), binary(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
lex_octal(Source, Content, Start) ->
    case Source of
        <<"_"/utf8, Source@1/binary>> ->
            lex_octal(Source@1, <<Content/binary, "_"/utf8>>, Start);

        <<"0"/utf8, Source@2/binary>> ->
            lex_octal(Source@2, <<Content/binary, "0"/utf8>>, Start);

        <<"1"/utf8, Source@3/binary>> ->
            lex_octal(Source@3, <<Content/binary, "1"/utf8>>, Start);

        <<"2"/utf8, Source@4/binary>> ->
            lex_octal(Source@4, <<Content/binary, "2"/utf8>>, Start);

        <<"3"/utf8, Source@5/binary>> ->
            lex_octal(Source@5, <<Content/binary, "3"/utf8>>, Start);

        <<"4"/utf8, Source@6/binary>> ->
            lex_octal(Source@6, <<Content/binary, "4"/utf8>>, Start);

        <<"5"/utf8, Source@7/binary>> ->
            lex_octal(Source@7, <<Content/binary, "5"/utf8>>, Start);

        <<"6"/utf8, Source@8/binary>> ->
            lex_octal(Source@8, <<Content/binary, "6"/utf8>>, Start);

        <<"7"/utf8, Source@9/binary>> ->
            lex_octal(Source@9, <<Content/binary, "7"/utf8>>, Start);

        Source@10 ->
            Lexer = {lexer, Source@10, Start + byte_size(Content)},
            {Lexer, {{int, Content}, {position, Start}}}
    end.

-spec lex_hexadecimal(binary(), binary(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
lex_hexadecimal(Source, Content, Start) ->
    case Source of
        <<"_"/utf8, Source@1/binary>> ->
            lex_hexadecimal(Source@1, <<Content/binary, "_"/utf8>>, Start);

        <<"0"/utf8, Source@2/binary>> ->
            lex_hexadecimal(Source@2, <<Content/binary, "0"/utf8>>, Start);

        <<"1"/utf8, Source@3/binary>> ->
            lex_hexadecimal(Source@3, <<Content/binary, "1"/utf8>>, Start);

        <<"2"/utf8, Source@4/binary>> ->
            lex_hexadecimal(Source@4, <<Content/binary, "2"/utf8>>, Start);

        <<"3"/utf8, Source@5/binary>> ->
            lex_hexadecimal(Source@5, <<Content/binary, "3"/utf8>>, Start);

        <<"4"/utf8, Source@6/binary>> ->
            lex_hexadecimal(Source@6, <<Content/binary, "4"/utf8>>, Start);

        <<"5"/utf8, Source@7/binary>> ->
            lex_hexadecimal(Source@7, <<Content/binary, "5"/utf8>>, Start);

        <<"6"/utf8, Source@8/binary>> ->
            lex_hexadecimal(Source@8, <<Content/binary, "6"/utf8>>, Start);

        <<"7"/utf8, Source@9/binary>> ->
            lex_hexadecimal(Source@9, <<Content/binary, "7"/utf8>>, Start);

        <<"8"/utf8, Source@10/binary>> ->
            lex_hexadecimal(Source@10, <<Content/binary, "8"/utf8>>, Start);

        <<"9"/utf8, Source@11/binary>> ->
            lex_hexadecimal(Source@11, <<Content/binary, "9"/utf8>>, Start);

        <<"A"/utf8, Source@12/binary>> ->
            lex_hexadecimal(Source@12, <<Content/binary, "A"/utf8>>, Start);

        <<"B"/utf8, Source@13/binary>> ->
            lex_hexadecimal(Source@13, <<Content/binary, "B"/utf8>>, Start);

        <<"C"/utf8, Source@14/binary>> ->
            lex_hexadecimal(Source@14, <<Content/binary, "C"/utf8>>, Start);

        <<"D"/utf8, Source@15/binary>> ->
            lex_hexadecimal(Source@15, <<Content/binary, "D"/utf8>>, Start);

        <<"E"/utf8, Source@16/binary>> ->
            lex_hexadecimal(Source@16, <<Content/binary, "E"/utf8>>, Start);

        <<"F"/utf8, Source@17/binary>> ->
            lex_hexadecimal(Source@17, <<Content/binary, "F"/utf8>>, Start);

        <<"a"/utf8, Source@18/binary>> ->
            lex_hexadecimal(Source@18, <<Content/binary, "a"/utf8>>, Start);

        <<"b"/utf8, Source@19/binary>> ->
            lex_hexadecimal(Source@19, <<Content/binary, "b"/utf8>>, Start);

        <<"c"/utf8, Source@20/binary>> ->
            lex_hexadecimal(Source@20, <<Content/binary, "c"/utf8>>, Start);

        <<"d"/utf8, Source@21/binary>> ->
            lex_hexadecimal(Source@21, <<Content/binary, "d"/utf8>>, Start);

        <<"e"/utf8, Source@22/binary>> ->
            lex_hexadecimal(Source@22, <<Content/binary, "e"/utf8>>, Start);

        <<"f"/utf8, Source@23/binary>> ->
            lex_hexadecimal(Source@23, <<Content/binary, "f"/utf8>>, Start);

        Source@24 ->
            Lexer = {lexer, Source@24, Start + byte_size(Content)},
            {Lexer, {{int, Content}, {position, Start}}}
    end.

-spec newline(lexer(), binary(), integer()) -> {lexer(),
    {glexer@token:token(), position()}}.
newline(Lexer, Src, Size) ->
    Start = erlang:element(3, Lexer),
    case consume_whitespace({lexer, Src, Start + Size}) of
        {Lexer@1, true} ->
            {Lexer@1, {empty_line, {position, Start}}};

        {Lexer@2, false} ->
            next(Lexer@2)
    end.

-spec next(lexer()) -> {lexer(), {glexer@token:token(), position()}}.
next(Lexer) ->
    case erlang:element(2, Lexer) of
        <<"\r\n"/utf8, Rest/binary>> ->
            newline(Lexer, Rest, 2);

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

        <<" "/utf8, Rest@2/binary>> ->
            next(advance(Lexer, Rest@2, 1));

        <<"\t"/utf8, Rest@2/binary>> ->
            next(advance(Lexer, Rest@2, 1));

        <<"////"/utf8, Rest@3/binary>> ->
            comment(Rest@3, erlang:element(3, Lexer), 4, comment_module);

        <<"///"/utf8, Rest@4/binary>> ->
            doc_comment(Rest@4, erlang:element(3, Lexer), 3, <<""/utf8>>);

        <<"//"/utf8, Rest@5/binary>> ->
            comment(Rest@5, erlang:element(3, Lexer), 2, comment_normal);

        <<"("/utf8, Rest@6/binary>> ->
            {advance(Lexer, Rest@6, 1), token(Lexer, left_paren)};

        <<")"/utf8, Rest@7/binary>> ->
            {advance(Lexer, Rest@7, 1), token(Lexer, right_paren)};

        <<"{"/utf8, Rest@8/binary>> ->
            {advance(Lexer, Rest@8, 1), token(Lexer, left_brace)};

        <<"}"/utf8, Rest@9/binary>> ->
            {advance(Lexer, Rest@9, 1), token(Lexer, right_brace)};

        <<"["/utf8, Rest@10/binary>> ->
            {advance(Lexer, Rest@10, 1), token(Lexer, left_square)};

        <<"]"/utf8, Rest@11/binary>> ->
            {advance(Lexer, Rest@11, 1), token(Lexer, right_square)};

        <<"@"/utf8, Rest@12/binary>> ->
            {advance(Lexer, Rest@12, 1), token(Lexer, at)};

        <<":"/utf8, Rest@13/binary>> ->
            {advance(Lexer, Rest@13, 1), token(Lexer, colon)};

        <<","/utf8, Rest@14/binary>> ->
            {advance(Lexer, Rest@14, 1), token(Lexer, comma)};

        <<".."/utf8, Rest@15/binary>> ->
            {advance(Lexer, Rest@15, 2), token(Lexer, dot_dot)};

        <<"."/utf8, Rest@16/binary>> ->
            {advance(Lexer, Rest@16, 1), token(Lexer, dot)};

        <<"#"/utf8, Rest@17/binary>> ->
            {advance(Lexer, Rest@17, 1), token(Lexer, hash)};

        <<"!="/utf8, Rest@18/binary>> ->
            {advance(Lexer, Rest@18, 2), token(Lexer, not_equal)};

        <<"!"/utf8, Rest@19/binary>> ->
            {advance(Lexer, Rest@19, 1), token(Lexer, bang)};

        <<"=="/utf8, Rest@20/binary>> ->
            {advance(Lexer, Rest@20, 2), token(Lexer, equal_equal)};

        <<"="/utf8, Rest@21/binary>> ->
            {advance(Lexer, Rest@21, 1), token(Lexer, equal)};

        <<"|>"/utf8, Rest@22/binary>> ->
            {advance(Lexer, Rest@22, 2), token(Lexer, pipe)};

        <<"||"/utf8, Rest@23/binary>> ->
            {advance(Lexer, Rest@23, 2), token(Lexer, v_bar_v_bar)};

        <<"|"/utf8, Rest@24/binary>> ->
            {advance(Lexer, Rest@24, 1), token(Lexer, v_bar)};

        <<"&&"/utf8, Rest@25/binary>> ->
            {advance(Lexer, Rest@25, 2), token(Lexer, amper_amper)};

        <<"<<"/utf8, Rest@26/binary>> ->
            {advance(Lexer, Rest@26, 2), token(Lexer, less_less)};

        <<">>"/utf8, Rest@27/binary>> ->
            {advance(Lexer, Rest@27, 2), token(Lexer, greater_greater)};

        <<"<-"/utf8, Rest@28/binary>> ->
            {advance(Lexer, Rest@28, 2), token(Lexer, left_arrow)};

        <<"->"/utf8, Rest@29/binary>> ->
            {advance(Lexer, Rest@29, 2), token(Lexer, right_arrow)};

        <<"<>"/utf8, Rest@30/binary>> ->
            {advance(Lexer, Rest@30, 2), token(Lexer, less_greater)};

        <<"+."/utf8, Rest@31/binary>> ->
            {advance(Lexer, Rest@31, 2), token(Lexer, plus_dot)};

        <<"-."/utf8, Rest@32/binary>> ->
            {advance(Lexer, Rest@32, 2), token(Lexer, minus_dot)};

        <<"*."/utf8, Rest@33/binary>> ->
            {advance(Lexer, Rest@33, 2), token(Lexer, star_dot)};

        <<"/."/utf8, Rest@34/binary>> ->
            {advance(Lexer, Rest@34, 2), token(Lexer, slash_dot)};

        <<"<=."/utf8, Rest@35/binary>> ->
            {advance(Lexer, Rest@35, 3), token(Lexer, less_equal_dot)};

        <<"<."/utf8, Rest@36/binary>> ->
            {advance(Lexer, Rest@36, 2), token(Lexer, less_dot)};

        <<">=."/utf8, Rest@37/binary>> ->
            {advance(Lexer, Rest@37, 3), token(Lexer, greater_equal_dot)};

        <<">."/utf8, Rest@38/binary>> ->
            {advance(Lexer, Rest@38, 2), token(Lexer, greater_dot)};

        <<"+"/utf8, Rest@39/binary>> ->
            {advance(Lexer, Rest@39, 1), token(Lexer, plus)};

        <<"-"/utf8, Rest@40/binary>> ->
            {advance(Lexer, Rest@40, 1), token(Lexer, minus)};

        <<"*"/utf8, Rest@41/binary>> ->
            {advance(Lexer, Rest@41, 1), token(Lexer, star)};

        <<"/"/utf8, Rest@42/binary>> ->
            {advance(Lexer, Rest@42, 1), token(Lexer, slash)};

        <<"<="/utf8, Rest@43/binary>> ->
            {advance(Lexer, Rest@43, 2), token(Lexer, less_equal)};

        <<"<"/utf8, Rest@44/binary>> ->
            {advance(Lexer, Rest@44, 1), token(Lexer, less)};

        <<">="/utf8, Rest@45/binary>> ->
            {advance(Lexer, Rest@45, 2), token(Lexer, greater_equal)};

        <<">"/utf8, Rest@46/binary>> ->
            {advance(Lexer, Rest@46, 1), token(Lexer, greater)};

        <<"%"/utf8, Rest@47/binary>> ->
            {advance(Lexer, Rest@47, 1), token(Lexer, percent)};

        <<"\""/utf8, Rest@48/binary>> ->
            lex_string(Rest@48, <<""/utf8>>, erlang:element(3, Lexer));

        <<"_"/utf8, Rest@49/binary>> ->
            {Name, Rest@50} = take_content(
                Rest@49,
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            {{lexer, Rest@50, erlang:element(3, Lexer) + byte_size(Name)},
                token(Lexer, {discard_name, Name})};

        <<"0b"/utf8, Source/binary>> ->
            lex_binary(Source, <<"0b"/utf8>>, erlang:element(3, Lexer));

        <<"0o"/utf8, Source@1/binary>> ->
            lex_octal(Source@1, <<"0o"/utf8>>, erlang:element(3, Lexer));

        <<"0x"/utf8, Source@2/binary>> ->
            lex_hexadecimal(Source@2, <<"0x"/utf8>>, erlang:element(3, Lexer));

        <<"0"/utf8, Source@3/binary>> ->
            lex_number(
                Source@3,
                <<"0"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"1"/utf8, Source@4/binary>> ->
            lex_number(
                Source@4,
                <<"1"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"2"/utf8, Source@5/binary>> ->
            lex_number(
                Source@5,
                <<"2"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"3"/utf8, Source@6/binary>> ->
            lex_number(
                Source@6,
                <<"3"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"4"/utf8, Source@7/binary>> ->
            lex_number(
                Source@7,
                <<"4"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"5"/utf8, Source@8/binary>> ->
            lex_number(
                Source@8,
                <<"5"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"6"/utf8, Source@9/binary>> ->
            lex_number(
                Source@9,
                <<"6"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"7"/utf8, Source@10/binary>> ->
            lex_number(
                Source@10,
                <<"7"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"8"/utf8, Source@11/binary>> ->
            lex_number(
                Source@11,
                <<"8"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"9"/utf8, Source@12/binary>> ->
            lex_number(
                Source@12,
                <<"9"/utf8>>,
                lex_int,
                erlang:element(3, Lexer)
            );

        <<"a"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"b"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"c"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"d"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"e"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"f"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"g"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"h"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"i"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"j"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"k"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"l"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"m"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"n"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"o"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"p"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"q"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"r"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"s"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"t"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"u"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"v"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"w"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"x"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"y"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"z"/utf8, _/binary>> ->
            {Name@1, Rest@51} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_name_grapheme/1
            ),
            As_token = case Name@1 of
                <<"assert"/utf8>> ->
                    assert;

                <<"as"/utf8>> ->
                    as;

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

                <<"const"/utf8>> ->
                    const;

                <<"external"/utf8>> ->
                    external;

                <<"fn"/utf8>> ->
                    fn;

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

                <<"import"/utf8>> ->
                    import;

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

                <<"opaque"/utf8>> ->
                    opaque;

                <<"panic"/utf8>> ->
                    panic;

                <<"pub"/utf8>> ->
                    pub;

                <<"todo"/utf8>> ->
                    todo;

                <<"type"/utf8>> ->
                    type;

                <<"use"/utf8>> ->
                    use;

                Name@2 ->
                    {name, Name@2}
            end,
            {{lexer, Rest@51, erlang:element(3, Lexer) + byte_size(Name@1)},
                token(Lexer, As_token)};

        <<"A"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"B"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"C"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"D"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"E"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"F"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"G"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"H"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"I"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"J"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"K"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"L"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"M"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"N"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"O"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"P"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"Q"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"R"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"S"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"T"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"U"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"V"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"W"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"X"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"Y"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        <<"Z"/utf8, _/binary>> ->
            {Name@3, Rest@52} = take_content(
                erlang:element(2, Lexer),
                <<""/utf8>>,
                fun glexer@internal@predicates:is_upname_grapheme/1
            ),
            As_token@1 = {upper_name, Name@3},
            {{lexer, Rest@52, erlang:element(3, Lexer) + byte_size(Name@3)},
                token(Lexer, As_token@1)};

        _ ->
            case gleam@string:pop_grapheme(erlang:element(2, Lexer)) of
                {error, _} ->
                    {Lexer, {end_of_file, {position, erlang:element(3, Lexer)}}};

                {ok, {Grapheme, Rest@53}} ->
                    T = {unexpected_grapheme, Grapheme},
                    {advance(Lexer, Rest@53, byte_size(Grapheme)),
                        token(Lexer, T)}
            end
    end.

-spec iterator(lexer()) -> gleam@iterator:iterator({glexer@token:token(),
    position()}).
iterator(Lexer) ->
    gleam@iterator:unfold(Lexer, fun(Lexer@1) -> case next(Lexer@1) of
                {_, {end_of_file, _}} ->
                    done;

                {Lexer@2, Token} ->
                    {next, Token, Lexer@2}
            end end).

-spec lex(lexer()) -> list({glexer@token:token(), position()}).
lex(Lexer) ->
    _pipe = iterator(Lexer),
    gleam@iterator:to_list(_pipe).
