erl_pp.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 838 行 · 第 1/2 页
ERL
838 行
{L,_P,R} = inop_prec('='), Fl = lexpr(F, L, Hook), Vl = lexpr(Val, R, Hook), {list,[{cstep,[Fl,' ='],Vl}]};record_field({record_field,_,F}, Hook) -> lexpr(F, 0, Hook).list({cons,_,H,T}, Es, Hook) -> list(T, [H|Es], Hook);list({nil,_}, Es, Hook) -> proper_list(reverse(Es), Hook);list(Other, Es, Hook) -> improper_list(reverse(Es, [Other]), Hook).%% if_clauses(Clauses, Hook) -> [Char].%% Print 'if' clauses.if_clauses(Cs, Hook) -> clauses(fun if_clause/2, Hook, Cs).if_clause({clause,_,[],G,B}, Hook) -> Gl = [guard_no_when(G, Hook),' ->'], {step,Gl,body(B, Hook)}.guard_no_when([E|Es], Hook) when is_list(E) -> expr_list([E|Es], $;, fun guard0/2, Hook);guard_no_when([E|Es], Hook) -> % before R6 guard_no_when([[E|Es]], Hook);guard_no_when([], _) -> % cannot happen leaf("true").%% cr_clauses(Clauses, Hook) -> [Char].%% Print 'case'/'receive' clauses.cr_clauses(Cs, Hook) -> clauses(fun cr_clause/2, Hook, Cs).cr_clause({clause,_,[T],G,B}, Hook) -> El = lexpr(T, 0, Hook), Gl = guard_when(El, G, Hook), Bl = body(B, Hook), {step,Gl,Bl}.%% try_clauses(Clauses, Hook) -> [Char].%% Print 'try' clauses.try_clauses(Cs, Hook) -> clauses(fun try_clause/2, Hook, Cs).try_clause({clause,_,[{tuple,_,[{atom,_,throw},V,S]}],G,B}, Hook) -> El = lexpr(V, 0, Hook), Sl = stack_backtrace(S, [El], Hook), Gl = guard_when(Sl, G, Hook), Bl = body(B, Hook), {step,Gl,Bl};try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Hook) -> Cs = lexpr(C, 0, Hook), El = lexpr(V, 0, Hook), CsEl = [Cs,$:,El], Sl = stack_backtrace(S, CsEl, Hook), Gl = guard_when(Sl, G, Hook), Bl = body(B, Hook), {step,Gl,Bl}.stack_backtrace({var,_,'_'}, El, _Hook) -> El;stack_backtrace(S, El, Hook) -> El++[$:,lexpr(S, 0, Hook)].%% fun_clauses(Clauses, Hook) -> [Char].%% Print 'fun' clauses.fun_clauses(Cs, Hook) -> nl_clauses(fun fun_clause/2, [$;], Hook, Cs).fun_clause({clause,_,A,G,B}, Hook) -> El = args(A, Hook), Gl = guard_when(El, G, Hook), Bl = body(B, Hook), {step,Gl,Bl}.%% cond_clauses(Clauses, Hook) -> [Char].%% Print 'cond' clauses.cond_clauses(Cs, Hook) -> clauses(fun cond_clause/2, Hook, Cs).cond_clause({clause,_,[],[[E]],B}, Hook) -> {step,[lexpr(E, Hook),' ->'],body(B, Hook)}.%% nl_clauses(Type, Hook, Clauses) -> [Char].%% Generic clause printing function (always breaks lines).nl_clauses(Type, Sep, Hook, Cs) -> {prefer_nl,Sep,lexprs(Cs, Type, Hook)}.%% clauses(Type, Hook, Clauses) -> [Char].%% Generic clause printing function.clauses(Type, Hook, Cs) -> expr_list(Cs, [$;], Type, Hook).%% lc_quals(Qualifiers, After, Hook)%% List comprehension qualifierslc_quals(Qs, Hook) -> {seq,[],[],[$,],lexprs(Qs, fun lc_qual/2, Hook)}.lc_qual({generate,_,Pat,E}, Hook) -> Pl = lexpr(Pat, 0, Hook), {list,[{step,[Pl,leaf(" <-")],lexpr(E, 0, Hook)}]};lc_qual(Q, Hook) -> lexpr(Q, 0, Hook).proper_list(Es, Hook) -> {seq,$[,$],$,,lexprs(Es, Hook)}.improper_list(Es, Hook) -> {seq,$[,$],{$,,$|},lexprs(Es, Hook)}.tuple(L, Hook) -> tuple(L, fun lexpr/2, Hook).tuple(Es, F, Hook) -> {seq,${,$},$,,lexprs(Es, F, Hook)}.args(As, Hook) -> {seq,$(,$),[$,],lexprs(As, Hook)}.expr_list(Es, Sep, F, Hook) -> {seq,[],[],Sep,lexprs(Es, F, Hook)}.lexprs(Es, Hook) -> lexprs(Es, fun lexpr/2, Hook).lexprs(Es, F, Hook) -> [F(E, Hook) || E <- Es].maybe_paren(P, Prec, Expr) when P < Prec -> [$(,Expr,$)];maybe_paren(_P, _Prec, Expr) -> Expr.leaf(S) -> {leaf,iolist_size(S),S}.%%% Do the formatting. Currently nothing fancy. Could probably have%%% done it in one single pass.frmt(Item) -> frmt(Item, 0).frmt(Item, I) -> ST = spacetab(), WT = wordtable(), {Chars,_Length} = f(Item, I, ST, WT), [Chars].%%% What the tags mean:%%% - C: a character%%% - [I|Is]: Is follow after I without newline or space%%% - {list,IPs}: try to put all IPs on one line, if that fails newlines%%% and indentation are inserted between IPs.%%% - {first,I,IP2}: IP2 follows after I, and is output with an indentation%%% updated with the width of I.%%% - {seq,Before,After,Separator,IPs}: a sequence of Is separated by %%% Separator. Before is output before IPs, and the indentation of IPs %%% is updated with the width of Before. After follows after IPs.%%% - {force_nl,ExtraInfo,I}: fun-info (a comment) forces linebreak before I.%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative%%% indentation.%%% - {string,S}: a string.%%% - {hook,...}, {ehook,...}: hook expressions.%%% %%% list, first, seq, force_nl, and prefer_nl all accept IPs, where each%%% element is either an item or a tuple {step|cstep,I1,I2}. step means%%% that I2 is output after linebreak and an incremented indentation.%%% cstep works similarly, but no linebreak if the width of I1 is less%%% than the indentation (this is for "A = <expression over several lines>).f([]=Nil, _I0, _ST, _WT) -> {Nil,0};f(C, _I0, _ST, _WT) when is_integer(C) -> {C,1};f({leaf,Length,Chars}, _I0, _ST, _WT) -> {Chars,Length};f([Item|Items], I0, ST, WT) -> consecutive(Items, f(Item, I0, ST, WT), I0, ST, WT);f({list,Items}, I0, ST, WT) -> f({seq,[],[],[],Items}, I0, ST, WT);f({first,E,Item}, I0, ST, WT) -> f({seq,E,[],[],[Item]}, I0, ST, WT);f({seq,Before,After,Sep,LItems}, I0, ST, WT) -> BCharsSize = f(Before, I0, ST, WT), I = indent(BCharsSize, I0), CharsSizeL = fl(LItems, Sep, I, After, ST, WT), {CharsL,SizeL} = unz(CharsSizeL), {BCharsL,BSizeL} = unz1([BCharsSize]), Sizes = BSizeL ++ SizeL, NSepChars = if is_list(Sep) -> lists:max([0,length(CharsL)-1]); true -> 0 end, case same_line(I0, Sizes, NSepChars) of {yes,Size} -> Chars = if NSepChars > 0 -> insert_sep(CharsL, $\s); true -> CharsL end, {BCharsL++Chars,Size}; no -> {BCharsL++insert_newlines(CharsSizeL, I, ST), nsz(lists:last(Sizes), I0)} end;f({force_nl,_ExtraInfoItem,Item}, I, ST, WT) when I < 0 -> %% Extra info is a comment; cannot have that on the same line f(Item, I, ST, WT);f({force_nl,ExtraInfoItem,Item}, I, ST, WT) -> f({prefer_nl,[],[ExtraInfoItem,Item]}, I, ST, WT);f({prefer_nl,Sep,LItems}, I, ST, WT) when I < 0 -> f({seq,[],[],Sep,LItems}, I, ST, WT);f({prefer_nl,Sep,LItems}, I0, ST, WT) -> CharsSize2L = fl(LItems, Sep, I0, [], ST, WT), {_CharsL,Sizes} = unz(CharsSize2L), {insert_newlines(CharsSize2L, I0, ST),nsz(lists:last(Sizes), I0)};f({string,S}, I, ST, WT) -> f(write_a_string(S, I), I, ST, WT);f({hook,HookExpr,Precedence,Func}, I, _ST, _WT) -> Chars = Func(HookExpr, I, Precedence, Func), {Chars,indentation(Chars, I)};f({ehook,HookExpr,Precedence,{Mod,Func,Eas}=ModFuncEas}, I, _ST, _WT) -> Chars = apply(Mod, Func, [HookExpr,I,Precedence,ModFuncEas|Eas]), {Chars,indentation(Chars, I)};f(WordName, _I, _ST, WT) -> % when is_atom(WordName) word(WordName, WT).-define(IND, 4).%% fl(ListItems, I0, ST, WT) -> [[CharsSize1,CharsSize2]]%% ListItems = [{Item,Items}|Item]fl([], _Sep, I0, After, ST, WT) -> [[f(After, I0, ST, WT),{[],0}]];fl(CItems, Sep0, I0, After, ST, WT) -> F = fun({step,Item1,Item2}, S) -> [f(Item1, I0, ST, WT),f([Item2,S], incr(I0, ?IND), ST, WT)]; ({cstep,Item1,Item2}, S) -> {_,Sz1} = CharSize1 = f(Item1, I0, ST, WT), if is_integer(Sz1), Sz1 < ?IND -> Item2p = [leaf("\s"),Item2,S], [consecutive(Item2p, CharSize1, I0, ST, WT),{[],0}]; true -> [CharSize1,f([Item2,S], incr(I0, ?IND), ST, WT)] end; (Item, S) -> [f([Item,S], I0, ST, WT),{[],0}] end, {Sep,LastSep} = case Sep0 of {_,_} -> Sep0; _ -> {Sep0,Sep0} end, fl1(CItems, F, Sep, LastSep, After).fl1([CItem], F, _Sep, _LastSep, After) -> [F(CItem,After)];fl1([CItem1,CItem2], F, _Sep, LastSep, After) -> [F(CItem1, LastSep),F(CItem2, After)];fl1([CItem|CItems], F, Sep, LastSep, After) -> [F(CItem, Sep)|fl1(CItems, F, Sep, LastSep, After)].consecutive(Items, CharSize1, I0, ST, WT) -> {CharsSizes,_Length} = mapfoldl(fun(Item, Len) -> CharsSize = f(Item, Len, ST, WT), {CharsSize,indent(CharsSize, Len)} end, indent(CharSize1, I0), Items), {CharsL,SizeL} = unz1([CharSize1|CharsSizes]), {CharsL,line_size(SizeL)}.unz(CharsSizesL) -> unz1(append(CharsSizesL)).unz1(CharSizes) -> lists:unzip(nonzero(CharSizes)).nonzero(CharSizes) -> lists:filter(fun({_,Sz}) -> Sz =/= 0 end, CharSizes).insert_newlines(CharsSizesL, I, ST) when I >= 0 -> insert_nl(foldr(fun([{_C1,0},{_C2,0}], A) -> A; ([{C1,_Sz1},{_C2,0}], A) -> [C1|A]; ([{C1,_Sz1},{C2,Sz2}], A) when Sz2 > 0 -> [insert_nl([C1,C2], I+?IND, ST)|A] end, [], CharsSizesL), I, ST).insert_nl(CharsL, I, ST) -> insert_sep(CharsL, nl_indent(I, ST)).insert_sep([Chars1 | CharsL], Sep) -> [Chars1 | [[Sep,Chars] || Chars <- CharsL]].nl_indent(0, _T) -> $\n;nl_indent(I, T) when I > 0 -> [$\n|spaces(I, T)].same_line(I0, SizeL, NSepChars) -> try Size = lists:sum(SizeL) + NSepChars, true = incr(I0, Size) =< ?MAXLINE, {yes,Size} catch _:_ -> no end.line_size(SizeL) -> line_size(SizeL, 0, false).line_size([], Size, false) -> Size;line_size([], Size, true) -> {line,Size};line_size([{line,Len}|SizeL], _, _) -> line_size(SizeL, Len, true);line_size([Sz|SizeL], SizeSoFar, LF) -> line_size(SizeL, SizeSoFar+Sz, LF).nsz({line,_Len}=Sz, _I) -> Sz;nsz(Size, I) when I >= 0 -> {line,Size+I}.indent({_Chars,{line,Len}}, _I) -> Len;indent({_Chars,Size}, I) -> incr(I, Size).incr(I, _Incr) when I < 0 -> I;incr(I, Incr) -> I+Incr.indentation(E, I) when I < 0 -> iolist_size(E);indentation(E, I0) -> I = io_lib_format:indentation(E, I0), case has_nl(E) of true -> {line,I}; false -> I end.has_nl([$\n|_]) -> true;has_nl([C|Cs]) when is_integer(C) -> has_nl(Cs);has_nl([C|Cs]) -> has_nl(C) orelse has_nl(Cs);has_nl([]) -> false.-define(MIN_SUBSTRING, 5).write_a_string(S, I) when I < 0; S =:= [] -> leaf(write_string(S));write_a_string(S, I) -> Len = lists:max([?MAXLINE-I,?MIN_SUBSTRING]), {list,write_a_string(S, Len, Len)}.write_a_string([], _N, _Len) -> [];write_a_string(S, N, Len) -> SS = string:sub_string(S, 1, N), Sl = write_string(SS), case (iolist_size(Sl) > Len) and (N > ?MIN_SUBSTRING) of true -> write_a_string(S, N-1, Len); false -> [leaf(Sl)|write_a_string(lists:nthtail(length(SS), S), Len, Len)] end.%%%% Utilities%%-define(N_SPACES, 30).spacetab() -> {[_|L],_} = mapfoldl(fun(_, A) -> {A,[$\s|A]} end, [], lists:seq(0, ?N_SPACES)), list_to_tuple(L). spaces(N, T) when N =< ?N_SPACES -> element(N, T);spaces(N, T) -> [element(?N_SPACES, T)|spaces(N-?N_SPACES, T)].wordtable() -> L = [begin {leaf,Sz,S} = leaf(W), {S,Sz} end || W <- [" ->"," =","<<",">>","[]","after","begin","case","catch", "end","fun","if","of","receive","try","when"]], list_to_tuple(L).word(' ->', WT) -> element(1, WT);word(' =', WT) -> element(2, WT);word('<<', WT) -> element(3, WT);word('>>', WT) -> element(4, WT);word('[]', WT) -> element(5, WT);word('after', WT) -> element(6, WT);word('begin', WT) -> element(7, WT);word('case', WT) -> element(8, WT);word('catch', WT) -> element(9, WT);word('end', WT) -> element(10, WT);word('fun', WT) -> element(11, WT);word('if', WT) -> element(12, WT);word('of', WT) -> element(13, WT);word('receive', WT) -> element(14, WT);word('try', WT) -> element(15, WT);word('when', WT) -> element(16, WT).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?