src/gleeam_code@internal@codegen.erl

-module(gleeam_code@internal@codegen).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeam_code/internal/codegen.gleam").
-export([generate_solution/5, extract_outputs/1, format_gleam_value/1, format_gleam_value_typed/2, generate_test/4]).

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

?MODULEDOC(false).

-file("src/gleeam_code/internal/codegen.gleam", 43).
?DOC(false).
-spec generate_imports(gleeam_code@internal@spec_parser:function_spec()) -> binary().
generate_imports(Spec) ->
    Needs_tree = gleeam_code@internal@spec_parser:uses_tree_node(Spec),
    Needs_list = gleeam_code@internal@spec_parser:uses_list_node(Spec),
    case Needs_tree orelse Needs_list of
        false ->
            <<""/utf8>>;

        true ->
            Option_import = <<"\nimport gleam/option.{type Option, None, Some}\n"/utf8>>,
            Type_imports = case {Needs_tree, Needs_list} of
                {true, true} ->
                    <<"import types.{type TreeNode, TreeNode, type ListNode, ListNode}\n"/utf8>>;

                {true, false} ->
                    <<"import types.{type TreeNode, TreeNode}\n"/utf8>>;

                {false, true} ->
                    <<"import types.{type ListNode, ListNode}\n"/utf8>>;

                {false, false} ->
                    <<""/utf8>>
            end,
            <<Option_import/binary, Type_imports/binary>>
    end.

-file("src/gleeam_code/internal/codegen.gleam", 6).
?DOC(false).
-spec generate_solution(
    binary(),
    binary(),
    binary(),
    binary(),
    gleeam_code@internal@spec_parser:function_spec()
) -> binary().
generate_solution(Frontend_id, Title, Title_slug, Difficulty, Spec) ->
    Header = <<<<<<<<<<<<<<<<"//// Problem "/utf8, Frontend_id/binary>>/binary,
                                ": "/utf8>>/binary,
                            Title/binary>>/binary,
                        "\n//// https://leetcode.com/problems/"/utf8>>/binary,
                    Title_slug/binary>>/binary,
                "/\n//// Difficulty: "/utf8>>/binary,
            Difficulty/binary>>/binary,
        "\n"/utf8>>,
    Imports = generate_imports(Spec),
    Params_str = begin
        _pipe = erlang:element(3, Spec),
        _pipe@1 = gleam@list:map(
            _pipe,
            fun(P) ->
                <<<<(erlang:element(2, P))/binary, ": "/utf8>>/binary,
                    (erlang:element(3, P))/binary>>
            end
        ),
        gleam@string:join(_pipe@1, <<", "/utf8>>)
    end,
    Func = <<<<<<<<<<<<"\npub fn "/utf8, (erlang:element(2, Spec))/binary>>/binary,
                        "("/utf8>>/binary,
                    Params_str/binary>>/binary,
                ") -> "/utf8>>/binary,
            (erlang:element(4, Spec))/binary>>/binary,
        " {\n  todo\n}\n"/utf8>>,
    <<<<Header/binary, Imports/binary>>/binary, Func/binary>>.

-file("src/gleeam_code/internal/codegen.gleam", 123).
?DOC(false).
-spec pad_outputs(list(binary()), integer()) -> list(binary()).
pad_outputs(Outputs, Target_len) ->
    Current_len = erlang:length(Outputs),
    case Current_len >= Target_len of
        true ->
            Outputs;

        false ->
            lists:append(
                Outputs,
                gleam@list:repeat(<<"todo"/utf8>>, Target_len - Current_len)
            )
    end.

-file("src/gleeam_code/internal/codegen.gleam", 151).
?DOC(false).
-spec take_until_delimiter(list(binary()), binary()) -> binary().
take_until_delimiter(Chars, Acc) ->
    case Chars of
        [] ->
            Acc;

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

        [<<"<"/utf8>> | _] ->
            Acc;

        [C | Rest] ->
            take_until_delimiter(Rest, <<Acc/binary, C/binary>>)
    end.

-file("src/gleeam_code/internal/codegen.gleam", 160).
?DOC(false).
-spec decode_html_entities(binary()) -> binary().
decode_html_entities(S) ->
    _pipe = S,
    _pipe@1 = gleam@string:replace(_pipe, <<"&quot;"/utf8>>, <<"\""/utf8>>),
    _pipe@2 = gleam@string:replace(_pipe@1, <<"&amp;"/utf8>>, <<"&"/utf8>>),
    _pipe@3 = gleam@string:replace(_pipe@2, <<"&lt;"/utf8>>, <<"<"/utf8>>),
    _pipe@4 = gleam@string:replace(_pipe@3, <<"&gt;"/utf8>>, <<">"/utf8>>),
    _pipe@5 = gleam@string:replace(_pipe@4, <<"&#39;"/utf8>>, <<"'"/utf8>>),
    gleam@string:replace(_pipe@5, <<"&nbsp;"/utf8>>, <<" "/utf8>>).

-file("src/gleeam_code/internal/codegen.gleam", 145).
?DOC(false).
-spec extract_output_value(binary()) -> binary().
extract_output_value(S) ->
    _pipe = take_until_delimiter(gleam@string:to_graphemes(S), <<""/utf8>>),
    _pipe@1 = gleam@string:trim(_pipe),
    decode_html_entities(_pipe@1).

-file("src/gleeam_code/internal/codegen.gleam", 135).
?DOC(false).
-spec do_extract_outputs(binary(), list(binary())) -> list(binary()).
do_extract_outputs(Content, Acc) ->
    case gleam@string:split_once(Content, <<"<strong>Output:</strong>"/utf8>>) of
        {error, _} ->
            lists:reverse(Acc);

        {ok, {_, After}} ->
            Value = extract_output_value(gleam@string:trim_start(After)),
            do_extract_outputs(After, [Value | Acc])
    end.

-file("src/gleeam_code/internal/codegen.gleam", 131).
?DOC(false).
-spec extract_outputs(binary()) -> list(binary()).
extract_outputs(Content) ->
    do_extract_outputs(Content, []).

-file("src/gleeam_code/internal/codegen.gleam", 258).
?DOC(false).
-spec split_list_items(binary()) -> list(binary()).
split_list_items(S) ->
    gleeam_code@internal@spec_parser:split_params(S).

-file("src/gleeam_code/internal/codegen.gleam", 198).
?DOC(false).
-spec format_tree_value(binary()) -> binary().
format_tree_value(Raw) ->
    case Raw of
        <<"null"/utf8>> ->
            <<"None"/utf8>>;

        <<"[]"/utf8>> ->
            <<"None"/utf8>>;

        <<"["/utf8, _/binary>> ->
            Inner = begin
                _pipe = Raw,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            Items = begin
                _pipe@2 = split_list_items(Inner),
                _pipe@3 = gleam@list:map(
                    _pipe@2,
                    fun(Item) ->
                        V = gleam@string:trim(Item),
                        case V of
                            <<"null"/utf8>> ->
                                <<"None"/utf8>>;

                            _ ->
                                <<<<"Some("/utf8, V/binary>>/binary, ")"/utf8>>
                        end
                    end
                ),
                gleam@string:join(_pipe@3, <<", "/utf8>>)
            end,
            <<<<"tree_from_level_order(["/utf8, Items/binary>>/binary,
                "])"/utf8>>;

        _ ->
            Raw
    end.

-file("src/gleeam_code/internal/codegen.gleam", 222).
?DOC(false).
-spec format_list_node_value(binary()) -> binary().
format_list_node_value(Raw) ->
    case Raw of
        <<"null"/utf8>> ->
            <<"None"/utf8>>;

        <<"[]"/utf8>> ->
            <<"None"/utf8>>;

        <<"["/utf8, _/binary>> ->
            Inner = begin
                _pipe = Raw,
                _pipe@1 = gleam@string:drop_start(_pipe, 1),
                gleam@string:drop_end(_pipe@1, 1)
            end,
            Items = begin
                _pipe@2 = split_list_items(Inner),
                _pipe@3 = gleam@list:map(
                    _pipe@2,
                    fun(Item) -> gleam@string:trim(Item) end
                ),
                gleam@string:join(_pipe@3, <<", "/utf8>>)
            end,
            <<<<"list_from_list(["/utf8, Items/binary>>/binary, "])"/utf8>>;

        _ ->
            Raw
    end.

-file("src/gleeam_code/internal/codegen.gleam", 177).
?DOC(false).
-spec format_gleam_value(binary()) -> binary().
format_gleam_value(Raw) ->
    format_gleam_value_typed(Raw, <<""/utf8>>).

-file("src/gleeam_code/internal/codegen.gleam", 181).
?DOC(false).
-spec format_gleam_value_typed(binary(), binary()) -> binary().
format_gleam_value_typed(Raw, Type_str) ->
    Trimmed = gleam@string:trim(Raw),
    case Type_str of
        <<"Option(TreeNode)"/utf8>> ->
            format_tree_value(Trimmed);

        <<"Option(ListNode)"/utf8>> ->
            format_list_node_value(Trimmed);

        _ ->
            case Trimmed of
                <<"\""/utf8, _/binary>> ->
                    Trimmed;

                <<"["/utf8, _/binary>> ->
                    format_gleam_list(Trimmed);

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

                <<"false"/utf8>> ->
                    <<"False"/utf8>>;

                <<"null"/utf8>> ->
                    <<"None"/utf8>>;

                _ ->
                    Trimmed
            end
    end.

-file("src/gleeam_code/internal/codegen.gleam", 240).
?DOC(false).
-spec format_gleam_list(binary()) -> binary().
format_gleam_list(S) ->
    Inner = begin
        _pipe = S,
        _pipe@1 = gleam@string:drop_start(_pipe, 1),
        gleam@string:drop_end(_pipe@1, 1)
    end,
    case gleam@string:trim(Inner) of
        <<""/utf8>> ->
            <<"[]"/utf8>>;

        Content ->
            Items = begin
                _pipe@2 = split_list_items(Content),
                _pipe@3 = gleam@list:map(
                    _pipe@2,
                    fun(Item) -> format_gleam_value(gleam@string:trim(Item)) end
                ),
                gleam@string:join(_pipe@3, <<", "/utf8>>)
            end,
            <<<<"["/utf8, Items/binary>>/binary, "]"/utf8>>
    end.

-file("src/gleeam_code/internal/codegen.gleam", 170).
?DOC(false).
-spec parse_testcase_input(
    binary(),
    list(gleeam_code@internal@spec_parser:param())
) -> binary().
parse_testcase_input(Input, Params) ->
    Lines = gleam@string:split(Input, <<"\n"/utf8>>),
    _pipe = gleam@list:zip(Lines, Params),
    _pipe@1 = gleam@list:map(
        _pipe,
        fun(Pair) ->
            format_gleam_value_typed(
                erlang:element(1, Pair),
                erlang:element(3, erlang:element(2, Pair))
            )
        end
    ),
    gleam@string:join(_pipe@1, <<", "/utf8>>).

-file("src/gleeam_code/internal/codegen.gleam", 62).
?DOC(false).
-spec generate_test(
    binary(),
    gleeam_code@internal@spec_parser:function_spec(),
    list(binary()),
    list(binary())
) -> binary().
generate_test(Module_path, Spec, Inputs, Outputs) ->
    Import_line = <<<<"import "/utf8, Module_path/binary>>/binary,
        "/solution\n"/utf8>>,
    Needs_tree = gleeam_code@internal@spec_parser:uses_tree_node(Spec),
    Needs_list = gleeam_code@internal@spec_parser:uses_list_node(Spec),
    Extra_imports = case Needs_tree orelse Needs_list of
        false ->
            <<""/utf8>>;

        true ->
            Option_import = <<"import gleam/option.{None, Some}\n"/utf8>>,
            Types_import = case {Needs_tree, Needs_list} of
                {true, true} ->
                    <<"import types.{tree_from_level_order, list_from_list}\n"/utf8>>;

                {true, false} ->
                    <<"import types.{tree_from_level_order}\n"/utf8>>;

                {false, true} ->
                    <<"import types.{list_from_list}\n"/utf8>>;

                {false, false} ->
                    <<""/utf8>>
            end,
            <<Option_import/binary, Types_import/binary>>
    end,
    Padded_outputs = pad_outputs(Outputs, erlang:length(Inputs)),
    Pairs = gleam@list:zip(Inputs, Padded_outputs),
    Uses_nodes = Needs_tree orelse Needs_list,
    Tests = begin
        _pipe = gleam@list:index_map(
            Pairs,
            fun(Pair, Idx) ->
                Example_num = erlang:integer_to_binary(Idx + 1),
                Args = parse_testcase_input(
                    erlang:element(1, Pair),
                    erlang:element(3, Spec)
                ),
                Expected = format_gleam_value_typed(
                    erlang:element(2, Pair),
                    erlang:element(4, Spec)
                ),
                case Uses_nodes of
                    true ->
                        <<<<<<<<<<<<<<<<"\npub fn example_"/utf8,
                                                        Example_num/binary>>/binary,
                                                    "_test() {\n  let expected = "/utf8>>/binary,
                                                Expected/binary>>/binary,
                                            "\n  let result = solution."/utf8>>/binary,
                                        (erlang:element(2, Spec))/binary>>/binary,
                                    "("/utf8>>/binary,
                                Args/binary>>/binary,
                            ")\n  let assert True = expected == result\n}\n"/utf8>>;

                    false ->
                        <<<<<<<<<<<<<<<<"\npub fn example_"/utf8,
                                                        Example_num/binary>>/binary,
                                                    "_test() {\n  let assert "/utf8>>/binary,
                                                Expected/binary>>/binary,
                                            " = solution."/utf8>>/binary,
                                        (erlang:element(2, Spec))/binary>>/binary,
                                    "("/utf8>>/binary,
                                Args/binary>>/binary,
                            ")\n}\n"/utf8>>
                end
            end
        ),
        gleam@string:join(_pipe, <<""/utf8>>)
    end,
    <<<<Import_line/binary, Extra_imports/binary>>/binary, Tests/binary>>.