1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%% Purpose : Core Erlang (naive) prettyprinter
21
22-module(core_pp).
23
24-export([format/1,format_all/1]).
25
26-include("core_parse.hrl").
27
28%% ====================================================================== %%
29%% format(Node) -> Text
30%%	Node = coreErlang()
31%%	Text = string() | [Text]
32%%
33%%	Prettyprint-formats (naively) an abstract Core Erlang syntax
34%%	tree.
35
36-record(ctxt, {indent = 0      :: integer(),
37	       item_indent = 2 :: integer(),
38	       body_indent = 4 :: integer(),
39	       line = 0        :: integer(),
40	       clean = true    :: boolean()}).
41
42-define(TAB_WIDTH, 8).
43
44-spec format(cerl:cerl()) -> iolist().
45
46format(Node) ->
47    format(Node, #ctxt{}).
48
49-spec format_all(cerl:cerl()) -> iolist().
50
51format_all(Node) ->
52    format(Node, #ctxt{clean=false}).
53
54maybe_anno(Node, Fun, #ctxt{clean=false}=Ctxt) ->
55    As = cerl:get_ann(Node),
56    maybe_anno(Node, Fun, Ctxt, As);
57maybe_anno(Node, Fun, #ctxt{clean=true}=Ctxt) ->
58    As0 = cerl:get_ann(Node),
59    case get_line(As0) of
60	none ->
61	    maybe_anno(Node, Fun, Ctxt, As0);
62  	Line ->
63	    As = strip_line(As0),
64	    if Line > Ctxt#ctxt.line ->
65		    [io_lib:format("%% Line ~w",[Line]),
66		     nl_indent(Ctxt),
67		     maybe_anno(Node, Fun, Ctxt#ctxt{line = Line}, As)
68		    ];
69		true ->
70		    maybe_anno(Node, Fun, Ctxt, As)
71	    end
72    end.
73
74maybe_anno(Node, Fun, Ctxt, []) ->
75    Fun(Node, Ctxt);
76maybe_anno(Node, Fun, Ctxt, List) ->
77    Ctxt1 = add_indent(Ctxt, 2),
78    Ctxt2 = add_indent(Ctxt1, 3),
79    ["( ",
80     Fun(Node, Ctxt1),
81     nl_indent(Ctxt1),
82     "-| ",format_anno(List, Ctxt2)," )"
83    ].
84
85format_anno([_|_]=List, Ctxt) ->
86    [$[,format_anno_list(List, Ctxt),$]];
87format_anno({file,Name}, _Ctxt) ->
88    %% Optimization: Reduces file size considerably.
89    io_lib:format("{'file',~p}", [Name]);
90format_anno(Tuple, Ctxt) when is_tuple(Tuple) ->
91    [${,format_anno_list(tuple_to_list(Tuple), Ctxt),$}];
92format_anno(Val, Ctxt) when is_atom(Val) ->
93    format_1(#c_literal{val=Val}, Ctxt);
94format_anno(Val, Ctxt) when is_integer(Val) ->
95    format_1(#c_literal{val=Val}, Ctxt).
96
97format_anno_list([H|[_|_]=T], Ctxt) ->
98    [format_anno(H, Ctxt), $, | format_anno_list(T, Ctxt)];
99format_anno_list([H], Ctxt) ->
100    format_anno(H, Ctxt).
101
102strip_line([A | As]) when is_integer(A) ->
103    strip_line(As);
104strip_line([{file,_File} | As]) ->
105    strip_line(As);
106strip_line([A | As]) ->
107    [A | strip_line(As)];
108strip_line([]) ->
109    [].
110
111get_line([L | _As]) when is_integer(L) ->
112    L;
113get_line([_ | As]) ->
114    get_line(As);
115get_line([]) ->
116    none.
117
118format(Node, Ctxt) ->
119    maybe_anno(Node, fun format_1/2, Ctxt).
120
121format_1(#c_literal{val=[]}, _) -> "[]";
122format_1(#c_literal{val=I}, _) when is_integer(I) -> integer_to_list(I);
123format_1(#c_literal{val=F}, _) when is_float(F) -> float_to_list(F);
124format_1(#c_literal{val=A}, _) when is_atom(A) -> core_atom(A);
125format_1(#c_literal{val=[H|T]}, Ctxt) ->
126    format_1(#c_cons{hd=#c_literal{val=H},tl=#c_literal{val=T}}, Ctxt);
127format_1(#c_literal{val=Tuple}, Ctxt) when is_tuple(Tuple) ->
128    format_1(#c_tuple{es=[#c_literal{val=E} || E <- tuple_to_list(Tuple)]}, Ctxt);
129format_1(#c_literal{anno=A,val=Bitstring}, Ctxt) when is_bitstring(Bitstring) ->
130    Segs = segs_from_bitstring(Bitstring),
131    format_1(#c_binary{anno=A,segments=Segs}, Ctxt);
132format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
133    Pairs = maps:to_list(M),
134    Op = #c_literal{val=assoc},
135    Cpairs = [#c_map_pair{op=Op,
136			  key=#c_literal{val=K},
137			  val=#c_literal{val=V}} || {K,V} <- Pairs],
138    format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
139format_1(#c_literal{val=F},_Ctxt) when is_function(F) ->
140    {module,M} = erlang:fun_info(F, module),
141    {name,N} = erlang:fun_info(F, name),
142    {arity,A} = erlang:fun_info(F, arity),
143    ["fun ",core_atom(M),$:,core_atom(N),$/,integer_to_list(A)];
144format_1(#c_var{name={I,A}}, _) ->
145    [core_atom(I),$/,integer_to_list(A)];
146format_1(#c_var{name=V}, _) ->
147    %% Internal variable names may be:
148    %%     - atoms representing proper Erlang variable names, or
149    %%       any atoms that may be printed without single-quoting
150    %%     - nonnegative integers.
151    %% It is important that when printing variables, no two names
152    %% should ever map to the same string.
153    if is_atom(V) ->
154	    S = atom_to_list(V),
155	    case S of
156		[C | _] when C >= $A, C =< $Z ->
157		    %% Ordinary uppercase-prefixed names are
158		    %% printed just as they are.
159		    S;
160		[$_ | _] ->
161		    %% Already "_"-prefixed names are prefixed
162		    %% with "_X", e.g. '_foo' => '_X_foo', to
163		    %% avoid generating things like "____foo" upon
164		    %% repeated writing and reading of code.
165		    %% ("_X_X_X_foo" is better.)
166		    [$_, $X | S];
167		_ ->
168		    %% Plain atoms are prefixed with a single "_".
169		    %% E.g. foo => "_foo".
170		    [$_ | S]
171	    end;
172       is_integer(V) ->
173	    %% Integers are also simply prefixed with "_".
174	    [$_ | integer_to_list(V)]
175    end;
176format_1(#c_binary{segments=Segs}, Ctxt) ->
177    ["#{",
178     format_vseq(Segs, "", ",", add_indent(Ctxt, 2),
179		 fun format_bitstr/2),
180     "}#"
181    ];
182format_1(#c_tuple{es=Es}, Ctxt) ->
183    [${,
184     format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
185     $}
186    ];
187format_1(#c_map{arg=#c_literal{val=M},es=Es}, Ctxt)
188  when is_map(M), map_size(M) =:= 0 ->
189    ["~{",
190     format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
191     "}~"
192    ];
193format_1(#c_map{arg=Var,es=Es}, Ctxt) ->
194    ["~{",
195     format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
196     "|",format(Var, add_indent(Ctxt, 1)),
197     "}~"
198    ];
199format_1(#c_map_pair{op=#c_literal{val=assoc},key=K,val=V}, Ctxt) ->
200    format_map_pair("=>", K, V, Ctxt);
201format_1(#c_map_pair{op=#c_literal{val=exact},key=K,val=V}, Ctxt) ->
202    format_map_pair(":=", K, V, Ctxt);
203format_1(#c_cons{hd=H,tl=T}, Ctxt) ->
204    Txt = ["["|format(H, add_indent(Ctxt, 1))],
205    [Txt|format_list_tail(T, add_indent(Ctxt, width(Txt, Ctxt)))];
206format_1(#c_values{es=Es}, Ctxt) ->
207    format_values(Es, Ctxt);
208format_1(#c_alias{var=V,pat=P}, Ctxt) ->
209    Txt = [format(V, Ctxt)|" = "],
210    [Txt|format(P, add_indent(Ctxt, width(Txt, Ctxt)))];
211format_1(#c_let{anno=Anno0,vars=Vs0,arg=A0,body=B}, #ctxt{clean=Clean}=Ctxt) ->
212    {Vs,A,Anno} = case Clean of
213		      false ->
214			  {Vs0,A0,Anno0};
215		      true ->
216			  {[cerl:set_ann(V, []) || V <- Vs0],
217			   cerl:set_ann(A0, []),
218			   []}
219		  end,
220    case is_simple_term(A) andalso Anno =:= [] of
221	false ->
222	    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
223	    ["let ",
224	     format_values(Vs, add_indent(Ctxt, 4)),
225	     " =",
226	     nl_indent(Ctxt1),
227	     format(A, Ctxt1),
228	     nl_indent(Ctxt),
229	     "in  "
230	     | format(B, add_indent(Ctxt, 4))
231	    ];
232	true ->
233	    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
234	    ["let ",
235	     format_values(Vs, add_indent(Ctxt, 4)),
236	     " = ",
237	     format(A, Ctxt1),
238	     nl_indent(Ctxt),
239	     "in  "
240	     | format(B, add_indent(Ctxt, 4))
241	    ]
242    end;
243format_1(#c_letrec{defs=Fs,body=B}, Ctxt) ->
244    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
245    ["letrec",
246     nl_indent(Ctxt1),
247     format_funcs(Fs, Ctxt1),
248     nl_indent(Ctxt),
249     "in  "
250     | format(B, add_indent(Ctxt, 4))
251    ];
252format_1(#c_seq{arg=A,body=B}, Ctxt) ->
253    Ctxt1 = add_indent(Ctxt, 4),
254    ["do  ",
255     format(A, Ctxt1),
256     nl_indent(Ctxt1)
257     | format(B, Ctxt1)
258    ];
259format_1(#c_case{arg=A,clauses=Cs}, Ctxt) ->
260    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.item_indent),
261    ["case ",
262     format(A, add_indent(Ctxt, 5)),
263     " of",
264     nl_indent(Ctxt1),
265     format_clauses(Cs, Ctxt1),
266     nl_indent(Ctxt)
267     | "end"
268    ];
269format_1(#c_receive{clauses=Cs,timeout=T,action=A}, Ctxt) ->
270    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.item_indent),
271    ["receive",
272     nl_indent(Ctxt1),
273     format_clauses(Cs, Ctxt1),
274     nl_indent(Ctxt),
275     "after ",
276     format(T, add_indent(Ctxt, 6)),
277     " ->",
278     nl_indent(Ctxt1),
279     format(A, Ctxt1)
280    ];
281format_1(#c_fun{vars=Vs,body=B}, Ctxt) ->
282    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
283    ["fun (",
284     format_hseq(Vs, ",", add_indent(Ctxt, 5), fun format/2),
285     ") ->",
286     nl_indent(Ctxt1)
287     | format(B, Ctxt1)
288    ];
289format_1(#c_apply{op=O,args=As}, Ctxt0) ->
290    Ctxt1 = add_indent(Ctxt0, 6),		%"apply "
291    Op = format(O, Ctxt1),
292    Ctxt2 = add_indent(Ctxt0, 4),
293    ["apply ",Op,
294     nl_indent(Ctxt2),
295     $(,format_hseq(As, ", ", add_indent(Ctxt2, 1), fun format/2),$)
296    ];
297format_1(#c_call{module=M,name=N,args=As}, Ctxt0) ->
298    Ctxt1 = add_indent(Ctxt0, 5),		%"call "
299    Mod = format(M, Ctxt1),
300    Ctxt2 = add_indent(Ctxt1, width(Mod, Ctxt1)+1),
301    Name = format(N, Ctxt2),
302    Ctxt3 = add_indent(Ctxt0, 4),
303    ["call ",Mod,":",Name,
304     nl_indent(Ctxt3),
305     $(,format_hseq(As, ", ", add_indent(Ctxt3, 1), fun format/2),$)
306    ];
307format_1(#c_primop{name=N,args=As}, Ctxt0) ->
308    Ctxt1 = add_indent(Ctxt0, 7),		%"primop "
309    Name = format(N, Ctxt1),
310    Ctxt2 = add_indent(Ctxt0, 4),
311    ["primop ",Name,
312     nl_indent(Ctxt2),
313     $(,format_hseq(As, ", ", add_indent(Ctxt2, 1), fun format/2),$)
314    ];
315format_1(#c_catch{body=B}, Ctxt) ->
316    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
317    ["catch",
318     nl_indent(Ctxt1),
319     format(B, Ctxt1)
320    ];
321format_1(#c_try{arg=E,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
322    Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
323    ["try",
324     nl_indent(Ctxt1),
325     format(E, Ctxt1),
326     nl_indent(Ctxt),
327     "of ",
328     format_values(Vs, add_indent(Ctxt, 3)),
329     " ->",
330     nl_indent(Ctxt1),
331     format(B, Ctxt1),
332     nl_indent(Ctxt),
333     "catch ",
334     format_values(Evs, add_indent(Ctxt, 6)),
335     " ->",
336     nl_indent(Ctxt1)
337     | format(H, Ctxt1)
338    ];
339format_1(#c_module{name=N,exports=Es,attrs=As,defs=Ds}, Ctxt) ->
340    Mod = ["module ", format(N, Ctxt)],
341    [Mod," [",
342     format_vseq(Es,
343		 "", ",",
344		 add_indent(Ctxt, width(Mod, Ctxt)+2),
345		 fun format/2),
346     "]",
347     nl_indent(Ctxt),
348     "    attributes [",
349     format_vseq(As,
350		 "", ",",
351		 add_indent(Ctxt, 16),
352		 fun format_def/2),
353     "]",
354     nl_indent(Ctxt),
355     format_funcs(Ds, Ctxt),
356     nl_indent(Ctxt)
357     | "end"
358    ].
359
360format_funcs(Fs, Ctxt) ->
361    format_vseq(Fs,
362		"", "",
363		Ctxt,
364		fun format_def/2).
365
366format_def({N,V}, Ctxt0) ->
367    Ctxt1 = add_indent(Ctxt0, Ctxt0#ctxt.body_indent),
368    [format(N, Ctxt0),
369     " =",
370     nl_indent(Ctxt1)
371     | format(V, Ctxt1)
372    ].
373
374
375format_values(Vs, Ctxt) ->
376    [$<,
377     format_hseq(Vs, ",", add_indent(Ctxt, 1), fun format/2),
378     $>].
379
380format_bitstr(Node, Ctxt) ->
381    maybe_anno(Node, fun do_format_bitstr/2, Ctxt).
382
383do_format_bitstr(#c_bitstr{val=V,size=S,unit=U,type=T,flags=Fs}, Ctxt0) ->
384    Vs = [S, U, T, Fs],
385    Ctxt1 = add_indent(Ctxt0, 2),
386    Val = format(V, Ctxt1),
387    Ctxt2 = add_indent(Ctxt1, width(Val, Ctxt1) + 2),
388    ["#<", Val, ">(", format_hseq(Vs,",", Ctxt2, fun format/2), $)].
389
390format_clauses(Cs, Ctxt) ->
391    format_vseq(Cs, "", "", Ctxt, fun format_clause/2).
392
393format_clause(Node, Ctxt) ->
394    maybe_anno(Node, fun format_clause_1/2, Ctxt).
395
396format_clause_1(#c_clause{pats=Ps,guard=G,body=B}, Ctxt) ->
397    Ptxt = format_values(Ps, Ctxt),
398    Ctxt2 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
399    [Ptxt,
400     case is_trivial_guard(G) of
401	 true ->
402	     [" when ",
403	      format_guard(G, add_indent(Ctxt, width(Ptxt, Ctxt) + 6))];
404	 false ->
405	     [nl_indent(Ctxt2), "when ",
406	      format_guard(G, add_indent(Ctxt2, 2))]
407     end++
408     " ->",
409     nl_indent(Ctxt2) | format(B, Ctxt2)
410    ].
411
412is_trivial_guard(#c_literal{val=Val}) when is_atom(Val) -> true;
413is_trivial_guard(_) -> false.
414
415format_guard(Node, Ctxt) ->
416    maybe_anno(Node, fun format_guard_1/2, Ctxt).
417
418format_guard_1(#c_call{module=M,name=N,args=As}, Ctxt0) ->
419    Ctxt1 = add_indent(Ctxt0, 5),		%"call "
420    Mod = format(M, Ctxt1),
421    Ctxt2 = add_indent(Ctxt1, width(Mod, Ctxt1)+1),
422    Name = format(N, Ctxt2),
423    Ctxt3 = add_indent(Ctxt0, 4),
424    ["call ",Mod,":",Name,
425     nl_indent(Ctxt3),
426     $(,format_vseq(As, "",",", add_indent(Ctxt3, 1), fun format_guard/2),$)
427    ];
428format_guard_1(E, Ctxt) -> format_1(E, Ctxt).	%Anno already done
429
430%% format_hseq([Thing], Separator, Context, Fun) -> Txt.
431%%  Format a sequence horizontally on the same line with Separator between.
432
433format_hseq([H], _, Ctxt, Fun) ->
434    Fun(H, Ctxt);
435format_hseq([H|T], Sep, Ctxt, Fun) ->
436    Txt = [Fun(H, Ctxt)|Sep],
437    Ctxt1 = add_indent(Ctxt, width(Txt, Ctxt)),
438    [Txt|format_hseq(T, Sep, Ctxt1, Fun)];
439format_hseq([], _, _, _) -> "".
440
441%% format_vseq([Thing], LinePrefix, LineSuffix, Context, Fun) -> Txt.
442%%  Format a sequence vertically in indented lines adding LinePrefix
443%%  to the beginning of each line and LineSuffix to the end of each
444%%  line.  No prefix on the first line or suffix on the last line.
445
446format_vseq([H], _Pre, _Suf, Ctxt, Fun) ->
447    Fun(H, Ctxt);
448format_vseq([H|T], Pre, Suf, Ctxt, Fun) ->
449    [Fun(H, Ctxt),Suf,nl_indent(Ctxt),Pre|
450     format_vseq(T, Pre, Suf, Ctxt, Fun)];
451format_vseq([], _, _, _, _) -> "".
452
453format_list_tail(#c_literal{anno=[],val=[]}, _) -> "]";
454format_list_tail(#c_cons{anno=[],hd=H,tl=T}, Ctxt) ->
455    Txt = [$,|format(H, Ctxt)],
456    Ctxt1 = add_indent(Ctxt, width(Txt, Ctxt)),
457    [Txt|format_list_tail(T, Ctxt1)];
458format_list_tail(Tail, Ctxt) ->
459    ["|",format(Tail, add_indent(Ctxt, 1)),"]"].
460
461format_map_pair(Op, K, V, Ctxt0) ->
462    Ctxt1 = add_indent(Ctxt0, 1),
463    Txt = format(K, Ctxt1),
464    Ctxt2 = add_indent(Ctxt0, width(Txt, Ctxt1)),
465    [Txt,Op,format(V, Ctxt2)].
466
467indent(#ctxt{indent=N}) ->
468    if
469	N =< 0 ->
470	    "";
471	true ->
472           lists:duplicate(N div ?TAB_WIDTH, $\t) ++ spaces(N rem ?TAB_WIDTH)
473    end.
474
475nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
476
477spaces(0) -> "";
478spaces(1) -> " ";
479spaces(2) -> "  ";
480spaces(3) -> "   ";
481spaces(4) -> "    ";
482spaces(5) -> "     ";
483spaces(6) -> "      ";
484spaces(7) -> "       ".
485
486%% Undo indentation done by nl_indent/1.
487unindent(T, Ctxt) ->
488    unindent(T, Ctxt#ctxt.indent, []).
489
490unindent(T, N, C) when N =< 0 ->
491    [T|C];
492unindent([$\s|T], N, C) ->
493    unindent(T, N - 1, C);
494unindent([$\t|T], N, C) ->
495    Tab = ?TAB_WIDTH,
496    if N >= Tab ->
497	    unindent(T, N - Tab, C);
498       true ->
499	    unindent([spaces(Tab - N)|T], 0, C)
500    end;
501unindent([L|T], N, C) when is_list(L) ->
502    unindent(L, N, [T|C]).
503
504
505width(Txt, Ctxt) ->
506    width(Txt, 0, Ctxt, []).
507
508width([$\t|T], A, Ctxt, C) ->
509    width(T, A + ?TAB_WIDTH, Ctxt, C);
510width([$\n|T], _, Ctxt, C) ->
511    width(unindent([T|C], Ctxt), Ctxt);
512width([H|T], A, Ctxt, C) when is_list(H) ->
513    width(H, A, Ctxt, [T|C]);
514width([_|T], A, Ctxt, C) ->
515    width(T, A + 1, Ctxt, C);
516width([], A, Ctxt, [H|T]) ->
517    width(H, A, Ctxt, T);
518width([], A, _, []) -> A.
519
520add_indent(Ctxt, Dx) ->
521    Ctxt#ctxt{indent = Ctxt#ctxt.indent + Dx}.
522
523core_atom(A) -> io_lib:write_string(atom_to_list(A), $').
524
525
526is_simple_term(#c_tuple{es=Es}) ->
527    length(Es) < 4 andalso lists:all(fun is_simple_term/1, Es);
528is_simple_term(#c_var{}) -> true;
529is_simple_term(#c_literal{val=[_|_]}) -> false;
530is_simple_term(#c_literal{val=V}) -> not is_tuple(V);
531is_simple_term(_) -> false.
532
533segs_from_bitstring(<<H,T/bitstring>>) ->
534    [#c_bitstr{val=#c_literal{val=H},
535	       size=#c_literal{val=8},
536	       unit=#c_literal{val=1},
537	       type=#c_literal{val=integer},
538	       flags=#c_literal{val=[unsigned,big]}}|segs_from_bitstring(T)];
539segs_from_bitstring(<<>>) ->
540    [];
541segs_from_bitstring(Bitstring) ->
542    N = bit_size(Bitstring),
543    <<I:N>> = Bitstring,
544    [#c_bitstr{val=#c_literal{val=I},
545	      size=#c_literal{val=N},
546	      unit=#c_literal{val=1},
547	      type=#c_literal{val=integer},
548	      flags=#c_literal{val=[unsigned,big]}}].
549