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