erl_eval.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,167 行 · 第 1/3 页
ERL
1,167 行
reverse(Xs) end.send_all([X|Xs], Self) -> Self ! X, send_all(Xs, Self);send_all([], _) -> true.%% match_clause -> {Body, Bindings} or nomatchmatch_clause(Cs, Vs, Bs, Lf) -> match_clause(Cs, Vs, Bs, Lf, none).match_clause([{clause,_,H,G,B}|Cs], Vals, Bs, Lf, Ef) -> case match_list(H, Vals, Bs) of {match, Bs1} -> case guard(G, Bs1, Lf, Ef) of true -> {B, Bs1}; false -> match_clause(Cs, Vals, Bs, Lf, Ef) end; nomatch -> match_clause(Cs, Vals, Bs, Lf, Ef) end;match_clause([], _Vals, _Bs, _Lf, _Ef) -> nomatch.%% guard(GuardTests, Bindings, LocalFuncHandler, ExtFuncHandler) -> bool()%% Evaluate a guard. We test if the guard is a true guard.guard(L=[G|_], Bs0, Lf, Ef) when is_list(G) -> guard1(L, Bs0, Lf, Ef);guard(L, Bs0, Lf, Ef) -> guard0(L, Bs0, Lf, Ef).%% disjunction of guard conjunctionsguard1([G|Gs], Bs0, Lf, Ef) when is_list(G) -> case guard0(G, Bs0, Lf, Ef) of true -> true; false -> guard1(Gs, Bs0, Lf, Ef) end;guard1([], _Bs, _Lf, _Ef) -> false.%% guard conjunctionguard0([G|Gs], Bs0, Lf, Ef) -> case erl_lint:is_guard_test(G) of true -> case guard_test(G, Bs0, Lf, Ef) of {value,true,Bs} -> guard0(Gs, Bs, Lf, Ef); {value,false,_} -> false end; false -> erlang:raise(error, guard_expr, stacktrace()) end;guard0([], _Bs, _Lf, _Ef) -> true.%% guard_test(GuardTest, Bindings, LocalFuncHandler, ExtFuncHandler) ->%% {value,bool(),NewBindings}.%% Evaluate one guard test. Never fails, returns bool().guard_test({call,_,{atom,_,Name},As0}, Bs0, Lf, Ef) -> try {As1,Bs1} = expr_list(As0, Bs0, Lf, Ef), {value,true,_} = type_test(Name, As1, Bs1, Ef) catch error:_ -> {value,false,Bs0} end;guard_test({op,_,Op,A0}, Bs0, Lf, Ef) -> try {[A],Bs1} = expr_list([A0], Bs0, Lf, Ef), {value,true,_} = eval_op(Op, A, Bs1, Ef, none) catch error:_ -> {value,false,Bs0} end;guard_test({op,_,'andalso',_Lhs0,_Rhs0}=G, Bs0, Lf, Ef) -> try {value,true,_} = expr(G, Bs0, Lf, Ef, none) catch error:_ -> {value,false,Bs0} end;guard_test({op,_,'orelse',_Lhs0,_Rhs0}=G, Bs0, Lf, Ef) -> try {value,true,_} = expr(G, Bs0, Lf, Ef, none) catch error:_ -> {value,false,Bs0} end;guard_test({op,_,Op,Lhs0,Rhs0}, Bs0, Lf, Ef) -> try {[Lhs,Rhs],Bs1} = expr_list([Lhs0,Rhs0], Bs0, Lf, Ef), {value,true,_} = eval_op(Op, Lhs, Rhs, Bs1, Ef, none) catch error:_ -> {value,false,Bs0} end; guard_test({atom,_,true}, Bs, _Lf, _Ef) -> {value,true,Bs};guard_test({atom,_,false}, Bs, _Lf, _Ef) -> {value,false,Bs};guard_test({var,_,V}, Bs, _Lf, _Ef) -> {value,Val} = binding(V, Bs), {value,Val =:= true,Bs};guard_test({call,_L,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,F}},As0}, Bs0, Lf, Ef) -> try {As1,Bs1} = expr_list(As0, Bs0, Lf, Ef), {value,true,_} = type_test(F, As1, Bs1, Ef) catch error:_ -> {value,false,Bs0} end;guard_test({call,L,{tuple,L1,[{atom,Lm,erlang},{atom,L2,F}]},As}, Bs0, Lf, Ef) -> guard_test({call,L,{remote,L1,{atom,Lm,erlang},{atom,L2,F}},As}, Bs0, Lf, Ef);guard_test(_Other, Bs, _Lf, _Ef) -> {value,false,Bs}.type_test(Test, As, Bs, Ef) -> do_apply({erlang,type_test(Test)}, As, Bs, Ef, none).type_test(integer) -> is_integer;type_test(float) -> is_float;type_test(number) -> is_number;type_test(atom) -> is_atom;type_test(constant) -> is_constant;type_test(list) -> is_list;type_test(tuple) -> is_tuple;type_test(pid) -> is_pid;type_test(reference) -> is_reference;type_test(port) -> is_port;type_test(function) -> is_function;type_test(binary) -> is_binary;type_test(record) -> is_record;type_test(Test) -> Test.%% match(Pattern, Term, Bindings) ->%% {match,NewBindings} | nomatch%% or erlang:error({illegal_pattern, Pattern}).%% Try to match Pattern against Term with the current bindings.match(Pat, Term, Bs) -> match(Pat, Term, Bs, Bs).%% Bs are the bindings that are augmented with new bindings. BBs are%% the bindings used for "binsize" variables (in <<X:Y>>, Y is a%% binsize variable).match(Pat, Term, Bs, BBs) -> case catch match1(Pat, Term, Bs, BBs) of invalid -> erlang:raise(error, {illegal_pattern,Pat}, stacktrace()); Other -> Other end.string_to_conses([], _, Tail) -> Tail;string_to_conses([E|Rest], Line, Tail) -> {cons, Line, {integer, Line, E}, string_to_conses(Rest, Line, Tail)}.match1({atom,_,A0}, A, Bs, _BBs) -> case A of A0 -> {match,Bs}; _ -> throw(nomatch) end;match1({integer,_,I0}, I, Bs, _BBs) -> case I of I0 -> {match,Bs}; _ -> throw(nomatch) end;match1({float,_,F0}, F, Bs, _BBs) -> case F of F0 -> {match,Bs}; _ -> throw(nomatch) end;match1({char,_,C0}, C, Bs, _BBs) -> case C of C0 -> {match,Bs}; _ -> throw(nomatch) end;match1({var,_,'_'}, _, Bs, _BBs) -> %Anonymous variable matches {match,Bs}; % everything, no new bindingsmatch1({var,_,Name}, Term, Bs, _BBs) -> case binding(Name, Bs) of {value,Term} -> {match,Bs}; {value,_} -> throw(nomatch); unbound -> {match,add_binding(Name, Term, Bs)} end;match1({match,_,Pat1,Pat2}, Term, Bs0, BBs) -> {match, Bs1} = match1(Pat1, Term, Bs0, BBs), match1(Pat2, Term, Bs1, BBs);match1({string,_,S0}, S, Bs, _BBs) -> case S of S0 -> {match,Bs}; _ -> throw(nomatch) end;match1({nil,_}, Nil, Bs, _BBs) -> case Nil of [] -> {match,Bs}; _ -> throw(nomatch) end;match1({cons,_,H,T}, [H1|T1], Bs0, BBs) -> {match,Bs} = match1(H, H1, Bs0, BBs), match1(T, T1, Bs, BBs);match1({cons,_,_,_}, _, _Bs, _BBs) -> throw(nomatch);match1({tuple,_,Elts}, Tuple, Bs, BBs) when is_tuple(Tuple), length(Elts) =:= size(Tuple) -> match_tuple(Elts, Tuple, 1, Bs, BBs);match1({tuple,_,_}, _, _Bs, _BBs) -> throw(nomatch);match1({bin, _, Fs}, <<_/bitstr>>=B, Bs0, BBs) -> eval_bits:match_bits(Fs, B, Bs0, BBs, fun(L, R, Bs) -> match1(L, R, Bs, BBs) end, fun(E, Bs) -> expr(E, Bs, none, none, none) end);match1({bin,_,_}, _, _Bs, _BBs) -> throw(nomatch);match1({op,_,'++',{nil,_},R}, Term, Bs, BBs) -> match1(R, Term, Bs, BBs);match1({op,_,'++',{cons,Li,{integer,L2,I},T},R}, Term, Bs, BBs) -> match1({cons,Li,{integer,L2,I},{op,Li,'++',T,R}}, Term, Bs, BBs);match1({op,_,'++',{string,Li,L},R}, Term, Bs, BBs) -> match1(string_to_conses(L, Li, R), Term, Bs, BBs);match1({op,Line,Op,A}, Term, Bs, BBs) -> case partial_eval({op,Line,Op,A}) of {op,Line,Op,A} -> throw(invalid); X -> match1(X, Term, Bs, BBs) end;match1({op,Line,Op,L,R}, Term, Bs, BBs) -> case partial_eval({op,Line,Op,L,R}) of {op,Line,Op,L,R} -> throw(invalid); X -> match1(X, Term, Bs, BBs) end;match1(_, _, _Bs, _BBs) -> throw(invalid).match_tuple([E|Es], Tuple, I, Bs0, BBs) -> {match,Bs} = match1(E, element(I, Tuple), Bs0, BBs), match_tuple(Es, Tuple, I+1, Bs, BBs);match_tuple([], _, _, Bs, _BBs) -> {match,Bs}.%% match_list(PatternList, TermList, Bindings) ->%% {match,NewBindings} | nomatch%% Try to match a list of patterns against a list of terms with the%% current bindings.match_list(Ps, Ts, Bs) -> match_list(Ps, Ts, Bs, Bs).match_list([P|Ps], [T|Ts], Bs0, BBs) -> case match(P, T, Bs0, BBs) of {match,Bs1} -> match_list(Ps, Ts, Bs1, BBs); nomatch -> nomatch end;match_list([], [], Bs, _BBs) -> {match,Bs};match_list(_, _, _Bs, _BBs) -> nomatch.%% new_bindings()%% bindings(Bindings)%% binding(Name, Bindings)%% add_binding(Name, Value, Bindings)%% del_binding(Name, Bindings)new_bindings() -> orddict:new().bindings(Bs) -> orddict:to_list(Bs).binding(Name, Bs) -> case orddict:find(Name, Bs) of {ok,Val} -> {value,Val}; error -> unbound end.add_binding(Name, Val, Bs) -> orddict:store(Name, Val, Bs).del_binding(Name, Bs) -> orddict:erase(Name, Bs).add_bindings(Bs1, Bs2) -> foldl(fun ({Name,Val}, Bs) -> orddict:store(Name, Val, Bs) end, Bs2, orddict:to_list(Bs1)).merge_bindings(Bs1, Bs2) -> foldl(fun ({Name,Val}, Bs) -> case orddict:find(Name, Bs) of {ok,Val} -> Bs; %Already with SAME value {ok,V1} -> erlang:raise(error, {badmatch,V1}, stacktrace()); error -> orddict:store(Name, Val, Bs) end end, Bs2, orddict:to_list(Bs1)).%% del_bindings(Bs1, Bs2) -> % del all in Bs1 from Bs2%% orddict:fold(%% fun (Name, Val, Bs) ->%% case orddict:find(Name, Bs) of%% {ok,Val} -> orddict:erase(Name, Bs);%% {ok,V1} -> erlang:raise(error,{badmatch,V1},stacktrace());%% error -> Bs%% end%% end, Bs2, Bs1).%%----------------------------------------------------------------------------%%%% Evaluate expressions:%% constants and %% op A%% L op R%% Things that evaluate to constants are accepted%% and guard_bifs are allowed in constant expressions%%----------------------------------------------------------------------------is_constant_expr(Expr) -> case eval_expr(Expr) of {ok, X} when is_number(X) -> true; _ -> false end.eval_expr(Expr) -> case catch ev_expr(Expr) of X when is_integer(X) -> {ok, X}; X when is_float(X) -> {ok, X}; X when is_atom(X) -> {ok,X}; {'EXIT',Reason} -> {error, Reason}; _ -> {error, badarg} end.partial_eval(Expr) -> Line = line(Expr), case catch ev_expr(Expr) of X when is_integer(X) -> ret_expr(Expr,{integer,Line,X}); X when is_float(X) -> ret_expr(Expr,{float,Line,X}); X when is_atom(X) -> ret_expr(Expr,{atom,Line,X}); _ -> Expr end.ev_expr({op,_,Op,L,R}) -> erlang:Op(ev_expr(L), ev_expr(R));ev_expr({op,_,Op,A}) -> erlang:Op(ev_expr(A));ev_expr({integer,_,X}) -> X;ev_expr({float,_,X}) -> X;ev_expr({atom,_,X}) -> X;ev_expr({tuple,_,Es}) -> list_to_tuple([ev_expr(X) || X <- Es]);ev_expr({nil,_}) -> [];ev_expr({cons,_,H,T}) -> [ev_expr(H) | ev_expr(T)].%%ev_expr({call,Line,{atom,_,F},As}) ->%% true = erl_internal:guard_bif(F, length(As)),%% apply(erlang, F, [ev_expr(X) || X <- As]);%%ev_expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,F}},As}) ->%% true = erl_internal:guard_bif(F, length(As)),%% apply(erlang, F, [ev_expr(X) || X <- As]);ret_expr(_Old, New) -> %% io:format("~w: reduced ~s => ~s~n", %% [line(Old), erl_pp:expr(Old), erl_pp:expr(New)]), New.line(Expr) -> element(2, Expr).%% In syntax trees, module/package names are atoms or lists of atoms.expand_module_name({atom,L,A} = M, Bs) -> case binding({module,A}, Bs) of {value, A1} -> {atom,L,A1}; unbound -> case packages:is_segmented(A) of true -> M; false ->%%% P = case binding({module,'$package'}, Bs) of%%% {value, P1} -> P1;%%% unbound -> ""%%% end,%%% A1 = list_to_atom(packages:concat(P, A)),%%% {atom,L,list_to_atom(A1)} {atom,L,A} end end;expand_module_name(M, _) -> case erl_parse:package_segments(M) of error -> M; M1 -> L = element(2,M), Mod = packages:concat(M1), case packages:is_valid(Mod) of true -> {atom,L,list_to_atom(Mod)}; false -> erlang:raise(error, {bad_module_name, Mod}, stacktrace()) end end.%% {?MODULE,expr,3} is still the stacktrace, despite the%% fact that expr() now takes two, three or four arguments...stacktrace() -> [{?MODULE,expr,3}].
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?