diff options
author | Christopher Faulet <[email protected]> | 2009-12-07 16:47:44 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2010-02-01 16:18:23 +0100 |
commit | 27d7ca04eb2933345b5be50870a197a3b19588c0 (patch) | |
tree | 8a3844d72982efff69b478ce1b82ba61995731ec | |
parent | 5023556e555fd99d6b5bbe77707066371e38abd7 (diff) | |
download | otp-27d7ca04eb2933345b5be50870a197a3b19588c0.tar.gz otp-27d7ca04eb2933345b5be50870a197a3b19588c0.tar.bz2 otp-27d7ca04eb2933345b5be50870a197a3b19588c0.zip |
epp: change rules to choose the right version of a macro
Now, when we have only the constant definition of a macro (without
arguments), we always use it. In all other cases, we try to find the
exact matching definition. We throw an error if we don't find it.
-rw-r--r-- | lib/stdlib/src/epp.erl | 95 | ||||
-rw-r--r-- | lib/stdlib/test/epp_SUITE.erl | 30 |
2 files changed, 72 insertions, 53 deletions
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index b7b759b7c2..d91a4408d7 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -111,18 +111,24 @@ format_error({bad,W}) -> io_lib:format("badly formed '~s'", [W]); format_error({call,What}) -> io_lib:format("illegal macro call '~s'",[What]); -format_error({undefined,M}) -> - io_lib:format("undefined macro '~w'", [M]); +format_error({undefined,M,none}) -> + io_lib:format("undefined macro '~s'", [M]); +format_error({undefined,M,A}) -> + io_lib:format("undefined macro '~s/~p'", [M,A]); format_error({depth,What}) -> io_lib:format("~s too deep",[What]); format_error({mismatch,M}) -> - io_lib:format("argument mismatch for macro '~w'", [M]); + io_lib:format("argument mismatch for macro '~s'", [M]); format_error({arg_error,M}) -> - io_lib:format("badly formed argument for macro '~w'", [M]); + io_lib:format("badly formed argument for macro '~s'", [M]); format_error({redefine,M}) -> - io_lib:format("redefining macro '~w'", [M]); -format_error({circular,M}) -> - io_lib:format("circular macro '~w'", [M]); + io_lib:format("redefining macro '~s'", [M]); +format_error({redefine_predef,M}) -> + io_lib:format("redefining predefined macro '~s'", [M]); +format_error({circular,M,none}) -> + io_lib:format("circular macro '~s'", [M]); +format_error({circular,M,A}) -> + io_lib:format("circular macro '~s/~p'", [M,A]); format_error({include,W,F}) -> io_lib:format("can't find include ~s \"~s\"", [W,F]); format_error({illegal,How,What}) -> @@ -258,16 +264,20 @@ user_predef([{M,Val,redefine}|Pdm], Ms) when is_atom(M) -> user_predef(Pdm, dict:store({atom,M}, {none,Exp}, Ms)); user_predef([{M,Val}|Pdm], Ms) when is_atom(M) -> case dict:find({atom,M}, Ms) of - {ok,_Def} -> + {ok,_Defs} when is_list(_Defs) -> %% User defined macros {error,{redefine,M}}; + {ok,_Def} -> %% Predefined macros + {error,{redefine_predef,M}}; error -> Exp = erl_parse:tokens(erl_parse:abstract(Val)), user_predef(Pdm, dict:store({atom,M}, [{none, {none,Exp}}], Ms)) end; user_predef([M|Pdm], Ms) when is_atom(M) -> case dict:find({atom,M}, Ms) of - {ok,_Def} -> + {ok,_Defs} when is_list(_Defs) -> %% User defined macros {error,{redefine,M}}; + {ok,_Def} -> %% Predefined macros + {error,{redefine_predef,M}}; error -> user_predef(Pdm, dict:store({atom,M}, [{none, {none,[{atom,1,true}]}}], Ms)) @@ -493,7 +503,7 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',_Lc}|Toks], _Def, From, St) end; {ok, _PreDef} -> %% Predefined macros: cannot be overloaded - epp_reply(From, {error,{loc(Mac),epp,{redefine,M}}}), + epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,M}}}), wait_req_scan(St); error -> scan_define_cont(From, St, @@ -518,7 +528,7 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{'(',_Lc}|Toks], Def, From, St) end; {ok, _PreDef} -> %% Predefined macros: cannot be overloaded - epp_reply(From, {error,{loc(Mac),epp,{redefine,M}}}), + epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,M}}}), wait_req_scan(St); error -> scan_define_cont(From, St, {atom, M}, {Len, {As, Me}}) @@ -541,9 +551,15 @@ scan_define(_Toks, Def, From, St) -> %%% is detected, an error message is thrown. scan_define_cont(F, St, M, {Arity, Def}) -> - Ms = dict:append_list(M, [{Arity, Def}], St#epp.macs), - U = dict:append_list(M, [{Arity, macro_uses(Def)}], St#epp.uses), - scan_toks(F, St#epp{uses=U, macs=Ms}). + try + Ms = dict:append_list(M, [{Arity, Def}], St#epp.macs), + U = dict:append_list(M, [{Arity, macro_uses(Def)}], St#epp.uses), + scan_toks(F, St#epp{uses=U, macs=Ms}) + catch + _:{error, Line, Reason} -> + epp_reply(F, {error,{Line,epp,Reason}}), + wait_req_scan(St) + end. macro_uses({_Args, Tokens}) -> Uses0 = macro_ref(Tokens), @@ -553,14 +569,12 @@ macro_ref([]) -> []; macro_ref([{'?', _}, {'?', _} | Rest]) -> macro_ref(Rest); -macro_ref([{'?', _}, {Type, Lm, A} | Rest]) when Type =:= atom; Type =:= var -> - try - Arity = count_args(Rest, Lm, A), - [{{atom, A}, Arity} | macro_ref(Rest)] - catch - _:_ -> - macro_ref(Rest) - end; +macro_ref([{'?', _}, {atom, Lm, A} | Rest]) -> + Arity = count_args(Rest, Lm, A), + [{{atom, A}, Arity} | macro_ref(Rest)]; +macro_ref([{'?', _}, {var, Lm, A} | Rest]) -> + Arity = count_args(Rest, Lm, A), + [{{atom, A}, Arity} | macro_ref(Rest)]; macro_ref([_Token | Rest]) -> macro_ref(Rest). @@ -821,26 +835,27 @@ expand_macros(Type, MacT, M, Toks, Ms0) -> {ok,{As,Exp}} -> check_uses([{{Type,M}, length(As)}], [], U, Lm), {Bs,Toks1} = bind_args(Toks, Lm, M, As, dict:new()), - expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), Ms0); - {ok,undefined} -> - throw({error,Lm,{undefined,M}}); - {ok,mismatch} -> - throw({error,Lm,{mismatch,M}}); - error -> - throw({error,Lm,{undefined,M}}) + expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), Ms0) end. expand_macro1(Type, Lm, M, Toks, Ms) -> Arity = count_args(Toks, Lm, M), case dict:find({Type,M}, Ms) of - {ok, Defs} when is_list(Defs) -> %% User defined macro - {ok, proplists:get_value(Arity, Defs, - proplists:get_value(none, Defs, - mismatch))}; + error -> %% macro not found + throw({error,Lm,{undefined,M,Arity}}); + {ok, undefined} -> %% Predefined macro without definition + throw({error,Lm,{undefined,M,Arity}}); + {ok, [{none, Def}]} -> + {ok, Def}; + {ok, Defs} when is_list(Defs) -> + case proplists:get_value(Arity, Defs) of + undefined -> + throw({error,Lm,{mismatch,M}}); + Def -> + {ok, Def} + end; {ok, PreDef} -> %% Predefined macro - {ok, PreDef}; - error -> - error + {ok, PreDef} end. check_uses([], _Anc, _U, _Lm) -> @@ -848,8 +863,8 @@ check_uses([], _Anc, _U, _Lm) -> check_uses([M|Rest], Anc, U, Lm) -> case lists:member(M, Anc) of true -> - {{_, Name},_} = M, - throw({error,Lm,{circular,Name}}); + {{_, Name},Arity} = M, + throw({error,Lm,{circular,Name,Arity}}); false -> L = get_macro_uses(M, U), check_uses(L, [M|Anc], U, Lm), @@ -918,6 +933,8 @@ store_arg(_L, _M, A, Arg, Bs) -> %% Count the number of arguments in a macro call. count_args([{'(', _Llp},{')',_Lrp}|_Toks], _Lm, _M) -> 0; +count_args([{'(', _Llp},{',',_Lc}|_Toks], Lm, M) -> + throw({error,Lm,{arg_error,M}}); count_args([{'(',_Llp}|Toks0], Lm, M) -> {_Arg,Toks1} = macro_arg(Toks0, [], []), count_args(Toks1, Lm, M, 1); @@ -926,6 +943,8 @@ count_args(_Toks, _Lm, _M) -> count_args([{')',_Lrp}|_Toks], _Lm, _M, NbArgs) -> NbArgs; +count_args([{',',_Lc},{')',_Lrp}|_Toks], Lm, M, _NbArgs) -> + throw({error,Lm,{arg_error,M}}); count_args([{',',_Lc}|Toks0], Lm, M, NbArgs) -> {_Arg,Toks1} = macro_arg(Toks0, [], []), count_args(Toks1, Lm, M, NbArgs+1); diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 0055aedda9..25dd69b6dd 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -467,7 +467,7 @@ otp_6277(Config) when is_list(Config) -> -define(ASSERT, ?MODULE). ?ASSERT().">>, - [{error,{{4,16},epp,{undefined,'MODULE'}}}]}], + [{error,{{4,16},epp,{undefined,'MODULE', none}}}]}], ?line [] = check(Config, Ts), ok. @@ -674,7 +674,7 @@ otp_8130(Config) when is_list(Config) -> {otp_8130_c7, <<"\nt() -> ?A.\n">>, - {errors,[{{2,9},epp,{undefined,'A'}}],[]}}, + {errors,[{{2,9},epp,{undefined,'A', none}}],[]}}, {otp_8130_c8, <<"\n-include_lib(\"$apa/foo.hrl\").\n">>, @@ -684,7 +684,7 @@ otp_8130(Config) when is_list(Config) -> {otp_8130_c9, <<"-define(S, ?S).\n" "t() -> ?S.\n">>, - {errors,[{{2,9},epp,{circular,'S'}}],[]}}, + {errors,[{{2,9},epp,{circular,'S', none}}],[]}}, {otp_8130_c10, <<"\n-file.">>, @@ -746,7 +746,7 @@ otp_8130(Config) when is_list(Config) -> {otp_8130_c23, <<"\n-file(?b, 3).\n">>, - {errors,[{{2,8},epp,{undefined,b}}],[]}}, + {errors,[{{2,8},epp,{undefined,b, none}}],[]}}, {otp_8130_c24, <<"\n-include(\"no such file.erl\").\n">>, @@ -1047,19 +1047,26 @@ overload_mac(Config) when is_list(Config) -> "-undef(A).\n" "t1() -> ?A.\n", "t2() -> ?A(1).">>, - {errors,[{{4,9},epp,{undefined,'A'}}, - {{5,9},epp,{undefined,'A'}}],[]}}, + {errors,[{{4,9},epp,{undefined,'A', none}}, + {{5,9},epp,{undefined,'A', 1}}],[]}}, %% cannot overload predefined macros {overload_mac_c2, <<"-define(MODULE(X), X).">>, - {errors,[{{1,9},epp,{redefine,'MODULE'}}],[]}}, + {errors,[{{1,9},epp,{redefine_predef,'MODULE'}}],[]}}, %% cannot overload macros with same arity {overload_mac_c3, <<"-define(A(X), X).\n" "-define(A(Y), Y).">>, - {errors,[{{2,9},epp,{redefine,'A'}}],[]}} + {errors,[{{2,9},epp,{redefine,'A'}}],[]}}, + + {overload_mac_c4, + <<"-define(A, a).\n" + "-define(A(X,Y), {X,Y}).\n" + "a(X) -> X.\n" + "t() -> ?A(1).">>, + {errors,[{{4,9},epp,{mismatch,'A'}}],[]}} ], ?line [] = compile(Config, Cs), @@ -1078,13 +1085,6 @@ overload_mac(Config) when is_list(Config) -> 1}, {overload_mac_r3, - <<"-define(A, a).\n" - "-define(A(X,Y), {X,Y}).\n" - "a(X) -> ?A(X,X).\n" - "t() -> ?A(1).">>, - {1,1}}, - - {overload_mac_r4, <<"-define(A, ?B).\n" "-define(B, a).\n" "-define(B(X), {b,X}).\n" |