aboutsummaryrefslogtreecommitdiffstats
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
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.
-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"