aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debugger')
-rw-r--r--lib/debugger/src/dbg_ieval.erl145
-rw-r--r--lib/debugger/src/dbg_iload.erl3
-rw-r--r--lib/debugger/test/erl_eval_SUITE.erl26
-rw-r--r--lib/debugger/test/fun_SUITE.erl17
4 files changed, 161 insertions, 30 deletions
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index f4b6d488a5..6ce3262ed2 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -204,7 +204,8 @@ meta(Int, Debugged, M, F, As) ->
%% If it's a fun we're evaluating, show a text
%% representation of the fun and its arguments,
%% not dbg_ieval:eval_fun(...)
- {dbg_ieval, eval_fun} ->
+ {dbg_ieval, EvalFun} when EvalFun =:= eval_fun;
+ EvalFun =:= eval_named_fun ->
{Mx, Fx} = lists:last(As),
{Mx, Fx, lists:nth(2, As)};
_ ->
@@ -432,7 +433,8 @@ eval_function(Mod, Name, As, Bs, Called, Ieval0, Lc) ->
do_eval_function(Mod, Fun, As0, Bs0, _, Ieval0) when is_function(Fun);
Mod =:= ?MODULE,
- Fun =:= eval_fun ->
+ Fun =:= eval_fun orelse
+ Fun =:= eval_named_fun ->
#ieval{level=Le,line=Li,top=Top} = Ieval0,
case lambda(Fun, As0) of
{[{clause,Fc,_,_,_}|_]=Cs,Module,Name,As,Bs} ->
@@ -487,13 +489,29 @@ lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) ->
true ->
{error,{badarity,{F,As}}}
end;
+lambda(eval_named_fun, [Cs,As,Bs0,FName,RF,{Mod,Name}=F]) ->
+ %% Fun defined in interpreted code, called from outside
+ if
+ length(element(3,hd(Cs))) =:= length(As) ->
+ db_ref(Mod), %% Adds ref between module and process
+ Bs1 = add_binding(FName, RF, Bs0),
+ {Cs,Mod,Name,As,Bs1};
+ true ->
+ {error,{badarity,{F,As}}}
+ end;
lambda(Fun, As) when is_function(Fun) ->
%% Fun called from within interpreted code...
case erlang:fun_info(Fun, module) of
%% ... and the fun was defined in interpreted code
{module, ?MODULE} ->
- {env, [{Mod,Name},Bs,Cs]} = erlang:fun_info(Fun, env),
+ {Mod,Name,Bs} =
+ case erlang:fun_info(Fun, env) of
+ {env,[{{M,F},Bs0,Cs}]} ->
+ {M,F,Bs0};
+ {env,[{{M,F},Bs0,Cs,FName}]} ->
+ {M,F,add_binding(FName, Fun, Bs0)}
+ end,
{arity, Arity} = erlang:fun_info(Fun, arity),
if
length(As) =:= Arity ->
@@ -727,50 +745,121 @@ expr({match,Line,Lhs,Rhs0}, Bs0, Ieval0) ->
%% Construct a fun
expr({make_fun,Line,Name,Cs}, Bs, #ieval{module=Module}=Ieval) ->
Arity = length(element(3,hd(Cs))),
- Info = {Module,Name},
+ Info = {{Module,Name},Bs,Cs},
Fun =
case Arity of
- 0 -> fun() -> eval_fun(Cs, [], Bs, Info) end;
- 1 -> fun(A) -> eval_fun(Cs, [A], Bs,Info) end;
- 2 -> fun(A,B) -> eval_fun(Cs, [A,B], Bs,Info) end;
- 3 -> fun(A,B,C) -> eval_fun(Cs, [A,B,C], Bs,Info) end;
- 4 -> fun(A,B,C,D) -> eval_fun(Cs, [A,B,C,D], Bs,Info) end;
- 5 -> fun(A,B,C,D,E) -> eval_fun(Cs, [A,B,C,D,E], Bs,Info) end;
- 6 -> fun(A,B,C,D,E,F) -> eval_fun(Cs, [A,B,C,D,E,F], Bs,Info) end;
+ 0 -> fun() -> eval_fun([], Info) end;
+ 1 -> fun(A) -> eval_fun([A], Info) end;
+ 2 -> fun(A,B) -> eval_fun([A,B], Info) end;
+ 3 -> fun(A,B,C) -> eval_fun([A,B,C], Info) end;
+ 4 -> fun(A,B,C,D) -> eval_fun([A,B,C,D], Info) end;
+ 5 -> fun(A,B,C,D,E) -> eval_fun([A,B,C,D,E], Info) end;
+ 6 -> fun(A,B,C,D,E,F) -> eval_fun([A,B,C,D,E,F], Info) end;
7 -> fun(A,B,C,D,E,F,G) ->
- eval_fun(Cs, [A,B,C,D,E,F,G], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G], Info) end;
8 -> fun(A,B,C,D,E,F,G,H) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H], Info) end;
9 -> fun(A,B,C,D,E,F,G,H,I) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I], Info) end;
10 -> fun(A,B,C,D,E,F,G,H,I,J) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J], Info) end;
11 -> fun(A,B,C,D,E,F,G,H,I,J,K) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K], Info) end;
12 -> fun(A,B,C,D,E,F,G,H,I,J,K,L) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L], Info) end;
13 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M], Info) end;
14 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N], Info) end;
15 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O], Info) end;
16 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P], Info) end;
17 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q], Info) end;
18 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R], Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R], Info) end;
19 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S],Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S],Info) end;
20 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) ->
- eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],Bs,Info) end;
+ eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],Info) end;
_Other ->
exception(error, {'argument_limit',{'fun',Cs}}, Bs,
Ieval#ieval{line=Line})
end,
{value,Fun,Bs};
+%% Construct a fun
+expr({make_named_fun,Line,Name,FName,Cs}, Bs, #ieval{module=Module}=Ieval) ->
+ Arity = length(element(3,hd(Cs))),
+ Info = {{Module,Name},Bs,Cs,FName},
+ Fun =
+ case Arity of
+ 0 -> fun RF() -> eval_named_fun([], RF, Info) end;
+ 1 -> fun RF(A) -> eval_named_fun([A], RF, Info) end;
+ 2 -> fun RF(A,B) ->
+ eval_named_fun([A,B], RF, Info) end;
+ 3 -> fun RF(A,B,C) ->
+ eval_named_fun([A,B,C], RF, Info) end;
+ 4 -> fun RF(A,B,C,D) ->
+ eval_named_fun([A,B,C,D], RF, Info) end;
+ 5 -> fun RF(A,B,C,D,E) ->
+ eval_named_fun([A,B,C,D,E],
+ RF, Info) end;
+ 6 -> fun RF(A,B,C,D,E,F) ->
+ eval_named_fun([A,B,C,D,E,F],
+ RF, Info) end;
+ 7 -> fun RF(A,B,C,D,E,F,G) ->
+ eval_named_fun([A,B,C,D,E,F,G],
+ RF, Info) end;
+ 8 -> fun RF(A,B,C,D,E,F,G,H) ->
+ eval_named_fun([A,B,C,D,E,F,G,H],
+ RF, Info) end;
+ 9 -> fun RF(A,B,C,D,E,F,G,H,I) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I],
+ RF, Info) end;
+ 10 -> fun RF(A,B,C,D,E,F,G,H,I,J) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J],
+ RF, Info) end;
+ 11 -> fun RF(A,B,C,D,E,F,G,H,I,J,K) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K],
+ RF, Info) end;
+ 12 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L],
+ RF, Info) end;
+ 13 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M],
+ RF, Info) end;
+ 14 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N],
+ RF, Info) end;
+ 15 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O],
+ RF, Info) end;
+ 16 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P],
+ RF, Info) end;
+ 17 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q],
+ RF, Info) end;
+ 18 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,
+ R],
+ RF, Info) end;
+ 19 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,
+ R,S],
+ RF, Info) end;
+ 20 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) ->
+ eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,
+ R,S,T],
+ RF, Info) end;
+ _Other ->
+ exception(error, {'argument_limit',{named_fun,FName,Cs}}, Bs,
+ Ieval#ieval{line=Line})
+ end,
+ {value,Fun,Bs};
+
%% Construct an external fun.
expr({make_ext_fun,Line,MFA0}, Bs0, Ieval0) ->
{[M,F,A],Bs} = eval_list(MFA0, Bs0, Ieval0),
@@ -960,9 +1049,13 @@ expr(E, _Bs, _Ieval) ->
erlang:error({'NYI',E}).
%% Interpreted fun() called from uninterpreted module, recurse
-eval_fun(Cs, As, Bs, Info) ->
+eval_fun(As, {Info,Bs,Cs}) ->
dbg_debugged:eval(?MODULE, eval_fun, [Cs,As,Bs,Info]).
+%% Interpreted named fun() called from uninterpreted module, recurse
+eval_named_fun(As, RF, {Info,Bs,Cs,FName}) ->
+ dbg_debugged:eval(?MODULE, eval_named_fun, [Cs,As,Bs,FName,RF,Info]).
+
%% eval_lc(Expr,[Qualifier],Bindings,IevalState) ->
%% {value,Value,Bindings}.
%% This is evaluating list comprehensions "straight out of the book".
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index 3c95ef8068..9806692afc 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -369,6 +369,9 @@ expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) ->
As = new_vars(A, Line),
Cs = [{clause,Line,As,[],[{local_call,Line,F,As,true}]}],
{make_fun,Line,Name,Cs};
+expr({named_fun,Line,FName,Cs0,{_,_,Name}}, _Lc) when is_atom(Name) ->
+ Cs = fun_clauses(Cs0),
+ {make_named_fun,Line,Name,FName,Cs};
expr({'fun',Line,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc)
when 0 =< A, A =< 255 ->
%% New format in R15 for fun M:F/A (literal values).
diff --git a/lib/debugger/test/erl_eval_SUITE.erl b/lib/debugger/test/erl_eval_SUITE.erl
index bb2669f450..be9312b68f 100644
--- a/lib/debugger/test/erl_eval_SUITE.erl
+++ b/lib/debugger/test/erl_eval_SUITE.erl
@@ -39,7 +39,8 @@
otp_8133/1,
funs/1,
try_catch/1,
- eval_expr_5/1]).
+ eval_expr_5/1,
+ eep37/1]).
%%
%% Define to run outside of test server
@@ -78,7 +79,7 @@ all() ->
pattern_expr, match_bin, guard_3, guard_4, lc,
simple_cases, unary_plus, apply_atom, otp_5269,
otp_6539, otp_6543, otp_6787, otp_6977, otp_7550,
- otp_8133, funs, try_catch, eval_expr_5].
+ otp_8133, funs, try_catch, eval_expr_5, eep37].
groups() ->
[].
@@ -1323,6 +1324,27 @@ eval_expr_5(Config) when is_list(Config) ->
ok
end.
+eep37(Config) when is_list(Config) ->
+ check(fun () -> (fun _(X) -> X end)(42) end,
+ "(fun _(X) -> X end)(42).",
+ 42),
+ check(fun () -> (fun _Id(X) -> X end)(42) end,
+ "(fun _Id(X) -> X end)(42).", 42),
+ check(fun () -> is_function((fun Self() -> Self end)(), 0) end,
+ "is_function((fun Self() -> Self end)(), 0).",
+ true),
+ check(fun () ->
+ F = fun Fact(N) when N > 0 ->
+ N * Fact(N - 1);
+ Fact(0) ->
+ 1
+ end,
+ F(6)
+ end,
+ "(fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end)(6).",
+ 720),
+ ok.
+
%% Check the string in different contexts: as is; in fun; from compiled code.
check(F, String, Result) ->
check1(F, String, Result),
diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl
index a06cdc7165..8425f973e6 100644
--- a/lib/debugger/test/fun_SUITE.erl
+++ b/lib/debugger/test/fun_SUITE.erl
@@ -24,7 +24,7 @@
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
good_call/1,bad_apply/1,bad_fun_call/1,badarity/1,
- ext_badarity/1,otp_6061/1,external/1]).
+ ext_badarity/1,otp_6061/1,external/1,eep37/1]).
%% Internal exports.
-export([nothing/0,call_me/1]).
@@ -48,7 +48,7 @@ end_per_group(_GroupName, Config) ->
cases() ->
[good_call, bad_apply, bad_fun_call, badarity,
- ext_badarity, otp_6061, external].
+ ext_badarity, otp_6061, external, eep37].
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
@@ -288,5 +288,18 @@ external(Config) when is_list(Config) ->
call_me(I) ->
{ok,I}.
+eep37(Config) when is_list(Config) ->
+ F = fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end,
+ Add = fun _(N) -> N + 1 end,
+ UnusedName = fun BlackAdder(N) -> N + 42 end,
+ 720 = F(6),
+ 10 = Add(9),
+ 50 = UnusedName(8),
+ [1,1,2,6,24,120] = lists:map(F, lists:seq(0, 5)),
+ {'EXIT',{{badarity,_},_}} = (catch lists:map(fun G() -> G() end, [1])),
+ {'EXIT',{{badarity,_},_}} = (catch F()),
+
+ ok.
+
id(I) ->
I.