-module(gleeam_code@internal@stdlib_bundler).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeam_code/internal/stdlib_bundler.gleam").
-export([bundle/2]).
-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/stdlib_bundler.gleam", 114).
?DOC(false).
-spec is_local_call_start(binary(), list(binary())) -> boolean().
is_local_call_start(C, Current) ->
case Current of
[] ->
gleeam_code@internal@char:is_lowercase(C) orelse (C =:= <<"_"/utf8>>);
_ ->
gleeam_code@internal@char:is_identifier(C)
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 83).
?DOC(false).
-spec scan_for_local_calls(list(binary()), list(binary()), list(binary())) -> list(binary()).
scan_for_local_calls(Chars, Current, Acc) ->
case Chars of
[] ->
Acc;
[C | Rest] ->
case is_local_call_start(C, Current) of
true ->
scan_for_local_calls(Rest, [C | Current], Acc);
false ->
case C of
<<"("/utf8>> ->
Name = erlang:list_to_binary(lists:reverse(Current)),
case Name of
<<""/utf8>> ->
scan_for_local_calls(Rest, [], Acc);
_ ->
case gleam_stdlib:contains_string(
Name,
<<":"/utf8>>
)
orelse gleam_stdlib:contains_string(
Name,
<<"@"/utf8>>
) of
true ->
scan_for_local_calls(Rest, [], Acc);
false ->
scan_for_local_calls(
Rest,
[],
[Name | Acc]
)
end
end;
_ ->
scan_for_local_calls(Rest, [], Acc)
end
end
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 76).
?DOC(false).
-spec extract_called_identifiers(binary()) -> list(binary()).
extract_called_identifiers(Body) ->
_pipe = Body,
_pipe@1 = gleam@string:to_graphemes(_pipe),
_pipe@2 = scan_for_local_calls(_pipe@1, [], []),
gleam@list:unique(_pipe@2).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 121).
?DOC(false).
-spec is_defined_in_source(binary(), binary()) -> boolean().
is_defined_in_source(Name, Source) ->
gleam_stdlib:contains_string(
Source,
<<<<"\n"/utf8, Name/binary>>/binary, "("/utf8>>
).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 63).
?DOC(false).
-spec find_local_calls(binary(), binary(), binary()) -> list(gleeam_code@internal@stdlib_scanner:stdlib_call()).
find_local_calls(Func_body, Module, Module_source) ->
Exported = gleeam_code@internal@stdlib_extractor:list_exported(
Module_source
),
All_identifiers = extract_called_identifiers(Func_body),
_pipe = All_identifiers,
_pipe@1 = gleam@list:filter(
_pipe,
fun(Name) -> not gleam@list:contains(Exported, Name) end
),
_pipe@2 = gleam@list:filter(
_pipe@1,
fun(Name@1) -> is_defined_in_source(Name@1, Module_source) end
),
gleam@list:map(_pipe@2, fun(Name@2) -> {stdlib_call, Module, Name@2} end).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 177).
?DOC(false).
-spec do_rename_bare(list(binary()), binary(), binary()) -> binary().
do_rename_bare(Parts, Func_name, Replacement) ->
case Parts of
[] ->
<<""/utf8>>;
[Only] ->
Only;
[First | Rest] ->
Should_rename = case gleam@string:last(First) of
{ok, C} ->
not gleeam_code@internal@char:is_identifier_no_at(C);
{error, _} ->
true
end,
case Should_rename of
true ->
<<<<First/binary, Replacement/binary>>/binary,
(do_rename_bare(Rest, Func_name, Replacement))/binary>>;
false ->
<<<<<<First/binary, Func_name/binary>>/binary, "("/utf8>>/binary,
(do_rename_bare(Rest, Func_name, Replacement))/binary>>
end
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 168).
?DOC(false).
-spec rename_bare_calls(binary(), binary(), binary()) -> binary().
rename_bare_calls(Code, Func_name, Replacement) ->
Target = <<Func_name/binary, "("/utf8>>,
do_rename_bare(gleam@string:split(Code, Target), Func_name, Replacement).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 219).
?DOC(false).
-spec make_local_name(binary(), binary()) -> binary().
make_local_name(Module, Function) ->
Safe_module = begin
_pipe = Module,
_pipe@1 = gleam@string:replace(_pipe, <<"@"/utf8>>, <<"_"/utf8>>),
gleam@string:replace(_pipe@1, <<"."/utf8>>, <<"_"/utf8>>)
end,
<<<<Safe_module/binary, "__"/utf8>>/binary, Function/binary>>.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 152).
?DOC(false).
-spec rename_local_calls(
binary(),
binary(),
list(gleeam_code@internal@stdlib_scanner:stdlib_call())
) -> binary().
rename_local_calls(Code, Current_module, All_calls) ->
Local_funcs = begin
_pipe = All_calls,
_pipe@1 = gleam@list:filter(
_pipe,
fun(C) -> erlang:element(2, C) =:= Current_module end
),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(C@1) -> erlang:element(3, C@1) end
),
gleam@list:unique(_pipe@2)
end,
gleam@list:fold(
Local_funcs,
Code,
fun(Acc, Func_name) ->
Renamed = <<(make_local_name(Current_module, Func_name))/binary,
"("/utf8>>,
rename_bare_calls(Acc, Func_name, Renamed)
end
).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 203).
?DOC(false).
-spec rename_external_calls(
binary(),
list(gleeam_code@internal@stdlib_scanner:stdlib_call())
) -> binary().
rename_external_calls(Code, Calls) ->
gleam@list:fold(
Calls,
Code,
fun(Acc, Call) ->
Original = <<<<<<(erlang:element(2, Call))/binary, ":"/utf8>>/binary,
(erlang:element(3, Call))/binary>>/binary,
"("/utf8>>,
Renamed = <<(make_local_name(
erlang:element(2, Call),
erlang:element(3, Call)
))/binary,
"("/utf8>>,
gleam@string:replace(Acc, Original, Renamed)
end
).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 143).
?DOC(false).
-spec rename_in_extracted(
binary(),
binary(),
list(gleeam_code@internal@stdlib_scanner:stdlib_call())
) -> binary().
rename_in_extracted(Code, Current_module, All_calls) ->
Code1 = rename_external_calls(Code, All_calls),
rename_local_calls(Code1, Current_module, All_calls).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 211).
?DOC(false).
-spec rename_calls_in_code(
binary(),
list(gleeam_code@internal@stdlib_scanner:stdlib_call())
) -> binary().
rename_calls_in_code(Code, Calls) ->
gleam@list:fold(
Calls,
Code,
fun(Acc, Call) ->
Original = <<<<<<(erlang:element(2, Call))/binary, ":"/utf8>>/binary,
(erlang:element(3, Call))/binary>>/binary,
"("/utf8>>,
Renamed = <<(make_local_name(
erlang:element(2, Call),
erlang:element(3, Call)
))/binary,
"("/utf8>>,
gleam@string:replace(Acc, Original, Renamed)
end
).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 227).
?DOC(false).
-spec module_to_path(binary(), binary()) -> binary().
module_to_path(Module, Stdlib_dir) ->
<<<<<<Stdlib_dir/binary, "/"/utf8>>/binary, Module/binary>>/binary,
".erl"/utf8>>.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 47).
?DOC(false).
-spec find_deps_of(gleeam_code@internal@stdlib_scanner:stdlib_call(), binary()) -> list(gleeam_code@internal@stdlib_scanner:stdlib_call()).
find_deps_of(Call, Stdlib_dir) ->
Module_file = module_to_path(erlang:element(2, Call), Stdlib_dir),
case gleeam_code@internal@file:read(Module_file) of
{error, _} ->
[];
{ok, Source} ->
case gleeam_code@internal@stdlib_extractor:extract_function(
Source,
erlang:element(3, Call)
) of
{error, _} ->
[];
{ok, Func_body} ->
Inner_calls = gleeam_code@internal@stdlib_scanner:scan(
Func_body
),
Local_calls = find_local_calls(
Func_body,
erlang:element(2, Call),
Source
),
lists:append(Inner_calls, Local_calls)
end
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 21).
?DOC(false).
-spec resolve_transitive(
list(gleeam_code@internal@stdlib_scanner:stdlib_call()),
binary(),
list(gleeam_code@internal@stdlib_scanner:stdlib_call())
) -> list(gleeam_code@internal@stdlib_scanner:stdlib_call()).
resolve_transitive(Worklist, Stdlib_dir, Resolved) ->
case Worklist of
[] ->
Resolved;
_ ->
New_calls = begin
_pipe = Worklist,
_pipe@1 = gleam@list:flat_map(
_pipe,
fun(Call) -> find_deps_of(Call, Stdlib_dir) end
),
_pipe@2 = gleam@list:filter(
_pipe@1,
fun(C) -> not gleam@list:contains(Resolved, C) end
),
gleam@list:unique(_pipe@2)
end,
case New_calls of
[] ->
Resolved;
_ ->
resolve_transitive(
New_calls,
Stdlib_dir,
lists:append(Resolved, New_calls)
)
end
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 238).
?DOC(false).
-spec add_to_group(list({binary(), list(binary())}), binary(), binary()) -> list({binary(),
list(binary())}).
add_to_group(Groups, Module, Func) ->
case Groups of
[] ->
[{Module, [Func]}];
[{M, Funcs} | Rest] ->
case M =:= Module of
true ->
case gleam@list:contains(Funcs, Func) of
true ->
[{M, Funcs} | Rest];
false ->
[{M, [Func | Funcs]} | Rest]
end;
false ->
[{M, Funcs} | add_to_group(Rest, Module, Func)]
end
end.
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 231).
?DOC(false).
-spec group_by_module(list(gleeam_code@internal@stdlib_scanner:stdlib_call())) -> list({binary(),
list(binary())}).
group_by_module(Calls) ->
_pipe = Calls,
gleam@list:fold(
_pipe,
[],
fun(Acc, Call) ->
add_to_group(Acc, erlang:element(2, Call), erlang:element(3, Call))
end
).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 125).
?DOC(false).
-spec extract_and_rename(
list(gleeam_code@internal@stdlib_scanner:stdlib_call()),
binary()
) -> binary().
extract_and_rename(Calls, Stdlib_dir) ->
Grouped = group_by_module(Calls),
_pipe = Grouped,
_pipe@1 = gleam@list:map(
_pipe,
fun(Group) ->
{Module, Func_names} = Group,
Module_file = module_to_path(Module, Stdlib_dir),
case gleeam_code@internal@file:read(Module_file) of
{error, _} ->
<<""/utf8>>;
{ok, Source} ->
Extracted = gleeam_code@internal@stdlib_extractor:extract_functions(
Source,
Func_names
),
rename_in_extracted(Extracted, Module, Calls)
end
end
),
_pipe@2 = gleam@list:filter(_pipe@1, fun(S) -> S /= <<""/utf8>> end),
gleam@string:join(_pipe@2, <<"\n\n"/utf8>>).
-file("src/gleeam_code/internal/stdlib_bundler.gleam", 8).
?DOC(false).
-spec bundle(binary(), binary()) -> binary().
bundle(Erl_code, Stdlib_dir) ->
Calls = gleeam_code@internal@stdlib_scanner:scan(Erl_code),
case Calls of
[] ->
Erl_code;
_ ->
All_calls = resolve_transitive(Calls, Stdlib_dir, Calls),
Bundled_code = extract_and_rename(All_calls, Stdlib_dir),
Renamed_solution = rename_calls_in_code(Erl_code, All_calls),
<<<<Bundled_code/binary, "\n"/utf8>>/binary,
Renamed_solution/binary>>
end.