1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2020. 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-module(erl_pp). 21 22%%% Pretty printer for Erlang code in the same format as returned from 23%%% the parser. It does not always produce pretty code. 24 25-export([form/1,form/2, 26 attribute/1,attribute/2,function/1,function/2, 27 guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4]). 28 29-import(lists, [append/1,foldr/3,map/2,mapfoldl/3,reverse/1,reverse/2]). 30-import(io_lib, [write/1,format/2]). 31-import(erl_parse, [inop_prec/1,preop_prec/1,func_prec/0,max_prec/0, 32 type_inop_prec/1, type_preop_prec/1]). 33 34-define(DEFAULT_LINEWIDTH, 72). 35-define(DEFAULT_INDENT, 4). 36 37-type(hook_function() :: none 38 | fun((Expr :: erl_parse:abstract_expr(), 39 CurrentIndentation :: integer(), 40 CurrentPrecedence :: non_neg_integer(), 41 Options :: options()) -> 42 io_lib:chars())). 43 44-type(option() :: {hook, hook_function()} 45 | {encoding, latin1 | unicode | utf8} 46 | {quote_singleton_atom_types, boolean()} 47 | {linewidth, pos_integer()} 48 | {indent, pos_integer()}). 49-type(options() :: hook_function() | [option()]). 50 51-record(pp, {value_fun, singleton_atom_type_fun, string_fun, char_fun, 52 linewidth=?DEFAULT_LINEWIDTH, indent=?DEFAULT_INDENT}). 53 54-record(options, {hook, encoding, opts}). 55 56%-define(DEBUG, true). 57 58-ifdef(DEBUG). 59-define(FORM_TEST(T), 60 _ = case T of 61 {eof, _Line} -> ok; 62 {warning, _W} -> ok; 63 {error, _E} -> ok; 64 _ -> ?TEST(T) 65 end). 66-define(EXPRS_TEST(L), 67 _ = [?TEST(E) || E <- L]). 68-define(TEST(T), 69 %% Assumes that erl_anno has been compiled with DEBUG=true. 70 %% erl_pp does not use the annoations, but test it anyway. 71 %% Note: hooks are not handled. 72 _ = try 73 erl_parse:map_anno(fun(A) when is_list(A) -> A end, T) 74 catch 75 _:_ -> 76 erlang:error(badarg, [T]) 77 end). 78-else. 79-define(FORM_TEST(T), ok). 80-define(EXPRS_TEST(T), ok). 81-define(TEST(T), ok). 82-endif. 83 84%%% 85%%% Exported functions 86%%% 87 88-spec(form(Form) -> io_lib:chars() when 89 Form :: erl_parse:abstract_form() | erl_parse:form_info()). 90 91form(Thing) -> 92 form(Thing, none). 93 94-spec(form(Form, Options) -> io_lib:chars() when 95 Form :: erl_parse:abstract_form() | erl_parse:form_info(), 96 Options :: options()). 97 98form(Thing, Options) -> 99 ?FORM_TEST(Thing), 100 State = state(Options), 101 frmt(lform(Thing, options(Options)), State). 102 103-spec(attribute(Attribute) -> io_lib:chars() when 104 Attribute :: erl_parse:abstract_form()). 105 106attribute(Thing) -> 107 attribute(Thing, none). 108 109-spec(attribute(Attribute, Options) -> io_lib:chars() when 110 Attribute :: erl_parse:abstract_form(), 111 Options :: options()). 112 113attribute(Thing, Options) -> 114 ?TEST(Thing), 115 State = state(Options), 116 frmt(lattribute(Thing, options(Options)), State). 117 118-spec(function(Function) -> io_lib:chars() when 119 Function :: erl_parse:abstract_form()). 120 121function(F) -> 122 function(F, none). 123 124-spec(function(Function, Options) -> io_lib:chars() when 125 Function :: erl_parse:abstract_form(), 126 Options :: options()). 127 128function(F, Options) -> 129 ?TEST(F), 130 frmt(lfunction(F, options(Options)), state(Options)). 131 132-spec(guard(Guard) -> io_lib:chars() when 133 Guard :: [erl_parse:abstract_expr()]). 134 135guard(Gs) -> 136 guard(Gs, none). 137 138-spec(guard(Guard, Options) -> io_lib:chars() when 139 Guard :: [erl_parse:abstract_expr()], 140 Options :: options()). 141 142guard(Gs, Options) -> 143 ?EXPRS_TEST(Gs), 144 frmt(lguard(Gs, options(Options)), state(Options)). 145 146-spec(exprs(Expressions) -> io_lib:chars() when 147 Expressions :: [erl_parse:abstract_expr()]). 148 149exprs(Es) -> 150 exprs(Es, 0, none). 151 152-spec(exprs(Expressions, Options) -> io_lib:chars() when 153 Expressions :: [erl_parse:abstract_expr()], 154 Options :: options()). 155 156exprs(Es, Options) -> 157 exprs(Es, 0, Options). 158 159-spec(exprs(Expressions, Indent, Options) -> io_lib:chars() when 160 Expressions :: [erl_parse:abstract_expr()], 161 Indent :: integer(), 162 Options :: options()). 163 164exprs(Es, I, Options) -> 165 ?EXPRS_TEST(Es), 166 frmt({seq,[],[],[$,],lexprs(Es, options(Options))}, I, state(Options)). 167 168-spec(expr(Expression) -> io_lib:chars() when 169 Expression :: erl_parse:abstract_expr()). 170 171expr(E) -> 172 ?TEST(E), 173 frmt(lexpr(E, 0, options(none)), state(none)). 174 175-spec(expr(Expression, Options) -> io_lib:chars() when 176 Expression :: erl_parse:abstract_expr(), 177 Options :: options()). 178 179expr(E, Options) -> 180 ?TEST(E), 181 frmt(lexpr(E, 0, options(Options)), state(Options)). 182 183-spec(expr(Expression, Indent, Options) -> io_lib:chars() when 184 Expression :: erl_parse:abstract_expr(), 185 Indent :: integer(), 186 Options :: options()). 187 188expr(E, I, Options) -> 189 ?TEST(E), 190 frmt(lexpr(E, 0, options(Options)), I, state(Options)). 191 192-spec(expr(Expression, Indent, Precedence, Options) -> io_lib:chars() when 193 Expression :: erl_parse:abstract_expr(), 194 Indent :: integer(), 195 Precedence :: non_neg_integer(), 196 Options :: options()). 197 198expr(E, I, P, Options) -> 199 ?TEST(E), 200 frmt(lexpr(E, P, options(Options)), I, state(Options)). 201 202%%% 203%%% Local functions 204%%% 205 206options(Options) when is_list(Options) -> 207 Hook = proplists:get_value(hook, Options, none), 208 Encoding = encoding(Options), 209 #options{hook = Hook, encoding = Encoding, opts = Options}; 210options(Hook) -> 211 #options{hook = Hook, encoding = encoding([]), opts = Hook}. 212 213state(Options) when is_list(Options) -> 214 Quote = proplists:get_bool(quote_singleton_atom_types, Options), 215 State = 216 case encoding(Options) of 217 latin1 -> latin1_state(Quote); 218 unicode -> unicode_state(Quote) 219 end, 220 Indent = proplists:get_value(indent, Options, ?DEFAULT_INDENT), 221 LineWidth = proplists:get_value(linewidth, Options, ?DEFAULT_LINEWIDTH), 222 State#pp{indent=Indent, linewidth=LineWidth}; 223state(_Hook) -> 224 latin1_state(false). 225 226latin1_state(Quote) -> 227 Options = [{encoding,latin1}], 228 ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end, 229 SingletonFun = 230 case Quote of 231 true -> 232 fun(A) -> 233 io_lib:write_string_as_latin1(atom_to_list(A), $') 234 end; %' 235 false -> 236 ValueFun 237 end, 238 #pp{value_fun = ValueFun, 239 singleton_atom_type_fun = SingletonFun, 240 string_fun = fun io_lib:write_string_as_latin1/1, 241 char_fun = fun io_lib:write_char_as_latin1/1}. 242 243unicode_state(Quote) -> 244 Options = [{encoding,unicode}], 245 ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end, 246 SingletonFun = 247 case Quote of 248 true -> 249 fun(A) -> io_lib:write_string(atom_to_list(A), $') end; %' 250 false -> 251 ValueFun 252 end, 253 #pp{value_fun = ValueFun, 254 singleton_atom_type_fun = SingletonFun, 255 string_fun = fun io_lib:write_string/1, 256 char_fun = fun io_lib:write_char/1}. 257 258encoding(Options) -> 259 case proplists:get_value(encoding, Options, epp:default_encoding()) of 260 latin1 -> latin1; 261 utf8 -> unicode; 262 unicode -> unicode 263 end. 264 265lform({attribute,Line,Name,Arg}, Opts) -> 266 lattribute({attribute,Line,Name,Arg}, Opts); 267lform({function,Line,Name,Arity,Clauses}, Opts) -> 268 lfunction({function,Line,Name,Arity,Clauses}, Opts); 269%% These are specials to make it easier for the compiler. 270lform({error,_}=E, Opts) -> 271 message(E, Opts); 272lform({warning,_}=W, Opts) -> 273 message(W, Opts); 274lform({eof,_Line}, _Opts) -> 275 $\n. 276 277message(M, #options{encoding = Encoding}) -> 278 F = case Encoding of 279 latin1 -> "~p\n"; 280 unicode -> "~tp\n" 281 end, 282 leaf(format(F, [M])). 283 284lattribute({attribute,_Line,type,Type}, Opts) -> 285 [typeattr(type, Type, Opts),leaf(".\n")]; 286lattribute({attribute,_Line,opaque,Type}, Opts) -> 287 [typeattr(opaque, Type, Opts),leaf(".\n")]; 288lattribute({attribute,_Line,spec,Arg}, _Opts) -> 289 [specattr(spec, Arg),leaf(".\n")]; 290lattribute({attribute,_Line,callback,Arg}, _Opts) -> 291 [specattr(callback, Arg),leaf(".\n")]; 292lattribute({attribute,_Line,Name,Arg}, Opts) -> 293 [lattribute(Name, Arg, Opts),leaf(".\n")]. 294 295lattribute(module, {M,Vs}, _Opts) -> 296 A = a0(), 297 attr(module,[{var,A,pname(M)}, 298 foldr(fun(V, C) -> {cons,A,{var,A,V},C} 299 end, {nil,A}, Vs)]); 300lattribute(module, M, _Opts) -> 301 attr(module, [{var,a0(),pname(M)}]); 302lattribute(export, Falist, _Opts) -> 303 attrib(export, falist(Falist)); 304lattribute(import, Name, _Opts) when is_list(Name) -> 305 attr(import, [{var,a0(),pname(Name)}]); 306lattribute(import, {From,Falist}, _Opts) -> 307 attrib(import, [leaf(pname(From)),falist(Falist)]); 308lattribute(export_type, Talist, _Opts) -> 309 attrib(export_type, falist(Talist)); 310lattribute(optional_callbacks, Falist, Opts) -> 311 try attrib(optional_callbacks, falist(Falist)) 312 catch _:_ -> attr(optional_callbacks, [abstract(Falist, Opts)]) 313 end; 314lattribute(file, {Name,Line}, _Opts) -> 315 attr(file, [{string,a0(),Name},{integer,a0(),Line}]); 316lattribute(record, {Name,Is}, Opts) -> 317 Nl = [leaf("-record("),{atom,Name},$,], 318 [{first,Nl,record_fields(Is, Opts)},$)]; 319lattribute(Name, Arg, Options) -> 320 attr(Name, [abstract(Arg, Options)]). 321 322abstract(Arg, #options{encoding = Encoding}) -> 323 erl_parse:abstract(Arg, [{encoding,Encoding}]). 324 325typeattr(Tag, {TypeName,Type,Args}, _Opts) -> 326 {first,leaf("-"++atom_to_list(Tag)++" "), 327 typed(call({atom,a0(),TypeName}, Args, 0, options(none)), Type)}. 328 329ltype(T) -> 330 ltype(T, 0). 331 332ltype({ann_type,_Line,[V,T]}, Prec) -> 333 {L,P,R} = type_inop_prec('::'), 334 Vl = ltype(V, L), 335 Tr = ltype(T, R), 336 El = {list,[{cstep,[Vl,' ::'],Tr}]}, 337 maybe_paren(P, Prec, El); 338ltype({paren_type,_Line,[T]}, P) -> 339 %% Generated before Erlang/OTP 18. 340 ltype(T, P); 341ltype({type,_Line,union,Ts}, Prec) -> 342 {_L,P,R} = type_inop_prec('|'), 343 E = {seq,[],[],[' |'],ltypes(Ts, R)}, 344 maybe_paren(P, Prec, E); 345ltype({type,_Line,list,[T]}, _) -> 346 {seq,$[,$],$,,[ltype(T)]}; 347ltype({type,_Line,nonempty_list,[T]}, _) -> 348 {seq,$[,$],[$,],[ltype(T),leaf("...")]}; 349ltype({type,Line,nil,[]}, _) -> 350 lexpr({nil,Line}, options(none)); 351ltype({type,Line,map,any}, _) -> 352 simple_type({atom,Line,map}, []); 353ltype({type,_Line,map,Pairs}, Prec) -> 354 {P,_R} = type_preop_prec('#'), 355 E = map_type(Pairs), 356 maybe_paren(P, Prec, E); 357ltype({type,Line,tuple,any}, _) -> 358 simple_type({atom,Line,tuple}, []); 359ltype({type,_Line,tuple,Ts}, _) -> 360 tuple_type(Ts, fun ltype/2); 361ltype({type,_Line,record,[{atom,_,N}|Fs]}, Prec) -> 362 {P,_R} = type_preop_prec('#'), 363 E = record_type(N, Fs), 364 maybe_paren(P, Prec, E); 365ltype({type,_Line,range,[_I1,_I2]=Es}, Prec) -> 366 {_L,P,R} = type_inop_prec('..'), 367 F = fun(E, Opts) -> lexpr(E, R, Opts) end, 368 E = expr_list(Es, '..', F, options(none)), 369 maybe_paren(P, Prec, E); 370ltype({type,_Line,binary,[I1,I2]}, _) -> 371 binary_type(I1, I2); % except binary() 372ltype({type,_Line,'fun',[]}, _) -> 373 leaf("fun()"); 374ltype({type,_,'fun',[{type,_,any},_]}=FunType, _) -> 375 [fun_type(['fun',$(], FunType),$)]; 376ltype({type,_Line,'fun',[{type,_,product,_},_]}=FunType, _) -> 377 [fun_type(['fun',$(], FunType),$)]; 378ltype({type,Line,T,Ts}, _) -> 379 simple_type({atom,Line,T}, Ts); 380ltype({user_type,Line,T,Ts}, _) -> 381 simple_type({atom,Line,T}, Ts); 382ltype({remote_type,Line,[M,F,Ts]}, _) -> 383 simple_type({remote,Line,M,F}, Ts); 384ltype({atom,_,T}, _) -> 385 {singleton_atom_type,T}; 386ltype(E, P) -> 387 lexpr(E, P, options(none)). 388 389binary_type(I1, I2) -> 390 B = [[] || {integer,_,0} <- [I1]] =:= [], 391 U = [[] || {integer,_,0} <- [I2]] =:= [], 392 P = max_prec(), 393 E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B], 394 E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U], 395 case E1++E2 of 396 [] -> 397 leaf("<<>>"); 398 Es -> 399 {seq,'<<','>>',[$,],Es} 400 end. 401 402map_type(Fs) -> 403 {first,[$#],map_pair_types(Fs)}. 404 405map_pair_types(Fs) -> 406 tuple_type(Fs, fun map_pair_type/2). 407 408map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) -> 409 {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]}; 410map_pair_type({type,_Line,map_field_exact,[KType,VType]}, Prec) -> 411 {list,[{cstep,[ltype(KType, Prec),leaf(" :=")],ltype(VType, Prec)}]}. 412 413record_type(Name, Fields) -> 414 {first,[record_name(Name)],field_types(Fields)}. 415 416field_types(Fs) -> 417 tuple_type(Fs, fun field_type/2). 418 419field_type({type,_Line,field_type,[Name,Type]}, _Prec) -> 420 typed(lexpr(Name, options(none)), Type). 421 422typed(B, Type) -> 423 {list,[{cstep,[B,' ::'],ltype(Type)}]}. 424 425tuple_type([], _) -> 426 leaf("{}"); 427tuple_type(Ts, F) -> 428 {seq,${,$},[$,],ltypes(Ts, F, 0)}. 429 430specattr(SpecKind, {FuncSpec,TypeSpecs}) -> 431 Func = case FuncSpec of 432 {F,_A} -> 433 {atom,F}; 434 {M,F,_A} -> 435 [{atom,M},$:,{atom,F}] 436 end, 437 {first,leaf(lists:concat(["-", SpecKind, " "])), 438 {list,[{first,Func,spec_clauses(TypeSpecs)}]}}. 439 440spec_clauses(TypeSpecs) -> 441 {prefer_nl,[$;],[sig_type(T) || T <- TypeSpecs]}. 442 443sig_type({type,_Line,bounded_fun,[T,Gs]}) -> 444 guard_type(fun_type([], T), Gs); 445sig_type(FunType) -> 446 fun_type([], FunType). 447 448guard_type(Before, Gs) -> 449 Opts = options(none), 450 Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]}, 451 {list,[{step,Before,Gl}]}. 452 453constraint({type,_Line,constraint,[{atom,_,is_subtype},[{var,_,_}=V,Type]]}, 454 _Opts) -> 455 typed(lexpr(V, options(none)), Type); 456constraint({type,_Line,constraint,[Tag,As]}, _Opts) -> 457 simple_type(Tag, As). 458 459fun_type(Before, {type,_,'fun',[FType,Ret]}) -> 460 {first,Before,{step,[type_args(FType),' ->'],ltype(Ret)}}. 461 462type_args({type,_Line,any}) -> 463 leaf("(...)"); 464type_args({type,_line,product,Ts}) -> 465 targs(Ts). 466 467simple_type(Tag, Types) -> 468 {first,lexpr(Tag, options(none)),targs(Types)}. 469 470targs(Ts) -> 471 {seq,$(,$),[$,],ltypes(Ts, 0)}. 472 473ltypes(Ts, Prec) -> 474 ltypes(Ts, fun ltype/2, Prec). 475 476ltypes(Ts, F, Prec) -> 477 [F(T, Prec) || T <- Ts]. 478 479attr(Name, Args) -> 480 {first,[$-,{atom,Name}],args(Args, options(none))}. 481 482attrib(Name, Args) -> 483 {first,[$-,{atom,Name}],[{seq,$(,$),[$,],Args}]}. 484 485pname(['' | As]) -> 486 [$. | pname(As)]; 487pname([A]) -> 488 write(A); 489pname([A | As]) -> 490 [write(A),$.|pname(As)]; 491pname(A) when is_atom(A) -> 492 write(A). 493 494falist([]) -> 495 ['[]']; 496falist(Falist) -> 497 L = [begin 498 {Name,Arity} = Fa, 499 [{atom,Name},leaf(format("/~w", [Arity]))] 500 end || Fa <- Falist], 501 [{seq,$[,$],$,,L}]. 502 503lfunction({function,_Line,Name,_Arity,Cs}, Opts) -> 504 Cll = nl_clauses(fun (C, H) -> func_clause(Name, C, H) end, $;, Opts, Cs), 505 [Cll,leaf(".\n")]. 506 507func_clause(Name, {clause,Line,Head,Guard,Body}, Opts) -> 508 Hl = call({atom,Line,Name}, Head, 0, Opts), 509 Gl = guard_when(Hl, Guard, Opts), 510 Bl = body(Body, Opts), 511 {step,Gl,Bl}. 512 513guard_when(Before, Guard, Opts) -> 514 guard_when(Before, Guard, Opts, ' ->'). 515 516guard_when(Before, Guard, Opts, After) -> 517 Gl = lguard(Guard, Opts), 518 [{list,[{step,Before,Gl}]},After]. 519 520lguard([E|Es], Opts) when is_list(E) -> 521 {list,[{step,'when',expr_list([E|Es], [$;], fun guard0/2, Opts)}]}; 522lguard([E|Es], Opts) -> % before R6 523 lguard([[E|Es]], Opts); 524lguard([], _) -> 525 []. 526 527guard0(Es, Opts) -> 528 expr_list(Es, [$,], fun lexpr/2, Opts). 529 530%% body(Before, Es, Opts) -> [Char]. 531 532body([E], Opts) -> 533 lexpr(E, Opts); 534body(Es, Opts) -> 535 {prefer_nl,[$,],lexprs(Es, Opts)}. 536 537lexpr(E, Opts) -> 538 lexpr(E, 0, Opts). 539 540lexpr({var,_,V}, _, _) when is_integer(V) -> %Special hack for Robert 541 leaf(format("_~w", [V])); 542lexpr({var,_,V}, _, _) -> leaf(format("~ts", [V])); 543lexpr({char,_,C}, _, _) -> {char,C}; 544lexpr({integer,_,N}, _, _) -> leaf(write(N)); 545lexpr({float,_,F}, _, _) -> leaf(write(F)); 546lexpr({atom,_,A}, _, _) -> {atom,A}; 547lexpr({string,_,S}, _, _) -> {string,S}; 548lexpr({nil,_}, _, _) -> '[]'; 549lexpr({cons,_,H,T}, _, Opts) -> 550 list(T, [H], Opts); 551lexpr({lc,_,E,Qs}, _Prec, Opts) -> 552 P = max_prec(), 553 Lcl = {list,[{step,[lexpr(E, P, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]}, 554 {list,[{seq,$[,[],[[]],[{force_nl,leaf(" "),[Lcl]}]},$]]}; 555 %% {list,[{step,$[,Lcl},$]]}; 556lexpr({bc,_,E,Qs}, _Prec, Opts) -> 557 P = max_prec(), 558 Lcl = {list,[{step,[lexpr(E, P, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]}, 559 {list,[{seq,'<<',[],[[]],[{force_nl,leaf(" "),[Lcl]}]},'>>']}; 560 %% {list,[{step,'<<',Lcl},'>>']}; 561lexpr({tuple,_,Elts}, _, Opts) -> 562 tuple(Elts, Opts); 563lexpr({record_index, _, Name, F}, Prec, Opts) -> 564 {P,R} = preop_prec('#'), 565 Nl = record_name(Name), 566 El = [Nl,$.,lexpr(F, R, Opts)], 567 maybe_paren(P, Prec, El); 568lexpr({record, _, Name, Fs}, Prec, Opts) -> 569 {P,_R} = preop_prec('#'), 570 Nl = record_name(Name), 571 El = {first,Nl,record_fields(Fs, Opts)}, 572 maybe_paren(P, Prec, El); 573lexpr({record_field, _, Rec, Name, F}, Prec, Opts) -> 574 {L,P,R} = inop_prec('#'), 575 Rl = lexpr(Rec, L, Opts), 576 Sep = hash_after_integer(Rec, [$#]), 577 Nl = [Sep,{atom,Name},$.], 578 El = [Rl,Nl,lexpr(F, R, Opts)], 579 maybe_paren(P, Prec, El); 580lexpr({record, _, Rec, Name, Fs}, Prec, Opts) -> 581 {L,P,_R} = inop_prec('#'), 582 Rl = lexpr(Rec, L, Opts), 583 Sep = hash_after_integer(Rec, []), 584 Nl = record_name(Name), 585 El = {first,[Rl,Sep,Nl],record_fields(Fs, Opts)}, 586 maybe_paren(P, Prec, El); 587lexpr({record_field, _, {atom,_,''}, F}, Prec, Opts) -> 588 {_L,P,R} = inop_prec('.'), 589 El = [$.,lexpr(F, R, Opts)], 590 maybe_paren(P, Prec, El); 591lexpr({record_field, _, Rec, F}, Prec, Opts) -> 592 {L,P,R} = inop_prec('.'), 593 El = [lexpr(Rec, L, Opts),$.,lexpr(F, R, Opts)], 594 maybe_paren(P, Prec, El); 595lexpr({map, _, Fs}, Prec, Opts) -> 596 {P,_R} = preop_prec('#'), 597 El = {first,$#,map_fields(Fs, Opts)}, 598 maybe_paren(P, Prec, El); 599lexpr({map, _, Map, Fs}, Prec, Opts) -> 600 {L,P,_R} = inop_prec('#'), 601 Rl = lexpr(Map, L, Opts), 602 Sep = hash_after_integer(Map, [$#]), 603 El = {first,[Rl|Sep],map_fields(Fs, Opts)}, 604 maybe_paren(P, Prec, El); 605lexpr({block,_,Es}, _, Opts) -> 606 {list,[{step,'begin',body(Es, Opts)},{reserved,'end'}]}; 607lexpr({'if',_,Cs}, _, Opts) -> 608 {list,[{step,'if',if_clauses(Cs, Opts)},{reserved,'end'}]}; 609lexpr({'case',_,Expr,Cs}, _, Opts) -> 610 {list,[{step,{list,[{step,'case',lexpr(Expr, Opts)},{reserved,'of'}]}, 611 cr_clauses(Cs, Opts)}, 612 {reserved,'end'}]}; 613lexpr({'cond',_,Cs}, _, Opts) -> 614 {list,[{step,leaf("cond"),cond_clauses(Cs, Opts)},{reserved,'end'}]}; 615lexpr({'receive',_,Cs}, _, Opts) -> 616 {list,[{step,'receive',cr_clauses(Cs, Opts)},{reserved,'end'}]}; 617lexpr({'receive',_,Cs,To,ToOpt}, _, Opts) -> 618 Al = {list,[{step,[lexpr(To, Opts),' ->'],body(ToOpt, Opts)}]}, 619 {list,[{step,'receive',cr_clauses(Cs, Opts)}, 620 {step,'after',Al}, 621 {reserved,'end'}]}; 622lexpr({'fun',_,{function,F,A}}, _Prec, _Opts) -> 623 [leaf("fun "),{atom,F},leaf(format("/~w", [A]))]; 624lexpr({'fun',L,{function,_,_}=Func,Extra}, Prec, Opts) -> 625 {force_nl,fun_info(Extra),lexpr({'fun',L,Func}, Prec, Opts)}; 626lexpr({'fun',L,{function,M,F,A}}, Prec, Opts) 627 when is_atom(M), is_atom(F), is_integer(A) -> 628 %% For backward compatibility with pre-R15 abstract format. 629 Mod = erl_parse:abstract(M), 630 Fun = erl_parse:abstract(F), 631 Arity = erl_parse:abstract(A), 632 lexpr({'fun',L,{function,Mod,Fun,Arity}}, Prec, Opts); 633lexpr({'fun',_,{function,M,F,A}}, _Prec, Opts) -> 634 %% New format in R15. 635 NameItem = lexpr(M, Opts), 636 CallItem = lexpr(F, Opts), 637 ArityItem = lexpr(A, Opts), 638 ["fun ",NameItem,$:,CallItem,$/,ArityItem]; 639lexpr({'fun',_,{clauses,Cs}}, _Prec, Opts) -> 640 {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},{reserved,'end'}]}; 641lexpr({named_fun,_,Name,Cs}, _Prec, Opts) -> 642 {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})}, 643 {reserved,'end'}]}; 644lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Opts) -> 645 {force_nl,fun_info(Extra), 646 {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},{reserved,'end'}]}}; 647lexpr({named_fun,_,Name,Cs,Extra}, _Prec, Opts) -> 648 {force_nl,fun_info(Extra), 649 {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})}, 650 {reserved,'end'}]}}; 651lexpr({call,_,{remote,_,{atom,_,M},{atom,_,F}=N}=Name,Args}, Prec, Opts) -> 652 case erl_internal:bif(M, F, length(Args)) of 653 true when F =/= float -> 654 call(N, Args, Prec, Opts); 655 true -> 656 call(Name, Args, Prec, Opts); 657 false -> 658 call(Name, Args, Prec, Opts) 659 end; 660lexpr({call,_,Name,Args}, Prec, Opts) -> 661 call(Name, Args, Prec, Opts); 662lexpr({'try',_,Es,Scs,Ccs,As}, _, Opts) -> 663 {list,[if 664 Scs =:= [] -> 665 {step,'try',body(Es, Opts)}; 666 true -> 667 {step,{list,[{step,'try',body(Es, Opts)},{reserved,'of'}]}, 668 cr_clauses(Scs, Opts)} 669 end] ++ 670 if 671 Ccs =:= [] -> 672 []; 673 true -> 674 [{step,'catch',try_clauses(Ccs, Opts)}] 675 end ++ 676 if 677 As =:= [] -> 678 []; 679 true -> 680 [{step,'after',body(As, Opts)}] 681 end ++ 682 [{reserved,'end'}]}; 683lexpr({'catch',_,Expr}, Prec, Opts) -> 684 {P,R} = preop_prec('catch'), 685 El = {list,[{step,'catch',lexpr(Expr, R, Opts)}]}, 686 maybe_paren(P, Prec, El); 687lexpr({match,_,Lhs,Rhs}, Prec, Opts) -> 688 {L,P,R} = inop_prec('='), 689 Pl = lexpr(Lhs, L, Opts), 690 Rl = lexpr(Rhs, R, Opts), 691 El = {list,[{cstep,[Pl,' ='],Rl}]}, 692 maybe_paren(P, Prec, El); 693lexpr({op,_,Op,Arg}, Prec, Opts) -> 694 {P,R} = preop_prec(Op), 695 Ol = {reserved, leaf(format("~s ", [Op]))}, 696 El = [Ol,lexpr(Arg, R, Opts)], 697 maybe_paren(P, Prec, El); 698lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) when Op =:= 'orelse'; 699 Op =:= 'andalso' -> 700 %% Breaks lines since R12B. 701 {L,P,R} = inop_prec(Op), 702 Ll = lexpr(Larg, L, Opts), 703 Ol = {reserved, leaf(format("~s", [Op]))}, 704 Lr = lexpr(Rarg, R, Opts), 705 El = {prefer_nl,[[]],[Ll,Ol,Lr]}, 706 maybe_paren(P, Prec, El); 707lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) -> 708 {L,P,R} = inop_prec(Op), 709 Ll = lexpr(Larg, L, Opts), 710 Ol = {reserved, leaf(format("~s", [Op]))}, 711 Lr = lexpr(Rarg, R, Opts), 712 El = {list,[Ll,Ol,Lr]}, 713 maybe_paren(P, Prec, El); 714%% Special expressions which are not really legal everywhere. 715lexpr({remote,_,M,F}, Prec, Opts) -> 716 {L,P,R} = inop_prec(':'), 717 NameItem = lexpr(M, L, Opts), 718 CallItem = lexpr(F, R, Opts), 719 maybe_paren(P, Prec, [NameItem,$:,CallItem]); 720%% BIT SYNTAX: 721lexpr({bin,_,Fs}, _, Opts) -> 722 bit_grp(Fs, Opts); 723%% Special case for straight values. 724lexpr({value,_,Val}, _,_) -> 725 {value,Val}; 726%% Now do the hook. 727lexpr(Other, _Precedence, #options{hook = none}) -> 728 leaf(format("INVALID-FORM:~w:",[Other])); 729lexpr(HookExpr, Precedence, #options{hook = {Mod,Func,Eas}}) 730 when Mod =/= 'fun' -> 731 {ehook,HookExpr,Precedence,{Mod,Func,Eas}}; 732lexpr(HookExpr, Precedence, #options{hook = Func, opts = Options}) -> 733 {hook,HookExpr,Precedence,Func,Options}. 734 735%% An integer is separated from the following '#' by a space, which 736%% erl_scan can handle. 737hash_after_integer({integer, _, _}, C) -> 738 [$\s|C]; 739hash_after_integer({'fun',_,{function, _, _}}, C) -> 740 [$\s|C]; 741hash_after_integer({'fun',_,{function, _, _, _}}, C) -> 742 [$\s|C]; 743hash_after_integer(_, C) -> 744 C. 745 746call(Name, Args, Prec, Opts) -> 747 {F,P} = func_prec(), 748 Item = {first,lexpr(Name, F, Opts),args(Args, Opts)}, 749 maybe_paren(P, Prec, Item). 750 751fun_info(Extra) -> 752 [leaf("% fun-info: "),{value,Extra}]. 753 754%% BITS: 755 756bit_grp([], _Opts) -> 757 leaf("<<>>"); 758bit_grp(Fs, Opts) -> 759 append([['<<'], [bit_elems(Fs, Opts)], ['>>']]). 760 761bit_elems(Es, Opts) -> 762 expr_list(Es, $,, fun bit_elem/2, Opts). 763 764bit_elem({bin_element,_,Expr,Sz,Types}, Opts) -> 765 P = max_prec(), 766 VChars = lexpr(Expr, P, Opts), 767 SChars = if 768 Sz =/= default -> 769 [VChars,$:,lexpr(Sz, P, Opts)]; 770 true -> 771 VChars 772 end, 773 if 774 Types =/= default -> 775 [SChars,$/|bit_elem_types(Types)]; 776 true -> 777 SChars 778 end. 779 780bit_elem_types([T]) -> 781 [bit_elem_type(T)]; 782bit_elem_types([T | Rest]) -> 783 [bit_elem_type(T), $-|bit_elem_types(Rest)]. 784 785bit_elem_type({A,B}) -> 786 [lexpr(erl_parse:abstract(A), options(none)), 787 $:, 788 lexpr(erl_parse:abstract(B), options(none))]; 789bit_elem_type(T) -> 790 lexpr(erl_parse:abstract(T), options(none)). 791 792%% end of BITS 793 794record_name(Name) -> 795 [$#,{atom,Name}]. 796 797record_fields(Fs, Opts) -> 798 tuple(Fs, fun record_field/2, Opts). 799 800record_field({record_field,_,F,Val}, Opts) -> 801 {L,_P,R} = inop_prec('='), 802 Fl = lexpr(F, L, Opts), 803 Vl = lexpr(Val, R, Opts), 804 {list,[{cstep,[Fl,' ='],Vl}]}; 805record_field({typed_record_field,{record_field,_,F,Val},Type}, Opts) -> 806 {L,_P,R} = inop_prec('='), 807 Fl = lexpr(F, L, Opts), 808 Vl = typed(lexpr(Val, R, Opts), Type), 809 {list,[{cstep,[Fl,' ='],Vl}]}; 810record_field({typed_record_field,Field,Type}, Opts) -> 811 typed(record_field(Field, Opts), Type); 812record_field({record_field,_,F}, Opts) -> 813 lexpr(F, 0, Opts). 814 815map_fields(Fs, Opts) -> 816 tuple(Fs, fun map_field/2, Opts). 817 818map_field({map_field_assoc,_,K,V}, Opts) -> 819 Pl = lexpr(K, 0, Opts), 820 {list,[{step,[Pl,leaf(" =>")],lexpr(V, 0, Opts)}]}; 821map_field({map_field_exact,_,K,V}, Opts) -> 822 Pl = lexpr(K, 0, Opts), 823 {list,[{step,[Pl,leaf(" :=")],lexpr(V, 0, Opts)}]}. 824 825list({cons,_,H,T}, Es, Opts) -> 826 list(T, [H|Es], Opts); 827list({nil,_}, Es, Opts) -> 828 proper_list(reverse(Es), Opts); 829list(Other, Es, Opts) -> 830 improper_list(reverse(Es, [Other]), Opts). 831 832%% if_clauses(Clauses, Opts) -> [Char]. 833%% Print 'if' clauses. 834 835if_clauses(Cs, Opts) -> 836 clauses(fun if_clause/2, Opts, Cs). 837 838if_clause({clause,_,[],G,B}, Opts) -> 839 Gl = [guard_no_when(G, Opts),' ->'], 840 {step,Gl,body(B, Opts)}. 841 842guard_no_when([E|Es], Opts) when is_list(E) -> 843 expr_list([E|Es], $;, fun guard0/2, Opts); 844guard_no_when([E|Es], Opts) -> % before R6 845 guard_no_when([[E|Es]], Opts); 846guard_no_when([], _) -> % cannot happen 847 leaf("true"). 848 849%% cr_clauses(Clauses, Opts) -> [Char]. 850%% Print 'case'/'receive' clauses. 851 852cr_clauses(Cs, Opts) -> 853 clauses(fun cr_clause/2, Opts, Cs). 854 855cr_clause({clause,_,[T],G,B}, Opts) -> 856 El = lexpr(T, 0, Opts), 857 Gl = guard_when(El, G, Opts), 858 Bl = body(B, Opts), 859 {step,Gl,Bl}. 860 861%% try_clauses(Clauses, Opts) -> [Char]. 862%% Print 'try' clauses. 863 864try_clauses(Cs, Opts) -> 865 clauses(fun try_clause/2, Opts, Cs). 866 867try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Opts) -> 868 Cs = lexpr(C, 0, Opts), 869 El = lexpr(V, 0, Opts), 870 CsEl = [Cs,$:,El], 871 Sl = stack_backtrace(S, CsEl, Opts), 872 Gl = guard_when(Sl, G, Opts), 873 Bl = body(B, Opts), 874 {step,Gl,Bl}. 875 876stack_backtrace({var,_,'_'}, El, _Opts) -> 877 El; 878stack_backtrace(S, El, Opts) -> 879 El++[$:,lexpr(S, 0, Opts)]. 880 881%% fun_clauses(Clauses, Opts) -> [Char]. 882%% Print 'fun' clauses. 883 884fun_clauses(Cs, Opts, unnamed) -> 885 nl_clauses(fun fun_clause/2, [$;], Opts, Cs); 886fun_clauses(Cs, Opts, {named, Name}) -> 887 nl_clauses(fun (C, H) -> 888 {step,Gl,Bl} = fun_clause(C, H), 889 {step,[atom_to_list(Name),Gl],Bl} 890 end, [$;], Opts, Cs). 891 892fun_clause({clause,_,A,G,B}, Opts) -> 893 El = args(A, Opts), 894 Gl = guard_when(El, G, Opts), 895 Bl = body(B, Opts), 896 {step,Gl,Bl}. 897 898%% cond_clauses(Clauses, Opts) -> [Char]. 899%% Print 'cond' clauses. 900 901cond_clauses(Cs, Opts) -> 902 clauses(fun cond_clause/2, Opts, Cs). 903 904cond_clause({clause,_,[],[[E]],B}, Opts) -> 905 {step,[lexpr(E, Opts),' ->'],body(B, Opts)}. 906 907%% nl_clauses(Type, Opts, Clauses) -> [Char]. 908%% Generic clause printing function (always breaks lines). 909 910nl_clauses(Type, Sep, Opts, Cs) -> 911 {prefer_nl,Sep,lexprs(Cs, Type, Opts)}. 912 913%% clauses(Type, Opts, Clauses) -> [Char]. 914%% Generic clause printing function (breaks lines since R12B). 915 916clauses(Type, Opts, Cs) -> 917 {prefer_nl,[$;],lexprs(Cs, Type, Opts)}. 918 919%% lc_quals(Qualifiers, After, Opts) 920%% List comprehension qualifiers (breaks lines since R12B). 921 922lc_quals(Qs, Opts) -> 923 {prefer_nl,[$,],lexprs(Qs, fun lc_qual/2, Opts)}. 924 925lc_qual({b_generate,_,Pat,E}, Opts) -> 926 Pl = lexpr(Pat, 0, Opts), 927 {list,[{step,[Pl,leaf(" <=")],lexpr(E, 0, Opts)}]}; 928lc_qual({generate,_,Pat,E}, Opts) -> 929 Pl = lexpr(Pat, 0, Opts), 930 {list,[{step,[Pl,leaf(" <-")],lexpr(E, 0, Opts)}]}; 931lc_qual(Q, Opts) -> 932 lexpr(Q, 0, Opts). 933 934proper_list(Es, Opts) -> 935 {seq,$[,$],[$,],lexprs(Es, Opts)}. 936 937improper_list(Es, Opts) -> 938 {seq,$[,$],[{$,,' |'}],lexprs(Es, Opts)}. 939 940tuple(L, Opts) -> 941 tuple(L, fun lexpr/2, Opts). 942 943tuple([], _F, _Opts) -> 944 leaf("{}"); 945tuple(Es, F, Opts) -> 946 {seq,${,$},[$,],lexprs(Es, F, Opts)}. 947 948args(As, Opts) -> 949 {seq,$(,$),[$,],lexprs(As, Opts)}. 950 951expr_list(Es, Sep, F, Opts) -> 952 {seq,[],[],Sep,lexprs(Es, F, Opts)}. 953 954lexprs(Es, Opts) -> 955 lexprs(Es, fun lexpr/2, Opts). 956 957lexprs(Es, F, Opts) -> 958 [F(E, Opts) || E <- Es]. 959 960maybe_paren(P, Prec, Expr) when P < Prec -> 961 [$(,Expr,$)]; 962maybe_paren(_P, _Prec, Expr) -> 963 Expr. 964 965leaf(S) -> 966 {leaf,string:length(S),S}. 967 968%%% Do the formatting. Currently nothing fancy. Could probably have 969%%% done it in one single pass. 970 971frmt(Item, PP) -> 972 frmt(Item, 0, PP). 973 974frmt(Item, I, PP) -> 975 ST = spacetab(), 976 WT = wordtable(), 977 {Chars,_Length} = f(Item, I, ST, WT, PP), 978 [Chars]. 979 980%%% What the tags mean: 981%%% - C: a character 982%%% - [I|Is]: Is follow after I without newline or space 983%%% - {list,IPs}: try to put all IPs on one line, if that fails newlines 984%%% and indentation are inserted between IPs. 985%%% - {first,I,IP2}: IP2 follows after I, and is output with an indentation 986%%% updated with the width of I. 987%%% - {seq,Before,After,Separator,IPs}: a sequence of Is separated by 988%%% Separator. Before is output before IPs, and the indentation of IPs 989%%% is updated with the width of Before. After follows after IPs. 990%%% - {force_nl,ExtraInfo,I}: fun-info (a comment) forces linebreak before I. 991%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative 992%%% indentation. 993%%% - {atom,A}: an atom 994%%% - {singleton_atom_type,A}: a singleton atom type 995%%% - {char,C}: a character 996%%% - {string,S}: a string. 997%%% - {value,T}: a term. 998%%% - {hook,...}, {ehook,...}: hook expressions. 999%%% 1000%%% list, first, seq, force_nl, and prefer_nl all accept IPs, where each 1001%%% element is either an item or a tuple {step|cstep,I1,I2}. step means 1002%%% that I2 is output after linebreak and an incremented indentation. 1003%%% cstep works similarly, but no linebreak if the width of I1 is less 1004%%% than the indentation (this is for "A = <expression over several lines>). 1005 1006f([]=Nil, _I0, _ST, _WT, _PP) -> 1007 {Nil,0}; 1008f(C, _I0, _ST, _WT, _PP) when is_integer(C) -> 1009 {C,1}; 1010f({leaf,Length,Chars}, _I0, _ST, _WT, _PP) -> 1011 {Chars,Length}; 1012f([Item|Items], I0, ST, WT, PP) -> 1013 consecutive(Items, f(Item, I0, ST, WT, PP), I0, ST, WT, PP); 1014f({list,Items}, I0, ST, WT, PP) -> 1015 f({seq,[],[],[[]],Items}, I0, ST, WT, PP); 1016f({first,E,Item}, I0, ST, WT, PP) -> 1017 f({seq,E,[],[[]],[Item]}, I0, ST, WT, PP); 1018f({seq,Before,After,Sep,LItems}, I0, ST, WT, PP) -> 1019 BCharsSize = f(Before, I0, ST, WT, PP), 1020 I = indent(BCharsSize, I0), 1021 CharsSizeL = fl(LItems, Sep, I, After, ST, WT, PP), 1022 {CharsL,SizeL} = unz(CharsSizeL), 1023 {BCharsL,BSizeL} = unz1([BCharsSize]), 1024 Sizes = BSizeL ++ SizeL, 1025 NSepChars = if 1026 is_list(Sep), Sep =/= [] -> 1027 erlang:max(0, length(CharsL)-1); % not string:length 1028 true -> 1029 0 1030 end, 1031 case same_line(I0, Sizes, NSepChars, PP) of 1032 {yes,Size} -> 1033 Chars = if 1034 NSepChars > 0 -> insert_sep(CharsL, $\s); 1035 true -> CharsL 1036 end, 1037 {BCharsL++Chars,Size}; 1038 no -> 1039 CharsList = handle_step(CharsSizeL, I, ST, PP), 1040 {LChars, LSize} = 1041 maybe_newlines(CharsList, LItems, I, NSepChars, ST, PP), 1042 {[BCharsL,LChars],nsz(LSize, I0)} 1043 end; 1044f({force_nl,_ExtraInfoItem,Item}, I, ST, WT, PP) when I < 0 -> 1045 %% Extra info is a comment; cannot have that on the same line 1046 f(Item, I, ST, WT, PP); 1047f({force_nl,ExtraInfoItem,Item}, I, ST, WT, PP) -> 1048 f({prefer_nl,[],[ExtraInfoItem,Item]}, I, ST, WT, PP); 1049f({prefer_nl,Sep,LItems}, I, ST, WT, PP) when I < 0 -> 1050 f({seq,[],[],Sep,LItems}, I, ST, WT, PP); 1051f({prefer_nl,Sep,LItems}, I0, ST, WT, PP) -> 1052 CharsSize2L = fl(LItems, Sep, I0, [], ST, WT, PP), 1053 {_CharsL,Sizes} = unz(CharsSize2L), 1054 if 1055 Sizes =:= [] -> 1056 {[], 0}; 1057 true -> 1058 {insert_newlines(CharsSize2L, I0, ST, PP), 1059 nsz(lists:last(Sizes), I0)} 1060 end; 1061f({value,V}, I, ST, WT, PP) -> 1062 f(write_a_value(V, PP), I, ST, WT, PP); 1063f({atom,A}, I, ST, WT, PP) -> 1064 f(write_an_atom(A, PP), I, ST, WT, PP); 1065f({singleton_atom_type,A}, I, ST, WT, PP) -> 1066 f(write_a_singleton_atom_type(A, PP), I, ST, WT, PP); 1067f({char,C}, I, ST, WT, PP) -> 1068 f(write_a_char(C, PP), I, ST, WT, PP); 1069f({string,S}, I, ST, WT, PP) -> 1070 f(write_a_string(S, I, PP), I, ST, WT, PP); 1071f({reserved,R}, I, ST, WT, PP) -> 1072 f(R, I, ST, WT, PP); 1073f({hook,HookExpr,Precedence,Func,Options}, I, _ST, _WT, _PP) -> 1074 Chars = Func(HookExpr, I, Precedence, Options), 1075 {Chars,indentation(Chars, I)}; 1076f({ehook,HookExpr,Precedence,{Mod,Func,Eas}=ModFuncEas}, I, _ST, _WT, _PP) -> 1077 Chars = apply(Mod, Func, [HookExpr,I,Precedence,ModFuncEas|Eas]), 1078 {Chars,indentation(Chars, I)}; 1079f(WordName, _I, _ST, WT, _PP) when is_atom(WordName) -> 1080 word(WordName, WT). 1081 1082%% fl(ListItems, I0, ST, WT) -> [[CharsSize1,CharsSize2]] 1083%% ListItems = [{Item,Items}|Item] 1084fl([], _Sep, I0, After, ST, WT, PP) -> 1085 [[f(After, I0, ST, WT, PP),{[],0}]]; 1086fl(CItems, Sep0, I0, After, ST, WT, PP) -> 1087 F = fun({step,Item1,Item2}, S) -> 1088 [f(Item1, I0, ST, WT, PP), 1089 f([Item2,S], incr(I0, PP#pp.indent), ST, WT, PP)]; 1090 ({cstep,Item1,Item2}, S) -> 1091 {_,Sz1} = CharSize1 = f(Item1, I0, ST, WT, PP), 1092 if 1093 is_integer(Sz1), Sz1 < PP#pp.indent -> 1094 Item2p = [leaf("\s"),Item2,S], 1095 [consecutive(Item2p, CharSize1, I0, ST, WT, PP),{[],0}]; 1096 true -> 1097 [CharSize1,f([Item2,S], incr(I0, PP#pp.indent), ST, WT, PP)] 1098 end; 1099 ({reserved,Word}, S) -> 1100 [f([Word,S], I0, ST, WT, PP),{[],0}]; 1101 (Item, S) -> 1102 [f([Item,S], I0, ST, WT, PP),{[],0}] 1103 end, 1104 {Sep,LastSep} = sep(Sep0), 1105 fl1(CItems, F, Sep, LastSep, After). 1106 1107sep([{S,LS}]) -> {[S],[LS]}; 1108sep({_,_}=Sep) -> Sep; 1109sep(S) -> {S, S}. 1110 1111fl1([CItem], F, _Sep, _LastSep, After) -> 1112 [F(CItem,After)]; 1113fl1([CItem1,CItem2], F, _Sep, LastSep, After) -> 1114 [F(CItem1, LastSep),F(CItem2, After)]; 1115fl1([CItem|CItems], F, Sep, LastSep, After) -> 1116 [F(CItem, Sep)|fl1(CItems, F, Sep, LastSep, After)]. 1117 1118consecutive(Items, CharSize1, I0, ST, WT, PP) -> 1119 {CharsSizes,_Length} = 1120 mapfoldl(fun(Item, Len) -> 1121 CharsSize = f(Item, Len, ST, WT, PP), 1122 {CharsSize,indent(CharsSize, Len)} 1123 end, indent(CharSize1, I0), Items), 1124 {CharsL,SizeL} = unz1([CharSize1|CharsSizes]), 1125 {CharsL,line_size(SizeL)}. 1126 1127unz(CharsSizesL) -> 1128 unz1(append(CharsSizesL)). 1129 1130unz1(CharSizes) -> 1131 lists:unzip(nonzero(CharSizes)). 1132 1133nonzero(CharSizes) -> 1134 lists:filter(fun({_,Sz}) -> Sz =/= 0 end, CharSizes). 1135 1136maybe_newlines([{Chars,Size}], [], _I, _NSepChars, _ST, _PP) -> 1137 {Chars,Size}; 1138maybe_newlines(CharsSizeList, Items, I, NSepChars, ST, PP) when I >= 0 -> 1139 maybe_sep(CharsSizeList, Items, I, NSepChars, nl_indent(I, ST), PP). 1140 1141maybe_sep([{Chars1,Size1}|CharsSizeL], [Item|Items], I0, NSepChars, Sep, PP) -> 1142 I1 = case classify_item(Item) of 1143 atomic -> 1144 I0 + Size1; 1145 _ -> 1146 PP#pp.linewidth+1 1147 end, 1148 maybe_sep1(CharsSizeL, Items, I0, I1, Sep, NSepChars, Size1, [Chars1], PP). 1149 1150maybe_sep1([{Chars,Size}|CharsSizeL], [Item|Items], 1151 I0, I, Sep, NSepChars, Sz0, A, PP) -> 1152 case classify_item(Item) of 1153 atomic when is_integer(Size) -> 1154 Size1 = Size + 1, 1155 I1 = I + Size1, 1156 if 1157 I1 =< PP#pp.linewidth -> 1158 A1 = if 1159 NSepChars > 0 -> [Chars,$\s|A]; 1160 true -> [Chars|A] 1161 end, 1162 maybe_sep1(CharsSizeL, Items, I0, I1, Sep, NSepChars, 1163 Sz0 + Size1, A1, PP); 1164 true -> 1165 A1 = [Chars,Sep|A], 1166 maybe_sep1(CharsSizeL, Items, I0, I0 + Size, Sep, 1167 NSepChars, Size1, A1, PP) 1168 end; 1169 _ -> 1170 A1 = [Chars,Sep|A], 1171 maybe_sep1(CharsSizeL, Items, I0, PP#pp.linewidth+1, Sep, NSepChars, 1172 0, A1, PP) 1173 end; 1174maybe_sep1(_CharsSizeL, _Items, _Io, _I, _Sep, _NSepChars, Sz, A, _PP) -> 1175 {lists:reverse(A), Sz}. 1176 1177insert_newlines(CharsSizesL, I, ST, PP) when I >= 0 -> 1178 {CharsL, _} = unz1(handle_step(CharsSizesL, I, ST, PP)), 1179 insert_nl(CharsL, I, ST). 1180 1181handle_step(CharsSizesL, I, ST, PP) -> 1182 map(fun([{_C1,0},{_C2,0}]) -> 1183 {[], 0}; 1184 ([{C1,Sz1},{_C2,0}]) -> 1185 {C1, Sz1}; 1186 ([{C1,Sz1},{C2,Sz2}]) when Sz2 > 0 -> 1187 {insert_nl([C1,C2], I+PP#pp.indent, ST),line_size([Sz1,Sz2])} 1188 end, CharsSizesL). 1189 1190insert_nl(CharsL, I, ST) -> 1191 insert_sep(CharsL, nl_indent(I, ST)). 1192 1193insert_sep([Chars1|CharsL], Sep) -> 1194 [Chars1 | [[Sep,Chars] || Chars <- CharsL]]. 1195 1196nl_indent(0, _T) -> 1197 $\n; 1198nl_indent(I, T) when I > 0 -> 1199 [$\n|spaces(I, T)]. 1200 1201classify_item({atom, _}) -> atomic; 1202classify_item({singleton_atom_type, _}) -> atomic; 1203classify_item(Atom) when is_atom(Atom) -> atomic; 1204classify_item({leaf, _, _}) -> atomic; 1205classify_item(_) -> complex. 1206 1207same_line(I0, SizeL, NSepChars, PP) -> 1208 try 1209 Size = lists:sum(SizeL) + NSepChars, 1210 true = incr(I0, Size) =< PP#pp.linewidth, 1211 {yes,Size} 1212 catch _:_ -> 1213 no 1214 end. 1215 1216line_size(SizeL) -> 1217 line_size(SizeL, 0, false). 1218 1219line_size([], Size, false) -> 1220 Size; 1221line_size([], Size, true) -> 1222 {line,Size}; 1223line_size([{line,Len}|SizeL], _, _) -> 1224 line_size(SizeL, Len, true); 1225line_size([Sz|SizeL], SizeSoFar, LF) -> 1226 line_size(SizeL, SizeSoFar+Sz, LF). 1227 1228nsz({line,_Len}=Sz, _I) -> 1229 Sz; 1230nsz(Size, I) when I >= 0 -> 1231 {line,Size+I}. 1232 1233indent({_Chars,{line,Len}}, _I) -> 1234 Len; 1235indent({_Chars,Size}, I) -> 1236 incr(I, Size). 1237 1238incr(I, _Incr) when I < 0 -> 1239 I; 1240incr(I, Incr) -> 1241 I+Incr. 1242 1243indentation(E, I) when I < 0 -> 1244 string:length(E); 1245indentation(E, I0) -> 1246 I = io_lib_format:indentation(E, I0), 1247 case has_nl(E) of 1248 true -> {line,I}; 1249 false -> I 1250 end. 1251 1252has_nl([$\n|_]) -> 1253 true; 1254has_nl([C|Cs]) when is_integer(C) -> 1255 has_nl(Cs); 1256has_nl([C|Cs]) -> 1257 has_nl(C) orelse has_nl(Cs); 1258has_nl([]) -> 1259 false. 1260 1261write_a_value(V, PP) -> 1262 flat_leaf(write_value(V, PP)). 1263 1264write_an_atom(A, PP) -> 1265 flat_leaf(write_atom(A, PP)). 1266 1267write_a_singleton_atom_type(A, PP) -> 1268 flat_leaf(write_singleton_atom_type(A, PP)). 1269 1270write_a_char(C, PP) -> 1271 flat_leaf(write_char(C, PP)). 1272 1273-define(MIN_SUBSTRING, 5). 1274 1275write_a_string(S, I, PP) when I < 0; S =:= [] -> 1276 flat_leaf(write_string(S, PP)); 1277write_a_string(S, I, PP) -> 1278 Len = erlang:max(PP#pp.linewidth-I, ?MIN_SUBSTRING), 1279 {list,write_a_string(S, Len, Len, PP)}. 1280 1281write_a_string([], _N, _Len, _PP) -> 1282 []; 1283write_a_string(S, N, Len, PP) -> 1284 SS = string:slice(S, 0, N), 1285 Sl = write_string(SS, PP), 1286 case (string:length(Sl) > Len) and (N > ?MIN_SUBSTRING) of 1287 true -> 1288 write_a_string(S, N-1, Len, PP); 1289 false -> 1290 [flat_leaf(Sl) | 1291 write_a_string(string:slice(S, string:length(SS)), Len, Len, PP)] 1292 end. 1293 1294flat_leaf(S) -> 1295 L = lists:flatten(S), 1296 {leaf,string:length(L),L}. 1297 1298write_value(V, PP) -> 1299 (PP#pp.value_fun)(V). 1300 1301write_atom(A, PP) -> 1302 (PP#pp.value_fun)(A). 1303 1304write_singleton_atom_type(A, PP) -> 1305 (PP#pp.singleton_atom_type_fun)(A). 1306 1307write_string(S, PP) -> 1308 (PP#pp.string_fun)(S). 1309 1310write_char(C, PP) -> 1311 (PP#pp.char_fun)(C). 1312 1313%% 1314%% Utilities 1315%% 1316 1317a0() -> 1318 erl_anno:new(0). 1319 1320-define(N_SPACES, 30). 1321 1322spacetab() -> 1323 {[_|L],_} = mapfoldl(fun(_, A) -> {A,[$\s|A]} 1324 end, [], lists:seq(0, ?N_SPACES)), 1325 list_to_tuple(L). 1326 1327spaces(N, T) when N =< ?N_SPACES -> 1328 element(N, T); 1329spaces(N, T) -> 1330 [element(?N_SPACES, T)|spaces(N-?N_SPACES, T)]. 1331 1332wordtable() -> 1333 L = [begin {leaf,Sz,S} = leaf(W), {S,Sz} end || 1334 W <- [" ->"," =","<<",">>","[]","after","begin","case","catch", 1335 "end","fun","if","of","receive","try","when"," ::","..", 1336 " |"]], 1337 list_to_tuple(L). 1338 1339word(' ->', WT) -> element(1, WT); 1340word(' =', WT) -> element(2, WT); 1341word('<<', WT) -> element(3, WT); 1342word('>>', WT) -> element(4, WT); 1343word('[]', WT) -> element(5, WT); 1344word('after', WT) -> element(6, WT); 1345word('begin', WT) -> element(7, WT); 1346word('case', WT) -> element(8, WT); 1347word('catch', WT) -> element(9, WT); 1348word('end', WT) -> element(10, WT); 1349word('fun', WT) -> element(11, WT); 1350word('if', WT) -> element(12, WT); 1351word('of', WT) -> element(13, WT); 1352word('receive', WT) -> element(14, WT); 1353word('try', WT) -> element(15, WT); 1354word('when', WT) -> element(16, WT); 1355word(' ::', WT) -> element(17, WT); 1356word('..', WT) -> element(18, WT); 1357word(' |', WT) -> element(19, WT). 1358