epp.erl

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

ERL
991
字号
	    leave_file(From, St)		%This serious, just exit!    end.scan_toks([{'-',_Lh},{atom,Ld,define}|Toks], From, St) ->    scan_define(Toks, Ld, From, St);scan_toks([{'-',_Lh},{atom,Ld,undef}|Toks], From, St) ->    scan_undef(Toks, Ld, From, St);scan_toks([{'-',_Lh},{atom,Li,include}|Toks], From, St) ->    scan_include(Toks, abs(Li), From, St);scan_toks([{'-',_Lh},{atom,Li,include_lib}|Toks], From, St) ->    scan_include_lib(Toks, abs(Li), From, St);scan_toks([{'-',_Lh},{atom,Li,ifdef}|Toks], From, St) ->    scan_ifdef(Toks, Li, From, St);scan_toks([{'-',_Lh},{atom,Li,ifndef}|Toks], From, St) ->    scan_ifndef(Toks, Li, From, St);scan_toks([{'-',_Lh},{atom,Le,else}|Toks], From, St) ->    scan_else(Toks, Le, From, St);scan_toks([{'-',_Lh},{atom,Le,'if'}|Toks], From, St) ->    scan_if(Toks, Le, From, St);scan_toks([{'-',_Lh},{atom,Le,elif}|Toks], From, St) ->    scan_elif(Toks, Le, From, St);scan_toks([{'-',_Lh},{atom,Le,endif}|Toks], From, St) ->    scan_endif(Toks, Le, From, St);scan_toks([{'-',_Lh},{atom,Lf,file}|Toks0], From, St) ->    case catch expand_macros(Toks0, {St#epp.macs, St#epp.uses}) of	Toks1 when is_list(Toks1) ->            scan_file(Toks1, Lf, From, St);	{error,ErrL,What} ->	    epp_reply(From, {error,{ErrL,epp,What}}),	    wait_req_scan(St)    end;scan_toks(Toks0, From, St) ->    case catch expand_macros(Toks0, {St#epp.macs, St#epp.uses}) of	Toks1 when is_list(Toks1) ->	    epp_reply(From, {ok,Toks1}),	    wait_req_scan(St#epp{macs=scan_module(Toks1, St#epp.macs)});	{error,ErrL,What} ->	    epp_reply(From, {error,{ErrL,epp,What}}),	    wait_req_scan(St)    end.scan_module([{'-',_Lh},{atom,_Lm,module},{'(',_Ll}|Ts], Ms) ->    scan_module_1(Ts, [], Ms);scan_module(_Ts, Ms) -> Ms.scan_module_1([{atom,_,_}=A,{',',L}|Ts], As, Ms) ->    %% Parameterized modules.    scan_module_1([A,{')',L}|Ts], As, Ms);scan_module_1([{atom,Ln,A},{')',_Lr}|_Ts], As, Ms0) ->    Mod = lists:concat(lists:reverse([A|As])),    Ms = dict:store({atom,'MODULE'},		     {none,[{atom,Ln,list_to_atom(Mod)}]}, Ms0),    dict:store({atom,'MODULE_STRING'}, {none,[{string,Ln,Mod}]}, Ms);scan_module_1([{atom,_Ln,A},{'.',_Lr}|Ts], As, Ms) ->    scan_module_1(Ts, [".",A|As], Ms);scan_module_1([{'.',_Lr}|Ts], As, Ms) ->    scan_module_1(Ts, As, Ms);scan_module_1(_Ts, _As, Ms) -> Ms.%% scan_define(Tokens, DefineLine, From, EppState)scan_define([{'(',_Lp},{atom,Lm,M},{',',_Lc}|Toks], _Ld, From, St) ->    case dict:find({atom,M}, St#epp.macs) of	{ok,_Def} ->	    epp_reply(From, {error,{Lm,epp,{redefine,M}}}),	    wait_req_scan(St);	error ->	    scan_define_cont(From, St,			     {atom, M},			     {none,macro_expansion(Toks)})    end;scan_define([{'(',_Lp},{atom,Lm,M},{'(',_Lc}|Toks], Ld, From, St) ->    case dict:find({atom,M}, St#epp.macs) of	{ok,_Def} ->	    epp_reply(From, {error,{Lm,epp,{redefine,M}}}),	    wait_req_scan(St);	error ->	    case catch macro_pars(Toks, []) of		{ok, {As, Me}} ->		    scan_define_cont(From, St,				    {atom, M},				    {As, Me});		_ ->		    epp_reply(From, {error,{Ld,epp,{bad,define}}}),		    wait_req_scan(St)	    end    end;scan_define([{'(',_Lp},{var,Lm,M},{',',_Lc}|Toks], _Ld, From, St) ->    case dict:find({atom,M}, St#epp.macs) of	{ok,_Def} ->	    epp_reply(From, {error,{Lm,epp,{redefine,M}}}),	    wait_req_scan(St);	error ->	    scan_define_cont(From, St,			     {atom, M},			     {none,macro_expansion(Toks)})    end;scan_define([{'(',_Lp},{var,Lm,M},{'(',_Lc}|Toks], Ld, From, St) ->    case dict:find({atom,M}, St#epp.macs) of	{ok,_Def} ->	    epp_reply(From, {error,{Lm,epp,{redefine,M}}}),	    wait_req_scan(St);	error ->	    case catch macro_pars(Toks, []) of		{ok, {As, Me}} ->		    scan_define_cont(From, St,				     {atom, M},				     {As, Me});		_ ->		    epp_reply(From, {error,{Ld,epp,{bad,define}}}),		    wait_req_scan(St)	    end    end;scan_define(_Toks, Ld, From, St) ->    epp_reply(From, {error,{Ld,epp,{bad,define}}}),    wait_req_scan(St).%%% Detection of circular macro expansions (which would either keep%%% the compiler looping forever, or run out of memory):%%% 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(undefined) ->    undefined;macro_uses({_Args, Tokens}) ->    Uses0 = macro_ref(Tokens),    lists:usort(Uses0).macro_ref([]) ->    [];macro_ref([{'?', _}, {'?', _} | Rest]) ->    macro_ref(Rest);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: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,NewName0},{')',_Lrp},{dot,_Ld}], Li, 	     From, St) ->    NewName = expand_var(NewName0),    enter_file(St#epp.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) ->    [Lib | Rest] = filename:split(NewName),    {code:lib_dir(Lib), Rest}.scan_include_lib([{'(',_Llp},{string,_Lf,_NewName0},{')',_Lrp},{dot,_Ld}], Li,		 From, St)  when length(St#epp.sstk) >= 8 ->    epp_reply(From, {error,{Li,epp,{depth,"include_lib"}}}),    wait_req_scan(St);scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}], Li,		 From, St) ->    NewName = expand_var(NewName0),    case file:path_open(St#epp.path, NewName, read) of	{ok,NewF,Pname} ->	    wait_req_scan(enter_file2(NewF, Pname, From, St, 1));	{error,_E1} ->	    case catch find_lib_dir(NewName) of		{LibDir, Rest} when is_list(LibDir) ->		    LibName = filename:join([LibDir | Rest]),		    case file:open(LibName, [read]) of			{ok,NewF} ->			    ExtraPath = [filename:dirname(LibName)],			    wait_req_scan(enter_file2(NewF, LibName, From,                                                       St, 1, ExtraPath));			{error,_E2} ->			    epp_reply(From,				      {error,{Li,epp,{include,lib,NewName}}}),			    wait_req_scan(St)		    end;		_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).%% scan_file(Tokens, FileLine, From, EppState)%%  Set the current file and line to the given file and line.%%  Note that the line of the attribute itself is kept.scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp},           {dot,_Ld}], Lf, From, St) ->    enter_file_reply(From, Name, Ln, -abs(Lf)),    Ms = dict:store({atom,'FILE'}, {none,[{string,1,Name}]}, St#epp.macs),    scan_toks(From, St#epp{name=Name,line=Ln+(St#epp.line-Lf),macs=Ms});scan_file(_Toks, Lf, From, St) ->    epp_reply(From, {error,{Lf,epp,{bad,file}}}),    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.

⌨️ 快捷键说明

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