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 роки тому
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 роки тому
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, $)].