epp.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 991 行 · 第 1/3 页

ERL
991
字号
skip_toks(From, St, [I|Sis]) ->    case io:scan_erl_form(St#epp.file, '', St#epp.line) of	{ok,[{'-',_Lh},{atom,_Li,ifdef}|_Toks],Cl} ->	    skip_toks(From, St#epp{line=Cl}, [ifdef,I|Sis]);	{ok,[{'-',_Lh},{atom,_Li,ifndef}|_Toks],Cl} ->	    skip_toks(From, St#epp{line=Cl}, [ifndef,I|Sis]);	{ok,[{'-',_Lh},{atom,_Li,'if'}|_Toks],Cl} ->	    skip_toks(From, St#epp{line=Cl}, ['if',I|Sis]);	{ok,[{'-',_Lh},{atom,Le,else}|_Toks],Cl}->	    skip_else(Le, From, St#epp{line=Cl}, [I|Sis]);	{ok,[{'-',_Lh},{atom,_Le,endif}|_Toks],Cl} ->	    skip_toks(From, St#epp{line=Cl}, Sis);	{ok,_Toks,Cl} ->	    skip_toks(From, St#epp{line=Cl}, [I|Sis]);	{error,_E,Cl} ->	    skip_toks(From, St#epp{line=Cl}, [I|Sis]);	{eof,Cl} ->	    leave_file(From, St#epp{line=Cl,istk=[I|Sis]});	{error,_E} ->            epp_reply(From, {error,{St#epp.line,epp,cannot_parse}}),	    leave_file(From, St)		%This serious, just exit!    end;skip_toks(From, St, []) ->    scan_toks(From, St).skip_else(Le, From, St, [else|Sis]) ->    epp_reply(From, {error,{Le,epp,{illegal,"repeated",else}}}),    wait_req_skip(St, [else|Sis]);skip_else(_Le, From, St, [_I]) ->    scan_toks (From, St#epp{istk=[else|St#epp.istk]});skip_else(_Le, From, St, Sis) ->    skip_toks(From, St, Sis).%% macro_pars(Tokens, ArgStack)%% macro_expansion(Tokens)%%  Extract the macro parameters and the expansion from a macro definition.macro_pars([{')',_Lp}, {',',_Ld}|Ex], Args) ->    {ok, {lists:reverse(Args), macro_expansion(Ex)}};macro_pars([{var,_,Name}, {')',_Lp}, {',',_Ld}|Ex], Args) ->    false = lists:member(Name, Args),		%Prolog is nice    {ok, {lists:reverse([Name|Args]), macro_expansion(Ex)}};macro_pars([{var,_L,Name}, {',',_}|Ts], Args) ->    false = lists:member(Name, Args),               macro_pars(Ts, [Name|Args]).macro_expansion([{')',_Lp},{dot,_Ld}]) -> [];macro_expansion([{dot,_Ld}]) -> [];		%Be nice, allow no right paren!macro_expansion([T|Ts]) ->    [T|macro_expansion(Ts)].%% expand_macros(Tokens, Macros)%% expand_macro(Tokens, MacroLine, RestTokens)%%  Expand the macros in a list of tokens, making sure that an expansion%%  gets the same line number as the macro call.expand_macros(Type, Lm, M, Toks, Ms0) ->    %% (Type will always be 'atom')    {Ms, U} = Ms0,    check_uses([{Type,M}], [], U, Lm),    case dict:find({Type,M}, Ms) of	{ok,{none,Exp}} ->	    expand_macros(expand_macro(Exp, Lm, Toks, dict:new()), Ms0);	{ok,{As,Exp}} ->	    {Bs,Toks1} = bind_args(Toks, Lm, M, As, dict:new()),	    %%io:format("Bound arguments to macro ~w (~w)~n", [M,Bs]),	    expand_macros(expand_macro(Exp, Lm, Toks1, Bs), Ms0);	{ok,undefined} ->	    throw({error,Lm,{undefined,M}});	error ->	    throw({error,Lm,{undefined,M}})    end.check_uses(undefined, _Anc, _U, _Lm) ->    ok;check_uses([], _Anc, _U, _Lm) ->    ok;check_uses([M|Rest], Anc, U, Lm) ->    case lists:member(M, Anc) of	true ->	    {_, Name} = M,	    throw({error,Lm,{circular,Name}});	false ->	    L = get_macro_uses(M, U),	    check_uses(L, [M|Anc], U, Lm),	    check_uses(Rest, Anc, U, Lm)    end.    get_macro_uses(M, U) ->    case dict:find(M, U) of	error ->	    [];	{ok, L} ->	    L    end.%% Macro expansionexpand_macros([{'?',_Lq},{atom,Lm,M}|Toks], Ms) ->    expand_macros(atom, Lm, M, Toks, Ms);%% Special macrosexpand_macros([{'?',_Lq},{var,Lm,'LINE'}|Toks], Ms) ->    [{integer,Lm,Lm}|expand_macros(Toks, Ms)];expand_macros([{'?',_Lq},{var,Lm,M}|Toks], Ms) ->    expand_macros(atom, Lm, M, Toks, Ms);%% Illegal macrosexpand_macros([{'?',_Lq},{Type,Lt}|_Toks], _Ms) ->    throw({error,Lt,{call,[$?|atom_to_list(Type)]}});expand_macros([{'?',_Lq},{_Type,Lt,What}|_Toks], _Ms) ->    throw({error,Lt,{call,[$?|io_lib:write(What)]}});expand_macros([T|Ts], Ms) ->    [T|expand_macros(Ts, Ms)];expand_macros([], _Ms) -> [].%% bind_args(Tokens, MacroLine, MacroName, ArgumentVars, Bindings)%%  Collect the arguments to a macro call and check for correct number.bind_args([{'(',_Llp},{')',_Lrp}|Toks], _Lm, _M, [], Bs) ->    {Bs,Toks};bind_args([{'(',_Llp}|Toks0], Lm, M, [A|As], Bs) ->    {Arg,Toks1} = macro_arg(Toks0, [], []),    macro_args(Toks1, Lm, M, As, dict:store(A, Arg, Bs));bind_args(_Toks, Lm, M, _As, _Bs) ->    throw({error,Lm,{mismatch,M}}).macro_args([{')',_Lrp}|Toks], _Lm, _M, [], Bs) ->    {Bs,Toks};macro_args([{',',_Lc}|Toks0], Lm, M, [A|As], Bs) ->    {Arg,Toks1} = macro_arg(Toks0, [], []),    macro_args(Toks1, Lm, M, As, dict:store(A, Arg, Bs));macro_args([], Lm, M, _As, _Bs) ->    throw({error,Lm,{arg_error,M}});macro_args(_Toks, Lm, M, _As, _Bs) ->    throw({error,Lm,{mismatch,M}}).%% macro_arg([Tok], [ClosePar], [ArgTok]) -> {[ArgTok],[RestTok]}.%%  Collect argument tokens until we hit a ',' or a ')'. We know a%%  enough about syntax to recognise "open parentheses" and keep%%  scanning until matching "close parenthesis".macro_arg([{',',Lc}|Toks], [], Arg) ->    {lists:reverse(Arg),[{',',Lc}|Toks]};macro_arg([{')',Lrp}|Toks], [], Arg) ->    {lists:reverse(Arg),[{')',Lrp}|Toks]};macro_arg([{'(',Llp}|Toks], E, Arg) ->    macro_arg(Toks, [')'|E], [{'(',Llp}|Arg]);macro_arg([{'<<',Lls}|Toks], E, Arg) ->    macro_arg(Toks, ['>>'|E], [{'<<',Lls}|Arg]);macro_arg([{'[',Lls}|Toks], E, Arg) ->    macro_arg(Toks, [']'|E], [{'[',Lls}|Arg]);macro_arg([{'{',Llc}|Toks], E, Arg) ->    macro_arg(Toks, ['}'|E], [{'{',Llc}|Arg]);macro_arg([{'begin',Lb}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'begin',Lb}|Arg]);macro_arg([{'if',Li}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'if',Li}|Arg]);macro_arg([{'case',Lc}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'case',Lc}|Arg]);macro_arg([{'receive',Lr}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'receive',Lr}|Arg]);macro_arg([{'try',Lr}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'try',Lr}|Arg]);macro_arg([{'cond',Lr}|Toks], E, Arg) ->    macro_arg(Toks, ['end'|E], [{'cond',Lr}|Arg]);macro_arg([{Rb,Lrb}|Toks], [Rb|E], Arg) ->	%Found matching close    macro_arg(Toks, E, [{Rb,Lrb}|Arg]);macro_arg([T|Toks], E, Arg) ->    macro_arg(Toks, E, [T|Arg]);macro_arg([], _E, Arg) ->    {lists:reverse(Arg),[]}.%% expand_macro(MacroDef, MacroLine, RestTokens, Bindings)%% expand_arg(Argtokens, MacroTokens, MacroLine, RestTokens, Bindings)%%  Insert the macro expansion replacing macro parameters with their%%  argument values, inserting the line number of first the macro call%%  and then the macro arguments, i.e. simulate textual expansion.expand_macro([{var,_Lv,V}|Ts], L, Rest, Bs) ->    case dict:find(V, Bs) of	{ok,Val} ->	    %% lists:append(Val, expand_macro(Ts, L, Rest, Bs));	    expand_arg(Val, Ts, L, Rest, Bs);	error ->	    [{var,L,V}|expand_macro(Ts, L, Rest, Bs)]    end;expand_macro([{'?', _}, {'?', _}, {var,_Lv,V}|Ts], L, Rest, Bs) ->    case dict:find(V, Bs) of	{ok,Val} ->	    %% lists:append(Val, expand_macro(Ts, L, Rest, Bs));	    expand_arg(stringify(Val), Ts, L, Rest, Bs);	error ->	    [{var,L,V}|expand_macro(Ts, L, Rest, Bs)]    end;expand_macro([T|Ts], L, Rest, Bs) ->    [setelement(2, T, L)|expand_macro(Ts, L, Rest, Bs)];expand_macro([], _L, Rest, _Bs) -> Rest.expand_arg([A|As], Ts, _L, Rest, Bs) ->    [A|expand_arg(As, Ts, element(2, A), Rest, Bs)];expand_arg([], Ts, L, Rest, Bs) ->    expand_macro(Ts, L, Rest, Bs).%%% stringify(L) returns a list of one token: a string which when%%% tokenized would yield the token list L.%tst(Str) ->%    {ok, T, _} = erl_scan:string(Str),%    [{string, _, S}] = stringify(T),%    S.token_src({dot, _}) ->    ".";token_src({X, _}) when is_atom(X) ->    atom_to_list(X);token_src({var, _, X}) ->    atom_to_list(X);token_src({string, _, X}) ->    lists:flatten(io_lib:format("~p", [X]));token_src({_, _, X}) ->    lists:flatten(io_lib:format("~w", [X])).stringify1([]) ->    [];stringify1([T | Tokens]) ->    [io_lib:format(" ~s", [token_src(T)]) | stringify1(Tokens)].stringify(L) ->    [$\s | S] = lists:flatten(stringify1(L)),    [{string, 1, S}].%% epp_request(Epp)%% epp_request(Epp, Request)%% epp_reply(From, Reply)%%  Handle communication with the epp.epp_request(Epp) ->    wait_epp_reply(Epp, erlang:monitor(process, Epp)).epp_request(Epp, Req) ->    Epp ! {epp_request,self(),Req},    wait_epp_reply(Epp, erlang:monitor(process, Epp)).epp_reply(From, Rep) ->    From ! {epp_reply,self(),Rep}.wait_epp_reply(Epp, Mref) ->    receive	{epp_reply,Epp,Rep} -> 	    erlang:demonitor(Mref),	    receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,	    Rep;	{'DOWN',Mref,_,_,E} -> 	    receive {epp_reply,Epp,Rep} -> Rep	    after 0 -> exit(E)	    end    end.expand_var([$$ | _] = NewName) ->    case catch expand_var1(NewName) of	{ok, ExpName} ->	    ExpName;	_ ->	    NewName    end;expand_var(NewName) ->    NewName.expand_var1(NewName) ->    [[$$ | Var] | Rest] = filename:split(NewName),    Value = os:getenv(Var),    true = Value =/= false,    {ok, filename:join([Value | Rest])}.%% epp has always output -file attributes when entering and leaving%% included files (-include, -include_lib). Starting with R11B the%% -file attribute is also recognized in the input file. This is%% mainly aimed at yecc, the parser generator, which uses the -file%% attribute to get correct lines in messages referring to code%% supplied by the user (actions etc in .yrl files).%% %% In a perfect world (read: perfectly implemented applications such%% as Xref, Cover, Debugger, etc.) it would not be necessary to%% distinguish -file attributes from epp and the input file. The%% Debugger for example could have one window for each referred file,%% each window with its own set of breakpoints etc. The line numbers%% of the abstract code would then point into different windows%% depending on the -file attribute. [Note that if, as is the case for%% yecc, code has been copied into the file, then it is possible that%% the copied code differ from the one referred to by the -file%% attribute, which means that line numbers can mismatch.] In practice%% however it is very rare with Erlang functions in included files, so%% only one window is used per module. This means that the line%% numbers of the abstract code have to be adjusted to refer to the%% top-most source file. The function interpret_file_attributes/1%% below interprets the -file attribute and returns forms where line%% numbers refer to the top-most file. The -file attribute forms that%% have been output by epp (corresponding to -include and%% -include_lib) are kept, but the user's -file attributes are%% removed. This seems sufficient for now.%% %% It turns out to be difficult to distinguish -file attributes in the%% input file from the ones added by epp unless some action is taken.%% The (less than perfect) solution employed is to let epp assign%% negative line number to user supplied -file attributes.interpret_file_attribute(Forms) ->    interpret_file_attr(Forms, 0, []).interpret_file_attr([{attribute,L,file,{_File,Line}} | Forms],                     Delta, Fs) when L < 0 ->    %% -file attribute    interpret_file_attr(Forms, (abs(L) + Delta) - Line, Fs);interpret_file_attr([{attribute,_AL,file,{File,_Line}}=Form | Forms],                     Delta, Fs) ->    %% -include or -include_lib    % true = _AL =:= _Line,    case Fs of        [_, Delta1, File | Fs1] -> % end of included file            [Form | interpret_file_attr(Forms, Delta1, [File | Fs1])];        _ -> % start of included file            [Form | interpret_file_attr(Forms, 0, [File, Delta | Fs])]    end;interpret_file_attr([Form0 | Forms], Delta, Fs) ->    Form = erl_lint:modify_line(Form0, fun(L) -> abs(L) + Delta end),    [Form | interpret_file_attr(Forms, Delta, Fs)];interpret_file_attr([], _Delta, _Fs) ->    [].

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?