erl_eval.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,167 行 · 第 1/3 页
ERL
1,167 行
unhide_calls({atom,Id,ok}, MaxLine, D) when Id > MaxLine -> dict:fetch(Id, D);unhide_calls({call,Id,{remote,L,_M,_F},Args}, MaxLine, D) when Id > MaxLine -> {call,Atom} = dict:fetch(Id, D), {call,L,Atom,unhide_calls(Args, MaxLine, D)};unhide_calls(T, MaxLine, D) when is_tuple(T) -> list_to_tuple(unhide_calls(tuple_to_list(T), MaxLine, D));unhide_calls([E | Es], MaxLine, D) -> [unhide_calls(E, MaxLine, D) | unhide_calls(Es, MaxLine, D)];unhide_calls(E, _MaxLine, _D) -> E.%% local_func(Function, Arguments, Bindings, LocalFuncHandler, RBs) ->%% {value,Value,Bindings} | Value when%% LocalFuncHandler = {value,F} | {value,F,Eas} |%% {eval,F} | {eval,F,Eas} | none.local_func(Func, As0, Bs0, {value,F}, value) -> {As1,_Bs1} = expr_list(As0, Bs0, {value,F}), %% Make tail recursive calls when possible. F(Func, As1);local_func(Func, As0, Bs0, {value,F}, RBs) -> {As1,Bs1} = expr_list(As0, Bs0, {value,F}), ret_expr(F(Func, As1), Bs1, RBs);local_func(Func, As0, Bs0, {value,F,Eas}, value) -> {As1,_Bs1} = expr_list(As0, Bs0, {value,F,Eas}), apply(F, [Func,As1|Eas]);local_func(Func, As0, Bs0, {value,F,Eas}, RBs) -> {As1,Bs1} = expr_list(As0, Bs0, {value,F,Eas}), ret_expr(apply(F, [Func,As1|Eas]), Bs1, RBs);local_func(Func, As, Bs, {eval,F}, RBs) -> local_func2(F(Func, As, Bs), RBs);local_func(Func, As, Bs, {eval,F,Eas}, RBs) -> local_func2(apply(F, [Func,As,Bs|Eas]), RBs);%% These two clauses are for backwards compatibility.local_func(Func, As0, Bs0, {M,F}, RBs) -> {As1,Bs1} = expr_list(As0, Bs0, {M,F}), ret_expr(M:F(Func,As1), Bs1, RBs);local_func(Func, As, _Bs, {M,F,Eas}, RBs) -> local_func2(apply(M, F, [Func,As|Eas]), RBs);%% Default unknown function handler to undefined function.local_func(Func, As0, _Bs0, none, _RBs) -> erlang:raise(error, undef, [{erl_eval,Func,length(As0)}|stacktrace()]).local_func2({value,V,Bs}, RBs) -> ret_expr(V, Bs, RBs);local_func2({eval,F,As,Bs}, RBs) -> % This reply is not documented. %% The shell found F. erl_eval tries to do a tail recursive call, %% something the shell cannot do. Do not use Ef here. do_apply(F, As, Bs, none, RBs).%% bif(Name, Arguments, RBs)%% Evaluate the Erlang auto-imported function Name. erlang:apply/2,3%% are "hidden" from the external function handler.bif(apply, [erlang,apply,As], Bs, Ef, RBs) -> bif(apply, As, Bs, Ef, RBs);bif(apply, [M,F,As], Bs, Ef, RBs) -> do_apply({M,F}, As, Bs, Ef, RBs);bif(apply, [F,As], Bs, Ef, RBs) -> do_apply(F, As, Bs, Ef, RBs);bif(Name, As, Bs, Ef, RBs) -> do_apply({erlang,Name}, As, Bs, Ef, RBs).%% do_apply(MF, Arguments, Bindings, ExternalFuncHandler, RBs) ->%% {value,Value,Bindings} | Value when%% ExternalFuncHandler = {value,F} | none.%% MF is a tuple {Module,Function} or a fun.do_apply({M,F}=Func, As, Bs0, Ef, RBs) when is_tuple(M), size(M) >= 1, is_atom(element(1, M)), is_atom(F) -> case Ef of none when RBs =:= value -> %% Make tail recursive calls when possible. apply(M, F, As); none -> ret_expr(apply(M, F, As), Bs0, RBs); {value,Fun} when RBs =:= value -> Fun(Func, As); {value,Fun} -> ret_expr(Fun(Func, As), Bs0, RBs) end;do_apply(Func, As, Bs0, Ef, RBs) -> Env = if is_function(Func) -> case {erlang:fun_info(Func, module), erlang:fun_info(Func, env)} of {{module,?MODULE},{env,Env1}} when Env1 =/= [] -> {env,Env1}; _ -> no_env end; true -> no_env end, case {Env,Ef} of {{env,[FBs, FEf, FLf, FCs]},_} -> %% If we are evaluting within another function body %% (RBs =/= none), we return RBs when this function body %% has been evalutated, otherwise we return Bs0, the %% bindings when evalution of this function body started. NRBs = if RBs =:= none -> Bs0; true -> RBs end, case {erlang:fun_info(Func, arity), length(As)} of {{arity, Arity}, Arity} -> eval_fun(FCs, As, FBs, FLf, FEf, NRBs); _ -> erlang:raise(error, {badarity,{Func,As}},stacktrace()) end; {no_env,none} when RBs =:= value -> %% Make tail recursive calls when possible. apply(Func, As); {no_env,none} -> ret_expr(apply(Func, As), Bs0, RBs); {no_env,{value,F}} when RBs =:= value -> F(Func,As); {no_env,{value,F}} -> ret_expr(F(Func, As), Bs0, RBs) end.%% eval_lc(Expr, [Qualifier], Bindings, LocalFunctionHandler, %% ExternalFuncHandler, RetBindings) ->%% {value,Value,Bindings} | Valueeval_lc(E, Qs, Bs, Lf, Ef, RBs) -> ret_expr(lists:reverse(eval_lc1(E, Qs, Bs, Lf, Ef, [])), Bs, RBs).eval_lc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> {value,L1,_Bs1} = expr(L0, Bs0, Lf, Ef, none), CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_generate(L1, P, Bs0, Lf, Ef, CompFun, Acc0);eval_lc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> {value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none), CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0);eval_lc1(E, [F|Qs], Bs0, Lf, Ef, Acc) -> CompFun = fun(Bs) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_filter(F, Bs0, Lf, Ef, CompFun, Acc);eval_lc1(E, [], Bs, Lf, Ef, Acc) -> {value,V,_} = expr(E, Bs, Lf, Ef, none), [V|Acc].%% eval_bc(Expr, [Qualifier], Bindings, LocalFunctionHandler, %% ExternalFuncHandler, RetBindings) ->%% {value,Value,Bindings} | Valueeval_bc(E, Qs, Bs, Lf, Ef, RBs) -> ret_expr(eval_bc1(E, Qs, Bs, Lf, Ef, <<>>), Bs, RBs).eval_bc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> {value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none), CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0);eval_bc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> {value,List,_Bs1} = expr(L0, Bs0, Lf, Ef, none), CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_generate(List, P, Bs0, Lf, Ef, CompFun, Acc0);eval_bc1(E, [F|Qs], Bs0, Lf, Ef, Acc) -> CompFun = fun(Bs) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, eval_filter(F, Bs0, Lf, Ef, CompFun, Acc);eval_bc1(E, [], Bs, Lf, Ef, Acc) -> {value,V,_} = expr(E, Bs, Lf, Ef, none), <<Acc/bitstr,V/bitstr>>.eval_generate([V|Rest], P, Bs0, Lf, Ef, CompFun, Acc) -> case match(P, V, new_bindings(), Bs0) of {match,Bsn} -> Bs2 = add_bindings(Bsn, Bs0), NewAcc = CompFun(Bs2, Acc), eval_generate(Rest, P, Bs0, Lf, Ef, CompFun, NewAcc); nomatch -> eval_generate(Rest, P, Bs0, Lf, Ef, CompFun, Acc) end;eval_generate([], _P, _Bs0, _Lf, _Ef, _CompFun, Acc) -> Acc;eval_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) -> erlang:raise(error, {bad_generator,Term}, stacktrace()).eval_b_generate(<<_/bitstr>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) -> Mfun = fun(L, R, Bs) -> match1(L, R, Bs, Bs0) end, Efun = fun(Exp, Bs) -> expr(Exp, Bs, Lf, Ef, none) end, case eval_bits:bin_gen(P, Bin, new_bindings(), Bs0, Mfun, Efun) of {match, Rest, Bs1} -> Bs2 = add_bindings(Bs1, Bs0), NewAcc = CompFun(Bs2, Acc), eval_b_generate(Rest, P, Bs0, Lf, Ef, CompFun, NewAcc); {nomatch, Rest} -> eval_b_generate(Rest, P, Bs0, Lf, Ef, CompFun, Acc); done -> Acc end;eval_b_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) -> erlang:raise(error, {bad_generator,Term}, stacktrace()).eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) -> case erl_lint:is_guard_test(F) of true -> case guard_test(F, Bs0, Lf, Ef) of {value,true,Bs1} -> CompFun(Bs1); {value,false,_} -> Acc end; false -> case expr(F, Bs0, Lf, Ef, none) of {value,true,Bs1} -> CompFun(Bs1); {value,false,_} -> Acc; {value,V,_} -> erlang:raise(error, {bad_filter,V}, stacktrace()) end end.%% RBs is the bindings to return when the evalution of a function%% (fun) has finished. If RBs =:= none, then the evalution took place%% outside a function. If RBs =:= value, only the value (not the bindings)%% is to be returned (to a compiled function).ret_expr(V, _Bs, value) -> V;ret_expr(V, Bs, none) -> {value,V,Bs};ret_expr(V, _Bs, RBs) when is_list(RBs) -> {value,V,RBs}.%% eval_fun(Clauses, Arguments, Bindings, LocalFunctionHandler, %% ExternalFunctionHandler) -> Value%% This function is called when the fun is called from compiled code%% or from apply.eval_fun(Cs, As, Bs0, Lf, Ef) -> eval_fun(Cs, As, Bs0, Lf, Ef, value).eval_fun([{clause,_,H,G,B}|Cs], As, Bs0, Lf, Ef, RBs) -> case match_list(H, As, new_bindings(), Bs0) of {match,Bsn} -> % The new bindings for the head Bs1 = add_bindings(Bsn, Bs0), % which then shadow! case guard(G, Bs1, Lf, Ef) of true -> exprs(B, Bs1, Lf, Ef, RBs); false -> eval_fun(Cs, As, Bs0, Lf, Ef, RBs) end; nomatch -> eval_fun(Cs, As, Bs0, Lf, Ef, RBs) end;eval_fun([], As, _Bs, _Lf, _Ef, _RBs) -> '-inside-a-shell-fun-'(), % Dummy call to avoid warning. %% list_to_tuple/1 below to avoid arity check. erlang:raise(error, function_clause, [{?MODULE,'-inside-a-shell-fun-',As}|stacktrace()]).'-inside-a-shell-fun-'() -> ok.%% expr_list(ExpressionList, Bindings)%% expr_list(ExpressionList, Bindings, LocalFuncHandler)%% expr_list(ExpressionList, Bindings, LocalFuncHandler, ExternalFuncHandler)%% Evaluate a list of expressions "in parallel" at the same level.expr_list(Es, Bs) -> expr_list(Es, Bs, none, none).expr_list(Es, Bs, Lf) -> expr_list(Es, Bs, Lf, none).expr_list(Es, Bs, Lf, Ef) -> expr_list(Es, [], Bs, Bs, Lf, Ef). expr_list([E|Es], Vs, BsOrig, Bs0, Lf, Ef) -> {value,V,Bs1} = expr(E, BsOrig, Lf, Ef, none), expr_list(Es, [V|Vs], BsOrig, merge_bindings(Bs1, Bs0), Lf, Ef);expr_list([], Vs, _, Bs, _Lf, _Ef) -> {reverse(Vs),Bs}.eval_op(Op, Arg1, Arg2, Bs, Ef, RBs) -> do_apply({erlang,Op}, [Arg1,Arg2], Bs, Ef, RBs).eval_op(Op, Arg, Bs, Ef, RBs) -> do_apply({erlang,Op}, [Arg], Bs, Ef, RBs).%% if_clauses(Clauses, Bindings, LocalFuncHandler, ExtFuncHandler, RBs)if_clauses([{clause,_,[],G,B}|Cs], Bs, Lf, Ef, RBs) -> case guard(G, Bs, Lf, Ef) of true -> exprs(B, Bs, Lf, Ef, RBs); false -> if_clauses(Cs, Bs, Lf, Ef, RBs) end;if_clauses([], _Bs, _Lf, _Ef, _RBs) -> erlang:raise(error, if_clause, stacktrace()).%% try_clauses(Body, CaseClauses, CatchClauses, AfterBody, Bindings, %% LocalFuncHandler, ExtFuncHandler, RBs)%% When/if variable bindings between the different parts of a%% try-catch expression are introduced this will have to be rewritten.try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) -> try exprs(B, Bs, Lf, Ef, none) of {value,V,Bs1} when Cases =:= [] -> ret_expr(V, Bs1, RBs); {value,V,Bs1} -> case match_clause(Cases, [V], Bs1, Lf, Ef) of {B2,Bs2} -> exprs(B2, Bs2, Lf, Ef, RBs); nomatch -> erlang:raise(error, {try_clause,V}, stacktrace()) end catch Class:Reason when Catches =:= [] -> %% Rethrow erlang:raise(Class, Reason, stacktrace()); Class:Reason ->%%% %% Set stacktrace%%% try erlang:raise(Class, Reason, stacktrace())%%% catch _:_ -> ok %%% end, V = {Class,Reason,erlang:get_stacktrace()}, case match_clause(Catches, [V],Bs, Lf, Ef) of {B2,Bs2} -> exprs(B2, Bs2, Lf, Ef, RBs); nomatch -> erlang:raise(Class, Reason, stacktrace()) end after if AB =:= [] -> Bs; % any true -> exprs(AB, Bs, Lf, Ef, none) end end.%% case_clauses(Value, Clauses, Bindings, LocalFuncHandler, ExtFuncHandler, %% RBs)case_clauses(Val, Cs, Bs, Lf, Ef, RBs) -> case match_clause(Cs, [Val], Bs, Lf, Ef) of {B, Bs1} -> exprs(B, Bs1, Lf, Ef, RBs); nomatch -> erlang:raise(error, {case_clause,Val}, stacktrace()) end.%%%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, Messages, RBs) %%receive_clauses(Cs, Bs, Lf, Ef, Ms, RBs) -> receive Val -> case match_clause(Cs, [Val], Bs, Lf, Ef) of {B, Bs1} -> merge_queue(Ms), exprs(B, Bs1, Lf, Ef, RBs); nomatch -> receive_clauses(Cs, Bs, Lf, Ef, [Val|Ms], RBs) end end.%%%% receive_clauses(TimeOut, Clauses, TimeoutBody, Bindings, %% ExternalFuncHandler, LocalFuncHandler, RBs)%%receive_clauses(T, Cs, TB, Bs, Lf, Ef, Ms, RBs) -> {_,_} = statistics(runtime), receive Val -> case match_clause(Cs, [Val], Bs, Lf, Ef) of {B, Bs1} -> merge_queue(Ms), exprs(B, Bs1, Lf, Ef, RBs); nomatch -> {_,T1} = statistics(runtime), if T =:= infinity -> receive_clauses(T, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs); T-T1 =< 0 -> receive_clauses(0, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs); true -> receive_clauses(T-T1, Cs,TB,Bs,Lf,Ef,[Val|Ms],RBs) end end after T -> merge_queue(Ms), {B, Bs1} = TB, exprs(B, Bs1, Lf, Ef, RBs) end.merge_queue(Ms) -> send_all(recv_all(Ms), self()).recv_all(Xs) -> receive X -> recv_all([X|Xs]) after 0 ->
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?