shell.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,268 行 · 第 1/3 页

ERL
1,268
字号
		false ->		    exit({{bad_module_name, Mod}, [{shell,import,1}]})	    end    end;local_func(import_all, [P], Bs0, _Shell, _RT, _Lf, _Ef) ->    case erl_parse:package_segments(P) of	error -> exit({function_clause,[{shell,import_all,1}]});	P1 ->	    Name = packages:concat(P1),	    case packages:is_valid(Name) of		true ->		    Bs1 = import_all(Name, Bs0),		    {value,ok,Bs1};		false ->		    exit({{bad_package_name, Name},			  [{shell,import_all,1}]})	    end    end;local_func(use, [M], Bs, Shell, RT, Lf, Ef) ->    local_func(import, [M], Bs, Shell, RT, Lf, Ef);local_func(use_all, [M], Bs, Shell, RT, Lf, Ef) ->    local_func(import_all, [M], Bs, Shell, RT, Lf, Ef);local_func(history, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) ->    {value,history(N),Bs};local_func(history, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) ->    exit({function_clause,{shell,history,1}});local_func(results, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) ->    {value,results(N),Bs};local_func(results, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) ->    exit({function_clause,[{shell,results,1}]});local_func(exit, [], _Bs, Shell, _RT, _Lf, _Ef) ->    shell_req(Shell, exit),			%This terminates us    exit(normal);local_func(F, As0, Bs0, _Shell, _RT, Lf, Ef) when is_atom(F) ->    {As,Bs} = expr_list(As0, Bs0, Lf, Ef),    non_builtin_local_func(F,As,Bs).non_builtin_local_func(F,As,Bs) ->    case erlang:function_exported(user_default, F, length(As)) of	true ->            {eval,{user_default,F},As,Bs};	false ->            {eval,{shell_default,F},As,Bs}    end.    local_func_handler(Shell, RT, Ef) ->    H = fun(Lf) ->                 fun(F, As, Bs) ->                         local_func(F, As, Bs, Shell, RT, {eval,Lf(Lf)}, Ef)                 end          end,    {eval,H(H)}.record_print_fun(RT) ->    fun(Tag, NoFields) ->            case ets:lookup(RT, Tag) of                [{_,{attribute,_,record,{Tag,Fields}}}]                                   when length(Fields) =:= NoFields ->                    record_fields(Fields);                _ ->                    no            end    end.record_fields([{record_field,_,{atom,_,Field}} | Fs]) ->    [Field | record_fields(Fs)];record_fields([{record_field,_,{atom,_,Field},_} | Fs]) ->    [Field | record_fields(Fs)];record_fields([]) ->    [].initiate_records(Bs, RT) ->    RNs1 = init_rec(shell_default, Bs, RT),    RNs2 = case code:is_loaded(user_default) of               {file,_File} ->                    init_rec(user_default, Bs, RT);               false ->                   []           end,    lists:usort(RNs1 ++ RNs2).init_rec(Module, Bs, RT) ->    case read_records(Module, []) of        RAs when is_list(RAs) ->            case catch add_records(RAs, Bs, RT) of                {'EXIT',_} ->                    [];                RNs ->                    RNs            end;        _Error ->            []    end.read_and_add_records(File, Selected, Options, Bs, RT) ->    case read_records(File, Selected, Options) of        RAs when is_list(RAs) ->            add_records(RAs, Bs, RT);        Error ->            Error    end.read_records(File, Selected, Options) ->    case read_records(File, listify(Options)) of        Error when is_tuple(Error) ->            Error;        RAs when Selected =:= '_' ->            RAs;        RAs ->            Sel = listify(Selected),            [RA || {attribute,_,_,{Name,_}}=RA <- RAs,                    lists:member(Name, Sel)]    end.add_records(RAs, Bs0, RT) ->    Recs = [{Name,D} || {attribute,_,_,{Name,_}}=D <- RAs],    Bs1 = record_bindings(Recs, Bs0),    case check_command([], Bs1) of        {error,{_Line,M,ErrDesc}} ->            %% A source file that has not been compiled.            ErrStr = io_lib:fwrite("~s", [M:format_error(ErrDesc)]),            exit(lists:flatten(ErrStr));        ok ->            true = ets:insert(RT, Recs),            lists:usort([Name || {Name,_} <- Recs])    end.listify(L) when is_list(L) ->    L;listify(E) ->    [E].check_command(Es, Bs) ->    erl_eval:check_command(Es, strip_bindings(Bs)).expr(E, Bs, Lf, Ef) ->    erl_eval:expr(E, strip_bindings(Bs), Lf, Ef).expr_list(Es, Bs, Lf, Ef) ->    erl_eval:expr_list(Es, strip_bindings(Bs), Lf, Ef).strip_bindings(Bs) ->    Bs -- [B || {{module,_},_}=B <- Bs].%% Note that a sequence number is used here to make sure that if a%% record is used by another record, then the first record is parsed%% before the second record. (erl_eval:check_command() calls the%% linter which needs the records in a proper order.)record_bindings([], Bs) ->    Bs;record_bindings(Recs0, Bs0) ->    {Recs1, _} = lists:mapfoldl(fun ({Name,Def}, I) -> {{Name,I,Def},I+1}                                 end, 0, Recs0),    Recs2 = lists:keysort(2, lists:ukeysort(1, Recs1)),    Bs1 = lists:foldl(fun ({Name,I,Def}, Bs) ->                              erl_eval:add_binding({record,I,Name},                                                    Def, Bs)                      end, Bs0, Recs2),    Bs1.%%% Read record information from file(s)read_records(FileOrModule, Opts0) ->    Opts = lists:delete(report_warnings, Opts0),    case find_file(FileOrModule) of        {files,[File]} ->            read_file_records(File, Opts);        {files,Files} ->            lists:flatmap(fun(File) ->                                  case read_file_records(File, Opts) of                                      RAs when is_list(RAs) -> RAs;                                      _ -> []                                  end                          end, Files);        Error ->            Error    end.-include_lib("kernel/include/file.hrl").find_file(Mod) when is_atom(Mod) ->    case code:which(Mod) of	File when is_list(File) ->	    {files,[File]};	preloaded ->	    {_M,_Bin,File} = code:get_object_code(Mod),            {files,[File]};        _Else -> % non_existing, interpreted, cover_compiled            {error,nofile}    end;find_file(File) ->    case catch filelib:wildcard(File) of        {'EXIT',_} ->            {error,invalid_filename};        Files ->            {files,Files}    end.read_file_records(File, Opts) ->    case filename:extension(File) of        ".beam" ->            case beam_lib:chunks(File, [abstract_code,"CInf"]) of                {ok,{_Mod,[{abstract_code,{Version,Forms}},{"CInf",CB}]}} ->                    case record_attrs(Forms) of                        [] when Version =:= raw_abstract_v1 ->                            [];                        [] ->                             %% If the version is raw_X, then this test                            %% is unnecessary.                            try_source(File, CB);                        Records ->                             Records                    end;                {ok,{_Mod,[{abstract_code,no_abstract_code},{"CInf",CB}]}} ->                    try_source(File, CB);                Error ->                    %% Could be that the "Abst" chunk is missing (pre R6).                    Error            end;        _ ->            parse_file(File, Opts)    end.%% This is how the debugger searches for source files. See int.erl.try_source(Beam, CB) ->    Os = case lists:keysearch(options, 1, binary_to_term(CB)) of             false -> [];             {value,{_,Os0}} -> Os0    end,    Src0 = filename:rootname(Beam) ++ ".erl",    case is_file(Src0) of	true -> parse_file(Src0, Os);	false ->	    EbinDir = filename:dirname(Beam),	    Src = filename:join([filename:dirname(EbinDir), "src",				 filename:basename(Src0)]),	    case is_file(Src) of		true -> parse_file(Src, Os);		false -> {error, nofile}	    end    end.is_file(Name) ->    case filelib:is_file(Name) of	true ->	    not filelib:is_dir(Name);	false ->	    false    end.parse_file(File, Opts) ->    Cwd = ".",    Dir = filename:dirname(File),    IncludePath = [Cwd,Dir|inc_paths(Opts)],    case epp:parse_file(File, IncludePath, pre_defs(Opts)) of        {ok,Forms} ->            record_attrs(Forms);        Error ->            Error    end.pre_defs([{d,M,V}|Opts]) ->    [{M,V}|pre_defs(Opts)];pre_defs([{d,M}|Opts]) ->    [M|pre_defs(Opts)];pre_defs([_|Opts]) ->    pre_defs(Opts);pre_defs([]) -> [].inc_paths(Opts) ->    [P || {i,P} <- Opts, is_list(P)].record_attrs(Forms) ->    [A || A = {attribute,_,record,_D} <- Forms].%%% End of reading record information from file(s)import_all(P, Bs0) ->    Ms = packages:find_modules(P),    lists:foldl(fun (M, Bs) ->			Key = list_to_atom(M),			M1 = list_to_atom(packages:concat(P, M)),			erl_eval:add_binding({module,Key}, M1, Bs)		end,		Bs0, Ms).shell_req(Shell, Req) ->    Shell ! {shell_req,self(),Req},    receive	{shell_rep,Shell,Rep} -> Rep    end.list_commands([{{N,command},Es0}, {{N,result}, V} |Ds], RT) ->    Es = prep_list_commands(Es0),    VS = io_lib_pretty:print(V, 4, 80, ?LINEMAX, record_print_fun(RT)),    Ns = io_lib:fwrite("~w: ", [N]),    I = iolist_size(Ns),    io:requests([{put_chars, Ns},                 {format,"~s~n",[erl_pp:exprs(Es, I, none)]},		 {format,"-> ",[]},                 {put_chars, VS},                 nl]),    list_commands(Ds, RT);list_commands([{{N,command},Es0} |Ds], RT) ->    Es = prep_list_commands(Es0),    Ns = io_lib:fwrite("~w: ", [N]),    I = iolist_size(Ns),    io:requests([{put_chars, Ns},                 {format,"~s~n",[erl_pp:exprs(Es, I, none)]}]),    list_commands(Ds, RT);list_commands([_D|Ds], RT) ->    list_commands(Ds, RT);list_commands([], _RT) -> ok.list_bindings([{{module,M},Val}|Bs], RT) ->    io:fwrite("~p is ~p~n", [M,Val]),    list_bindings(Bs, RT);list_bindings([{Name,Val}|Bs], RT) ->    case erl_eval:fun_data(Val) of        {fun_data,_FBs,FCs0} ->            FCs = expand_value(FCs0), % looks nicer            F = {'fun',0,{clauses,FCs}},            M = {match,0,{var,0,Name},F},            io:fwrite("~s~n", [erl_pp:expr(M)]);        false ->            Namel = io_lib:fwrite("~s = ", [Name]),            Nl = iolist_size(Namel)+1,            io:put_chars(Namel),            ValS = io_lib_pretty:print(Val, Nl, 80, ?LINEMAX,                                        record_print_fun(RT)),            io:put_chars(ValS),            io:nl()    end,    list_bindings(Bs, RT);list_bindings([], _RT) ->    ok.list_records(Records) ->    lists:foreach(fun({_Name,Attr}) ->                           io:fwrite("~s", [erl_pp:attribute(Attr)])                  end, Records).record_defs(RT, Names) ->    lists:flatmap(fun(Name) -> ets:lookup(RT, Name)                  end, Names).expand_value(E) ->    substitute_v1(fun({value,CommandN,V}) -> try_abstract(V, CommandN)                  end, E).%% There is no abstract representation of funs.try_abstract(V, CommandN) ->    try erl_parse:abstract(V)    catch _:_ -> {call,0,{atom,0,v},[{integer,0,CommandN}]}    end.%% Rather than listing possibly huge results the calls to v/1 are shown.prep_list_commands(E) ->    substitute_v1(fun({value,CommandN,_V}) ->                           {call,0,{atom,0,v},[{integer,0,CommandN}]}                  end, E).substitute_v1(F, {value,_,_}=Value) ->    F(Value);substitute_v1(F, T) when is_tuple(T) ->     list_to_tuple(substitute_v1(F, tuple_to_list(T)));substitute_v1(F, [E | Es]) ->     [substitute_v1(F, E) | substitute_v1(F, Es)];substitute_v1(_F, E) ->     E.check_and_get_history_and_results() ->    check_env(shell_history_length, "shell history length"),    check_env(shell_saved_results, "max number of saved results"),    get_history_and_results().get_history_and_results() ->    History = get_env(shell_history_length, ?DEF_HISTORY),    Results = get_env(shell_saved_results, ?DEF_RESULTS),    {History, min(Results, History)}.min(X, Y) when X < Y ->    X;min(_X, Y) ->    Y.get_env(V, Def) ->    case application:get_env(stdlib, V) of	{ok, Val} when is_integer(Val), Val >= 0 ->	    Val;	_ ->	    Def    end.	    check_env(V, Name) ->    case application:get_env(stdlib, V) of	undefined ->	    ok;	{ok, Val} when is_integer(Val), Val >= 0 ->	    ok;	{ok, Val} ->	    Txt = io_lib:fwrite("Invalid ~s ~p~n", [Name, Val]),	    error_logger:info_report(lists:flatten(Txt))    end.	    set_env(App, Name, Val, Default) ->    Prev = case application:get_env(App, Name) of	       undefined ->		   Default;	       {ok, Old} ->		   Old    end,    application_controller:set_env(App, Name, Val),    Prev.history(L) when is_integer(L), L >= 0 ->    set_env(stdlib, shell_history_length, L, ?DEF_HISTORY).results(L) when is_integer(L), L >= 0 ->    set_env(stdlib, shell_saved_results, L, ?DEF_RESULTS).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?