rewrite from lager
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

393 行
13 KiB

4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
  1. -module(rumStdlib).
  2. -compile(inline).
  3. -compile({inline_size, 128}).
  4. -export([
  5. isErrorReport/1,
  6. is_my_info_report/1
  7. ]).
  8. -export([sup_get/2]).
  9. -export([proc_lib_format/2]).
  10. %% From OTP sasl's sasl_report.erl ... These functions aren't
  11. %% exported.
  12. -spec isErrorReport(atom()) -> boolean().
  13. isErrorReport(supervisor_report) -> true;
  14. isErrorReport(crash_report) -> true;
  15. isErrorReport(_) -> false.
  16. -spec is_my_info_report(atom()) -> boolean().
  17. is_my_info_report(progress) -> true;
  18. is_my_info_report(_) -> false.
  19. -spec sup_get(term(), [proplists:property()]) -> term().
  20. sup_get(Tag, Report) ->
  21. case lists:keysearch(Tag, 1, Report) of
  22. {value, {_, Value}} ->
  23. Value;
  24. _ ->
  25. ""
  26. end.
  27. %% From OTP stdlib's proc_lib.erl ... These functions aren't exported.
  28. -spec proc_lib_format([term()], pos_integer()) -> string().
  29. proc_lib_format([OwnReport, LinkReport], FmtMaxBytes) ->
  30. OwnFormat = format_report(OwnReport, FmtMaxBytes),
  31. LinkFormat = format_report(LinkReport, FmtMaxBytes),
  32. %% io_lib:format here is OK because we're limiting max length elsewhere.
  33. Str = io_lib:format(" crasher:~n~s neighbours:~n~s", [OwnFormat, LinkFormat]),
  34. lists:flatten(Str).
  35. format_report(Rep, FmtMaxBytes) when is_list(Rep) ->
  36. format_rep(Rep, FmtMaxBytes);
  37. format_report(Rep, FmtMaxBytes) ->
  38. eFmt:formatBin(<<"~p~n">>, [Rep], [{charsLimit, FmtMaxBytes}]).
  39. format_rep([{initial_call, InitialCall} | Rep], FmtMaxBytes) ->
  40. [format_mfa(InitialCall, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
  41. format_rep([{error_info, {Class, Reason, StackTrace}} | Rep], FmtMaxBytes) ->
  42. [format_exception(Class, Reason, StackTrace, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
  43. format_rep([{Tag, Data} | Rep], FmtMaxBytes) ->
  44. [format_tag(Tag, Data, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
  45. format_rep(_, _S) ->
  46. [].
  47. format_exception(Class, Reason, StackTrace, FmtMaxBytes) ->
  48. PF = pp_fun(FmtMaxBytes),
  49. StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
  50. %% EI = " exception: ",
  51. EI = " ",
  52. [EI, lib_format_exception(1 + length(EI), Class, Reason,
  53. StackTrace, StackFun, PF), "\n"].
  54. format_mfa({M, F, Args} = StartF, FmtMaxBytes) ->
  55. try
  56. A = length(Args),
  57. [" initial call: ", atom_to_list(M), $:, atom_to_list(F), $/,
  58. integer_to_list(A), "\n"]
  59. catch
  60. error:_ ->
  61. format_tag(initial_call, StartF, FmtMaxBytes)
  62. end.
  63. pp_fun(FmtMaxBytes) ->
  64. fun(Term, _I) ->
  65. eFmt:formatBin(<<"~p">>, [Term], [{charsLimit ,FmtMaxBytes}])
  66. end.
  67. format_tag(Tag, Data, FmtMaxBytes) ->
  68. eFmt:formatBin(<<"~p: ~p~n">>, [Tag, Data], [{charsLimit ,FmtMaxBytes}]).
  69. %% From OTP stdlib's lib.erl ... These functions aren't exported.
  70. lib_format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun)
  71. when is_integer(I), I >= 1, is_function(StackFun, 3),
  72. is_function(FormatFun, 2) ->
  73. Str = n_spaces(I - 1),
  74. {Term, Trace1, Trace} = analyze_exception(Class, Reason, StackTrace),
  75. Expl0 = explain_reason(Term, Class, Trace1, FormatFun, Str),
  76. Expl = io_lib:fwrite(<<"~s~s">>, [exited(Class), Expl0]),
  77. case format_stacktrace1(Str, Trace, FormatFun, StackFun) of
  78. [] -> Expl;
  79. Stack -> [Expl, $\n, Stack]
  80. end.
  81. analyze_exception(error, Term, Stack) ->
  82. case {is_stacktrace(Stack), Stack, Term} of
  83. {true, [{_M, _F, As} = MFA | MFAs], function_clause} when is_list(As) ->
  84. {Term, [MFA], MFAs};
  85. {true, [{shell, F, A}], function_clause} when is_integer(A) ->
  86. {Term, [{F, A}], []};
  87. {true, [{_M, _F, _AorAs} = MFA | MFAs], undef} ->
  88. {Term, [MFA], MFAs};
  89. {true, _, _} ->
  90. {Term, [], Stack};
  91. {false, _, _} ->
  92. {{Term, Stack}, [], []}
  93. end;
  94. analyze_exception(_Class, Term, Stack) ->
  95. case is_stacktrace(Stack) of
  96. true ->
  97. {Term, [], Stack};
  98. false ->
  99. {{Term, Stack}, [], []}
  100. end.
  101. is_stacktrace([]) ->
  102. true;
  103. is_stacktrace([{M, F, A} | Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
  104. is_stacktrace(Fs);
  105. is_stacktrace([{M, F, As} | Fs]) when is_atom(M), is_atom(F), length(As) >= 0 ->
  106. is_stacktrace(Fs);
  107. is_stacktrace(_) ->
  108. false.
  109. %% ERTS exit codes (some of them are also returned by erl_eval):
  110. explain_reason(badarg, error, [], _PF, _Str) ->
  111. <<"bad argument">>;
  112. explain_reason({badarg, V}, error = Cl, [], PF, Str) -> % orelse, andalso
  113. format_value(V, <<"bad argument: ">>, Cl, PF, Str);
  114. explain_reason(badarith, error, [], _PF, _Str) ->
  115. <<"bad argument in an arithmetic expression">>;
  116. explain_reason({badarity, {Fun, As}}, error, [], _PF, _Str)
  117. when is_function(Fun) ->
  118. %% Only the arity is displayed, not the arguments As.
  119. io_lib:fwrite(<<"~s called with ~s">>,
  120. [format_fun(Fun), argss(length(As))]);
  121. explain_reason({badfun, Term}, error = Cl, [], PF, Str) ->
  122. format_value(Term, <<"bad function ">>, Cl, PF, Str);
  123. explain_reason({badmatch, Term}, error = Cl, [], PF, Str) ->
  124. format_value(Term, <<"no match of right hand side value ">>, Cl, PF, Str);
  125. explain_reason({case_clause, V}, error = Cl, [], PF, Str) ->
  126. %% "there is no case clause with a true guard sequence and a
  127. %% pattern matching..."
  128. format_value(V, <<"no case clause matching ">>, Cl, PF, Str);
  129. explain_reason(function_clause, error, [{F, A}], _PF, _Str) ->
  130. %% Shell commands
  131. FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
  132. [<<"no function clause matching call to ">> | FAs];
  133. explain_reason(function_clause, error = Cl, [{M, F, As}], PF, Str) ->
  134. String = <<"no function clause matching ">>,
  135. format_errstr_call(String, Cl, {M, F}, As, PF, Str);
  136. explain_reason(if_clause, error, [], _PF, _Str) ->
  137. <<"no true branch found when evaluating an if expression">>;
  138. explain_reason(noproc, error, [], _PF, _Str) ->
  139. <<"no such process or port">>;
  140. explain_reason(notalive, error, [], _PF, _Str) ->
  141. <<"the node cannot be part of a distributed system">>;
  142. explain_reason(system_limit, error, [], _PF, _Str) ->
  143. <<"a system limit has been reached">>;
  144. explain_reason(timeout_value, error, [], _PF, _Str) ->
  145. <<"bad receive timeout value">>;
  146. explain_reason({try_clause, V}, error = Cl, [], PF, Str) ->
  147. %% "there is no try clause with a true guard sequence and a
  148. %% pattern matching..."
  149. format_value(V, <<"no try clause matching ">>, Cl, PF, Str);
  150. explain_reason(undef, error, [{M, F, A}], _PF, _Str) ->
  151. %% Only the arity is displayed, not the arguments, if there are any.
  152. io_lib:fwrite(<<"undefined function ~s">>,
  153. [mfa_to_string(M, F, n_args(A))]);
  154. explain_reason({shell_undef, F, A}, error, [], _PF, _Str) ->
  155. %% Give nicer reports for undefined shell functions
  156. %% (but not when the user actively calls shell_default:F(...)).
  157. io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]);
  158. %% Exit codes returned by erl_eval only:
  159. explain_reason({argument_limit, _Fun}, error, [], _PF, _Str) ->
  160. io_lib:fwrite(<<"limit of number of arguments to interpreted function"
  161. " exceeded">>, []);
  162. explain_reason({bad_filter, V}, error = Cl, [], PF, Str) ->
  163. format_value(V, <<"bad filter ">>, Cl, PF, Str);
  164. explain_reason({bad_generator, V}, error = Cl, [], PF, Str) ->
  165. format_value(V, <<"bad generator ">>, Cl, PF, Str);
  166. explain_reason({unbound, V}, error, [], _PF, _Str) ->
  167. io_lib:fwrite(<<"variable ~w is unbound">>, [V]);
  168. %% Exit codes local to the shell module (restricted shell):
  169. explain_reason({restricted_shell_bad_return, V}, exit = Cl, [], PF, Str) ->
  170. String = <<"restricted shell module returned bad value ">>,
  171. format_value(V, String, Cl, PF, Str);
  172. explain_reason({restricted_shell_disallowed, {ForMF, As}},
  173. exit = Cl, [], PF, Str) ->
  174. %% ForMF can be a fun, but not a shell fun.
  175. String = <<"restricted shell does not allow ">>,
  176. format_errstr_call(String, Cl, ForMF, As, PF, Str);
  177. explain_reason(restricted_shell_started, exit, [], _PF, _Str) ->
  178. <<"restricted shell starts now">>;
  179. explain_reason(restricted_shell_stopped, exit, [], _PF, _Str) ->
  180. <<"restricted shell stopped">>;
  181. %% Other exit code:
  182. explain_reason(Reason, Class, [], PF, Str) ->
  183. PF(Reason, (iolist_size(Str) + 1) + exited_size(Class)).
  184. n_spaces(N) ->
  185. lists:duplicate(N, $\s).
  186. exited_size(Class) ->
  187. iolist_size(exited(Class)).
  188. exited(error) ->
  189. <<"exception error: ">>;
  190. exited(exit) ->
  191. <<"exception exit: ">>;
  192. exited(throw) ->
  193. <<"exception throw: ">>.
  194. format_stacktrace1(S0, Stack0, PF, SF) ->
  195. Stack1 = lists:dropwhile(fun({M, F, A}) -> SF(M, F, A)
  196. end, lists:reverse(Stack0)),
  197. S = [" " | S0],
  198. Stack = lists:reverse(Stack1),
  199. format_stacktrace2(S, Stack, 1, PF).
  200. format_stacktrace2(S, [{M, F, A} | Fs], N, PF) when is_integer(A) ->
  201. [io_lib:fwrite(<<"~s~s ~s">>,
  202. [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A)])
  203. | format_stacktrace2(S, Fs, N + 1, PF)];
  204. format_stacktrace2(S, [{M, F, As} | Fs], N, PF) when is_list(As) ->
  205. A = length(As),
  206. CalledAs = [S, <<" called as ">>],
  207. C = format_call("", CalledAs, {M, F}, As, PF),
  208. [io_lib:fwrite(<<"~s~s ~s\n~s~s">>,
  209. [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A),
  210. CalledAs, C])
  211. | format_stacktrace2(S, Fs, N + 1, PF)];
  212. format_stacktrace2(_S, [], _N, _PF) ->
  213. "".
  214. argss(0) ->
  215. <<"no arguments">>;
  216. argss(1) ->
  217. <<"one argument">>;
  218. argss(2) ->
  219. <<"two arguments">>;
  220. argss(I) ->
  221. io_lib:fwrite(<<"~w arguments">>, [I]).
  222. format_value(V, ErrStr, Class, PF, Str) ->
  223. Pre1Sz = exited_size(Class),
  224. Str1 = PF(V, Pre1Sz + iolist_size([Str, ErrStr]) + 1),
  225. [ErrStr | case count_nl(Str1) of
  226. N1 when N1 > 1 ->
  227. Str2 = PF(V, iolist_size(Str) + 1 + Pre1Sz),
  228. case count_nl(Str2) < N1 of
  229. true ->
  230. [$\n, Str, n_spaces(Pre1Sz) | Str2];
  231. false ->
  232. Str1
  233. end;
  234. _ ->
  235. Str1
  236. end].
  237. format_fun(Fun) when is_function(Fun) ->
  238. {module, M} = erlang:fun_info(Fun, module),
  239. {name, F} = erlang:fun_info(Fun, name),
  240. {arity, A} = erlang:fun_info(Fun, arity),
  241. case erlang:fun_info(Fun, type) of
  242. {type, local} when F =:= "" ->
  243. io_lib:fwrite(<<"~w">>, [Fun]);
  244. {type, local} when M =:= erl_eval ->
  245. io_lib:fwrite(<<"interpreted function with arity ~w">>, [A]);
  246. {type, local} ->
  247. mfa_to_string(M, F, A);
  248. {type, external} ->
  249. mfa_to_string(M, F, A)
  250. end.
  251. format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0) ->
  252. Pre1 = [Pre0 | n_spaces(exited_size(Class))],
  253. format_call(ErrStr, Pre1, ForMForFun, As, PF).
  254. format_call(ErrStr, Pre1, ForMForFun, As, PF) ->
  255. Arity = length(As),
  256. [ErrStr |
  257. case is_op(ForMForFun, Arity) of
  258. {yes, Op} ->
  259. format_op(ErrStr, Pre1, Op, As, PF);
  260. no ->
  261. MFs = mf_to_string(ForMForFun, Arity),
  262. I1 = iolist_size([Pre1, ErrStr | MFs]),
  263. S1 = pp_arguments(PF, As, I1),
  264. S2 = pp_arguments(PF, As, iolist_size([Pre1 | MFs])),
  265. Long = count_nl(pp_arguments(PF, [a2345, b2345], I1)) > 0,
  266. case Long or (count_nl(S2) < count_nl(S1)) of
  267. true ->
  268. [$\n, Pre1, MFs, S2];
  269. false ->
  270. [MFs, S1]
  271. end
  272. end].
  273. mfa_to_string(M, F, A) ->
  274. io_lib:fwrite(<<"~s/~w">>, [mf_to_string({M, F}, A), A]).
  275. mf_to_string({M, F}, A) ->
  276. case erl_internal:bif(M, F, A) of
  277. true ->
  278. io_lib:fwrite(<<"~w">>, [F]);
  279. false ->
  280. case is_op({M, F}, A) of
  281. {yes, '/'} ->
  282. io_lib:fwrite(<<"~w">>, [F]);
  283. {yes, F} ->
  284. atom_to_list(F);
  285. no ->
  286. io_lib:fwrite(<<"~w:~w">>, [M, F])
  287. end
  288. end;
  289. mf_to_string(Fun, _A) when is_function(Fun) ->
  290. format_fun(Fun);
  291. mf_to_string(F, _A) ->
  292. io_lib:fwrite(<<"~w">>, [F]).
  293. n_args(A) when is_integer(A) ->
  294. A;
  295. n_args(As) when is_list(As) ->
  296. length(As).
  297. origin(1, M, F, A) ->
  298. case is_op({M, F}, n_args(A)) of
  299. {yes, F} -> <<"in operator ">>;
  300. no -> <<"in function ">>
  301. end;
  302. origin(_N, _M, _F, _A) ->
  303. <<"in call from">>.
  304. sep(1, S) -> S;
  305. sep(_, S) -> [$\n | S].
  306. count_nl([E | Es]) ->
  307. count_nl(E) + count_nl(Es);
  308. count_nl($\n) ->
  309. 1;
  310. count_nl(Bin) when is_binary(Bin) ->
  311. count_nl(binary_to_list(Bin));
  312. count_nl(_) ->
  313. 0.
  314. is_op(ForMForFun, A) ->
  315. try
  316. {erlang, F} = ForMForFun,
  317. _ = erl_internal:op_type(F, A),
  318. {yes, F}
  319. catch error:_ -> no
  320. end.
  321. format_op(ErrStr, Pre, Op, [A1, A2], PF) ->
  322. I1 = iolist_size([ErrStr, Pre]),
  323. S1 = PF(A1, I1 + 1),
  324. S2 = PF(A2, I1 + 1),
  325. OpS = atom_to_list(Op),
  326. Pre1 = [$\n | n_spaces(I1)],
  327. case count_nl(S1) > 0 of
  328. true ->
  329. [S1, Pre1, OpS, Pre1 | S2];
  330. false ->
  331. OpS2 = io_lib:fwrite(<<" ~s ">>, [Op]),
  332. S2_2 = PF(A2, iolist_size([ErrStr, Pre, S1 | OpS2]) + 1),
  333. case count_nl(S2) < count_nl(S2_2) of
  334. true ->
  335. [S1, Pre1, OpS, Pre1 | S2];
  336. false ->
  337. [S1, OpS2 | S2_2]
  338. end
  339. end.
  340. pp_arguments(PF, As, I) ->
  341. case {As, io_lib:printable_list(As)} of
  342. {[Int | T], true} ->
  343. L = integer_to_list(Int),
  344. Ll = length(L),
  345. A = list_to_atom(lists:duplicate(Ll, $a)),
  346. S0 = binary_to_list(iolist_to_binary(PF([A | T], I + 1))),
  347. brackets_to_parens([$[, L, string:sub_string(S0, 2 + Ll)]);
  348. _ ->
  349. brackets_to_parens(PF(As, I + 1))
  350. end.
  351. brackets_to_parens(S) ->
  352. B = iolist_to_binary(S),
  353. Sz = byte_size(B) - 2,
  354. <<$[, R:Sz/binary, $]>> = B,
  355. [$(, R, $)].