aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src/lib.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src/lib.erl')
-rw-r--r--lib/stdlib/src/lib.erl746
1 files changed, 0 insertions, 746 deletions
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
deleted file mode 100644
index be11e86100..0000000000
--- a/lib/stdlib/src/lib.erl
+++ /dev/null
@@ -1,746 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(lib).
-
--export([flush_receive/0, error_message/2, progname/0, nonl/1, send/2,
- sendw/2, eval_str/1]).
-
--export([extended_parse_exprs/1, extended_parse_term/1,
- subst_values_for_vars/2]).
-
--export([format_exception/6, format_exception/7,
- format_stacktrace/4, format_stacktrace/5,
- format_call/4, format_call/5, format_fun/1, format_fun/2]).
-
--spec flush_receive() -> 'ok'.
-
-flush_receive() ->
- receive
- _Any ->
- flush_receive()
- after
- 0 ->
- ok
- end.
-
-%%
-%% Functions for doing standard system format i/o.
-%%
--spec error_message(Format, Args) -> 'ok' when
- Format :: io:format(),
- Args :: [term()].
-
-error_message(Format, Args) ->
- io:format(<<"** ~ts **\n">>, [io_lib:format(Format, Args)]).
-
-%% Return the name of the script that starts (this) erlang
-%%
--spec progname() -> atom().
-
-progname() ->
- case init:get_argument(progname) of
- {ok, [[Prog]]} ->
- list_to_atom(Prog);
- _Other ->
- no_prog_name
- end.
-
--spec nonl(String1) -> String2 when
- String1 :: string(),
- String2 :: string().
-
-nonl([10]) -> [];
-nonl([]) -> [];
-nonl([H|T]) -> [H|nonl(T)].
-
--spec send(To, Msg) -> Msg when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-send(To, Msg) -> To ! Msg.
-
--spec sendw(To, Msg) -> term() when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-sendw(To, Msg) ->
- To ! {self(), Msg},
- receive
- Reply -> Reply
- end.
-
-%% eval_str(InStr) -> {ok, OutStr} | {error, ErrStr'}
-%% InStr must represent a body
-%% Note: If InStr is a binary it has to be a Latin-1 string.
-%% If you have a UTF-8 encoded binary you have to call
-%% unicode:characters_to_list/1 before the call to eval_str().
-
--define(result(F,D), lists:flatten(io_lib:format(F, D))).
-
--spec eval_str(string() | unicode:latin1_binary()) ->
- {'ok', string()} | {'error', string()}.
-
-eval_str(Str) when is_list(Str) ->
- case erl_scan:tokens([], Str, 0) of
- {more, _} ->
- {error, "Incomplete form (missing .<cr>)??"};
- {done, {ok, Toks, _}, Rest} ->
- case all_white(Rest) of
- true ->
- case erl_parse:parse_exprs(Toks) of
- {ok, Exprs} ->
- case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
- {value, Val, _} ->
- {ok, Val};
- Other ->
- {error, ?result("*** eval: ~p", [Other])}
- end;
- {error, {_Line, Mod, Args}} ->
- Msg = ?result("*** ~ts",[Mod:format_error(Args)]),
- {error, Msg}
- end;
- false ->
- {error, ?result("Non-white space found after "
- "end-of-form :~ts", [Rest])}
- end
- end;
-eval_str(Bin) when is_binary(Bin) ->
- eval_str(binary_to_list(Bin)).
-
-all_white([$\s|T]) -> all_white(T);
-all_white([$\n|T]) -> all_white(T);
-all_white([$\t|T]) -> all_white(T);
-all_white([]) -> true;
-all_white(_) -> false.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%% The annotations of the returned expressions are locations.
-%%
-%% Can handle pids, ports, references, and external funs ("items").
-%% Known items are represented by variables in the erl_parse tree, and
-%% the items themselves are stored in the returned bindings.
-
--spec extended_parse_exprs(Tokens) ->
- {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_exprs(Tokens) ->
- Ts = tokens_fixup(Tokens),
- case erl_parse:parse_exprs(Ts) of
- {ok, Exprs0} ->
- {Exprs, Bs} = expr_fixup(Exprs0),
- {ok, reset_expr_anno(Exprs), Bs};
- _ErrorInfo ->
- erl_parse:parse_exprs(reset_token_anno(Ts))
- end.
-
-tokens_fixup([]) -> [];
-tokens_fixup([T|Ts]=Ts0) ->
- try token_fixup(Ts0) of
- {NewT, NewTs} ->
- [NewT|tokens_fixup(NewTs)]
- catch
- _:_ ->
- [T|tokens_fixup(Ts)]
- end.
-
-token_fixup(Ts) ->
- {AnnoL, NewTs, FixupTag} = unscannable(Ts),
- String = lists:append([erl_anno:text(A) || A <- AnnoL]),
- _ = (fixup_fun(FixupTag))(String),
- NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
- {{string, NewAnno, String}, NewTs}.
-
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
- {'>', A9}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
-unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, pid};
-unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, port};
-unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
-
-expr_fixup(Expr0) ->
- {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
- {Expr, Bs}.
-
-expr_fixup({string,A,S}=T, Bs0, I) ->
- try string_fixup(A, S) of
- Value ->
- Var = new_var(I),
- Bs = erl_eval:add_binding(Var, Value, Bs0),
- {{var, A, Var}, Bs, I+1}
- catch
- _:_ ->
- {T, Bs0, I}
- end;
-expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
- {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
- {list_to_tuple(L), Bs, I};
-expr_fixup([E0|Es0], Bs0, I0) ->
- {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
- {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
- {[E|Es], Bs, I};
-expr_fixup(T, Bs, I) ->
- {T, Bs, I}.
-
-string_fixup(A, S) ->
- Text = erl_anno:text(A),
- FixupTag = fixup_tag(Text, S),
- (fixup_fun(FixupTag))(S).
-
-new_var(I) ->
- list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
-
-reset_token_anno(Tokens) ->
- [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
-
-reset_expr_anno(Exprs) ->
- [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
-
-reset_anno() ->
- fun(A) -> erl_anno:new(erl_anno:location(A)) end.
-
-fixup_fun(function) -> fun function/1;
-fixup_fun(pid) -> fun erlang:list_to_pid/1;
-fixup_fun(port) -> fun erlang:list_to_port/1;
-fixup_fun(reference) -> fun erlang:list_to_ref/1.
-
-function(S) ->
- %% External function.
- {ok, [_, _, _,
- {atom, _, Module}, _,
- {atom, _, Function}, _,
- {integer, _, Arity}|_], _} = erl_scan:string(S),
- erlang:make_fun(Module, Function, Arity).
-
-fixup_text(function) -> "function";
-fixup_text(pid) -> "pid";
-fixup_text(port) -> "port";
-fixup_text(reference) -> "reference".
-
-fixup_tag("function", "#"++_) -> function;
-fixup_tag("pid", "<"++_) -> pid;
-fixup_tag("port", "#"++_) -> port;
-fixup_tag("reference", "#"++_) -> reference.
-
-%%% End of extended_parse_exprs.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%%
-%% Can handle pids, ports, references, and external funs.
-
--spec extended_parse_term(Tokens) ->
- {'ok', Term} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- Term :: term(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_term(Tokens) ->
- case extended_parse_exprs(Tokens) of
- {ok, [Expr], Bindings} ->
- try normalise(Expr, Bindings) of
- Term ->
- {ok, Term}
- catch
- _:_ ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}}
- end;
- {ok, [_,Expr|_], _Bindings} ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}};
- {error, _} = Error ->
- Error
- end.
-
-%% From erl_parse.
-normalise({var, _, V}, Bs) ->
- {value, Value} = erl_eval:binding(V, Bs),
- Value;
-normalise({char,_,C}, _Bs) -> C;
-normalise({integer,_,I}, _Bs) -> I;
-normalise({float,_,F}, _Bs) -> F;
-normalise({atom,_,A}, _Bs) -> A;
-normalise({string,_,S}, _Bs) -> S;
-normalise({nil,_}, _Bs) -> [];
-normalise({bin,_,Fs}, Bs) ->
- {value, B, _} =
- eval_bits:expr_grp(Fs, [],
- fun(E, _) ->
- {value, normalise(E, Bs), []}
- end, [], true),
- B;
-normalise({cons,_,Head,Tail}, Bs) ->
- [normalise(Head, Bs)|normalise(Tail, Bs)];
-normalise({tuple,_,Args}, Bs) ->
- list_to_tuple(normalise_list(Args, Bs));
-normalise({map,_,Pairs}, Bs) ->
- maps:from_list(lists:map(fun
- %% only allow '=>'
- ({map_field_assoc,_,K,V}) ->
- {normalise(K, Bs),normalise(V, Bs)}
- end, Pairs));
-%% Special case for unary +/-.
-normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
-normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
-normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
-normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
-normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
- %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
- fun M:F/A.
-
-normalise_list([H|T], Bs) ->
- [normalise(H, Bs)|normalise_list(T, Bs)];
-normalise_list([], _Bs) ->
- [].
-
-%% To be used on ExprList and Bindings returned from extended_parse_exprs().
-%% Substitute {value, A, Item} for {var, A, ExtendedParseVar}.
-%% {value, A, Item} is a shell/erl_eval convention, and for example
-%% the linter cannot handle it.
-
--spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct().
-
-subst_values_for_vars({var, A, V}=Var, Bs) ->
- case erl_eval:binding(V, Bs) of
- {value, Value} ->
- {value, A, Value};
- unbound ->
- Var
- end;
-subst_values_for_vars(L, Bs) when is_list(L) ->
- [subst_values_for_vars(E, Bs) || E <- L];
-subst_values_for_vars(T, Bs) when is_tuple(T) ->
- list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
-subst_values_for_vars(T, _Bs) ->
- T.
-
-%%% Formatting of exceptions, mfa:s and funs.
-
-%% -> iolist() (no \n at end)
-%% I is the current column, starting from 1 (it will be used
-%% as indentation whenever newline has been inserted);
-%% Class, Reason and StackTrace are the exception;
-%% FormatFun = fun(Term, I) -> iolist() formats terms;
-%% StackFun = fun(Mod, Fun, Arity) -> boolean() is used for trimming the
-%% end of the stack (typically calls to erl_eval are skipped).
-format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun) ->
- format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun,
- latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-%% FormatFun = fun(Term, I) -> iolist() | unicode:charlist().
-format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun, Encoding)
- when is_integer(I), I >= 1, is_function(StackFun, 3),
- is_function(FormatFun, 2) ->
- S = n_spaces(I-1),
- {Term,Trace1,Trace} = analyze_exception(Class, Reason, StackTrace),
- Expl0 = explain_reason(Term, Class, Trace1, FormatFun, S, Encoding),
- FormatString = case Encoding of
- latin1 -> "~s~s";
- _ -> "~s~ts"
- end,
- Expl = io_lib:fwrite(FormatString, [exited(Class), Expl0]),
- case format_stacktrace1(S, Trace, FormatFun, StackFun, Encoding) of
- [] -> Expl;
- Stack -> [Expl, $\n, Stack]
- end.
-
-%% -> iolist() (no \n at end)
-format_stacktrace(I, StackTrace, StackFun, FormatFun) ->
- format_stacktrace(I, StackTrace, StackFun, FormatFun, latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-format_stacktrace(I, StackTrace, StackFun, FormatFun, Encoding)
- when is_integer(I), I >= 1, is_function(StackFun, 3),
- is_function(FormatFun, 2) ->
- S = n_spaces(I-1),
- format_stacktrace1(S, StackTrace, FormatFun, StackFun, Encoding).
-
-%% -> iolist() (no \n at end)
-format_call(I, ForMForFun, As, FormatFun) ->
- format_call(I, ForMForFun, As, FormatFun, latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-format_call(I, ForMForFun, As, FormatFun, Enc)
- when is_integer(I), I >= 1, is_list(As), is_function(FormatFun, 2) ->
- format_call("", n_spaces(I-1), ForMForFun, As, FormatFun, Enc).
-
-%% -> iolist() (no \n at end)
-format_fun(Fun) ->
- format_fun(Fun, latin1).
-
-%% -> iolist() (no \n at end)
-format_fun(Fun, Enc) 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, Enc);
- {type, external} ->
- mfa_to_string(M, F, A, Enc)
- end.
-
-analyze_exception(error, Term, Stack) ->
- case {is_stacktrace(Stack), Stack, Term} of
- {true, [{_,_,As,_}=MFAL|MFAs], function_clause} when is_list(As) ->
- {Term,[MFAL],MFAs};
- {true, [{shell,F,A,_}], function_clause} when is_integer(A) ->
- {Term, [{F,A}], []};
- {true, [{_,_,_,_}=MFAL|MFAs], undef} ->
- {Term,[MFAL],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,I}|Fs])
- when is_atom(M), is_atom(F), is_integer(A), is_list(I) ->
- is_stacktrace(Fs);
-is_stacktrace([{M,F,As,I}|Fs])
- when is_atom(M), is_atom(F), length(As) >= 0, is_list(I) ->
- is_stacktrace(Fs);
-is_stacktrace(_) ->
- false.
-
-%% ERTS exit codes (some of them are also returned by erl_eval):
-explain_reason(badarg, error, [], _PF, _S, _Enc) ->
- <<"bad argument">>;
-explain_reason({badarg,V}, error=Cl, [], PF, S, _Enc) -> % orelse, andalso
- format_value(V, <<"bad argument: ">>, Cl, PF, S);
-explain_reason(badarith, error, [], _PF, _S, _Enc) ->
- <<"an error occurred when evaluating an arithmetic expression">>;
-explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, Enc)
- when is_function(Fun) ->
- %% Only the arity is displayed, not the arguments As.
- io_lib:fwrite(<<"~ts called with ~s">>,
- [format_fun(Fun, Enc), argss(length(As))]);
-explain_reason({badfun,Term}, error=Cl, [], PF, S, _Enc) ->
- format_value(Term, <<"bad function ">>, Cl, PF, S);
-explain_reason({badmatch,Term}, error=Cl, [], PF, S, _Enc) ->
- Str = <<"no match of right hand side value ">>,
- format_value(Term, Str, Cl, PF, S);
-explain_reason({case_clause,V}, error=Cl, [], PF, S, _Enc) ->
- %% "there is no case clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no case clause matching ">>, Cl, PF, S);
-explain_reason(function_clause, error, [{F,A}], _PF, _S, _Enc) ->
- %% 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,Loc}], PF, S, Enc) ->
- Str = <<"no function clause matching ">>,
- [format_errstr_call(Str, Cl, {M,F}, As, PF, S, Enc),$\s|location(Loc)];
-explain_reason(if_clause, error, [], _PF, _S, _Enc) ->
- <<"no true branch found when evaluating an if expression">>;
-explain_reason(noproc, error, [], _PF, _S, _Enc) ->
- <<"no such process or port">>;
-explain_reason(notalive, error, [], _PF, _S, _Enc) ->
- <<"the node cannot be part of a distributed system">>;
-explain_reason(system_limit, error, [], _PF, _S, _Enc) ->
- <<"a system limit has been reached">>;
-explain_reason(timeout_value, error, [], _PF, _S, _Enc) ->
- <<"bad receive timeout value">>;
-explain_reason({try_clause,V}, error=Cl, [], PF, S, _Enc) ->
- %% "there is no try clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no try clause matching ">>, Cl, PF, S);
-explain_reason(undef, error, [{M,F,A,_}], _PF, _S, Enc) ->
- %% Only the arity is displayed, not the arguments, if there are any.
- io_lib:fwrite(<<"undefined function ~ts">>,
- [mfa_to_string(M, F, n_args(A), Enc)]);
-explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, Enc) ->
- %% Give nicer reports for undefined shell functions
- %% (but not when the user actively calls shell_default:F(...)).
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"undefined shell command ~ts/~w">>, [FS, n_args(A)]);
-%% Exit codes returned by erl_eval only:
-explain_reason({argument_limit,_Fun}, error, [], _PF, _S, _Enc) ->
- io_lib:fwrite(<<"limit of number of arguments to interpreted function"
- " exceeded">>, []);
-explain_reason({bad_filter,V}, error=Cl, [], PF, S, _Enc) ->
- format_value(V, <<"bad filter ">>, Cl, PF, S);
-explain_reason({bad_generator,V}, error=Cl, [], PF, S, _Enc) ->
- format_value(V, <<"bad generator ">>, Cl, PF, S);
-explain_reason({unbound,V}, error, [], _PF, _S, _Enc) ->
- 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, S, _Enc) ->
- Str = <<"restricted shell module returned bad value ">>,
- format_value(V, Str, Cl, PF, S);
-explain_reason({restricted_shell_disallowed,{ForMF,As}},
- exit=Cl, [], PF, S, Enc) ->
- %% ForMF can be a fun, but not a shell fun.
- Str = <<"restricted shell does not allow ">>,
- format_errstr_call(Str, Cl, ForMF, As, PF, S, Enc);
-explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc) ->
- <<"restricted shell starts now">>;
-explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc) ->
- <<"restricted shell stopped">>;
-%% Other exit code:
-explain_reason(Reason, Class, [], PF, S, _Enc) ->
- PF(Reason, (iolist_size(S)+1) + exited_size(Class)).
-
-n_args(A) when is_integer(A) ->
- A;
-n_args(As) when is_list(As) ->
- length(As).
-
-argss(0) ->
- <<"no arguments">>;
-argss(1) ->
- <<"one argument">>;
-argss(2) ->
- <<"two arguments">>;
-argss(I) ->
- io_lib:fwrite(<<"~w arguments">>, [I]).
-
-format_stacktrace1(S0, Stack0, PF, SF, Enc) ->
- 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, Enc).
-
-format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~ts ~ts">>,
- [sep(N, S), origin(N, M, F, A),
- mfa_to_string(M, F, A, Enc),
- location(L)])
- | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
-format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF, Enc) when is_list(As) ->
- A = length(As),
- CalledAs = [S,<<" called as ">>],
- C = format_call("", CalledAs, {M,F}, As, PF, Enc),
- [io_lib:fwrite(<<"~s~s ~ts\n~s~ts">>,
- [sep(N, S), origin(N, M, F, A),
- mfa_to_string(M, F, A, Enc),
- CalledAs, C])
- | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
-format_stacktrace2(_S, [], _N, _PF, _Enc) ->
- "".
-
-location(L) ->
- File = proplists:get_value(file, L),
- Line = proplists:get_value(line, L),
- if
- File =/= undefined, Line =/= undefined ->
- io_lib:format("(~ts, line ~w)", [File, Line]);
- true ->
- ""
- end.
-
-sep(1, S) -> S;
-sep(_, S) -> [$\n | S].
-
-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">>.
-
-format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0, Enc) ->
- Pre1 = [Pre0 | n_spaces(exited_size(Class))],
- format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc).
-
-format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc) ->
- Arity = length(As),
- [ErrStr |
- case is_op(ForMForFun, Arity) of
- {yes,Op} ->
- format_op(ErrStr, Pre1, Op, As, PF, Enc);
- no ->
- MFs = mf_to_string(ForMForFun, Arity, Enc),
- I1 = string:length([Pre1,ErrStr|MFs]),
- S1 = pp_arguments(PF, As, I1, Enc),
- S2 = pp_arguments(PF, As, string:length([Pre1|MFs]), Enc),
- Long = count_nl(pp_arguments(PF, [a2345,b2345], I1, Enc)) > 0,
- case Long or (count_nl(S2) < count_nl(S1)) of
- true ->
- [$\n, Pre1, MFs, S2];
- false ->
- [MFs, S1]
- end
- end].
-
-format_op(ErrStr, Pre, Op, [A1], PF, _Enc) ->
- OpS = io_lib:fwrite(<<"~s ">>, [Op]),
- I1 = iolist_size([ErrStr,Pre,OpS]),
- [OpS | PF(A1, I1+1)];
-format_op(ErrStr, Pre, Op, [A1, A2], PF, Enc) ->
- 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]),
- Size1 = iolist_size([ErrStr,Pre|OpS2]),
- {Size2,S1_2} = size(Enc, S1),
- S2_2 = PF(A2, Size1+Size2+1),
- case count_nl(S2) < count_nl(S2_2) of
- true ->
- [S1_2,Pre1,OpS,Pre1|S2];
- false ->
- [S1_2,OpS2|S2_2]
- end
- end.
-
-pp_arguments(PF, As, I, Enc) ->
- case {As, printable_list(Enc, As)} of
- {[Int | T], true} ->
- L = integer_to_list(Int),
- Ll = length(L),
- A = list_to_atom(lists:duplicate(Ll, $a)),
- S0 = unicode:characters_to_list(PF([A | T], I+1), Enc),
- brackets_to_parens([$[,L,string:sub_string(S0, 2+Ll)], Enc);
- _ ->
- brackets_to_parens(PF(As, I+1), Enc)
- end.
-
-brackets_to_parens(S, Enc) ->
- B = unicode:characters_to_binary(S, Enc),
- Sz = byte_size(B) - 2,
- <<$[,R:Sz/binary,$]>> = B,
- [$(,R,$)].
-
-printable_list(latin1, As) ->
- io_lib:printable_latin1_list(As);
-printable_list(_, As) ->
- io_lib:printable_list(As).
-
-mfa_to_string(M, F, A, Enc) ->
- io_lib:fwrite(<<"~ts/~w">>, [mf_to_string({M, F}, A, Enc), A]).
-
-mf_to_string({M, F}, A, Enc) ->
- 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 ->
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"~w:~ts">>, [M, FS])
- end
- end;
-mf_to_string(Fun, _A, Enc) when is_function(Fun) ->
- format_fun(Fun, Enc);
-mf_to_string(F, _A, Enc) ->
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"~ts">>, [FS]).
-
-format_value(V, ErrStr, Class, PF, S) ->
- Pre1Sz = exited_size(Class),
- S1 = PF(V, Pre1Sz + iolist_size([S, ErrStr])+1),
- [ErrStr | case count_nl(S1) of
- N1 when N1 > 1 ->
- S2 = PF(V, iolist_size(S) + 1 + Pre1Sz),
- case count_nl(S2) < N1 of
- true ->
- [$\n, S, n_spaces(Pre1Sz) | S2];
- false ->
- S1
- end;
- _ ->
- S1
- end].
-
-%% Handles deep lists, but not all iolists.
-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.
-
-n_spaces(N) ->
- lists:duplicate(N, $\s).
-
-is_op(ForMForFun, A) ->
- try
- {erlang,F} = ForMForFun,
- _ = erl_internal:op_type(F, A),
- {yes,F}
- catch error:_ -> no
- end.
-
-exited_size(Class) ->
- iolist_size(exited(Class)).
-
-exited(error) ->
- <<"exception error: ">>;
-exited(exit) ->
- <<"exception exit: ">>;
-exited(throw) ->
- <<"exception throw: ">>.
-
-to_string(A, latin1) ->
- io_lib:write_atom_as_latin1(A);
-to_string(A, _) ->
- io_lib:write_atom(A).
-
-size(latin1, S) ->
- {iolist_size(S),S};
-size(_, S0) ->
- S = unicode:characters_to_list(S0, unicode),
- true = is_list(S),
- {string:length(S),S}.