Skip to main content

src/girard@internal@reference.erl

-module(girard@internal@reference).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/girard/internal/reference.gleam").
-export([in_function/1, in_constant/1]).

-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/girard/internal/reference.gleam", 190).
?DOC(false).
-spec assignment_name(glance:assignment_name()) -> list(binary()).
assignment_name(Name) ->
    case Name of
        {named, N} ->
            [N];

        {discarded, _} ->
            []
    end.

-file("src/girard/internal/reference.gleam", 206).
?DOC(false).
-spec pattern_names(glance:pattern()) -> list(binary()).
pattern_names(Pattern) ->
    case Pattern of
        {pattern_int, _, _} ->
            [];

        {pattern_float, _, _} ->
            [];

        {pattern_string, _, _} ->
            [];

        {pattern_discard, _, _} ->
            [];

        {pattern_variable, _, Name} ->
            [Name];

        {pattern_tuple, _, Elements} ->
            gleam@list:flat_map(Elements, fun pattern_names/1);

        {pattern_list, _, Elements@1, Tail} ->
            case Tail of
                {some, T} ->
                    lists:append(
                        gleam@list:flat_map(Elements@1, fun pattern_names/1),
                        pattern_names(T)
                    );

                none ->
                    gleam@list:flat_map(Elements@1, fun pattern_names/1)
            end;

        {pattern_assignment, _, Pattern@1, Name@1} ->
            [Name@1 | pattern_names(Pattern@1)];

        {pattern_concatenate, _, _, Prefix_name, Rest_name} ->
            lists:append(case Prefix_name of
                    {some, N} ->
                        assignment_name(N);

                    none ->
                        []
                end, assignment_name(Rest_name));

        {pattern_bit_string, _, Segments} ->
            gleam@list:flat_map(
                Segments,
                fun(Segment) -> pattern_names(erlang:element(1, Segment)) end
            );

        {pattern_variant, _, _, _, Arguments, _} ->
            gleam@list:flat_map(Arguments, fun(Field) -> case Field of
                        {unlabelled_field, P} ->
                            pattern_names(P);

                        {labelled_field, _, _, P@1} ->
                            pattern_names(P@1);

                        {shorthand_field, Label, _} ->
                            [Label]
                    end end)
    end.

-file("src/girard/internal/reference.gleam", 41).
?DOC(false).
-spec value({list(binary()), list(binary())}, gleam@set:set(binary()), binary()) -> {list(binary()),
    list(binary())}.
value(Acc, Bound, Name) ->
    gleam@bool:guard(
        gleam@set:contains(Bound, Name),
        Acc,
        fun() -> {[Name | erlang:element(1, Acc)], erlang:element(2, Acc)} end
    ).

-file("src/girard/internal/reference.gleam", 46).
?DOC(false).
-spec qualifier(
    {list(binary()), list(binary())},
    gleam@set:set(binary()),
    binary()
) -> {list(binary()), list(binary())}.
qualifier(Acc, Bound, Name) ->
    gleam@bool:guard(
        gleam@set:contains(Bound, Name),
        Acc,
        fun() -> {erlang:element(1, Acc), [Name | erlang:element(2, Acc)]} end
    ).

-file("src/girard/internal/reference.gleam", 201).
?DOC(false).
-spec fn_param_names(glance:fn_parameter()) -> list(binary()).
fn_param_names(Param) ->
    assignment_name(erlang:element(2, Param)).

-file("src/girard/internal/reference.gleam", 82).
?DOC(false).
-spec in_optional(
    gleam@option:option(glance:expression()),
    gleam@set:set(binary()),
    {list(binary()), list(binary())}
) -> {list(binary()), list(binary())}.
in_optional(Expr, Bound, Acc) ->
    case Expr of
        {some, E} ->
            in_expr(E, Bound, Acc);

        none ->
            Acc
    end.

-file("src/girard/internal/reference.gleam", 93).
?DOC(false).
-spec in_exprs(
    list(glance:expression()),
    gleam@set:set(binary()),
    {list(binary()), list(binary())}
) -> {list(binary()), list(binary())}.
in_exprs(Exprs, Bound, Acc) ->
    gleam@list:fold(Exprs, Acc, fun(Acc@1, E) -> in_expr(E, Bound, Acc@1) end).

-file("src/girard/internal/reference.gleam", 101).
?DOC(false).
-spec in_fields(
    list(glance:field(glance:expression())),
    gleam@set:set(binary()),
    {list(binary()), list(binary())}
) -> {list(binary()), list(binary())}.
in_fields(Fields, Bound, Acc) ->
    gleam@list:fold(Fields, Acc, fun(Acc@1, Field) -> case Field of
                {unlabelled_field, Item} ->
                    in_expr(Item, Bound, Acc@1);

                {labelled_field, _, _, Item@1} ->
                    in_expr(Item@1, Bound, Acc@1);

                {shorthand_field, Label, _} ->
                    value(Acc@1, Bound, Label)
            end end).

-file("src/girard/internal/reference.gleam", 115).
?DOC(false).
-spec in_expr(
    glance:expression(),
    gleam@set:set(binary()),
    {list(binary()), list(binary())}
) -> {list(binary()), list(binary())}.
in_expr(Expr, Bound, Acc) ->
    case Expr of
        {int, _, _} ->
            Acc;

        {float, _, _} ->
            Acc;

        {string, _, _} ->
            Acc;

        {variable, _, Name} ->
            value(Acc, Bound, Name);

        {negate_int, _, V} ->
            in_expr(V, Bound, Acc);

        {negate_bool, _, V} ->
            in_expr(V, Bound, Acc);

        {block, _, Statements} ->
            in_statements(Statements, Bound, Acc);

        {panic, _, Message} ->
            in_optional(Message, Bound, Acc);

        {todo, _, Message} ->
            in_optional(Message, Bound, Acc);

        {tuple, _, Elements} ->
            in_exprs(Elements, Bound, Acc);

        {list, _, Elements@1, Rest} ->
            in_optional(Rest, Bound, in_exprs(Elements@1, Bound, Acc));

        {fn, _, Arguments, _, Body} ->
            Bound@1 = gleam@set:union(
                Bound,
                gleam@set:from_list(
                    gleam@list:flat_map(Arguments, fun fn_param_names/1)
                )
            ),
            in_statements(Body, Bound@1, Acc);

        {record_update, _, _, _, Record, Fields} ->
            gleam@list:fold(
                Fields,
                in_expr(Record, Bound, Acc),
                fun(Acc@1, Field) ->
                    in_optional(erlang:element(3, Field), Bound, Acc@1)
                end
            );

        {field_access, _, {variable, _, Name@1}, _} ->
            qualifier(Acc, Bound, Name@1);

        {field_access, _, Container, _} ->
            in_expr(Container, Bound, Acc);

        {call, _, Function, Arguments@1} ->
            in_fields(Arguments@1, Bound, in_expr(Function, Bound, Acc));

        {tuple_index, _, Tuple, _} ->
            in_expr(Tuple, Bound, Acc);

        {fn_capture, _, _, Function@1, Before, After} ->
            in_fields(
                After,
                Bound,
                in_fields(Before, Bound, in_expr(Function@1, Bound, Acc))
            );

        {bit_string, _, Segments} ->
            gleam@list:fold(
                Segments,
                Acc,
                fun(Acc@2, Segment) ->
                    in_expr(erlang:element(1, Segment), Bound, Acc@2)
                end
            );

        {'case', _, Subjects, Clauses} ->
            gleam@list:fold(
                Clauses,
                in_exprs(Subjects, Bound, Acc),
                fun(Acc@3, Clause) ->
                    Names = gleam@list:flat_map(
                        lists:append(erlang:element(2, Clause)),
                        fun pattern_names/1
                    ),
                    Bound@2 = gleam@set:union(Bound, gleam@set:from_list(Names)),
                    in_optional(
                        erlang:element(3, Clause),
                        Bound@2,
                        in_expr(erlang:element(4, Clause), Bound@2, Acc@3)
                    )
                end
            );

        {binary_operator, _, _, Left, Right} ->
            in_expr(Right, Bound, in_expr(Left, Bound, Acc));

        {echo, _, Expression, Message@1} ->
            in_optional(Message@1, Bound, in_optional(Expression, Bound, Acc))
    end.

-file("src/girard/internal/reference.gleam", 51).
?DOC(false).
-spec in_statements(
    list(glance:statement()),
    gleam@set:set(binary()),
    {list(binary()), list(binary())}
) -> {list(binary()), list(binary())}.
in_statements(Statements, Bound, Acc) ->
    {_, Acc@4} = gleam@list:fold(
        Statements,
        {Bound, Acc},
        fun(State, Statement) ->
            {Bound@1, Acc@1} = State,
            case Statement of
                {expression, Expr} ->
                    {Bound@1, in_expr(Expr, Bound@1, Acc@1)};

                {assignment, _, _, Pattern, _, Value} ->
                    Acc@2 = in_expr(Value, Bound@1, Acc@1),
                    {gleam@set:union(
                            Bound@1,
                            gleam@set:from_list(pattern_names(Pattern))
                        ),
                        Acc@2};

                {assert, _, Expr@1, Message} ->
                    {Bound@1,
                        in_optional(
                            Message,
                            Bound@1,
                            in_expr(Expr@1, Bound@1, Acc@1)
                        )};

                {use, _, Patterns, Function} ->
                    Acc@3 = in_expr(Function, Bound@1, Acc@1),
                    Names = gleam@list:flat_map(
                        Patterns,
                        fun(P) -> pattern_names(erlang:element(2, P)) end
                    ),
                    {gleam@set:union(Bound@1, gleam@set:from_list(Names)),
                        Acc@3}
            end
        end
    ),
    Acc@4.

-file("src/girard/internal/reference.gleam", 197).
?DOC(false).
-spec param_names(glance:function_parameter()) -> list(binary()).
param_names(Param) ->
    assignment_name(erlang:element(3, Param)).

-file("src/girard/internal/reference.gleam", 28).
?DOC(false).
-spec in_function(glance:function_()) -> {list(binary()), list(binary())}.
in_function(Function) ->
    Bound = gleam@set:from_list(
        gleam@list:flat_map(erlang:element(5, Function), fun param_names/1)
    ),
    in_statements(erlang:element(7, Function), Bound, {[], []}).

-file("src/girard/internal/reference.gleam", 34).
?DOC(false).
-spec in_constant(glance:constant()) -> {list(binary()), list(binary())}.
in_constant(Constant) ->
    in_expr(erlang:element(6, Constant), gleam@set:new(), {[], []}).