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