aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorChristopher Faulet <[email protected]>2009-12-07 16:47:44 +0100
committerBjörn Gustavsson <[email protected]>2010-02-01 16:18:23 +0100
commit27d7ca04eb2933345b5be50870a197a3b19588c0 (patch)
tree8a3844d72982efff69b478ce1b82ba61995731ec /lib
parent5023556e555fd99d6b5bbe77707066371e38abd7 (diff)
downloadotp-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.
Diffstat (limited to 'lib')
-rw-r--r--lib/stdlib/src/epp.erl95
-rw-r--r--lib/stdlib/test/epp_SUITE.erl30
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"