fake_demand_epp.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 848 行 · 第 1/2 页
ERL
848 行
%%% When a macro is defined, we store the names of other macros it%%% uses in St#epp.uses. If any macro is undef'ed, that information%%% becomes invalid, so we redo it for all remaining macros.%%% The circularity detection itself is done when a macro is expanded:%%% the information from St#epp.uses is traversed, and if a circularity%%% is detected, an error message is thrown.scan_define_cont(F, St, M, Def) -> Ms = dict:store(M, Def, St#epp.macs), U = dict:store(M, macro_uses(Def), St#epp.uses), scan_toks(F, St#epp{uses=U, macs=Ms}).macro_uses({Args, Tokens}) -> Uses0 = macro_ref(Tokens), lists:usort(Uses0).macro_ref([]) -> [];macro_ref([{'?', _}, {atom, _, A} | Rest]) -> [{atom, A} | macro_ref(Rest)];macro_ref([{'?', _}, {var, _, A} | Rest]) -> [{atom, A} | macro_ref(Rest)];macro_ref([Token | Rest]) -> macro_ref(Rest).all_macro_uses(D0) -> L = dict:dict_to_list(D0), D = dict:new(), add_macro_uses(L, D).add_macro_uses([], D) -> D;add_macro_uses([{Key, Def} | Rest], D0) -> add_macro_uses(Rest, dict:store(Key, macro_uses(Def), D0)).%% scan_undef(Tokens, UndefLine, From, EppState)scan_undef([{'(',Llp},{atom,Lm,M},{')',Lrp},{dot,Ld}], Lu, From, St) -> scan_toks(From, St#epp{macs=dict:erase({atom,M}, St#epp.macs), uses=all_macro_uses(St#epp.macs)});scan_undef([{'(',Llp},{var,Lm,M},{')',Lrp},{dot,Ld}], Lu, From,St) -> scan_toks(From, St#epp{macs=dict:erase({atom,M}, St#epp.macs), uses=all_macro_uses(St#epp.macs)});scan_undef(Toks, Lu, From,St) -> epp_reply(From, {error,{Lu,epp,{bad,undef}}}), wait_req_scan(St).%% scan_include(Tokens, IncludeLine, From, St)scan_include([{'(',Llp},{string,Lf,NewName},{')',Lrp},{dot,Ld}], Li, From, St) -> enter_file(get(user_path), NewName, Li, From, St);scan_include(Toks, Li, From, St) -> epp_reply(From, {error,{Li,epp,{bad,include}}}), wait_req_scan(St).%% scan_include_lib(Tokens, IncludeLine, From, EppState)%% For include_lib we first test if we can find the file through the%% normal search path, if not we assume that the first directory name%% is a library name, find its true directory and try with that.find_lib_dir(NewName) -> Sc = string:chr(NewName, $/), Lib = string:substr(NewName, 1, Sc-1), Rest = string:substr(NewName, Sc+1), {Lib, Rest}.scan_include_lib([{'(',Llp},{string,Lf,NewName},{')',Lrp},{dot,Ld}], Li, From, St) -> case catch find_lib_dir(NewName) of {LibDir, Rest} when list(LibDir) -> Inc = filename:rootname(filename:basename(Rest)), %% erlang:display({include_lib,here1, LibDir,Inc}), case boot_code_loader:include_file(LibDir, Inc) of {ok, Bin} -> %% io:format("Found it in a binary! -- hack city~n"), {ok, NewF} = bin_io:open_read(Bin), wait_req_scan(enter_file(NewF, LibDir, From, St)); error -> epp_reply(From, {error,{Li,epp,{include,lib,NewName}}}), wait_req_scan(St); Error -> epp_reply(From, {error,{Li,epp,{include,lib,NewName}}}), wait_req_scan(St) end end;scan_include_lib(Toks, Li, From, St) -> epp_reply(From, {error,{Li,epp,{bad,include_lib}}}), wait_req_scan(St).%% scan_ifdef(Tokens, IfdefLine, From, EppState)%% scan_ifndef(Tokens, IfdefLine, From, EppSate)%% Handle the conditional parsing of a file.%% Report a badly formed if[n]def test and then treat as undefined macro.scan_ifdef([{'(',Llp},{atom,Lm,M},{')',Lrp},{dot,Ld}], Li, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]}); error -> skip_toks(From, St, [ifdef]) end;scan_ifdef([{'(',Llp},{var,Lm,M},{')',Lrp},{dot,Ld}], Li, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]}); error -> skip_toks(From, St, [ifdef]) end;scan_ifdef(Toks, Li, From, St) -> epp_reply(From, {error,{Li,epp,{bad,ifdef}}}), wait_req_skip(St, [ifdef]).scan_ifndef([{'(',Llp},{atom,Lm,M},{')',Lrp},{dot,Ld}], Li, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> skip_toks(From, St, [ifndef]); error -> scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]}) end;scan_ifndef([{'(',Llp},{var,Lm,M},{')',Lrp},{dot,Ld}], Li, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> skip_toks(From, St, [ifndef]); error -> scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]}) end;scan_ifndef(Toks, Li, From, St) -> epp_reply(From, {error,{Li,epp,{bad,ifndef}}}), wait_req_scan(St).%% scan_else(Tokens, ElseLine, From, EppState)%% If we are in an if body then convert to else and skip, if we are in an%% else or not in anything report an error.scan_else([{dot,Ld}], Le, From, St) -> case St#epp.istk of [else|Cis] -> epp_reply(From, {error,{Le,epp,{illegal,"repeated",else}}}), wait_req_skip(St#epp{istk=Cis}, [else]); [I|Cis] -> skip_toks(From, St#epp{istk=Cis}, [else]); [] -> epp_reply(From, {error,{Le,epp,{illegal,"unbalanced",else}}}), wait_req_scan(St) end;scan_else(Toks, Le, From, St) -> epp_reply(From, {error,{Le,epp,{bad,else}}}), wait_req_scan(St).%% scan_if(Tokens, EndifLine, From, EppState)%% Handle the conditional parsing of a file.%% Report a badly formed if test and then treat as false macro.scan_if(Toks, Le, From, St) -> epp_reply(From, {error,{Le,epp,{'NYI','if'}}}), wait_req_skip(St, ['if']).%% scan_elif(Tokens, EndifLine, From, EppState)%% Handle the conditional parsing of a file.%% Report a badly formed if test and then treat as false macro.scan_elif(Toks, Le, From, St) -> epp_reply(From, {error,{Le,epp,{'NYI','elif'}}}), wait_req_skip(St, ['elif']).%% scan_endif(Tokens, EndifLine, From, EppState)%% If we are in an if body then exit it, else report an error.scan_endif([{dot,Ld}], Le, From, St) -> case St#epp.istk of [I|Cis] -> scan_toks(From, St#epp{istk=Cis}); [] -> epp_reply(From, {error,{Le,epp,{illegal,"unbalanced",endif}}}), wait_req_scan(St) end;scan_endif(Toks, Le, From, St) -> epp_reply(From, {error,{Le,epp,{bad,endif}}}), wait_req_scan(St).%% skip_toks(From, EppState, SkipIstack)%% Skip over forms until current conditional has been exited. Handle%% nested conditionals and repeated 'else's.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,E}), true %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([], 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([{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 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, Request)%% epp_reply(From, Reply)%% wait_epp_reply(Epp)%% Handle communication with the epp.epp_request(Epp, Req) -> Epp ! {epp_request,self(),Req}.epp_reply(From, Rep) -> From ! {epp_reply,self(),Rep}.wait_epp_reply(Epp) -> receive {epp_reply,Epp,Rep} -> Rep end.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?