1%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
2%% --------------------------------------------------
3%% This file is provided to you under the Apache License,
4%% Version 2.0 (the "License"); you may not use this file
5%% except in compliance with the License.  You may obtain
6%% a copy of the License at
7%%
8%%   http://www.apache.org/licenses/LICENSE-2.0
9%%
10%% Unless required by applicable law or agreed to in writing,
11%% software distributed under the License is distributed on an
12%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13%% KIND, either express or implied.  See the License for the
14%% specific language governing permissions and limitations
15%% under the License.
16%% --------------------------------------------------
17%% File    : parse_trans.erl
18%% @author  : Ulf Wiger <ulf@wiger.net>
19%% @end
20%% Description :
21%%
22%% Created : 13 Feb 2006 by Ulf Wiger <ulf@wiger.net> (then Ericsson)
23%%%-------------------------------------------------------------------
24
25%% @doc Generic parse transform library for Erlang.
26%%
27%% <p>...</p>
28%%
29%% @end
30
31-module(parse_trans).
32
33-export([plain_transform/2]).
34
35-export([
36         inspect/4,
37         transform/4,
38         depth_first/4,
39         revert/1,
40         revert_form/1,
41         format_exception/2, format_exception/3,
42         return/2
43        ]).
44
45-export([
46         error/3,
47         format_error/1
48        ]).
49
50-export([
51         initial_context/2,
52         do_inspect/4,
53         do_transform/4,
54         do_depth_first/4,
55         top/3
56        ]).
57
58-export([do_insert_forms/4,
59         replace_function/4,
60         replace_function/5,
61         export_function/3]).
62
63-export([
64         context/2,
65         get_pos/1,
66         get_file/1,
67         get_module/1,
68         get_attribute/2,
69         get_attribute/3,
70         get_orig_syntax_tree/1,
71         function_exists/3,
72         optionally_pretty_print/3,
73         pp_src/2,
74         pp_beam/1, pp_beam/2
75        ]).
76
77-import(erl_syntax, [atom_value/1,
78                     attribute_name/1,
79                     attribute_arguments/1,
80                     string_value/1,
81                     type/1
82                    ]).
83
84-record(context, {module,
85                  function,
86                  arity,
87                  file,
88                  options}).
89
90%% Useful macros for debugging and error reporting
91-define(HERE, {?MODULE, ?LINE}).
92
93-define(DUMMY_LINE, 9999).
94
95-define(ERROR(R, F, I, Trace),
96        begin
97            rpt_error(R, F, I, Trace),
98            throw({error,get_pos(I),{R, Trace}})
99        end).
100
101-ifdef(OTP_RELEASE).
102-define(WITH_STACKTRACE(T, R, S), T:R:S ->).
103-else.
104-define(WITH_STACKTRACE(T, R, S), T:R -> S = erlang:get_stacktrace(),).
105-endif.
106
107-export_type([forms/0]).
108
109%% Typedefs
110-type form()    :: any().
111-type forms()   :: [form()].
112-type options() :: [{atom(), any()}].
113-type type()    :: atom().
114-type xform_f_rec() :: fun((type(), form(), #context{}, Acc) ->
115                                  {form(), boolean(), Acc}
116                                      | {forms(), form(), forms(), boolean(), Acc}).
117-type xform_f_df() :: fun((type(), form(), #context{}, Acc) ->
118                                 {form(), Acc}
119                                     | {forms(), form(), forms(), Acc}).
120-type insp_f()  :: fun((type(), form(), #context{}, A) -> {boolean(), A}).
121
122
123%%% @spec (Reason, Form, Info) -> throw()
124%%% Info = [{Key,Value}]
125%%%
126%%% @doc
127%%% <p>Used to report errors detected during the parse transform.</p>
128%%% @end
129%%%
130-spec error(string(), any(), [{any(),any()}]) ->
131    none().
132error(R, _F, I) ->
133    ST = erlang:process_info(self(), current_stacktrace),
134    % rpt_error(R, F, I, ST),
135    throw({error,get_pos(I),{R, ST}}).
136
137%% @spec plain_transform(Fun, Forms) -> forms()
138%% Fun = function()
139%% Forms = forms()
140%%
141%% @doc
142%% Performs a transform of `Forms' using the fun `Fun(Form)'. `Form' is always
143%% an Erlang abstract form, i.e. it is not converted to syntax_tools
144%% representation. The intention of this transform is for the fun to have a
145%% catch-all clause returning `continue'. This will ensure that it stays robust
146%% against additions to the language.
147%%
148%% `Fun(Form)' must return either of the following:
149%%
150%% * `NewForm' - any valid form
151%% * `continue' - dig into the sub-expressions of the form
152%% * `{done, NewForm}' - Replace `Form' with `NewForm'; return all following
153%%   forms unchanged
154%% * `{error, Reason}' - Abort transformation with an error message.
155%%
156%% Example - This transform fun would convert all instances of `P ! Msg' to
157%% `gproc:send(P, Msg)':
158%% <pre>
159%% parse_transform(Forms, _Options) -&gt;
160%%     parse_trans:plain_transform(fun do_transform/1, Forms).
161%%
162%% do_transform({'op', L, '!', Lhs, Rhs}) -&gt;
163%%      [NewLhs] = parse_trans:plain_transform(fun do_transform/1, [Lhs]),
164%%      [NewRhs] = parse_trans:plain_transform(fun do_transform/1, [Rhs]),
165%%     {call, L, {remote, L, {atom, L, gproc}, {atom, L, send}},
166%%      [NewLhs, NewRhs]};
167%% do_transform(_) -&gt;
168%%     continue.
169%% </pre>
170%% @end
171%%
172plain_transform(Fun, Forms) when is_function(Fun, 1), is_list(Forms) ->
173    plain_transform1(Fun, Forms).
174
175plain_transform1(_, []) ->
176    [];
177plain_transform1(Fun, [F|Fs]) when is_atom(element(1,F)) ->
178    case Fun(F) of
179        skip ->
180            plain_transform1(Fun, Fs);
181        continue ->
182            [list_to_tuple(plain_transform1(Fun, tuple_to_list(F))) |
183             plain_transform1(Fun, Fs)];
184        {done, NewF} ->
185            [NewF | Fs];
186        {error, Reason} ->
187            error(Reason, F, [{form, F}]);
188        NewF when is_tuple(NewF) ->
189            [NewF | plain_transform1(Fun, Fs)]
190    end;
191plain_transform1(Fun, [L|Fs]) when is_list(L) ->
192    [plain_transform1(Fun, L) | plain_transform1(Fun, Fs)];
193plain_transform1(Fun, [F|Fs]) ->
194    [F | plain_transform1(Fun, Fs)];
195plain_transform1(_, F) ->
196    F.
197
198
199%% @spec (list()) -> integer()
200%%
201%% @doc
202%% Tries to retrieve the line number from an erl_syntax form. Returns a
203%% (very high) dummy number if not successful.
204%% @end
205%%
206-spec get_pos(list()) ->
207    integer().
208get_pos(I) when is_list(I) ->
209    case proplists:get_value(form, I) of
210        undefined ->
211            ?DUMMY_LINE;
212        Form ->
213            erl_syntax:get_pos(Form)
214    end.
215
216
217%%% @spec (Forms) -> string()
218%%% @doc
219%%% Returns the name of the file being compiled.
220%%% @end
221%%%
222-spec get_file(forms()) ->
223    string().
224get_file(Forms) ->
225    string_value(hd(get_attribute(file, Forms, [erl_syntax:string("undefined")]))).
226
227
228
229%%% @spec (Forms) -> atom()
230%%% @doc
231%%% Returns the name of the module being compiled.
232%%% @end
233%%%
234-spec get_module([any()]) ->
235    atom().
236get_module(Forms) ->
237    atom_value(hd(get_attribute(module, Forms, [erl_syntax:atom(undefined)]))).
238
239
240
241%%% @spec (A, Forms) -> any()
242%%% A = atom()
243%%%
244%%% @doc
245%%% Returns the value of the first occurence of attribute A.
246%%% @end
247%%%
248-spec get_attribute(atom(), [any()]) ->
249                           'none' | [erl_syntax:syntaxTree()].
250%%
251get_attribute(A, Forms) -> get_attribute(A,Forms,[erl_syntax:atom(undefined)]).
252get_attribute(A, Forms, Undef) ->
253    case find_attribute(A, Forms) of
254        false ->
255            Undef;
256        Other ->
257            Other
258    end.
259
260find_attribute(A, [F|Forms]) ->
261    case type(F) == attribute
262        andalso atom_value(attribute_name(F)) == A of
263        true ->
264            attribute_arguments(F);
265        false ->
266            find_attribute(A, Forms)
267    end;
268find_attribute(_, []) ->
269    false.
270
271%% @spec (Fname::atom(), Arity::integer(), Forms) -> boolean()
272%%
273%% @doc
274%% Checks whether the given function is defined in Forms.
275%% @end
276%%
277-spec function_exists(atom(), integer(), forms()) ->
278    boolean().
279function_exists(Fname, Arity, Forms) ->
280    Fns = proplists:get_value(
281            functions, erl_syntax_lib:analyze_forms(Forms), []),
282    lists:member({Fname,Arity}, Fns).
283
284
285%%% @spec (Forms, Options) -> #context{}
286%%%
287%%% @doc
288%%% Initializes a context record. When traversing through the form
289%%% list, the context is updated to reflect the current function and
290%%% arity. Static elements in the context are the file name, the module
291%%% name and the options passed to the transform function.
292%%% @end
293%%%
294-spec initial_context(forms(), options()) ->
295    #context{}.
296initial_context(Forms, Options) ->
297    File = get_file(Forms),
298    Module = get_module(Forms),
299    #context{file = File,
300             module = Module,
301             options = Options}.
302
303%%% @spec (Fun, Acc, Forms, Options) -> {TransformedForms, NewAcc}
304%%% Fun = function()
305%%% Options = [{Key,Value}]
306%%%
307%%% @doc
308%%% Makes one pass
309%%% @end
310-spec transform(xform_f_rec(), Acc, forms(), options()) ->
311    {forms(), Acc} | {error, list()}.
312transform(Fun, Acc, Forms, Options) when is_function(Fun, 4) ->
313    do(fun do_transform/4, Fun, Acc, Forms, Options).
314
315-spec depth_first(xform_f_df(), Acc, forms(), options()) ->
316    {forms(), Acc} | {error, list()}.
317depth_first(Fun, Acc, Forms, Options) when is_function(Fun, 4) ->
318    do(fun do_depth_first/4, Fun, Acc, Forms, Options).
319
320do(Transform, Fun, Acc, Forms, Options) ->
321    Context = initial_context(Forms, Options),
322    File = Context#context.file,
323    try Transform(Fun, Acc, Forms, Context) of
324        {NewForms, Acc1} when is_list(NewForms) ->
325            NewForms1 = optionally_renumber(NewForms, Options),
326            optionally_pretty_print(NewForms1, Options, Context),
327            {NewForms1, Acc1}
328    catch
329        ?WITH_STACKTRACE(error, Reason, ST)
330            {error,
331             [{File, [{?DUMMY_LINE, ?MODULE,
332                       {Reason, ST}}]}]};
333        throw:{error, Ln, What} ->
334            {error, [{error, {Ln, ?MODULE, What}}]}
335    end.
336
337-spec top(function(), forms(), list()) ->
338    forms() | {error, term()}.
339top(F, Forms, Options) ->
340    Context = initial_context(Forms, Options),
341    File = Context#context.file,
342    try F(Forms, Context) of
343        {error, Reason} -> {error, Reason};
344        NewForms when is_list(NewForms) ->
345            NewForms1 = optionally_renumber(NewForms, Options),
346            optionally_pretty_print(NewForms1, Options, Context),
347            NewForms1
348    catch
349        ?WITH_STACKTRACE(error, Reason, ST)
350            {error,
351             [{File, [{?DUMMY_LINE, ?MODULE,
352                       {Reason, ST}}]}]};
353        throw:{error, Ln, What} ->
354            {error, [{File, [{Ln, ?MODULE, What}]}], []}
355    end.
356
357replace_function(F, Arity, NewForm, Forms) ->
358    replace_function(F, Arity, NewForm, Forms, []).
359
360replace_function(F, Arity, NewForm, Forms, Opts) ->
361    {NewForms, _} =
362        do_transform(
363          fun(function, Form, _Ctxt, Acc) ->
364                  case erl_syntax:revert(Form) of
365                      {function, _, F, Arity, _} = RevForm ->
366                          {[], NewForm, with_original_f(RevForm, Opts),
367                           false, Acc};
368                      _ ->
369                          {Form, false, Acc}
370                  end;
371             (_, Form, _Ctxt, Acc) ->
372                  {Form, false, Acc}
373          end, false, Forms, initial_context(Forms, [])),
374    revert(maybe_export_renamed(NewForms, Arity, Opts)).
375
376with_original_f({function,_,_,_,_} = Form, Opts) ->
377    case lists:keyfind(rename_original, 1, Opts) of
378        {_, NewName} when is_atom(NewName) ->
379            [setelement(3, Form, NewName)];
380        _ ->
381            []
382    end.
383
384maybe_export_renamed(Forms, Arity, Opts) ->
385    case lists:keyfind(rename_original, 1, Opts) of
386        {_, NewName} when is_atom(NewName) ->
387            export_function(NewName, Arity, Forms);
388        _ ->
389            Forms
390    end.
391
392export_function(F, Arity, Forms) ->
393    do_insert_forms(above, [{attribute, 1, export, [{F, Arity}]}], Forms,
394                    initial_context(Forms, [])).
395
396-spec do_insert_forms(above | below, forms(), forms(), #context{}) ->
397    forms().
398do_insert_forms(above, Insert, Forms, Context) when is_list(Insert) ->
399    {NewForms, _} =
400        do_transform(
401          fun(function, F, _Ctxt, false) ->
402                  {Insert, F, [], _Recurse = false, true};
403             (_, F, _Ctxt, Acc) ->
404                  {F, _Recurse = false, Acc}
405          end, false, Forms, Context),
406    NewForms;
407do_insert_forms(below, Insert, Forms, _Context) when is_list(Insert) ->
408    insert_below(Forms, Insert).
409
410
411insert_below([F|Rest], Insert) ->
412    case type(F) of
413        eof_marker ->
414            Insert ++ [F];
415        _ ->
416            [F|insert_below(Rest, Insert)]
417    end.
418
419-spec optionally_pretty_print(forms(), options(), #context{}) ->
420    ok.
421optionally_pretty_print(Result, Options, Context) ->
422    DoPP = option_value(pt_pp_src, Options, Result),
423    DoLFs = option_value(pt_log_forms, Options, Result),
424    File = Context#context.file,
425    if DoLFs ->
426            Out1 = outfile(File, forms),
427            {ok,Fd} = file:open(Out1, [write]),
428            try lists:foreach(fun(F) -> io:fwrite(Fd, "~p.~n", [F]) end, Result)
429            after
430                ok = file:close(Fd)
431            end;
432       true -> ok
433    end,
434    if DoPP ->
435            Out2 = outfile(File, pp),
436            pp_src(Result, Out2),
437            io:fwrite("Pretty-printed in ~p~n", [Out2]);
438       true -> ok
439    end.
440
441optionally_renumber(Result, Options) ->
442    case option_value(pt_renumber, Options, Result) of
443        true ->
444            io:fwrite("renumbering...~n", []),
445            Rev = revert(Result),
446            renumber_(Rev);
447        false ->
448            Result
449    end.
450
451renumber_(L) when is_list(L) ->
452    {Result, _} = renumber_(L, 1),
453    Result.
454
455renumber_(L, Acc) when is_list(L) ->
456    lists:mapfoldl(fun renumber_/2, Acc, L);
457renumber_(T, Prev) when is_tuple(T) ->
458    case is_form(T) of
459        true ->
460            New = Prev+1,
461            T1 = setelement(2, T, New),
462            {Res, NewAcc} = renumber_(tuple_to_list(T1), New),
463            {list_to_tuple(Res), NewAcc};
464        false ->
465            L = tuple_to_list(T),
466            {Res, NewAcc} = renumber_(L, Prev),
467            {list_to_tuple(Res), NewAcc}
468    end;
469renumber_(X, Prev) ->
470    {X, Prev}.
471
472is_form(T) when element(1,T)==type -> true;
473is_form(T) ->
474    try erl_syntax:type(T),
475         true
476    catch
477        error:_ ->
478            false
479    end.
480
481option_value(Key, Options, Result) ->
482    case proplists:get_value(Key, Options) of
483        undefined ->
484            case find_attribute(Key,Result) of
485                [Expr] ->
486                    type(Expr) == atom andalso
487                        atom_value(Expr) == true;
488                _ ->
489                    false
490            end;
491        V when is_boolean(V) ->
492            V
493    end.
494
495
496%%% @spec (Fun, Forms, Acc, Options) -> NewAcc
497%%% Fun = function()
498%%% @doc
499%%% Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)).
500%%% @end
501%%%
502-spec inspect(insp_f(), A, forms(), options()) ->
503    A.
504inspect(F, Acc, Forms, Options) ->
505    Context = initial_context(Forms, Options),
506    do_inspect(F, Acc, Forms, Context).
507
508
509
510outfile(File, Type) ->
511    "lre." ++ RevF = lists:reverse(File),
512    lists:reverse(RevF) ++ ext(Type).
513
514ext(pp)    -> ".xfm";
515ext(forms) -> ".xforms".
516
517%% @spec (Forms, Out::filename()) -> ok
518%%
519%% @doc Pretty-prints the erlang source code corresponding to Forms into Out
520%%
521-spec pp_src(forms(), string()) ->
522    ok.
523pp_src(Res, F) ->
524    parse_trans_pp:pp_src(Res, F).
525%%     Str = [io_lib:fwrite("~s~n",
526%%                          [lists:flatten([erl_pp:form(Fm) ||
527%%                                             Fm <- revert(Res)])])],
528%%     file:write_file(F, list_to_binary(Str)).
529
530%% @spec (Beam::file:filename()) -> string() | {error, Reason}
531%%
532%% @doc
533%% Reads debug_info from the beam file Beam and returns a string containing
534%% the pretty-printed corresponding erlang source code.
535%% @end
536-spec pp_beam(file:filename()) -> ok.
537pp_beam(Beam) ->
538    parse_trans_pp:pp_beam(Beam).
539
540%% @spec (Beam::filename(), Out::filename()) -> ok | {error, Reason}
541%%
542%% @doc
543%% Reads debug_info from the beam file Beam and pretty-prints it as
544%% Erlang source code, storing it in the file Out.
545%% @end
546%%
547-spec pp_beam(file:filename(), file:filename()) -> ok.
548pp_beam(F, Out) ->
549    parse_trans_pp:pp_beam(F, Out).
550
551
552%%% @spec (File) -> Forms
553%%%
554%%% @doc
555%%% <p>Fetches a Syntax Tree representing the code before pre-processing,
556%%% that is, including record and macro definitions. Note that macro
557%%% definitions must be syntactically complete forms (this function
558%%% uses epp_dodger).</p>
559%%% @end
560%%%
561-spec get_orig_syntax_tree(string()) ->
562    forms().
563get_orig_syntax_tree(File) ->
564    case epp_dodger:parse_file(File) of
565        {ok, Forms} ->
566            Forms;
567        Err ->
568            error(error_reading_file, ?HERE, [{File,Err}])
569    end.
570
571%%% @spec (Tree) -> Forms
572%%%
573%%% @doc Reverts back from Syntax Tools format to Erlang forms.
574%%% <p>Note that the Erlang forms are a subset of the Syntax Tools
575%%% syntax tree, so this function is safe to call even on a list of
576%%% regular Erlang forms.</p>
577%%% <p>Note2: R16B03 introduced a bug, where forms produced by
578%%% `erl_syntax:revert/1' (specifically, implicit funs) could crash the linter.
579%%% This function works around that limitation, after first verifying that it's
580%%% necessary to do so. Use of the workaround can be forced with the help of
581%%% the `parse_trans' environment variable {revert_workaround, true}. This
582%%% variable will be removed when R16B03 is no longer 'supported'.</p>
583%%% @end
584%%%
585-spec revert(forms()) ->
586    forms().
587revert(Tree) when is_list(Tree) ->
588    WorkAround = needs_revert_workaround(),
589    [revert_form(T, WorkAround) || T <- lists:flatten(Tree)].
590
591%%% @spec (Tree) -> Form
592%%%
593%%% @doc Reverts a single form back from Syntax Tools format to Erlang forms.
594%%% <p>`erl_syntax:revert/1' has had a long-standing bug where it doesn't
595%%% completely revert attribute forms. This function deals properly with those
596%%% cases.</p>
597%%% <p>Note that the Erlang forms are a subset of the Syntax Tools
598%%% syntax tree, so this function is safe to call even on a regular Erlang
599%%% form.</p>
600%%% <p>Note2: R16B03 introduced a bug, where forms produced by
601%%% `erl_syntax:revert/1' (specifically, implicit funs) could crash the linter.
602%%% This function works around that limitation, after first verifying that it's
603%%% necessary to do so. Use of the workaround can be forced with the help of
604%%% the `parse_trans' environment variable {revert_workaround, true}. This
605%%% variable will be removed when R16B03 is no longer 'supported'.</p>
606%%% @end
607revert_form(F) ->
608    revert_form(F, needs_revert_workaround()).
609
610revert_form(F, W) ->
611    case erl_syntax:revert(F) of
612        {attribute,L,A,Tree} when element(1,Tree) == tree ->
613            {attribute,L,A,erl_syntax:revert(Tree)};
614        Result ->
615            if W -> fix_impl_fun(Result);
616               true -> Result
617            end
618    end.
619
620fix_impl_fun({'fun',L,{function,{atom,_,Fn},{integer,_,Ay}}}) ->
621    {'fun',L,{function,Fn,Ay}};
622fix_impl_fun({'fun',L,{function,{atom,_,M},{atom,_,Fn},{integer,_,Ay}}}) ->
623    {'fun',L,{function,M,Fn,Ay}};
624fix_impl_fun(T) when is_tuple(T) ->
625    list_to_tuple([fix_impl_fun(F) || F <- tuple_to_list(T)]);
626fix_impl_fun([H|T]) ->
627    [fix_impl_fun(H) | fix_impl_fun(T)];
628fix_impl_fun(X) ->
629    X.
630
631needs_revert_workaround() ->
632    case application:get_env(parse_trans,revert_workaround) of
633        {ok, Bool} when is_boolean(Bool) -> Bool;
634        _ ->
635            Res = try lint_reverted()
636                  catch
637                      error:_ ->
638                          true
639                  end,
640            application:set_env(parse_trans,revert_workaround,Res),
641            Res
642    end.
643
644lint_reverted() ->
645    Ts = [{attribute,1,module,m},
646          {attribute,2,export,[{f,0}]},
647          erl_syntax:function(erl_syntax:atom(f),
648                              [erl_syntax:clause(
649                                 [],
650                                 [erl_syntax:implicit_fun(
651                                    erl_syntax:atom(f),
652                                    erl_syntax:integer(0))])])],
653    Rev = erl_syntax:revert_forms(Ts),
654    erl_lint:module(Rev),
655    false.
656
657
658%%% @spec (Forms, Context) -> Forms | {error,Es,Ws} | {warnings,Forms,Ws}
659%%%
660%%% @doc Checks the transformed result for errors and warnings
661%%% <p>Errors and warnings can be produced from inside a parse transform, with
662%%% a bit of care. The easiest way is to simply produce an `{error, Err}' or
663%%% `{warning, Warn}' form in place. This function finds such forms, and
664%%% removes them from the form list (otherwise, the linter will crash), and
665%%% produces a return value that the compiler can work with.</p>
666%%%
667%%% The format of the `error' and `warning' "forms" must be
668%%% `{Tag, {Pos, Module, Info}}', where:
669%%% <ul>
670%%% <li>`Tag :: error | warning'</li>
671%%% <li>`Pos :: LineNumber | {LineNumber, ColumnNumber}'</li>
672%%% <li>`Module' is a module that exports a corresponding
673%%%    `Module:format_error(Info)'</li>
674%%% <li>`Info :: term()'</li>
675%%% </ul>
676%%% <p>If the error is in the form of a caught exception, `Info' may be produced
677%%% using the function {@link format_exception/2}.</p>
678%%% @end
679return(Forms, Context) ->
680    JustForms = plain_transform(
681                  fun({error,_}) -> skip;
682                     ({warning,_}) -> skip;
683                     (_) -> continue
684                  end, Forms),
685    File = case Context of
686               #context{file = F} -> F;
687               _ -> "parse_transform"
688           end,
689    case {find_forms(Forms, error), find_forms(Forms, warning)} of
690        {[], []} ->
691            JustForms;
692        {[], Ws} ->
693            {warnings, JustForms, [{File, [W || {warning,W} <- Ws]}]};
694        {Es, Ws} ->
695            {error,
696             [{File, [E || {error,E} <- Es]}],
697             [{File, [W || {warning,W} <- Ws]}]}
698    end.
699
700find_forms([H|T], Tag) when element(1, H) == Tag ->
701    [H|find_forms(T, Tag)];
702find_forms([H|T], Tag) when is_tuple(H) ->
703    find_forms(tuple_to_list(H), Tag) ++ find_forms(T, Tag);
704find_forms([H|T], Tag) when is_list(H) ->
705    find_forms(H, Tag) ++ find_forms(T, Tag);
706find_forms([_|T], Tag) ->
707    find_forms(T, Tag);
708find_forms([], _) ->
709    [].
710
711
712-define(LINEMAX, 5).
713-define(CHAR_MAX, 60).
714
715%%% @spec (Class, Reason) -> String
716%%% @equiv format_exception(Class, Reason, 4)
717format_exception(Class, Reason) ->
718    format_exception(Class, Reason, 4).
719
720%%% @spec (Class, Reason, Lines) -> String
721%%% Class = error | throw | exit
722%%% Reason = term()
723%%% Lines = integer() | infinity
724%%%
725%%% @doc Produces a few lines of user-friendly formatting of exception info
726%%%
727%%% This function is very similar to the exception pretty-printing in the shell,
728%%% but returns a string that can be used as error info e.g. by error forms
729%%% handled by {@link return/2}. By default, the first 4 lines of the
730%%% pretty-printed exception info are returned, but this can be controlled
731%%% with the `Lines' parameter.
732%%%
733%%% Note that a stacktrace is generated inside this function.
734%%% @end
735format_exception(Class, Reason, Lines) ->
736    ST = erlang:process_info(self(), current_stacktrace),
737    PrintF = fun(Term, I) ->
738                     io_lib_pretty:print(
739                       Term, I, columns(), ?LINEMAX, ?CHAR_MAX,
740                       record_print_fun())
741             end,
742    StackF = fun(_, _, _) -> false end,
743    lines(Lines, lib:format_exception(
744                   1, Class, Reason, ST, StackF, PrintF)).
745
746columns() ->
747    case io:columns() of
748        {ok, N} -> N;
749        _-> 80
750    end.
751
752lines(infinity, S) -> S;
753lines(N, S) ->
754    [L1|Ls] = re:split(iolist_to_binary([S]), <<"\n">>, [{return,list}]),
755    [L1|["\n" ++ L || L <- lists:sublist(Ls, 1, N-1)]].
756
757record_print_fun() ->
758    fun(_,_) -> no end.
759
760%%% @spec (Attr, Context) -> any()
761%%% Attr = module | function | arity | options
762%%%
763%%% @doc
764%%% Accessor function for the Context record.
765%%% @end
766-spec context(atom(), #context{}) ->
767    term().
768context(module,   #context{module = M}  ) -> M;
769context(function, #context{function = F}) -> F;
770context(arity,    #context{arity = A}   ) -> A;
771context(file,     #context{file = F}    ) -> F;
772context(options,  #context{options = O} ) -> O.
773
774
775-spec do_inspect(insp_f(), term(), forms(), #context{}) ->
776    term().
777do_inspect(F, Acc, Forms, Context) ->
778    F1 =
779        fun(Form, Acc0) ->
780                Type = type(Form),
781                {Recurse, Acc1} = apply_F(F, Type, Form, Context, Acc0),
782                if_recurse(
783                  Recurse, Form, _Else = Acc1,
784                  fun(ListOfLists) ->
785                          lists:foldl(
786                            fun(L, AccX) ->
787                                    do_inspect(
788                                      F, AccX, L,
789                                      update_context(Form, Context))
790                            end, Acc1, ListOfLists)
791                  end)
792        end,
793    lists:foldl(F1, Acc, Forms).
794
795if_recurse(true, Form, Else, F) -> recurse(Form, Else, F);
796if_recurse(false, _, Else, _)   -> Else.
797
798recurse(Form, Else, F) ->
799    case erl_syntax:subtrees(Form) of
800        [] ->
801            Else;
802        [_|_] = ListOfLists ->
803            F(ListOfLists)
804    end.
805
806-spec do_transform(xform_f_rec(), term(), forms(), #context{}) ->
807    {forms(), term()}.
808do_transform(F, Acc, Forms, Context) ->
809    Rec = fun do_transform/4, % this function
810    F1 =
811        fun(Form, Acc0) ->
812                {Before1, Form1, After1, Recurse, Acc1} =
813                    this_form_rec(F, Form, Context, Acc0),
814                if Recurse ->
815                        {NewForm, NewAcc} =
816                            enter_subtrees(Form1, F,
817                                update_context(Form1, Context), Acc1, Rec),
818                        {Before1, NewForm, After1, NewAcc};
819                   true ->
820                        {Before1, Form1, After1, Acc1}
821                end
822        end,
823    mapfoldl(F1, Acc, Forms).
824
825-spec do_depth_first(xform_f_df(), term(), forms(), #context{}) ->
826    {forms(), term()}.
827do_depth_first(F, Acc, Forms, Context) ->
828    Rec = fun do_depth_first/4,  % this function
829    F1 =
830        fun(Form, Acc0) ->
831                {NewForm, NewAcc} =
832                    enter_subtrees(Form, F, Context, Acc0, Rec),
833                this_form_df(F, NewForm, Context, NewAcc)
834        end,
835    mapfoldl(F1, Acc, Forms).
836
837enter_subtrees(Form, F, Context, Acc, Recurse) ->
838    case erl_syntax:subtrees(Form) of
839        [] ->
840            {Form, Acc};
841        [_|_] = ListOfLists ->
842            {NewListOfLists, NewAcc} =
843                mapfoldl(
844                  fun(L, AccX) ->
845                          Recurse(F, AccX, L, Context)
846                  end, Acc, ListOfLists),
847            NewForm =
848                erl_syntax:update_tree(
849                  Form, NewListOfLists),
850            {NewForm, NewAcc}
851    end.
852
853
854this_form_rec(F, Form, Context, Acc) ->
855    Type = type(Form),
856    case apply_F(F, Type, Form, Context, Acc) of
857        {Form1x, Rec1x, A1x} ->
858            {[], Form1x, [], Rec1x, A1x};
859        {_Be1, _F1, _Af1, _Rec1, _Ac1} = Res1 ->
860            Res1
861    end.
862this_form_df(F, Form, Context, Acc) ->
863    Type = type(Form),
864    case apply_F(F, Type, Form, Context, Acc) of
865        {Form1x, A1x} ->
866            {[], Form1x, [], A1x};
867        {_Be1, _F1, _Af1, _Ac1} = Res1 ->
868            Res1
869    end.
870
871apply_F(F, Type, Form, Context, Acc) ->
872    try F(Type, Form, Context, Acc)
873    catch
874        ?WITH_STACKTRACE(error, Reason, ST)
875            ?ERROR(Reason,
876                   ?HERE,
877                   [{type, Type},
878                    {context, Context},
879                    {acc, Acc},
880                    {apply_f, F},
881                    {form, Form}] ++ [{stack, ST}],
882                   ST)
883    end.
884
885
886update_context(Form, Context0) ->
887    case type(Form) of
888        function ->
889            {Fun, Arity} =
890                erl_syntax_lib:analyze_function(Form),
891            Context0#context{function = Fun,
892                             arity = Arity};
893        _ ->
894            Context0
895    end.
896
897
898
899
900%%% Slightly modified version of lists:mapfoldl/3
901%%% Here, F/2 is able to insert forms before and after the form
902%%% in question. The inserted forms are not transformed afterwards.
903mapfoldl(F, Accu0, [Hd|Tail]) ->
904    {Before, Res, After, Accu1} =
905        case F(Hd, Accu0) of
906            {Be, _, Af, _} = Result when is_list(Be), is_list(Af) ->
907                Result;
908            {R1, A1} ->
909                {[], R1, [], A1}
910        end,
911    {Rs, Accu2} = mapfoldl(F, Accu1, Tail),
912    {Before ++ [Res| After ++ Rs], Accu2};
913mapfoldl(F, Accu, []) when is_function(F, 2) -> {[], Accu}.
914
915
916rpt_error(_Reason, _Fun, _Info, _Trace) ->
917    %% Fmt = lists:flatten(
918    %%      ["*** ERROR in parse_transform function:~n"
919    %%       "*** Reason     = ~p~n",
920    %%          "*** Location: ~p~n",
921    %%       "*** Trace: ~p~n",
922    %%       ["*** ~10w = ~p~n" || _ <- Info]]),
923    %% Args = [Reason, Fun, Trace |
924    %%      lists:foldr(
925    %%        fun({K,V}, Acc) ->
926    %%                [K, V | Acc]
927    %%        end, [], Info)],
928    %%io:format(Fmt, Args),
929    ok.
930
931-spec format_error({atom(), term()}) ->
932    iolist().
933format_error({E, [{M,F,A}|_]} = Error) ->
934    try lists:flatten(io_lib:fwrite("~p in ~s:~s/~s", [E, atom_to_list(M),
935                                                       atom_to_list(F), integer_to_list(A)]))
936    catch
937        error:_ ->
938            format_error_(Error)
939    end;
940format_error(Error) ->
941    format_error_(Error).
942
943format_error_(Error) ->
944    lists:flatten(io_lib:fwrite("~p", [Error])).
945