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 + -
显示快捷键?