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