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: v3_kernel_pp.erl,v 1.1 2008/12/17 09:53:43 mikpe Exp $
18
%% Purpose : Kernel Erlang (naive) prettyprinter
20
-module(v3_kernel_pp).
22
-include("v3_kernel.hrl").
26
%% These are "internal" structures in sys_kernel which are here for
27
%% debugging purposes.
28
-record(iset, {anno=[],vars,arg,body}).
29
-record(ifun, {anno=[],vars,body}).
31
%% ====================================================================== %%
32
%% format(Node) -> Text
33
%% Node = coreErlang()
34
%% Text = string() | [Text]
36
%% Prettyprint-formats (naively) an abstract Core Erlang syntax
39
-record(ctxt, {indent = 0,
44
canno(Cthing) -> element(2, Cthing).
46
format(Node) -> format(Node, #ctxt{}).
53
format_anno(List, Ctxt, fun (Ctxt1) -> format_1(Node, Ctxt1) end)
56
format_anno(Anno, Ctxt, ObjFun) ->
57
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
61
"-| ",io_lib:write(Anno),
64
%% format_1(Kexpr, Context) -> string().
66
format_1(#k_atom{val=A}, _Ctxt) -> core_atom(A);
67
%%format_1(#k_char{val=C}, _Ctxt) -> io_lib:write_char(C);
68
format_1(#k_float{val=F}, _Ctxt) -> float_to_list(F);
69
format_1(#k_int{val=I}, _Ctxt) -> integer_to_list(I);
70
format_1(#k_nil{}, _Ctxt) -> "[]";
71
format_1(#k_string{val=S}, _Ctxt) -> io_lib:write_string(S);
72
format_1(#k_var{name=V}, _Ctxt) ->
74
case atom_to_list(V) of
75
[$_|Cs] -> "_X" ++ Cs;
76
[C|Cs] when C >= $A, C =< $Z -> [C|Cs];
79
integer(V) -> [$_|integer_to_list(V)]
81
format_1(#k_cons{hd=H,tl=T}, Ctxt) ->
82
Txt = ["["|format(H, ctxt_bump_indent(Ctxt, 1))],
83
[Txt|format_list_tail(T, ctxt_bump_indent(Ctxt, width(Txt, Ctxt)))];
84
format_1(#k_tuple{es=Es}, Ctxt) ->
86
format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
89
format_1(#k_binary{segs=S}, Ctxt) ->
90
["#<",format(S, ctxt_bump_indent(Ctxt, 2)),">#"];
91
format_1(#k_bin_seg{}=S, Ctxt) ->
92
[format_bin_seg_1(S, Ctxt),
93
format_bin_seg(S#k_bin_seg.next, ctxt_bump_indent(Ctxt, 2))];
94
format_1(#k_bin_end{}, _Ctxt) -> "#<>#";
95
format_1(#k_local{name=N,arity=A}, Ctxt) ->
96
"local " ++ format_fa_pair({N,A}, Ctxt);
97
format_1(#k_remote{mod=M,name=N,arity=A}, _Ctxt) ->
98
%% This is for our internal translator.
99
io_lib:format("remote ~s:~s/~w", [format(M),format(N),A]);
100
format_1(#k_internal{name=N,arity=A}, Ctxt) ->
101
"internal " ++ format_fa_pair({N,A}, Ctxt);
102
format_1(#k_seq{arg=A,body=B}, Ctxt) ->
103
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
112
format_1(#k_match{vars=Vs,body=Bs,ret=Rs}, Ctxt) ->
113
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.item_indent),
115
format_hseq(Vs, ",", ctxt_bump_indent(Ctxt, 6), fun format/2),
120
format_ret(Rs, Ctxt1)
122
format_1(#k_alt{first=O,then=T}, Ctxt) ->
123
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.item_indent),
129
format_1(#k_select{var=V,types=Cs}, Ctxt) ->
130
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
134
format_vseq(Cs, "", "", Ctxt1, fun format/2)
136
format_1(#k_type_clause{type=T,values=Cs}, Ctxt) ->
137
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
141
format_vseq(Cs, "", "", Ctxt1, fun format/2)
143
format_1(#k_val_clause{val=Val,body=B}, Ctxt) ->
144
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
150
format_1(#k_guard{clauses=Gs}, Ctxt) ->
151
Ctxt1 = ctxt_bump_indent(Ctxt, 5),
154
format_vseq(Gs, "", "", Ctxt1, fun format/2)];
155
format_1(#k_guard_clause{guard=G,body=B}, Ctxt) ->
156
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
163
format_1(#k_call{op=Op,args=As,ret=Rs}, Ctxt) ->
164
Txt = ["call (",format(Op, ctxt_bump_indent(Ctxt, 6)),$)],
165
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
166
[Txt,format_args(As, Ctxt1),
167
format_ret(Rs, Ctxt1)
169
format_1(#k_enter{op=Op,args=As}, Ctxt) ->
170
Txt = ["enter (",format(Op, ctxt_bump_indent(Ctxt, 7)),$)],
171
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
172
[Txt,format_args(As, Ctxt1)];
173
format_1(#k_bif{op=Op,args=As,ret=Rs}, Ctxt) ->
174
Txt = ["bif (",format(Op, ctxt_bump_indent(Ctxt, 5)),$)],
175
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
176
[Txt,format_args(As, Ctxt1),
177
format_ret(Rs, Ctxt1)
179
format_1(#k_test{op=Op,args=As}, Ctxt) ->
180
Txt = ["test (",format(Op, ctxt_bump_indent(Ctxt, 6)),$)],
181
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
182
[Txt,format_args(As, Ctxt1)];
183
format_1(#k_put{arg=A,ret=Rs}, Ctxt) ->
185
format_ret(Rs, ctxt_bump_indent(Ctxt, 1))
187
format_1(#k_try{arg=A,vars=Vs,body=B,evars=Evs,handler=H,ret=Rs}, Ctxt) ->
188
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
194
format_hseq(Vs, ", ", ctxt_bump_indent(Ctxt, 3), fun format/2),
199
format_hseq(Evs, ", ", ctxt_bump_indent(Ctxt, 6), fun format/2),
204
format_ret(Rs, Ctxt1)
206
format_1(#k_catch{body=B,ret=Rs}, Ctxt) ->
207
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
213
format_ret(Rs, Ctxt1)
215
format_1(#k_receive{var=V,body=B,timeout=T,action=A,ret=Rs}, Ctxt) ->
216
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.item_indent),
223
format(T, ctxt_bump_indent(Ctxt, 6)),
229
format_ret(Rs, Ctxt1)
231
format_1(#k_receive_accept{}, _Ctxt) -> "receive_accept";
232
format_1(#k_receive_next{}, _Ctxt) -> "receive_next";
233
format_1(#k_break{args=As}, Ctxt) ->
235
format_hseq(As, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
238
format_1(#k_return{args=As}, Ctxt) ->
240
format_hseq(As, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
243
format_1(#k_fdef{func=F,arity=A,vars=Vs,body=B}, Ctxt) ->
244
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
246
format_fa_pair({F,A}, ctxt_bump_indent(Ctxt, 5)),
247
format_args(Vs, ctxt_bump_indent(Ctxt, 14)),
252
format_1(#k_mdef{name=N,exports=Es,attributes=As,body=B}, Ctxt) ->
254
format(#k_atom{val=N}, ctxt_bump_indent(Ctxt, 7)),
259
ctxt_bump_indent(Ctxt, 8),
260
fun format_fa_pair/2),
266
ctxt_bump_indent(Ctxt, 12),
267
fun format_attribute/2),
277
%% Internal sys_kernel structures.
278
format_1(#iset{vars=Vs,arg=A,body=B}, Ctxt) ->
279
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
281
format_hseq(Vs, ", ", ctxt_bump_indent(Ctxt, 5), fun format/2),
287
| format(B, ctxt_bump_indent(Ctxt, 2))
289
format_1(#ifun{vars=Vs,body=B}, Ctxt) ->
290
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
292
format_args(Vs, ctxt_bump_indent(Ctxt, 4)),
297
format_1(Type, _Ctxt) ->
298
["** Unsupported type: ",
303
%% format_ret([RetVar], Context) -> Txt.
304
%% Format the return vars of kexpr.
306
format_ret(Rs, Ctxt) ->
309
format_hseq(Rs, ",", ctxt_bump_indent(Ctxt, 5), fun format/2),
312
%% format_args([Arg], Context) -> Txt.
315
format_args(As, Ctxt) ->
316
[$(,format_hseq(As, ", ", ctxt_bump_indent(Ctxt, 1), fun format/2),$)].
318
%% format_hseq([Thing], Separator, Context, Fun) -> Txt.
319
%% Format a sequence horizontally.
321
format_hseq([H], _Sep, Ctxt, Fun) ->
323
format_hseq([H|T], Sep, Ctxt, Fun) ->
324
Txt = [Fun(H, Ctxt)|Sep],
325
Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt, Ctxt)),
326
[Txt|format_hseq(T, Sep, Ctxt1, Fun)];
327
format_hseq([], _, _, _) -> "".
329
%% format_vseq([Thing], LinePrefix, LineSuffix, Context, Fun) -> Txt.
330
%% Format a sequence vertically.
332
format_vseq([H], _Pre, _Suf, Ctxt, Fun) ->
334
format_vseq([H|T], Pre, Suf, Ctxt, Fun) ->
335
[Fun(H, Ctxt),Suf,nl_indent(Ctxt),Pre|
336
format_vseq(T, Pre, Suf, Ctxt, Fun)];
337
format_vseq([], _, _, _, _) -> "".
339
format_fa_pair({F,A}, _Ctxt) -> [core_atom(F),$/,integer_to_list(A)].
341
%% format_attribute({Name,Val}, Context) -> Txt.
343
format_attribute({Name,Val}, Ctxt) when list(Val) ->
344
Txt = format(#k_atom{val=Name}, Ctxt),
345
Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt,Ctxt)+4),
347
$[,format_vseq(Val, "", ",", Ctxt1,
348
fun (A, _C) -> io_lib:write(A) end),$]
350
format_attribute({Name,Val}, Ctxt) ->
351
Txt = format(#k_atom{val=Name}, Ctxt),
352
[Txt," = ",io_lib:write(Val)].
354
format_list_tail(#k_nil{anno=[]}, _Ctxt) -> "]";
355
format_list_tail(#k_cons{anno=[],hd=H,tl=T}, Ctxt) ->
356
Txt = [$,|format(H, Ctxt)],
357
Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt, Ctxt)),
358
[Txt|format_list_tail(T, Ctxt1)];
359
format_list_tail(Tail, Ctxt) ->
360
["|",format(Tail, ctxt_bump_indent(Ctxt, 1)), "]"].
362
format_bin_seg(#k_bin_end{anno=[]}, _Ctxt) -> "";
363
format_bin_seg(#k_bin_seg{anno=[],next=N}=Seg, Ctxt) ->
364
Txt = [$,|format_bin_seg_1(Seg, Ctxt)],
365
[Txt|format_bin_seg(N, ctxt_bump_indent(Ctxt, width(Txt, Ctxt)))];
366
format_bin_seg(Seg, Ctxt) ->
367
["|",format(Seg, ctxt_bump_indent(Ctxt, 2))].
369
format_bin_seg_1(#k_bin_seg{size=S,unit=U,type=T,flags=Fs,seg=Seg}, Ctxt) ->
371
":",format(S, Ctxt),"*",io_lib:write(U),
373
lists:map(fun (F) -> [$-,io_lib:write(F)] end, Fs)
376
% format_bin_elements(#k_binary_cons{hd=H,tl=T,size=S,info=I}, Ctxt) ->
378
% Fe = fun (Eh, Es, Ei, Ct) ->
379
% [format(Eh, Ct),":",format(Es, Ct),"/",io_lib:write(Ei)]
382
% #k_zero_binary{} when A == [] ->
384
% #k_binary_cons{} when A == [] ->
385
% Txt = [Fe(H, S, I, Ctxt)|","],
386
% Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt, Ctxt)),
387
% [Txt|format_bin_elements(T, Ctxt1)];
389
% Txt = [Fe(H, S, I, Ctxt)|"|"],
390
% [Txt|format(T, ctxt_bump_indent(Ctxt, width(Txt, Ctxt)))]
393
indent(Ctxt) -> indent(Ctxt#ctxt.indent, Ctxt).
395
indent(N, _Ctxt) when N =< 0 -> "";
397
T = Ctxt#ctxt.tab_width,
398
string:chars($\t, N div T, string:chars($\s, N rem T)).
400
nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
404
unindent(T, Ctxt#ctxt.indent, Ctxt, []).
406
unindent(T, N, _Ctxt, C) when N =< 0 ->
408
unindent([$\s|T], N, Ctxt, C) ->
409
unindent(T, N - 1, Ctxt, C);
410
unindent([$\t|T], N, Ctxt, C) ->
411
Tab = Ctxt#ctxt.tab_width,
413
unindent(T, N - Tab, Ctxt, C);
415
unindent([string:chars($\s, Tab - N)|T], 0, Ctxt, C)
417
unindent([L|T], N, Ctxt, C) when list(L) ->
418
unindent(L, N, Ctxt, [T|C]);
419
unindent([H|T], _N, _Ctxt, C) ->
421
unindent([], N, Ctxt, [H|T]) ->
422
unindent(H, N, Ctxt, T);
423
unindent([], _, _, []) -> [].
427
width(Txt, 0, Ctxt, []).
429
width([$\t|T], A, Ctxt, C) ->
430
width(T, A + Ctxt#ctxt.tab_width, Ctxt, C);
431
width([$\n|T], _A, Ctxt, C) ->
432
width(unindent([T|C], Ctxt), Ctxt);
433
width([H|T], A, Ctxt, C) when list(H) ->
434
width(H, A, Ctxt, [T|C]);
435
width([_|T], A, Ctxt, C) ->
436
width(T, A + 1, Ctxt, C);
437
width([], A, Ctxt, [H|T]) ->
438
width(H, A, Ctxt, T);
439
width([], A, _, []) -> A.
441
ctxt_bump_indent(Ctxt, Dx) ->
442
Ctxt#ctxt{indent=Ctxt#ctxt.indent + Dx}.
444
core_atom(A) -> io_lib:write_string(atom_to_list(A), $').