1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
16
%% $Id: core_pp.erl,v 1.1 2008/12/17 09:53:42 mikpe Exp $
18
%% Purpose : Core Erlang (naive) prettyprinter
24
-include("core_parse.hrl").
26
%% ====================================================================== %%
27
%% format(Node) -> Text
28
%% Node = coreErlang()
29
%% Text = string() | [Text]
31
%% Prettyprint-formats (naively) an abstract Core Erlang syntax
34
-record(ctxt, {class = term,
41
format(Node) -> case catch format(Node, #ctxt{}) of
42
{'EXIT',_} -> io_lib:format("~p",[Node]);
46
maybe_anno(Node, Fun, Ctxt) ->
47
As = core_lib:get_anno(Node),
50
maybe_anno(Node, Fun, Ctxt, As);
52
if Line > Ctxt#ctxt.line ->
53
[io_lib:format("%% Line ~w",[Line]),
55
maybe_anno(Node, Fun, Ctxt#ctxt{line = Line}, As)
58
maybe_anno(Node, Fun, Ctxt, As)
62
maybe_anno(Node, Fun, Ctxt, As) ->
63
case strip_line(As) of
67
Ctxt1 = add_indent(Ctxt, 2),
68
Ctxt2 = add_indent(Ctxt1, 3),
72
"-| ",format_1(core_lib:make_literal(List), Ctxt2)," )"
76
strip_line([A | As]) when integer(A) ->
78
strip_line([A | As]) ->
83
get_line([L | _As]) when integer(L) ->
91
maybe_anno(Node, fun format_1/2, Ctxt).
93
format_1(#c_char{val=C}, _) -> io_lib:write_char(C);
94
format_1(#c_int{val=I}, _) -> integer_to_list(I);
95
format_1(#c_float{val=F}, _) -> float_to_list(F);
96
format_1(#c_atom{val=A}, _) -> core_atom(A);
97
format_1(#c_nil{}, _) -> "[]";
98
format_1(#c_string{val=S}, _) -> io_lib:write_string(S);
99
format_1(#c_var{name=V}, _) ->
100
%% Internal variable names may be:
101
%% - atoms representing proper Erlang variable names, or
102
%% any atoms that may be printed without single-quoting
103
%% - nonnegative integers.
104
%% It is important that when printing variables, no two names
105
%% should ever map to the same string.
109
[C | _] when C >= $A, C =< $Z ->
110
%% Ordinary uppercase-prefixed names are
111
%% printed just as they are.
114
%% Already "_"-prefixed names are prefixed
115
%% with "_X", e.g. '_foo' => '_X_foo', to
116
%% avoid generating things like "____foo" upon
117
%% repeated writing and reading of code.
118
%% ("_X_X_X_foo" is better.)
121
%% Plain atoms are prefixed with a single "_".
122
%% E.g. foo => "_foo".
126
%% Integers are also simply prefixed with "_".
127
[$_ | integer_to_list(V)]
129
format_1(#c_binary{segments=Segs}, Ctxt) ->
131
format_vseq(Segs, "", ",", add_indent(Ctxt, 2),
132
fun format_bitstr/2),
135
format_1(#c_tuple{es=Es}, Ctxt) ->
137
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
140
format_1(#c_cons{hd=H,tl=T}, Ctxt) ->
141
Txt = ["["|format(H, add_indent(Ctxt, 1))],
142
[Txt|format_list_tail(T, add_indent(Ctxt, width(Txt, Ctxt)))];
143
format_1(#c_values{es=Es}, Ctxt) ->
144
format_values(Es, Ctxt);
145
format_1(#c_alias{var=V,pat=P}, Ctxt) ->
146
Txt = [format(V, Ctxt)|" = "],
147
[Txt|format(P, add_indent(Ctxt, width(Txt, Ctxt)))];
148
format_1(#c_let{vars=Vs,arg=A,body=B}, Ctxt) ->
149
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
151
format_values(Vs, add_indent(Ctxt, 4)),
157
| format(B, add_indent(Ctxt, 4))
159
format_1(#c_letrec{defs=Fs,body=B}, Ctxt) ->
160
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
163
format_funcs(Fs, Ctxt1),
166
| format(B, add_indent(Ctxt, 4))
168
format_1(#c_seq{arg=A,body=B}, Ctxt) ->
169
Ctxt1 = add_indent(Ctxt, 4),
175
format_1(#c_case{arg=A,clauses=Cs}, Ctxt) ->
176
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.item_indent),
178
format(A, add_indent(Ctxt, 5)),
181
format_clauses(Cs, Ctxt1),
185
format_1(#c_receive{clauses=Cs,timeout=T,action=A}, Ctxt) ->
186
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.item_indent),
189
format_clauses(Cs, Ctxt1),
192
format(T, add_indent(Ctxt, 6)),
197
format_1(#c_fname{id=I,arity=A}, _) ->
198
[core_atom(I),$/,integer_to_list(A)];
199
format_1(#c_fun{vars=Vs,body=B}, Ctxt) ->
200
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
202
format_hseq(Vs, ",", add_indent(Ctxt, 5), fun format/2),
207
format_1(#c_apply{op=O,args=As}, Ctxt0) ->
208
Ctxt1 = add_indent(Ctxt0, 6), %"apply "
209
Op = format(O, Ctxt1),
210
Ctxt2 = add_indent(Ctxt0, 4),
213
$(,format_hseq(As, ", ", add_indent(Ctxt2, 1), fun format/2),$)
215
format_1(#c_call{module=M,name=N,args=As}, Ctxt0) ->
216
Ctxt1 = add_indent(Ctxt0, 5), %"call "
217
Mod = format(M, Ctxt1),
218
Ctxt2 = add_indent(Ctxt1, width(Mod, Ctxt1)+1),
219
Name = format(N, Ctxt2),
220
Ctxt3 = add_indent(Ctxt0, 4),
221
["call ",Mod,":",Name,
223
$(,format_hseq(As, ", ", add_indent(Ctxt3, 1), fun format/2),$)
225
format_1(#c_primop{name=N,args=As}, Ctxt0) ->
226
Ctxt1 = add_indent(Ctxt0, 7), %"primop "
227
Name = format(N, Ctxt1),
228
Ctxt2 = add_indent(Ctxt0, 4),
231
$(,format_hseq(As, ", ", add_indent(Ctxt2, 1), fun format/2),$)
233
format_1(#c_catch{body=B}, Ctxt) ->
234
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
239
format_1(#c_try{arg=E,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
240
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
246
format_values(Vs, add_indent(Ctxt, 3)),
252
format_values(Evs, add_indent(Ctxt, 6)),
257
format_1(#c_def{name=N,val=V}, Ctxt) ->
258
Ctxt1 = add_indent(set_class(Ctxt, expr), Ctxt#ctxt.body_indent),
264
format_1(#c_module{name=N,exports=Es,attrs=As,defs=Ds}, Ctxt) ->
265
Mod = ["module ", format(N, Ctxt)],
269
add_indent(set_class(Ctxt, term), width(Mod, Ctxt)+2),
276
add_indent(set_class(Ctxt, def), 16),
280
format_funcs(Ds, Ctxt),
285
["** Unsupported type: ",
290
format_funcs(Fs, Ctxt) ->
293
set_class(Ctxt, def),
296
format_values(Vs, Ctxt) ->
298
format_hseq(Vs, ",", add_indent(Ctxt, 1), fun format/2),
301
format_bitstr(#c_bitstr{val=V,size=S,unit=U,type=T,flags=Fs}, Ctxt0) ->
303
Ctxt1 = add_indent(Ctxt0, 2),
304
Val = format(V, Ctxt1),
305
Ctxt2 = add_indent(Ctxt1, width(Val, Ctxt1) + 2),
306
["#<", Val, ">(", format_hseq(Vs,",", Ctxt2, fun format/2), $)].
308
format_clauses(Cs, Ctxt) ->
309
format_vseq(Cs, "", "", set_class(Ctxt, clause),
310
fun format_clause/2).
312
format_clause(Node, Ctxt) ->
313
maybe_anno(Node, fun format_clause_1/2, Ctxt).
315
format_clause_1(#c_clause{pats=Ps,guard=G,body=B}, Ctxt) ->
316
Ptxt = format_values(Ps, Ctxt),
317
Ctxt2 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
320
format_guard(G, add_indent(set_class(Ctxt, expr),
321
width(Ptxt, Ctxt) + 6)),
324
| format(B, set_class(Ctxt2, expr))
327
format_guard(Node, Ctxt) ->
328
maybe_anno(Node, fun format_guard_1/2, Ctxt).
330
format_guard_1(#c_call{module=M,name=N,args=As}, Ctxt0) ->
331
Ctxt1 = add_indent(Ctxt0, 5), %"call "
332
Mod = format(M, Ctxt1),
333
Ctxt2 = add_indent(Ctxt1, width(Mod, Ctxt1)+1),
334
Name = format(N, Ctxt2),
335
Ctxt3 = add_indent(Ctxt0, 4),
336
["call ",Mod,":",Name,
338
$(,format_vseq(As, "",",", add_indent(Ctxt3, 1), fun format_guard/2),$)
340
format_guard_1(E, Ctxt) -> format_1(E, Ctxt). %Anno already done
342
%% format_hseq([Thing], Separator, Context, Fun) -> Txt.
343
%% Format a sequence horizontally on the same line with Separator between.
345
format_hseq([H], _, Ctxt, Fun) ->
347
format_hseq([H|T], Sep, Ctxt, Fun) ->
348
Txt = [Fun(H, Ctxt)|Sep],
349
Ctxt1 = add_indent(Ctxt, width(Txt, Ctxt)),
350
[Txt|format_hseq(T, Sep, Ctxt1, Fun)];
351
format_hseq([], _, _, _) -> "".
353
%% format_vseq([Thing], LinePrefix, LineSuffix, Context, Fun) -> Txt.
354
%% Format a sequence vertically in indented lines adding LinePrefix
355
%% to the beginning of each line and LineSuffix to the end of each
356
%% line. No prefix on the first line or suffix on the last line.
358
format_vseq([H], _Pre, _Suf, Ctxt, Fun) ->
360
format_vseq([H|T], Pre, Suf, Ctxt, Fun) ->
361
[Fun(H, Ctxt),Suf,nl_indent(Ctxt),Pre|
362
format_vseq(T, Pre, Suf, Ctxt, Fun)];
363
format_vseq([], _, _, _, _) -> "".
365
format_list_tail(#c_nil{anno=[]}, _) -> "]";
366
format_list_tail(#c_cons{anno=[],hd=H,tl=T}, Ctxt) ->
367
Txt = [$,|format(H, Ctxt)],
368
Ctxt1 = add_indent(Ctxt, width(Txt, Ctxt)),
369
[Txt|format_list_tail(T, Ctxt1)];
370
format_list_tail(Tail, Ctxt) ->
371
["|",format(Tail, add_indent(Ctxt, 1)),"]"].
373
indent(Ctxt) -> indent(Ctxt#ctxt.indent, Ctxt).
375
indent(N, _) when N =< 0 -> "";
377
T = Ctxt#ctxt.tab_width,
378
string:chars($\t, N div T, string:chars($\s, N rem T)).
380
nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
384
unindent(T, Ctxt#ctxt.indent, Ctxt, []).
386
unindent(T, N, _, C) when N =< 0 ->
388
unindent([$\s|T], N, Ctxt, C) ->
389
unindent(T, N - 1, Ctxt, C);
390
unindent([$\t|T], N, Ctxt, C) ->
391
Tab = Ctxt#ctxt.tab_width,
393
unindent(T, N - Tab, Ctxt, C);
395
unindent([string:chars($\s, Tab - N)|T], 0, Ctxt, C)
397
unindent([L|T], N, Ctxt, C) when list(L) ->
398
unindent(L, N, Ctxt, [T|C]);
399
unindent([H|T], _, _, C) ->
401
unindent([], N, Ctxt, [H|T]) ->
402
unindent(H, N, Ctxt, T);
403
unindent([], _, _, []) -> [].
407
case catch width(Txt, 0, Ctxt, []) of
408
{'EXIT',_} -> exit({bad_text,Txt});
412
width([$\t|T], A, Ctxt, C) ->
413
width(T, A + Ctxt#ctxt.tab_width, Ctxt, C);
414
width([$\n|T], _, Ctxt, C) ->
415
width(unindent([T|C], Ctxt), Ctxt);
416
width([H|T], A, Ctxt, C) when list(H) ->
417
width(H, A, Ctxt, [T|C]);
418
width([_|T], A, Ctxt, C) ->
419
width(T, A + 1, Ctxt, C);
420
width([], A, Ctxt, [H|T]) ->
421
width(H, A, Ctxt, T);
422
width([], A, _, []) -> A.
424
add_indent(Ctxt, Dx) ->
425
Ctxt#ctxt{indent = Ctxt#ctxt.indent + Dx}.
427
set_class(Ctxt, Class) ->
428
Ctxt#ctxt{class = Class}.
430
core_atom(A) -> io_lib:write_string(atom_to_list(A), $').