aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnders Svensson <[email protected]>2014-09-12 16:31:24 +0200
committerAnders Svensson <[email protected]>2014-09-12 17:10:21 +0200
commit8e5e66b66cf318722e5b128c1b690fa2d080f1db (patch)
tree9ea5f8fb75a3baaafdc4dbed08d0dcaa1e755fcb
parent0f9cdbaf4d7fde93d319be7789dd4119092d91c6 (diff)
downloadotp-8e5e66b66cf318722e5b128c1b690fa2d080f1db.tar.gz
otp-8e5e66b66cf318722e5b128c1b690fa2d080f1db.tar.bz2
otp-8e5e66b66cf318722e5b128c1b690fa2d080f1db.zip
Fix ?MODULE in preprocessed dictionary forms
By replacing literal diameter_gen_relay atoms in forms extracted from that module by the name of the module in question. This has been wrong for some time, but only became noticable when the parent commit started using ?MODULE as more than a process dictionary key or tag to match on. In particular, the function dict/1 in diameter_gen.hrl (included by every dictionary module) can now return ?MODULE, which is (not surprisingly) expected to be the name of the dictionary module in question. It wasn't in the case of a module compiled from forms: it was diameter_gen_relay, since that's the module the forms were extracted from. The fix only affects dictionaries compiled from forms, as returned by diameter_make:codec/2. In particular, dictionaries compiled from Erlang source returned by this function, or by diameterc(1), are unaffected.
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl33
1 files changed, 28 insertions, 5 deletions
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 5a068c1a25..d91a776321 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -132,7 +132,7 @@ gen(parse, ParseD, _Mod) ->
[?VERSION | ParseD];
gen(forms, ParseD, Mod) ->
- pp(erl_forms(Mod, ParseD));
+ preprocess(Mod, erl_forms(Mod, ParseD));
gen(hrl, ParseD, Mod) ->
gen_hrl(Mod, ParseD);
@@ -838,19 +838,19 @@ rec_name(Name, Prefix) ->
Prefix ++ Name.
%% ===========================================================================
-%% pp/1
+%% preprocess/2
%%
%% Preprocess forms as generated by 'forms' option. In particular,
%% replace the include_lib attributes in generated forms by the
%% corresponding forms, extracting the latter from an existing
%% dictionary (diameter_gen_relay). The resulting forms can be
%% compiled to beam using compile:forms/2 (which does no preprocessing
-%% or it's own; DiY currently appears to be the only way to preprocess
+%% of it's own; DiY currently appears to be the only way to preprocess
%% a forms list).
-pp(Forms) ->
+preprocess(Mod, Forms) ->
{_, Beam, _} = code:get_object_code(diameter_gen_relay),
- pp(Forms, abstract_code(Beam)).
+ pp(Forms, remod(Mod, abstract_code(Beam))).
pp(Forms, {ok, Code}) ->
Files = files(Code, []),
@@ -859,6 +859,25 @@ pp(Forms, {ok, Code}) ->
pp(Forms, {error, Reason}) ->
erlang:error({forms, Reason, Forms}).
+%% Replace literal diameter_gen_relay atoms in the extracted forms.
+%% ?MODULE for example.
+
+remod(Mod, L)
+ when is_list(L) ->
+ [remod(Mod, T) || T <- L];
+
+remod(Mod, {atom, _, diameter_gen_relay} = T) ->
+ setelement(3, T, Mod);
+
+remod(Mod, T)
+ when is_tuple(T) ->
+ list_to_tuple(remod(Mod, tuple_to_list(T)));
+
+remod(_, T) ->
+ T.
+
+%% Replace include_lib by the corresponding forms.
+
include({attribute, _, include_lib, Path}, Files) ->
Inc = filename:basename(Path),
[{Inc, Forms}] = [T || {F, _} = T <- Files, F == Inc], %% expect one
@@ -867,6 +886,8 @@ include({attribute, _, include_lib, Path}, Files) ->
include(T, _) ->
[T].
+%% Extract abstract code.
+
abstract_code(Beam) ->
case beam_lib:chunks(Beam, [abstract_code]) of
{ok, {_Mod, [{abstract_code, {_Vsn, Code}}]}} ->
@@ -877,6 +898,8 @@ abstract_code(Beam) ->
{E, Reason}
end.
+%% Extract filename/forms pairs for included forms.
+
files([{attribute, _, file, {Path, _}} | T], Acc) ->
{Body, Rest} = lists:splitwith(fun({attribute, _, file, _}) -> false;
(_) -> true