-module(graded@internal@extract). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/graded/internal/extract.gleam"). -export([build_import_context/1, extract_calls/2]). -export_type([import_context/0, extract_result/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(false). -type import_context() :: {import_context, gleam@dict:dict(binary(), binary()), gleam@dict:dict(binary(), graded@internal@types:qualified_name())}. -type extract_result() :: {extract_result, list(graded@internal@types:resolved_call()), list(graded@internal@types:local_call()), list(graded@internal@types:field_call()), list(graded@internal@types:resolved_call())}. -file("src/graded/internal/extract.gleam", 85). ?DOC(false). -spec is_constructor_name(binary()) -> boolean(). is_constructor_name(Name) -> case gleam@string:first(Name) of {ok, Char} -> (Char =:= string:uppercase(Char)) andalso (Char /= string:lowercase( Char )); {error, nil} -> false end. -file("src/graded/internal/extract.gleam", 119). ?DOC(false). -spec last_segment(binary()) -> binary(). last_segment(Module_path) -> _pipe = Module_path, _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), _pipe@2 = gleam@list:last(_pipe@1), gleam@result:unwrap(_pipe@2, Module_path). -file("src/graded/internal/extract.gleam", 33). ?DOC(false). -spec build_import_context(glance:module_()) -> import_context(). build_import_context(Module) -> {Aliases, Unqualified} = gleam@list:fold( erlang:element(2, Module), {maps:new(), maps:new()}, fun(State, Definition) -> Import_ = erlang:element(3, Definition), Module_path = erlang:element(3, Import_), Alias = case erlang:element(4, Import_) of {some, {named, Name}} -> Name; {some, {discarded, _}} -> last_segment(Module_path); none -> last_segment(Module_path) end, New_aliases = gleam@dict:insert( erlang:element(1, State), Alias, Module_path ), New_unqualified = gleam@list:fold( erlang:element(6, Import_), erlang:element(2, State), fun(Unqualified_map, Unqualified_import) -> Name@1 = case erlang:element(3, Unqualified_import) of {some, Alias_name} -> Alias_name; none -> erlang:element(2, Unqualified_import) end, gleam@dict:insert( Unqualified_map, Name@1, {qualified_name, Module_path, erlang:element(2, Unqualified_import)} ) end ), {New_aliases, New_unqualified} end ), {import_context, Aliases, Unqualified}. -file("src/graded/internal/extract.gleam", 392). ?DOC(false). -spec empty() -> extract_result(). empty() -> {extract_result, [], [], [], []}. -file("src/graded/internal/extract.gleam", 92). ?DOC(false). -spec resolve_unqualified_call(binary(), glance:span(), import_context()) -> extract_result(). resolve_unqualified_call(Name, Span, Context) -> case is_constructor_name(Name) of true -> empty(); false -> case gleam_stdlib:map_get(erlang:element(3, Context), Name) of {ok, Qualified_name} -> {extract_result, [{resolved_call, Qualified_name, Span}], [], [], []}; {error, nil} -> {extract_result, [], [{local_call, Name, Span}], [], []} end end. -file("src/graded/internal/extract.gleam", 396). ?DOC(false). -spec merge(extract_result(), extract_result()) -> extract_result(). merge(Left, Right) -> {extract_result, lists:append(erlang:element(2, Left), erlang:element(2, Right)), lists:append(erlang:element(3, Left), erlang:element(3, Right)), lists:append(erlang:element(4, Left), erlang:element(4, Right)), lists:append(erlang:element(5, Left), erlang:element(5, Right))}. -file("src/graded/internal/extract.gleam", 151). ?DOC(false). -spec extract_from_expression(glance:expression(), import_context()) -> extract_result(). extract_from_expression(Expression, Context) -> case Expression of {call, Span, {field_access, _, {variable, _, Alias}, Function_name}, Arguments} -> Call_result = case gleam_stdlib:map_get( erlang:element(2, Context), Alias ) of {ok, Module_path} -> {extract_result, [{resolved_call, {qualified_name, Module_path, Function_name}, Span}], [], [], []}; {error, nil} -> {extract_result, [], [], [{field_call, Alias, Function_name, Span}], []} end, merge(Call_result, extract_from_arguments(Arguments, Context)); {call, Span@1, {variable, _, Name}, Arguments@1} -> merge( resolve_unqualified_call(Name, Span@1, Context), extract_from_arguments(Arguments@1, Context) ); {call, _, Function_expression, Arguments@2} -> merge( extract_from_expression(Function_expression, Context), extract_from_arguments(Arguments@2, Context) ); {binary_operator, _, pipe, Left, Right} -> merge( extract_from_expression(Left, Context), extract_pipe_target(Right, Context) ); {binary_operator, _, _, Left@1, Right@1} -> merge( extract_from_expression(Left@1, Context), extract_from_expression(Right@1, Context) ); {fn, _, _, _, Statements} -> extract_calls(Statements, Context); {block, _, Statements@1} -> extract_calls(Statements@1, Context); {'case', _, Subjects, Clauses} -> merge( fold_expressions(Subjects, Context), gleam@list:fold( Clauses, empty(), fun(Accumulated, Clause) -> merge(Accumulated, extract_from_clause(Clause, Context)) end ) ); {tuple, _, Elements} -> fold_expressions(Elements, Context); {list, _, Elements@1, Rest} -> merge_optional(fold_expressions(Elements@1, Context), Rest, Context); {negate_int, _, Value} -> extract_from_expression(Value, Context); {negate_bool, _, Value@1} -> extract_from_expression(Value@1, Context); {record_update, _, _, _, Record, _} -> extract_from_expression(Record, Context); {field_access, Span@2, {variable, _, Alias@1}, Function_name@1} -> case gleam_stdlib:map_get(erlang:element(2, Context), Alias@1) of {ok, Module_path@1} -> {extract_result, [], [], [], [{resolved_call, {qualified_name, Module_path@1, Function_name@1}, Span@2}]}; {error, nil} -> empty() end; {field_access, _, Container, _} -> extract_from_expression(Container, Context); {tuple_index, _, Tuple, _} -> extract_from_expression(Tuple, Context); {fn_capture, _, _, Function_expression@1, Arguments_before, Arguments_after} -> merge( extract_from_expression(Function_expression@1, Context), merge( extract_from_arguments(Arguments_before, Context), extract_from_arguments(Arguments_after, Context) ) ); {echo, _, {some, Inner}, _} -> extract_from_expression(Inner, Context); {echo, _, none, _} -> empty(); {variable, Span@3, Name@1} -> case gleam_stdlib:map_get(erlang:element(3, Context), Name@1) of {ok, Qualified_name} -> {extract_result, [], [], [], [{resolved_call, Qualified_name, Span@3}]}; {error, nil} -> empty() end; {int, _, _} -> empty(); {float, _, _} -> empty(); {string, _, _} -> empty(); {panic, _, _} -> empty(); {todo, _, _} -> empty(); {bit_string, _, _} -> empty() end. -file("src/graded/internal/extract.gleam", 74). ?DOC(false). -spec extract_calls(list(glance:statement()), import_context()) -> extract_result(). extract_calls(Statements, Context) -> gleam@list:fold( Statements, empty(), fun(Accumulated, Statement) -> merge(Accumulated, extract_from_statement(Statement, Context)) end ). -file("src/graded/internal/extract.gleam", 126). ?DOC(false). -spec extract_from_statement(glance:statement(), import_context()) -> extract_result(). extract_from_statement(Statement, Context) -> case Statement of {expression, Expression} -> extract_from_expression(Expression, Context); {assignment, _, _, _, _, Expression@1} -> extract_from_expression(Expression@1, Context); {use, _, _, Expression@2} -> extract_from_expression(Expression@2, Context); {assert, _, Expression@3, Message} -> Expression_result = extract_from_expression(Expression@3, Context), case Message of {some, Message_expression} -> merge( Expression_result, extract_from_expression(Message_expression, Context) ); none -> Expression_result end end. -file("src/graded/internal/extract.gleam", 307). ?DOC(false). -spec extract_pipe_target(glance:expression(), import_context()) -> extract_result(). extract_pipe_target(Expression, Context) -> case Expression of {field_access, Span, {variable, _, Alias}, Function_name} -> case gleam_stdlib:map_get(erlang:element(2, Context), Alias) of {ok, Module_path} -> {extract_result, [{resolved_call, {qualified_name, Module_path, Function_name}, Span}], [], [], []}; {error, nil} -> {extract_result, [], [], [{field_call, Alias, Function_name, Span}], []} end; {variable, Span@1, Name} -> resolve_unqualified_call(Name, Span@1, Context); _ -> extract_from_expression(Expression, Context) end. -file("src/graded/internal/extract.gleam", 346). ?DOC(false). -spec extract_from_clause(glance:clause(), import_context()) -> extract_result(). extract_from_clause(Clause, Context) -> Body_result = extract_from_expression(erlang:element(4, Clause), Context), case erlang:element(3, Clause) of {some, Guard} -> merge(Body_result, extract_from_expression(Guard, Context)); none -> Body_result end. -file("src/graded/internal/extract.gleam", 354). ?DOC(false). -spec extract_from_arguments( list(glance:field(glance:expression())), import_context() ) -> extract_result(). extract_from_arguments(Arguments, Context) -> gleam@list:fold( Arguments, empty(), fun(Accumulated, Field) -> Expression = case Field of {labelled_field, _, _, Item} -> {some, Item}; {shorthand_field, _, _} -> none; {unlabelled_field, Item@1} -> {some, Item@1} end, case Expression of {some, Inner} -> merge(Accumulated, extract_from_expression(Inner, Context)); none -> Accumulated end end ). -file("src/graded/internal/extract.gleam", 371). ?DOC(false). -spec fold_expressions(list(glance:expression()), import_context()) -> extract_result(). fold_expressions(Expressions, Context) -> gleam@list:fold( Expressions, empty(), fun(Accumulated, Expression) -> merge(Accumulated, extract_from_expression(Expression, Context)) end ). -file("src/graded/internal/extract.gleam", 380). ?DOC(false). -spec merge_optional( extract_result(), gleam@option:option(glance:expression()), import_context() ) -> extract_result(). merge_optional(Base, Optional_expression, Context) -> case Optional_expression of {some, Expression} -> merge(Base, extract_from_expression(Expression, Context)); none -> Base end.