Skip to content

Commit

Permalink
erl_eval: Support the fun Name/Arity syntax for creating a fun
Browse files Browse the repository at this point in the history
Attempting to create a fun referering to either an auto-imported
BIF or a local fun defined in shell would fail:

    1> fun is_atom/1.
    ** exception error: undefined function erl_eval:is_atom/1
    2> id(I) -> I.
    ok
    3> fun id/1.
    ** exception error: undefined function erl_eval:id/1

This commit adds support for defining a fun based on either
an auto-imported BIF:

    1> F = fun is_atom/1.
    fun erlang:is_atom/1
    2> F(a).
    true
    3> F(42).
    false

Or on a local function defined in the shell:

    1> I = fun id/1.
    #Fun<erl_eval.42.18682967>
    2> I(42).
    ** exception error: undefined shell command id/1
    3> id(I) -> I.
    ok
    4> I(42).
    42

As shown in the example, it not necessary that the local fun is
defined at the time the fun is created; only that it is defined
when the fun is called.
  • Loading branch information
bjorng committed Oct 25, 2024
1 parent 755e301 commit a1d421f
Showing 1 changed file with 29 additions and 3 deletions.
32 changes: 29 additions & 3 deletions lib/stdlib/test/erl_eval_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
-export([count_down/2, count_down_fun/0, do_apply/2,
local_func/3, local_func_value/2]).
-export([simple/0]).
-export([my_div/2]).

-ifdef(STANDALONE).
-define(config(A,B),config(A,B)).
Expand Down Expand Up @@ -1217,8 +1218,6 @@ custom_stacktrace(Config) when is_list(Config) ->
backtrace_check("#unknown.index.", {undef_record,unknown},
[erl_eval, mystack(1)], none, EFH),

backtrace_check("fun foo/2.", undef,
[{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH),
backtrace_check("foo(1, 2).", undef,
[{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH),

Expand Down Expand Up @@ -1369,7 +1368,6 @@ funs(Config) when is_list(Config) ->
error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.",
got_it, none, AnnEFH),

error_check("fun c/1.", undef),
error_check("fun a:b/0().", undef),

MaxArgs = 20,
Expand All @@ -1387,8 +1385,36 @@ funs(Config) when is_list(Config) ->
%% Test that {M,F} is not accepted as a fun.
error_check("{" ?MODULE_STRING ",module_info}().",
{badfun,{?MODULE,module_info}}),

%% Test defining and calling a fun based on an auto-imported BIF.
check(fun() ->
F = fun is_binary/1,
true = F(<<>>),
false = F(a)
end,
~S"""
F = fun is_binary/1,
true = F(<<>>),
false = F(a).
""",
false, ['F'], lfh(), none),

%% Test defining and calling a local fun defined in the shell.
check(fun() ->
D = fun my_div/2,
3 = D(15, 5)
end,
~S"""
D = fun my_div/2,
3 = D(15, 5).
""",
3, ['D'], lfh(), efh()),

ok.

my_div(A, B) ->
A div B.

run_many_args({S, As}) ->
apply(eval_string(S), As) =:= As.

Expand Down

0 comments on commit a1d421f

Please sign in to comment.