|
|
- -module(rumStdlib).
-
- -compile(inline).
- -compile({inline_size, 128}).
-
- -export([
- isErrorReport/1,
- is_my_info_report/1
- ]).
- -export([sup_get/2]).
- -export([proc_lib_format/2]).
-
- %% From OTP sasl's sasl_report.erl ... These functions aren't
- %% exported.
- -spec isErrorReport(atom()) -> boolean().
- isErrorReport(supervisor_report) -> true;
- isErrorReport(crash_report) -> true;
- isErrorReport(_) -> false.
-
- -spec is_my_info_report(atom()) -> boolean().
- is_my_info_report(progress) -> true;
- is_my_info_report(_) -> false.
-
- -spec sup_get(term(), [proplists:property()]) -> term().
- sup_get(Tag, Report) ->
- case lists:keysearch(Tag, 1, Report) of
- {value, {_, Value}} ->
- Value;
- _ ->
- ""
- end.
-
- %% From OTP stdlib's proc_lib.erl ... These functions aren't exported.
- -spec proc_lib_format([term()], pos_integer()) -> string().
- proc_lib_format([OwnReport, LinkReport], FmtMaxBytes) ->
- OwnFormat = format_report(OwnReport, FmtMaxBytes),
- LinkFormat = format_report(LinkReport, FmtMaxBytes),
- %% io_lib:format here is OK because we're limiting max length elsewhere.
- Str = io_lib:format(" crasher:~n~s neighbours:~n~s", [OwnFormat, LinkFormat]),
- lists:flatten(Str).
-
- format_report(Rep, FmtMaxBytes) when is_list(Rep) ->
- format_rep(Rep, FmtMaxBytes);
- format_report(Rep, FmtMaxBytes) ->
- eFmt:formatBin(<<"~p~n">>, [Rep], [{charsLimit, FmtMaxBytes}]).
-
- format_rep([{initial_call, InitialCall} | Rep], FmtMaxBytes) ->
- [format_mfa(InitialCall, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
- format_rep([{error_info, {Class, Reason, StackTrace}} | Rep], FmtMaxBytes) ->
- [format_exception(Class, Reason, StackTrace, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
- format_rep([{Tag, Data} | Rep], FmtMaxBytes) ->
- [format_tag(Tag, Data, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
- format_rep(_, _S) ->
- [].
-
- format_exception(Class, Reason, StackTrace, FmtMaxBytes) ->
- PF = pp_fun(FmtMaxBytes),
- StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- %% EI = " exception: ",
- EI = " ",
- [EI, lib_format_exception(1 + length(EI), Class, Reason,
- StackTrace, StackFun, PF), "\n"].
-
- format_mfa({M, F, Args} = StartF, FmtMaxBytes) ->
- try
- A = length(Args),
- [" initial call: ", atom_to_list(M), $:, atom_to_list(F), $/,
- integer_to_list(A), "\n"]
- catch
- error:_ ->
- format_tag(initial_call, StartF, FmtMaxBytes)
- end.
-
- pp_fun(FmtMaxBytes) ->
- fun(Term, _I) ->
- eFmt:formatBin(<<"~p">>, [Term], [{charsLimit ,FmtMaxBytes}])
- end.
-
- format_tag(Tag, Data, FmtMaxBytes) ->
- eFmt:formatBin(<<"~p: ~p~n">>, [Tag, Data], [{charsLimit ,FmtMaxBytes}]).
-
- %% From OTP stdlib's lib.erl ... These functions aren't exported.
-
- lib_format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun)
- when is_integer(I), I >= 1, is_function(StackFun, 3),
- is_function(FormatFun, 2) ->
- Str = n_spaces(I - 1),
- {Term, Trace1, Trace} = analyze_exception(Class, Reason, StackTrace),
- Expl0 = explain_reason(Term, Class, Trace1, FormatFun, Str),
- Expl = io_lib:fwrite(<<"~s~s">>, [exited(Class), Expl0]),
- case format_stacktrace1(Str, Trace, FormatFun, StackFun) of
- [] -> Expl;
- Stack -> [Expl, $\n, Stack]
- end.
-
- analyze_exception(error, Term, Stack) ->
- case {is_stacktrace(Stack), Stack, Term} of
- {true, [{_M, _F, As} = MFA | MFAs], function_clause} when is_list(As) ->
- {Term, [MFA], MFAs};
- {true, [{shell, F, A}], function_clause} when is_integer(A) ->
- {Term, [{F, A}], []};
- {true, [{_M, _F, _AorAs} = MFA | MFAs], undef} ->
- {Term, [MFA], MFAs};
- {true, _, _} ->
- {Term, [], Stack};
- {false, _, _} ->
- {{Term, Stack}, [], []}
- end;
- analyze_exception(_Class, Term, Stack) ->
- case is_stacktrace(Stack) of
- true ->
- {Term, [], Stack};
- false ->
- {{Term, Stack}, [], []}
- end.
-
- is_stacktrace([]) ->
- true;
- is_stacktrace([{M, F, A} | Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
- is_stacktrace(Fs);
- is_stacktrace([{M, F, As} | Fs]) when is_atom(M), is_atom(F), length(As) >= 0 ->
- is_stacktrace(Fs);
- is_stacktrace(_) ->
- false.
-
- %% ERTS exit codes (some of them are also returned by erl_eval):
- explain_reason(badarg, error, [], _PF, _Str) ->
- <<"bad argument">>;
- explain_reason({badarg, V}, error = Cl, [], PF, Str) -> % orelse, andalso
- format_value(V, <<"bad argument: ">>, Cl, PF, Str);
- explain_reason(badarith, error, [], _PF, _Str) ->
- <<"bad argument in an arithmetic expression">>;
- explain_reason({badarity, {Fun, As}}, error, [], _PF, _Str)
- when is_function(Fun) ->
- %% Only the arity is displayed, not the arguments As.
- io_lib:fwrite(<<"~s called with ~s">>,
- [format_fun(Fun), argss(length(As))]);
- explain_reason({badfun, Term}, error = Cl, [], PF, Str) ->
- format_value(Term, <<"bad function ">>, Cl, PF, Str);
- explain_reason({badmatch, Term}, error = Cl, [], PF, Str) ->
- format_value(Term, <<"no match of right hand side value ">>, Cl, PF, Str);
- explain_reason({case_clause, V}, error = Cl, [], PF, Str) ->
- %% "there is no case clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no case clause matching ">>, Cl, PF, Str);
- explain_reason(function_clause, error, [{F, A}], _PF, _Str) ->
- %% Shell commands
- FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
- [<<"no function clause matching call to ">> | FAs];
- explain_reason(function_clause, error = Cl, [{M, F, As}], PF, Str) ->
- String = <<"no function clause matching ">>,
- format_errstr_call(String, Cl, {M, F}, As, PF, Str);
- explain_reason(if_clause, error, [], _PF, _Str) ->
- <<"no true branch found when evaluating an if expression">>;
- explain_reason(noproc, error, [], _PF, _Str) ->
- <<"no such process or port">>;
- explain_reason(notalive, error, [], _PF, _Str) ->
- <<"the node cannot be part of a distributed system">>;
- explain_reason(system_limit, error, [], _PF, _Str) ->
- <<"a system limit has been reached">>;
- explain_reason(timeout_value, error, [], _PF, _Str) ->
- <<"bad receive timeout value">>;
- explain_reason({try_clause, V}, error = Cl, [], PF, Str) ->
- %% "there is no try clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no try clause matching ">>, Cl, PF, Str);
- explain_reason(undef, error, [{M, F, A}], _PF, _Str) ->
- %% Only the arity is displayed, not the arguments, if there are any.
- io_lib:fwrite(<<"undefined function ~s">>,
- [mfa_to_string(M, F, n_args(A))]);
- explain_reason({shell_undef, F, A}, error, [], _PF, _Str) ->
- %% Give nicer reports for undefined shell functions
- %% (but not when the user actively calls shell_default:F(...)).
- io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]);
- %% Exit codes returned by erl_eval only:
- explain_reason({argument_limit, _Fun}, error, [], _PF, _Str) ->
- io_lib:fwrite(<<"limit of number of arguments to interpreted function"
- " exceeded">>, []);
- explain_reason({bad_filter, V}, error = Cl, [], PF, Str) ->
- format_value(V, <<"bad filter ">>, Cl, PF, Str);
- explain_reason({bad_generator, V}, error = Cl, [], PF, Str) ->
- format_value(V, <<"bad generator ">>, Cl, PF, Str);
- explain_reason({unbound, V}, error, [], _PF, _Str) ->
- io_lib:fwrite(<<"variable ~w is unbound">>, [V]);
- %% Exit codes local to the shell module (restricted shell):
- explain_reason({restricted_shell_bad_return, V}, exit = Cl, [], PF, Str) ->
- String = <<"restricted shell module returned bad value ">>,
- format_value(V, String, Cl, PF, Str);
- explain_reason({restricted_shell_disallowed, {ForMF, As}},
- exit = Cl, [], PF, Str) ->
- %% ForMF can be a fun, but not a shell fun.
- String = <<"restricted shell does not allow ">>,
- format_errstr_call(String, Cl, ForMF, As, PF, Str);
- explain_reason(restricted_shell_started, exit, [], _PF, _Str) ->
- <<"restricted shell starts now">>;
- explain_reason(restricted_shell_stopped, exit, [], _PF, _Str) ->
- <<"restricted shell stopped">>;
- %% Other exit code:
- explain_reason(Reason, Class, [], PF, Str) ->
- PF(Reason, (iolist_size(Str) + 1) + exited_size(Class)).
-
- n_spaces(N) ->
- lists:duplicate(N, $\s).
-
- exited_size(Class) ->
- iolist_size(exited(Class)).
-
- exited(error) ->
- <<"exception error: ">>;
- exited(exit) ->
- <<"exception exit: ">>;
- exited(throw) ->
- <<"exception throw: ">>.
-
- format_stacktrace1(S0, Stack0, PF, SF) ->
- Stack1 = lists:dropwhile(fun({M, F, A}) -> SF(M, F, A)
- end, lists:reverse(Stack0)),
- S = [" " | S0],
- Stack = lists:reverse(Stack1),
- format_stacktrace2(S, Stack, 1, PF).
-
- format_stacktrace2(S, [{M, F, A} | Fs], N, PF) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~s">>,
- [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A)])
- | format_stacktrace2(S, Fs, N + 1, PF)];
- format_stacktrace2(S, [{M, F, As} | Fs], N, PF) when is_list(As) ->
- A = length(As),
- CalledAs = [S, <<" called as ">>],
- C = format_call("", CalledAs, {M, F}, As, PF),
- [io_lib:fwrite(<<"~s~s ~s\n~s~s">>,
- [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A),
- CalledAs, C])
- | format_stacktrace2(S, Fs, N + 1, PF)];
- format_stacktrace2(_S, [], _N, _PF) ->
- "".
-
- argss(0) ->
- <<"no arguments">>;
- argss(1) ->
- <<"one argument">>;
- argss(2) ->
- <<"two arguments">>;
- argss(I) ->
- io_lib:fwrite(<<"~w arguments">>, [I]).
-
- format_value(V, ErrStr, Class, PF, Str) ->
- Pre1Sz = exited_size(Class),
- Str1 = PF(V, Pre1Sz + iolist_size([Str, ErrStr]) + 1),
- [ErrStr | case count_nl(Str1) of
- N1 when N1 > 1 ->
- Str2 = PF(V, iolist_size(Str) + 1 + Pre1Sz),
- case count_nl(Str2) < N1 of
- true ->
- [$\n, Str, n_spaces(Pre1Sz) | Str2];
- false ->
- Str1
- end;
- _ ->
- Str1
- end].
-
- format_fun(Fun) when is_function(Fun) ->
- {module, M} = erlang:fun_info(Fun, module),
- {name, F} = erlang:fun_info(Fun, name),
- {arity, A} = erlang:fun_info(Fun, arity),
- case erlang:fun_info(Fun, type) of
- {type, local} when F =:= "" ->
- io_lib:fwrite(<<"~w">>, [Fun]);
- {type, local} when M =:= erl_eval ->
- io_lib:fwrite(<<"interpreted function with arity ~w">>, [A]);
- {type, local} ->
- mfa_to_string(M, F, A);
- {type, external} ->
- mfa_to_string(M, F, A)
- end.
-
- format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0) ->
- Pre1 = [Pre0 | n_spaces(exited_size(Class))],
- format_call(ErrStr, Pre1, ForMForFun, As, PF).
-
- format_call(ErrStr, Pre1, ForMForFun, As, PF) ->
- Arity = length(As),
- [ErrStr |
- case is_op(ForMForFun, Arity) of
- {yes, Op} ->
- format_op(ErrStr, Pre1, Op, As, PF);
- no ->
- MFs = mf_to_string(ForMForFun, Arity),
- I1 = iolist_size([Pre1, ErrStr | MFs]),
- S1 = pp_arguments(PF, As, I1),
- S2 = pp_arguments(PF, As, iolist_size([Pre1 | MFs])),
- Long = count_nl(pp_arguments(PF, [a2345, b2345], I1)) > 0,
- case Long or (count_nl(S2) < count_nl(S1)) of
- true ->
- [$\n, Pre1, MFs, S2];
- false ->
- [MFs, S1]
- end
- end].
-
- mfa_to_string(M, F, A) ->
- io_lib:fwrite(<<"~s/~w">>, [mf_to_string({M, F}, A), A]).
-
- mf_to_string({M, F}, A) ->
- case erl_internal:bif(M, F, A) of
- true ->
- io_lib:fwrite(<<"~w">>, [F]);
- false ->
- case is_op({M, F}, A) of
- {yes, '/'} ->
- io_lib:fwrite(<<"~w">>, [F]);
- {yes, F} ->
- atom_to_list(F);
- no ->
- io_lib:fwrite(<<"~w:~w">>, [M, F])
- end
- end;
- mf_to_string(Fun, _A) when is_function(Fun) ->
- format_fun(Fun);
- mf_to_string(F, _A) ->
- io_lib:fwrite(<<"~w">>, [F]).
-
- n_args(A) when is_integer(A) ->
- A;
- n_args(As) when is_list(As) ->
- length(As).
-
- origin(1, M, F, A) ->
- case is_op({M, F}, n_args(A)) of
- {yes, F} -> <<"in operator ">>;
- no -> <<"in function ">>
- end;
- origin(_N, _M, _F, _A) ->
- <<"in call from">>.
-
- sep(1, S) -> S;
- sep(_, S) -> [$\n | S].
-
- count_nl([E | Es]) ->
- count_nl(E) + count_nl(Es);
- count_nl($\n) ->
- 1;
- count_nl(Bin) when is_binary(Bin) ->
- count_nl(binary_to_list(Bin));
- count_nl(_) ->
- 0.
-
- is_op(ForMForFun, A) ->
- try
- {erlang, F} = ForMForFun,
- _ = erl_internal:op_type(F, A),
- {yes, F}
- catch error:_ -> no
- end.
-
- format_op(ErrStr, Pre, Op, [A1, A2], PF) ->
- I1 = iolist_size([ErrStr, Pre]),
- S1 = PF(A1, I1 + 1),
- S2 = PF(A2, I1 + 1),
- OpS = atom_to_list(Op),
- Pre1 = [$\n | n_spaces(I1)],
- case count_nl(S1) > 0 of
- true ->
- [S1, Pre1, OpS, Pre1 | S2];
- false ->
- OpS2 = io_lib:fwrite(<<" ~s ">>, [Op]),
- S2_2 = PF(A2, iolist_size([ErrStr, Pre, S1 | OpS2]) + 1),
- case count_nl(S2) < count_nl(S2_2) of
- true ->
- [S1, Pre1, OpS, Pre1 | S2];
- false ->
- [S1, OpS2 | S2_2]
- end
- end.
-
- pp_arguments(PF, As, I) ->
- case {As, io_lib:printable_list(As)} of
- {[Int | T], true} ->
- L = integer_to_list(Int),
- Ll = length(L),
- A = list_to_atom(lists:duplicate(Ll, $a)),
- S0 = binary_to_list(iolist_to_binary(PF([A | T], I + 1))),
- brackets_to_parens([$[, L, string:sub_string(S0, 2 + Ll)]);
- _ ->
- brackets_to_parens(PF(As, I + 1))
- end.
-
- brackets_to_parens(S) ->
- B = iolist_to_binary(S),
- Sz = byte_size(B) - 2,
- <<$[, R:Sz/binary, $]>> = B,
- [$(, R, $)].
-
|