From eadf8443197e59f98dd0aa3de8058df0a8fa3711 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 20 Sep 2013 16:20:08 +0200 Subject: Change extensions for debug output: .spec/forms -> .D/F "spec" is an old term the internal representation of a dictionary. The new extensions are in the style or those that compile(3) can generate. --- lib/diameter/bin/diameterc | 2 +- lib/diameter/src/compiler/diameter_codegen.erl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc index 2f5834d359..3bcfc59343 100755 --- a/lib/diameter/bin/diameterc +++ b/lib/diameter/bin/diameterc @@ -50,7 +50,7 @@ usage() -> " -i dir = set an include directory for inherited beams~n" " -E = no .erl output~n" " -H = no .hrl output~n" - " -d = write intermediate files (.spec and .forms)~n", + " -d = write intermediate files (.D and .F)~n", [?MODULE]). main(Args) -> diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index e687145263..b99adb7b52 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -121,7 +121,7 @@ mod(_, {ok, Mod}) -> Mod. gen(spec, Spec, _Mod, Path) -> - write_term(Path ++ ".spec", [?VERSION | Spec]); + write_term(Path ++ ".D", [?VERSION | Spec]); gen(hrl, Spec, Mod, Path) -> gen_hrl(Path ++ ".hrl", Mod, Spec); @@ -173,7 +173,7 @@ gen(erl, Spec, Mod, Path) -> gen_erl(Path, insert_hrl_forms(Spec, Forms)). gen_erl(Path, Forms) -> - getr(debug) andalso write_term(Path ++ ".forms", Forms), + getr(debug) andalso write_term(Path ++ ".F", Forms), write(Path ++ ".erl", header() ++ erl_prettypr:format(erl_syntax:form_list(Forms))). -- cgit v1.2.3 From c22a639edccb443792e600bdc4b7f0117f12c9de Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 20 Sep 2013 12:26:12 +0200 Subject: Write as last step in code generation In preparation for allowing return instead of write. --- lib/diameter/src/compiler/diameter_codegen.erl | 214 +++++++++++-------------- 1 file changed, 93 insertions(+), 121 deletions(-) (limited to 'lib') diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index b99adb7b52..9b3bd4ec5d 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -98,17 +98,6 @@ file(F, Outdir, Mode) -> get_value(Key, Plist) -> proplists:get_value(Key, Plist, []). -write(Path, Str) -> - w(Path, Str, "~s"). - -write_term(Path, T) -> - w(Path, T, "~p."). - -w(Path, T, Fmt) -> - {ok, Fd} = file:open(Path, [write]), - io:fwrite(Fd, Fmt ++ "~n", [T]), - file:close(Fd). - codegen(File, Spec, Outdir, Mode) -> Mod = mod(File, orddict:find(name, Spec)), Path = filename:join(Outdir, Mod), %% minus extension @@ -124,67 +113,70 @@ gen(spec, Spec, _Mod, Path) -> write_term(Path ++ ".D", [?VERSION | Spec]); gen(hrl, Spec, Mod, Path) -> - gen_hrl(Path ++ ".hrl", Mod, Spec); + write(Path ++ ".hrl", gen_hrl(Mod, Spec)); gen(erl, Spec, Mod, Path) -> - Forms = [{?attribute, module, Mod}, - {?attribute, compile, {parse_transform, diameter_exprecs}}, - {?attribute, compile, nowarn_unused_function}, - {?attribute, export, [{name, 0}, - {id, 0}, - {vendor_id, 0}, - {vendor_name, 0}, - {decode_avps, 2}, %% in diameter_gen.hrl - {encode_avps, 2}, %% - {msg_name, 2}, - {msg_header, 1}, - {rec2msg, 1}, - {msg2rec, 1}, - {name2rec, 1}, - {avp_name, 2}, - {avp_arity, 2}, - {avp_header, 1}, - {avp, 3}, - {grouped_avp, 3}, - {enumerated_avp, 3}, - {empty_value, 1}, - {dict, 0}]}, - %% diameter.hrl is included for #diameter_avp - {?attribute, include_lib, "diameter/include/diameter.hrl"}, - {?attribute, include_lib, "diameter/include/diameter_gen.hrl"}, - f_name(Mod), - f_id(Spec), - f_vendor_id(Spec), - f_vendor_name(Spec), - f_msg_name(Spec), - f_msg_header(Spec), - f_rec2msg(Spec), - f_msg2rec(Spec), - f_name2rec(Spec), - f_avp_name(Spec), - f_avp_arity(Spec), - f_avp_header(Spec), - f_avp(Spec), - f_enumerated_avp(Spec), - f_empty_value(Spec), - f_dict(Spec), - {eof, ?LINE}], - - gen_erl(Path, insert_hrl_forms(Spec, Forms)). - -gen_erl(Path, Forms) -> - getr(debug) andalso write_term(Path ++ ".F", Forms), - write(Path ++ ".erl", - header() ++ erl_prettypr:format(erl_syntax:form_list(Forms))). - -insert_hrl_forms(Spec, Forms) -> - {H,T} = lists:splitwith(fun is_header/1, Forms), - H ++ make_hrl_forms(Spec) ++ T. - -is_header({attribute, _, export, _}) -> - false; -is_header(_) -> - true. + Forms = erl_forms(Mod, Spec), + getr(debug) andalso write_term(Path ++ ".F", [Forms]), + write(Path ++ ".erl", [header(), prettypr(Forms), $\n]). + +write(Path, T) -> + write(Path, "~s", T). + +write_term(Path, T) -> + write(Path, "~p.~n", T). + +write(Path, Fmt, T) -> + {ok, Fd} = file:open(Path, [write]), + io:fwrite(Fd, Fmt, [T]), + file:close(Fd). + +erl_forms(Mod, Spec) -> + Forms = [[{?attribute, module, Mod}, + {?attribute, compile, {parse_transform, diameter_exprecs}}, + {?attribute, compile, nowarn_unused_function}], + make_hrl_forms(Spec), + [{?attribute, export, [{name, 0}, + {id, 0}, + {vendor_id, 0}, + {vendor_name, 0}, + {decode_avps, 2}, %% in diameter_gen.hrl + {encode_avps, 2}, %% + {msg_name, 2}, + {msg_header, 1}, + {rec2msg, 1}, + {msg2rec, 1}, + {name2rec, 1}, + {avp_name, 2}, + {avp_arity, 2}, + {avp_header, 1}, + {avp, 3}, + {grouped_avp, 3}, + {enumerated_avp, 3}, + {empty_value, 1}, + {dict, 0}]}, + %% diameter.hrl is included for #diameter_avp + {?attribute, include_lib, "diameter/include/diameter.hrl"}, + {?attribute, include_lib, "diameter/include/diameter_gen.hrl"}, + f_name(Mod), + f_id(Spec), + f_vendor_id(Spec), + f_vendor_name(Spec), + f_msg_name(Spec), + f_msg_header(Spec), + f_rec2msg(Spec), + f_msg2rec(Spec), + f_name2rec(Spec), + f_avp_name(Spec), + f_avp_arity(Spec), + f_avp_header(Spec), + f_avp(Spec), + f_enumerated_avp(Spec), + f_empty_value(Spec), + f_dict(Spec), + {eof, ?LINE}]], + + lists:append(Forms). make_hrl_forms(Spec) -> {_Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} @@ -208,7 +200,7 @@ make_record_forms(Spec) -> ImportedGrpRecs = [{M, a_record(Prefix, fun grp_proj/1, Gs)} || {M,Gs} <- get_value(import_groups, Spec)], - {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs}. + {to_upper(Prefix), MsgRecs, GrpRecs, ImportedGrpRecs}. msg_proj({Name, _, _, _, Avps}) -> {Name, Avps}. @@ -711,67 +703,47 @@ f_dict(Spec) -> [{?clause, [], [], [?TERM([?VERSION | Spec])]}]}. %%% ------------------------------------------------------------------------ -%%% # gen_hrl/3 +%%% # gen_hrl/2 %%% ------------------------------------------------------------------------ -gen_hrl(Path, Mod, Spec) -> - {ok, Fd} = file:open(Path, [write]), - +gen_hrl(Mod, Spec) -> {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} = make_record_forms(Spec), - file:write(Fd, hrl_header(Mod)), - - forms("Message records", Fd, MsgRecs), - forms("Grouped AVP records", Fd, GrpRecs), - - lists:foreach(fun({M,Fs}) -> - forms("Grouped AVP records from " ++ atom_to_list(M), - Fd, - Fs) - end, - ImportedGrpRecs), - - PREFIX = to_upper(Prefix), - - write("ENUM Macros", - Fd, - m_enums(PREFIX, false, get_value(enum, Spec))), - write("DEFINE Macros", - Fd, - m_enums(PREFIX, false, get_value(define, Spec))), - - lists:foreach(fun({M,Es}) -> - write("ENUM Macros from " ++ atom_to_list(M), - Fd, - m_enums(PREFIX, true, Es)) - end, - get_value(import_enums, Spec)), - - file:close(Fd). - -forms(_, _, []) -> - ok; -forms(Banner, Fd, Forms) -> - write(Banner, Fd, prettypr(Forms)). - -write(_, _, []) -> - ok; -write(Banner, Fd, Str) -> - banner(Fd, Banner), - io:fwrite(Fd, "~s~n", [Str]). + [hrl_header(Mod), + forms("Message records", MsgRecs), + forms("Grouped AVP records", GrpRecs), + lists:map(fun({M,Fs}) -> + forms("Grouped AVP records from " ++ atom_to_list(M), + Fs) + end, + ImportedGrpRecs), + format("ENUM Macros", m_enums(Prefix, false, get_value(enum, Spec))), + format("DEFINE Macros", m_enums(Prefix, false, get_value(define, Spec))), + lists:map(fun({M,Es}) -> + format("ENUM Macros from " ++ atom_to_list(M), + m_enums(Prefix, true, Es)) + end, + get_value(import_enums, Spec))]. + +forms(_, [] = No) -> + No; +forms(Banner, Forms) -> + format(Banner, prettypr(Forms)). + +format(_, [] = No) -> + No; +format(Banner, Str) -> + [banner(Banner), Str, $\n]. prettypr(Forms) -> erl_prettypr:format(erl_syntax:form_list(Forms)). -banner(Fd, Heading) -> - file:write(Fd, banner(Heading)). - banner(Heading) -> - ("\n\n" + ["\n\n" "%%% -------------------------------------------------------\n" - "%%% " ++ Heading ++ ":\n" - "%%% -------------------------------------------------------\n\n"). + "%%% ", Heading, ":\n" + "%%% -------------------------------------------------------\n\n"]. z(S) -> string:join(string:tokens(S, "\s\t"), "\s"). -- cgit v1.2.3 From a3fa81eafff105086cf3f0c942c5247686edac28 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 09:08:14 +0200 Subject: Remove last remnants of "spec" --- lib/diameter/bin/diameterc | 10 +- lib/diameter/src/compiler/diameter_codegen.erl | 250 ++++++++++++------------- lib/diameter/src/compiler/diameter_make.erl | 4 +- lib/diameter/test/diameter_compiler_SUITE.erl | 2 +- 4 files changed, 133 insertions(+), 133 deletions(-) (limited to 'lib') diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc index 3bcfc59343..cae2bcedbe 100755 --- a/lib/diameter/bin/diameterc +++ b/lib/diameter/bin/diameterc @@ -74,10 +74,10 @@ gen(Args) -> compile(#argv{file = File, options = Opts} = A) -> try diameter_dict_util:parse({path, File}, Opts) of - {ok, Spec} -> - maybe_output(A, Spec, Opts, spec), %% the spec file - maybe_output(A, Spec, Opts, erl), %% the erl file - maybe_output(A, Spec, Opts, hrl), %% The hrl file + {ok, Dict} -> + maybe_output(A, Dict, Opts, dict), %% parsed dictionary + maybe_output(A, Dict, Opts, erl), %% the erl file + maybe_output(A, Dict, Opts, hrl), %% The hrl file 0; {error, Reason} -> error_msg(diameter_dict_util:format_error(Reason), []), @@ -139,7 +139,7 @@ arg(["-H" | Args], #argv{output = Output} = A) -> arg(["-d" | Args], #argv{options = Opts, output = Output} = A) -> arg(Args, A#argv{options = [debug | Opts], - output = [spec | Output]}); + output = [dict | Output]}); arg([[$- = M, C, H | T] | Args], A) %% clustered options when C /= $i, C /= $o, C /= $- -> diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index 9b3bd4ec5d..e606e61052 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -48,18 +48,18 @@ %% =========================================================================== --spec from_dict(File, Spec, Opts, Mode) +-spec from_dict(File, ParseD, Opts, Mode) -> ok when File :: string(), - Spec :: orddict:orddict(), + ParseD :: orddict:orddict(), Opts :: list(), - Mode :: spec | erl | hrl. + Mode :: dict | erl | hrl. -from_dict(File, Spec, Opts, Mode) -> +from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), putr(verbose, lists:member(verbose, Opts)), putr(debug, lists:member(debug, Opts)), - codegen(File, Spec, Outdir, Mode). + codegen(File, ParseD, Outdir, Mode). %% Optional reports when running verbosely. report(What, Data) -> @@ -83,14 +83,14 @@ getr(Key) -> %% Generate from parsed dictionary in a file. file(F) -> - file(F, spec). + file(F, dict). file(F, Mode) -> file(F, ".", Mode). file(F, Outdir, Mode) -> - {ok, [Spec]} = file:consult(F), - from_dict(F, Spec, Outdir, Mode). + {ok, [ParseD]} = file:consult(F), + from_dict(F, ParseD, Outdir, Mode). %% =========================================================================== %% =========================================================================== @@ -98,10 +98,10 @@ file(F, Outdir, Mode) -> get_value(Key, Plist) -> proplists:get_value(Key, Plist, []). -codegen(File, Spec, Outdir, Mode) -> - Mod = mod(File, orddict:find(name, Spec)), +codegen(File, ParseD, Outdir, Mode) -> + Mod = mod(File, orddict:find(name, ParseD)), Path = filename:join(Outdir, Mod), %% minus extension - gen(Mode, Spec, ?A(Mod), Path), + gen(Mode, ParseD, ?A(Mod), Path), ok. mod(File, error) -> @@ -109,14 +109,14 @@ mod(File, error) -> mod(_, {ok, Mod}) -> Mod. -gen(spec, Spec, _Mod, Path) -> - write_term(Path ++ ".D", [?VERSION | Spec]); +gen(dict, ParseD, _Mod, Path) -> + write_term(Path ++ ".D", [?VERSION | ParseD]); -gen(hrl, Spec, Mod, Path) -> - write(Path ++ ".hrl", gen_hrl(Mod, Spec)); +gen(hrl, ParseD, Mod, Path) -> + write(Path ++ ".hrl", gen_hrl(Mod, ParseD)); -gen(erl, Spec, Mod, Path) -> - Forms = erl_forms(Mod, Spec), +gen(erl, ParseD, Mod, Path) -> + Forms = erl_forms(Mod, ParseD), getr(debug) andalso write_term(Path ++ ".F", [Forms]), write(Path ++ ".erl", [header(), prettypr(Forms), $\n]). @@ -131,11 +131,11 @@ write(Path, Fmt, T) -> io:fwrite(Fd, Fmt, [T]), file:close(Fd). -erl_forms(Mod, Spec) -> +erl_forms(Mod, ParseD) -> Forms = [[{?attribute, module, Mod}, {?attribute, compile, {parse_transform, diameter_exprecs}}, {?attribute, compile, nowarn_unused_function}], - make_hrl_forms(Spec), + make_hrl_forms(ParseD), [{?attribute, export, [{name, 0}, {id, 0}, {vendor_id, 0}, @@ -159,28 +159,28 @@ erl_forms(Mod, Spec) -> {?attribute, include_lib, "diameter/include/diameter.hrl"}, {?attribute, include_lib, "diameter/include/diameter_gen.hrl"}, f_name(Mod), - f_id(Spec), - f_vendor_id(Spec), - f_vendor_name(Spec), - f_msg_name(Spec), - f_msg_header(Spec), - f_rec2msg(Spec), - f_msg2rec(Spec), - f_name2rec(Spec), - f_avp_name(Spec), - f_avp_arity(Spec), - f_avp_header(Spec), - f_avp(Spec), - f_enumerated_avp(Spec), - f_empty_value(Spec), - f_dict(Spec), + f_id(ParseD), + f_vendor_id(ParseD), + f_vendor_name(ParseD), + f_msg_name(ParseD), + f_msg_header(ParseD), + f_rec2msg(ParseD), + f_msg2rec(ParseD), + f_name2rec(ParseD), + f_avp_name(ParseD), + f_avp_arity(ParseD), + f_avp_header(ParseD), + f_avp(ParseD), + f_enumerated_avp(ParseD), + f_empty_value(ParseD), + f_dict(ParseD), {eof, ?LINE}]], lists:append(Forms). -make_hrl_forms(Spec) -> +make_hrl_forms(ParseD) -> {_Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} - = make_record_forms(Spec), + = make_record_forms(ParseD), RecordForms = MsgRecs ++ GrpRecs ++ lists:flatmap(fun({_,Fs}) -> Fs end, ImportedGrpRecs), @@ -191,14 +191,14 @@ make_hrl_forms(Spec) -> %% export_records is used by the diameter_exprecs parse transform. [{?attribute, export_records, RecNames} | RecordForms]. -make_record_forms(Spec) -> - Prefix = prefix(Spec), +make_record_forms(ParseD) -> + Prefix = prefix(ParseD), - MsgRecs = a_record(Prefix, fun msg_proj/1, get_value(messages, Spec)), - GrpRecs = a_record(Prefix, fun grp_proj/1, get_value(grouped, Spec)), + MsgRecs = a_record(Prefix, fun msg_proj/1, get_value(messages, ParseD)), + GrpRecs = a_record(Prefix, fun grp_proj/1, get_value(grouped, ParseD)), ImportedGrpRecs = [{M, a_record(Prefix, fun grp_proj/1, Gs)} - || {M,Gs} <- get_value(import_groups, Spec)], + || {M,Gs} <- get_value(import_groups, ParseD)], {to_upper(Prefix), MsgRecs, GrpRecs, ImportedGrpRecs}. @@ -238,9 +238,9 @@ f_name(Name) -> %%% # id/0 %%% ------------------------------------------------------------------------ -f_id(Spec) -> +f_id(ParseD) -> {?function, id, 0, - [c_id(orddict:find(id, Spec))]}. + [c_id(orddict:find(id, ParseD))]}. c_id({ok, Id}) -> {?clause, [], [], [?INTEGER(Id)]}; @@ -252,9 +252,9 @@ c_id(error) -> %%% # vendor_id/0 %%% ------------------------------------------------------------------------ -f_vendor_id(Spec) -> +f_vendor_id(ParseD) -> {?function, vendor_id, 0, - [{?clause, [], [], [b_vendor_id(orddict:find(vendor, Spec))]}]}. + [{?clause, [], [], [b_vendor_id(orddict:find(vendor, ParseD))]}]}. b_vendor_id({ok, {Id, _}}) -> ?INTEGER(Id); @@ -265,9 +265,9 @@ b_vendor_id(error) -> %%% # vendor_name/0 %%% ------------------------------------------------------------------------ -f_vendor_name(Spec) -> +f_vendor_name(ParseD) -> {?function, vendor_name, 0, - [{?clause, [], [], [b_vendor_name(orddict:find(vendor, Spec))]}]}. + [{?clause, [], [], [b_vendor_name(orddict:find(vendor, ParseD))]}]}. b_vendor_name({ok, {_, Name}}) -> ?Atom(Name); @@ -278,15 +278,15 @@ b_vendor_name(error) -> %%% # msg_name/1 %%% ------------------------------------------------------------------------ -f_msg_name(Spec) -> - {?function, msg_name, 2, msg_name(Spec)}. +f_msg_name(ParseD) -> + {?function, msg_name, 2, msg_name(ParseD)}. %% Return the empty name for any unknown command to which %% DIAMETER_COMMAND_UNSUPPORTED should be replied. -msg_name(Spec) -> +msg_name(ParseD) -> lists:flatmap(fun c_msg_name/1, proplists:get_value(command_codes, - Spec, + ParseD, [])) ++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?ATOM('')]}]. @@ -302,12 +302,12 @@ c_msg_name({Code, Req, Ans}) -> %%% # msg2rec/1 %%% ------------------------------------------------------------------------ -f_msg2rec(Spec) -> - {?function, msg2rec, 1, msg2rec(Spec)}. +f_msg2rec(ParseD) -> + {?function, msg2rec, 1, msg2rec(ParseD)}. -msg2rec(Spec) -> - Pre = prefix(Spec), - lists:map(fun(T) -> c_msg2rec(T, Pre) end, get_value(messages, Spec)) +msg2rec(ParseD) -> + Pre = prefix(ParseD), + lists:map(fun(T) -> c_msg2rec(T, Pre) end, get_value(messages, ParseD)) ++ [?BADARG(1)]. c_msg2rec({N,_,_,_,_}, Pre) -> @@ -317,12 +317,12 @@ c_msg2rec({N,_,_,_,_}, Pre) -> %%% # rec2msg/1 %%% ------------------------------------------------------------------------ -f_rec2msg(Spec) -> - {?function, rec2msg, 1, rec2msg(Spec)}. +f_rec2msg(ParseD) -> + {?function, rec2msg, 1, rec2msg(ParseD)}. -rec2msg(Spec) -> - Pre = prefix(Spec), - lists:map(fun(T) -> c_rec2msg(T, Pre) end, get_value(messages, Spec)) +rec2msg(ParseD) -> + Pre = prefix(ParseD), + lists:map(fun(T) -> c_rec2msg(T, Pre) end, get_value(messages, ParseD)) ++ [?BADARG(1)]. c_rec2msg({N,_,_,_,_}, Pre) -> @@ -332,13 +332,13 @@ c_rec2msg({N,_,_,_,_}, Pre) -> %%% # name2rec/1 %%% ------------------------------------------------------------------------ -f_name2rec(Spec) -> - {?function, name2rec, 1, name2rec(Spec)}. +f_name2rec(ParseD) -> + {?function, name2rec, 1, name2rec(ParseD)}. -name2rec(Spec) -> - Pre = prefix(Spec), - Groups = get_value(grouped, Spec) - ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), +name2rec(ParseD) -> + Pre = prefix(ParseD), + Groups = get_value(grouped, ParseD) + ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)), lists:map(fun({N,_,_,_}) -> c_name2rec(N, Pre) end, Groups) ++ [{?clause, [?VAR('T')], [], [?CALL(msg2rec, [?VAR('T')])]}]. @@ -352,8 +352,8 @@ avps({_Mod, Avps}) -> %%% # avp_name/1 %%% ------------------------------------------------------------------------ -f_avp_name(Spec) -> - {?function, avp_name, 2, avp_name(Spec)}. +f_avp_name(ParseD) -> + {?function, avp_name, 2, avp_name(ParseD)}. %% 3588, 4.1: %% @@ -364,11 +364,11 @@ f_avp_name(Spec) -> %% field. AVP numbers 256 and above are used for Diameter, which are %% allocated by IANA (see Section 11.1). -avp_name(Spec) -> - Avps = get_value(avp_types, Spec), - Imported = get_value(import_avps, Spec), - Vid = orddict:find(vendor, Spec), - Vs = vendor_id_map(Spec), +avp_name(ParseD) -> + Avps = get_value(avp_types, ParseD), + Imported = get_value(import_avps, ParseD), + Vid = orddict:find(vendor, ParseD), + Vs = vendor_id_map(ParseD), lists:map(fun(T) -> c_avp_name(T, Vs, Vid) end, Avps) ++ lists:flatmap(fun(T) -> c_imported_avp_name(T, Vs) end, Imported) @@ -399,25 +399,25 @@ c_avp_name_(T, Code, Vid) -> [], [T]}. -vendor_id_map(Spec) -> +vendor_id_map(ParseD) -> lists:flatmap(fun({V,Ns}) -> [{N,V} || N <- Ns] end, - get_value(avp_vendor_id, Spec)) + get_value(avp_vendor_id, ParseD)) ++ lists:flatmap(fun({_,_,[],_}) -> []; ({N,_,[V],_}) -> [{N,V}] end, - get_value(grouped, Spec)). + get_value(grouped, ParseD)). %%% ------------------------------------------------------------------------ %%% # avp_arity/2 %%% ------------------------------------------------------------------------ -f_avp_arity(Spec) -> - {?function, avp_arity, 2, avp_arity(Spec)}. +f_avp_arity(ParseD) -> + {?function, avp_arity, 2, avp_arity(ParseD)}. -avp_arity(Spec) -> - Msgs = get_value(messages, Spec), - Groups = get_value(grouped, Spec) - ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), +avp_arity(ParseD) -> + Msgs = get_value(messages, ParseD), + Groups = get_value(grouped, ParseD) + ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)), c_avp_arity(Msgs ++ Groups) ++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?INTEGER(0)]}]. @@ -441,15 +441,15 @@ c_arity(Name, Avp) -> %%% # avp/3 %%% ------------------------------------------------------------------------ -f_avp(Spec) -> - {?function, avp, 3, avp(Spec) ++ [?BADARG(3)]}. +f_avp(ParseD) -> + {?function, avp, 3, avp(ParseD) ++ [?BADARG(3)]}. -avp(Spec) -> - Native = get_value(avp_types, Spec), - CustomMods = get_value(custom_types, Spec), - TypeMods = get_value(codecs, Spec), - Imported = get_value(import_avps, Spec), - Enums = get_value(enum, Spec), +avp(ParseD) -> + Native = get_value(avp_types, ParseD), + CustomMods = get_value(custom_types, ParseD), + TypeMods = get_value(codecs, ParseD), + Imported = get_value(import_avps, ParseD), + Enums = get_value(enum, ParseD), Custom = lists:map(fun({M,As}) -> {M, custom_types, As} end, CustomMods) @@ -540,14 +540,14 @@ custom(codecs, AvpName, Type) -> %%% # enumerated_avp/3 %%% ------------------------------------------------------------------------ -f_enumerated_avp(Spec) -> - {?function, enumerated_avp, 3, enumerated_avp(Spec) ++ [?BADARG(3)]}. +f_enumerated_avp(ParseD) -> + {?function, enumerated_avp, 3, enumerated_avp(ParseD) ++ [?BADARG(3)]}. -enumerated_avp(Spec) -> - Enums = get_value(enum, Spec), +enumerated_avp(ParseD) -> + Enums = get_value(enum, ParseD), lists:flatmap(fun cs_enumerated_avp/1, Enums) ++ lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end, - get_value(import_enums, Spec)). + get_value(import_enums, ParseD)). enumerated_avp(Mod, Es, Enums) -> lists:flatmap(fun({N,_}) -> @@ -577,16 +577,16 @@ c_enumerated_avp(AvpName, {_,I}) -> %%% msg_header/1 %%% ------------------------------------------------------------------------ -f_msg_header(Spec) -> - {?function, msg_header, 1, msg_header(Spec) ++ [?BADARG(1)]}. +f_msg_header(ParseD) -> + {?function, msg_header, 1, msg_header(ParseD) ++ [?BADARG(1)]}. -msg_header(Spec) -> - msg_header(get_value(messages, Spec), Spec). +msg_header(ParseD) -> + msg_header(get_value(messages, ParseD), ParseD). msg_header([], _) -> []; -msg_header(Msgs, Spec) -> - ApplId = orddict:fetch(id, Spec), +msg_header(Msgs, ParseD) -> + ApplId = orddict:fetch(id, ParseD), lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end, Msgs). @@ -608,14 +608,14 @@ emf('ERR', N) -> N bor 2#00100000. %%% # avp_header/1 %%% ------------------------------------------------------------------------ -f_avp_header(Spec) -> - {?function, avp_header, 1, avp_header(Spec) ++ [?BADARG(1)]}. +f_avp_header(ParseD) -> + {?function, avp_header, 1, avp_header(ParseD) ++ [?BADARG(1)]}. -avp_header(Spec) -> - Native = get_value(avp_types, Spec), - Imported = get_value(import_avps, Spec), - Vid = orddict:find(vendor, Spec), - Vs = vendor_id_map(Spec), +avp_header(ParseD) -> + Native = get_value(avp_types, ParseD), + Imported = get_value(import_avps, ParseD), + Vid = orddict:find(vendor, ParseD), + Vs = vendor_id_map(ParseD), lists:flatmap(fun(A) -> c_avp_header(A, Vs, Vid) end, Native ++ Imported). @@ -671,14 +671,14 @@ v(false, _, _, _) -> %%% # empty_value/0 %%% ------------------------------------------------------------------------ -f_empty_value(Spec) -> - {?function, empty_value, 1, empty_value(Spec)}. +f_empty_value(ParseD) -> + {?function, empty_value, 1, empty_value(ParseD)}. -empty_value(Spec) -> - Imported = lists:flatmap(fun avps/1, get_value(import_enums, Spec)), - Groups = get_value(grouped, Spec) - ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), - Enums = [T || {N,_} = T <- get_value(enum, Spec), +empty_value(ParseD) -> + Imported = lists:flatmap(fun avps/1, get_value(import_enums, ParseD)), + Groups = get_value(grouped, ParseD) + ++ lists:flatmap(fun avps/1, get_value(import_groups, ParseD)), + Enums = [T || {N,_} = T <- get_value(enum, ParseD), not lists:keymember(N, 1, Imported)] ++ Imported, lists:map(fun c_empty_value/1, Groups ++ Enums) @@ -698,17 +698,17 @@ c_empty_value({Name, _}) -> %%% # dict/0 %%% ------------------------------------------------------------------------ -f_dict(Spec) -> +f_dict(ParseD) -> {?function, dict, 0, - [{?clause, [], [], [?TERM([?VERSION | Spec])]}]}. + [{?clause, [], [], [?TERM([?VERSION | ParseD])]}]}. %%% ------------------------------------------------------------------------ %%% # gen_hrl/2 %%% ------------------------------------------------------------------------ -gen_hrl(Mod, Spec) -> +gen_hrl(Mod, ParseD) -> {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} - = make_record_forms(Spec), + = make_record_forms(ParseD), [hrl_header(Mod), forms("Message records", MsgRecs), @@ -718,13 +718,13 @@ gen_hrl(Mod, Spec) -> Fs) end, ImportedGrpRecs), - format("ENUM Macros", m_enums(Prefix, false, get_value(enum, Spec))), - format("DEFINE Macros", m_enums(Prefix, false, get_value(define, Spec))), + format("ENUM Macros", m_enums(Prefix, false, get_value(enum, ParseD))), + format("DEFINE Macros", m_enums(Prefix, false, get_value(define, ParseD))), lists:map(fun({M,Es}) -> format("ENUM Macros from " ++ atom_to_list(M), m_enums(Prefix, true, Es)) end, - get_value(import_enums, Spec))]. + get_value(import_enums, ParseD))]. forms(_, [] = No) -> No; @@ -817,8 +817,8 @@ arity([_], '*' = Inf) -> {0, Inf}; arity({_}, '*' = Inf) -> {1, Inf}; arity(_, {_,_} = Q) -> Q. -prefix(Spec) -> - case orddict:find(prefix, Spec) of +prefix(ParseD) -> + case orddict:find(prefix, ParseD) of {ok, P} -> P ++ "_"; error -> diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index 16e30c1ffb..f77273d3a5 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -61,7 +61,7 @@ codec(File, Opts) -> make(File, Opts, Dict, - [spec || _ <- [1], lists:member(debug, Opts)] ++ [erl, hrl]); + [dict || lists:member(debug, Opts)] ++ [erl, hrl]); {error, _} = E -> E end. diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 81722c8dca..40d0bf7c63 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -403,7 +403,7 @@ generate(Config) -> [] = ?util:run([{?MODULE, [generate, M, Bin, N, T]} || {E,N} <- Rs, {ok, M} <- [norm(E)], - T <- [erl, hrl, spec]]). + T <- [erl, hrl, dict]]). generate(Mods, Bin, N, Mode) -> B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]), -- cgit v1.2.3 From da973668bcfee7cba0aa6e0c498fee4aa1b24cce Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 09:45:00 +0200 Subject: Make forms a separate output from diameter_codegen Instead of being output as a consequence of a debug option. --- lib/diameter/bin/diameterc | 5 ++--- lib/diameter/src/compiler/diameter_codegen.erl | 10 +++++----- lib/diameter/src/compiler/diameter_make.erl | 3 ++- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc index cae2bcedbe..d4dd3153c5 100755 --- a/lib/diameter/bin/diameterc +++ b/lib/diameter/bin/diameterc @@ -137,9 +137,8 @@ arg(["-E" | Args], #argv{output = Output} = A) -> arg(["-H" | Args], #argv{output = Output} = A) -> arg(Args, A#argv{output = lists:delete(hrl, Output)}); -arg(["-d" | Args], #argv{options = Opts, output = Output} = A) -> - arg(Args, A#argv{options = [debug | Opts], - output = [dict | Output]}); +arg(["-d" | Args], #argv{output = Output} = A) -> + arg(Args, A#argv{output = [dict, forms | Output]}); arg([[$- = M, C, H | T] | Args], A) %% clustered options when C /= $i, C /= $o, C /= $- -> diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index e606e61052..325a37e20d 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -53,12 +53,11 @@ when File :: string(), ParseD :: orddict:orddict(), Opts :: list(), - Mode :: dict | erl | hrl. + Mode :: dict | forms | erl | hrl. from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), putr(verbose, lists:member(verbose, Opts)), - putr(debug, lists:member(debug, Opts)), codegen(File, ParseD, Outdir, Mode). %% Optional reports when running verbosely. @@ -115,10 +114,11 @@ gen(dict, ParseD, _Mod, Path) -> gen(hrl, ParseD, Mod, Path) -> write(Path ++ ".hrl", gen_hrl(Mod, ParseD)); +gen(forms, ParseD, Mod, Path) -> + write_term(Path ++ ".F", [erl_forms(Mod, ParseD)]); + gen(erl, ParseD, Mod, Path) -> - Forms = erl_forms(Mod, ParseD), - getr(debug) andalso write_term(Path ++ ".F", [Forms]), - write(Path ++ ".erl", [header(), prettypr(Forms), $\n]). + write(Path ++ ".erl", [header(), prettypr(erl_forms(Mod, ParseD)), $\n]). write(Path, T) -> write(Path, "~s", T). diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index f77273d3a5..e4486973dd 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -61,7 +61,8 @@ codec(File, Opts) -> make(File, Opts, Dict, - [dict || lists:member(debug, Opts)] ++ [erl, hrl]); + lists:append([[dict, forms] || lists:member(debug, Opts)]) + ++ [erl, hrl]); {error, _} = E -> E end. -- cgit v1.2.3 From 5682e18c8a31e3c32e9abd41120b2c1ae4c6930f Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 09:53:13 +0200 Subject: Don't pollute process dictionary in diameter_codegen:from_dict/4 Didn't matter before diameter_make since the module was only called from diameterc(1). --- lib/diameter/src/compiler/diameter_codegen.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index 325a37e20d..f2c10f1748 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -58,7 +58,11 @@ from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), putr(verbose, lists:member(verbose, Opts)), - codegen(File, ParseD, Outdir, Mode). + try + codegen(File, ParseD, Outdir, Mode) + after + eraser(verbose) + end. %% Optional reports when running verbosely. report(What, Data) -> @@ -76,6 +80,9 @@ putr(Key, Value) -> getr(Key) -> get({?MODULE, Key}). +eraser(Key) -> + erase({?MODULE, Key}). + %% =========================================================================== %% =========================================================================== -- cgit v1.2.3 From 265c88664b93f9069c86bf6c25e5d07b7f41d2dc Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 10:31:21 +0200 Subject: Extend diameter_make:codec/2 Function can now take a literal dictionary as input, instead of a path, and can return results instead of writing them to the filesystem. --- lib/diameter/doc/src/diameter_make.xml | 19 +++- lib/diameter/src/compiler/diameter_codegen.erl | 79 ++++++++++------- lib/diameter/src/compiler/diameter_dict_util.erl | 2 +- lib/diameter/src/compiler/diameter_make.erl | 105 +++++++++++++++++------ 4 files changed, 147 insertions(+), 58 deletions(-) (limited to 'lib') diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml index ec71251be1..2e69fca1ae 100644 --- a/lib/diameter/doc/src/diameter_make.xml +++ b/lib/diameter/doc/src/diameter_make.xml @@ -64,12 +64,15 @@ interface.

-codec(Path::string(), [Opt]) -> ok | {error, Reason} +codec(File :: iolist() | binary(), [Opt]) -> ok | {ok, Ret} | {error, Reason} Compile a dictionary file into Erlang source.

Compile a single dictionary file to Erlang source. +The input File can be either a path or a literal dictionary, +the occurrence of newline (ascii NL) or carriage return (ascii CR) +identifying the latter. Opt can have the following types.

@@ -93,6 +96,13 @@ Write generated source to the specified directory. Defaults to the current working directory.

+return + +

+Return erl and hrl source as two iolists rather than writing them to +the filesystem.

+
+ {name|prefix, string()}

@@ -127,6 +137,13 @@ Multiple inherits options can be specified.

+

+Note that a dictionary's &dict_name;, together with the +outdir option, determine the output paths when the +return option is not specified. +The &dict_name; of a literal input dictionary defaults to +dictionary.

+
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index f2c10f1748..91bab2205c 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -50,6 +50,7 @@ -spec from_dict(File, ParseD, Opts, Mode) -> ok + | list() when File :: string(), ParseD :: orddict:orddict(), Opts :: list(), @@ -57,13 +58,51 @@ from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), + Return = proplists:get_value(return, Opts, false), + Mod = mod(File, orddict:find(name, ParseD)), putr(verbose, lists:member(verbose, Opts)), try - codegen(File, ParseD, Outdir, Mode) + maybe_write(Return, Mode, Outdir, Mod, gen(Mode, ParseD, ?A(Mod))) after eraser(verbose) end. +mod(File, error) -> + filename:rootname(filename:basename(File)); +mod(_, {ok, Mod}) -> + Mod. + +maybe_write(true, _, _, _, T) -> + T; +maybe_write(_, Mode, Outdir, Mod, T) -> + Path = filename:join(Outdir, Mod), %% minus extension + do_write(Mode, [Path, $., ext(Mode)], T). + +ext(dict) -> + "D"; +ext(forms) -> + "F"; +ext(T) -> + ?S(T). + +do_write(M, Path, T) + when M == dict; + M == forms -> + write_term(Path, T); +do_write(_, Path, T) -> + write(Path, T). + +write(Path, T) -> + write(Path, "~s", T). + +write_term(Path, T) -> + write(Path, "~p.~n", T). + +write(Path, Fmt, T) -> + {ok, Fd} = file:open(Path, [write]), + io:fwrite(Fd, Fmt, [T]), + ok = file:close(Fd). + %% Optional reports when running verbosely. report(What, Data) -> report(getr(verbose), What, Data), @@ -104,39 +143,17 @@ file(F, Outdir, Mode) -> get_value(Key, Plist) -> proplists:get_value(Key, Plist, []). -codegen(File, ParseD, Outdir, Mode) -> - Mod = mod(File, orddict:find(name, ParseD)), - Path = filename:join(Outdir, Mod), %% minus extension - gen(Mode, ParseD, ?A(Mod), Path), - ok. - -mod(File, error) -> - filename:rootname(filename:basename(File)); -mod(_, {ok, Mod}) -> - Mod. - -gen(dict, ParseD, _Mod, Path) -> - write_term(Path ++ ".D", [?VERSION | ParseD]); - -gen(hrl, ParseD, Mod, Path) -> - write(Path ++ ".hrl", gen_hrl(Mod, ParseD)); +gen(dict, ParseD, _Mod) -> + [?VERSION | ParseD]; -gen(forms, ParseD, Mod, Path) -> - write_term(Path ++ ".F", [erl_forms(Mod, ParseD)]); +gen(hrl, ParseD, Mod) -> + gen_hrl(Mod, ParseD); -gen(erl, ParseD, Mod, Path) -> - write(Path ++ ".erl", [header(), prettypr(erl_forms(Mod, ParseD)), $\n]). +gen(forms, ParseD, Mod) -> + erl_forms(Mod, ParseD); -write(Path, T) -> - write(Path, "~s", T). - -write_term(Path, T) -> - write(Path, "~p.~n", T). - -write(Path, Fmt, T) -> - {ok, Fd} = file:open(Path, [write]), - io:fwrite(Fd, Fmt, [T]), - file:close(Fd). +gen(erl, ParseD, Mod) -> + [header(), prettypr(erl_forms(Mod, ParseD)), $\n]. erl_forms(Mod, ParseD) -> Forms = [[{?attribute, module, Mod}, diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl index 36a6efa294..eef0cb26d4 100644 --- a/lib/diameter/src/compiler/diameter_dict_util.erl +++ b/lib/diameter/src/compiler/diameter_dict_util.erl @@ -46,7 +46,7 @@ -spec parse(File, Opts) -> {ok, orddict:orddict()} | {error, term()} - when File :: {path, string()} + when File :: {path, file:name_all()} | iolist() | binary(), Opts :: list(). diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index e4486973dd..c883eb91a9 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -39,30 +39,40 @@ -export_type([opt/0]). +%% Options passed to codec/2. -type opt() :: {include|outdir|name|prefix|inherits, string()} + | return | verbose | debug. +%% Literal dictionary or path. A NL of CR identifies the former. +-type dict() :: iolist() + | binary(). + +%% Name of a literal dictionary if otherwise unspecified. +-define(DEFAULT_DICT_NAME, "dictionary.dia"). + %% =========================================================================== %% codec/1-2 %% -%% Parse a dictionary file and generate a codec module. +%% Parse a dictionary file and generate a codec module. Input +%% dictionary can be either a path or the dictionary itself: the +%% occurrence of \n or \r in the argument is used to distinguish the +%% two. --spec codec(Path, [opt()]) +-spec codec(File, [opt()]) -> ok + | {ok, Ret} | {error, Reason} - when Path :: string(), + when File :: dict(), + Ret :: list(), %% [Erl, Hrl | Debug], Debug = [] | [ParseD, Forms] Reason :: string(). codec(File, Opts) -> - case dict(File, Opts) of - {ok, Dict} -> - make(File, - Opts, - Dict, - lists:append([[dict, forms] || lists:member(debug, Opts)]) - ++ [erl, hrl]); + case to_dict(File, Opts) of + {ok, {Dict, Dictish}} -> + make(file(Dictish), Opts, Dict); {error, _} = E -> E end. @@ -70,30 +80,63 @@ codec(File, Opts) -> codec(File) -> codec(File, []). +file({path, Path}) -> + Path; +file(_) -> + ?DEFAULT_DICT_NAME. + %% dict/2 %% %% Parse a dictionary file and return the orddict that a codec module %% returns from dict/0. --spec dict(string(), [opt()]) +-spec dict(File, [opt()]) -> {ok, orddict:orddict()} - | {error, string()}. + | {error, string()} + when File :: dict(). -dict(Path, Opts) -> - case diameter_dict_util:parse({path, Path}, Opts) of - {ok, _} = Ok -> - Ok; - {error = E, Reason} -> - {E, diameter_dict_util:format_error(Reason)} +dict(File, Opts) -> + case to_dict(File, Opts) of + {ok, {Dict, _}} -> + {ok, Dict}; + {error, _} = E -> + E end. dict(File) -> dict(File, []). +%% to_dict/2 + +to_dict(File, Opts) -> + Dictish = maybe_path(File), + case diameter_dict_util:parse(Dictish, Opts) of + {ok, Dict} -> + {ok, {Dict, Dictish}}; + {error = E, Reason} -> + {E, diameter_dict_util:format_error(Reason)} + end. + +maybe_path(File) -> + Bin = iolist_to_binary([File]), + case is_path(Bin) of + true -> {path, File}; + false -> Bin + end. + +%% Interpret anything containing \n or \r as a literal dictionary, +%% otherwise a path. (Which might be the wrong guess in the worst case.) +is_path(Bin) -> + try + [throw(C) || <> <= Bin, $\n == C orelse $\r == C], + true + catch + throw:_ -> false + end. + %% format/1 %% -%% Turn an orddict returned by dict/1-2 back into a dictionary file -%% in the form of an iolist(). +%% Turn an orddict returned by dict/1-2 back into a dictionary. -spec format(orddict:orddict()) -> iolist(). @@ -108,7 +151,7 @@ format(Dict) -> -spec reformat(File) -> {ok, iolist()} | {error, Reason} - when File :: string(), + when File :: dict(), Reason :: string(). reformat(File) -> @@ -121,12 +164,24 @@ reformat(File) -> %% =========================================================================== -make(_, _, _, []) -> +make(File, Opts, Dict) -> + ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end, + [], + lists:append([[dict, forms] || lists:member(debug, Opts)]) + ++ [erl, hrl])). +%% The order in which results are generated (dict/forms/erl/hrl) is +%% intentional, in order of more processing (except for hrl, which +%% isn't needed by diameter itself), since an error raises an +%% exception. The order of return results is the reverse. + +ok([ok,_|_]) -> ok; -make(File, Opts, Dict, [Mode | Rest]) -> +ok([_,_|_] = L) -> + {ok, L}. + +make(File, Opts, Dict, Mode) -> try - ok = diameter_codegen:from_dict(File, Dict, Opts, Mode), - make(File, Opts, Dict, Rest) + diameter_codegen:from_dict(File, Dict, Opts, Mode) catch error: Reason -> erlang:error({Reason, Mode, erlang:get_stacktrace()}) -- cgit v1.2.3 From 5313da9fc31e14b7b676b8c24a539256a551ebb7 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 14:05:29 +0200 Subject: Remove dead code from codec suite --- lib/diameter/test/diameter_codec_test.erl | 6 ------ 1 file changed, 6 deletions(-) (limited to 'lib') diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl index 295d23912b..0b4568a9e5 100644 --- a/lib/diameter/test/diameter_codec_test.erl +++ b/lib/diameter/test/diameter_codec_test.erl @@ -473,9 +473,6 @@ pack(true, Arity, Avp, Value, Acc) -> pack(false, Arity, Avp, Value, Acc) -> min(Arity, Avp, Value, Acc). -all(Mod, Name, Avp, V) -> - all(Mod:avp_arity(Name, Avp), Avp, V). - all(1, Avp, V) -> {Avp, V}; all({0,'*'}, Avp, V) -> @@ -489,9 +486,6 @@ a(N, Avp, V) when N /= 0 -> {Avp, lists:duplicate(N,V)}. -min(Mod, Name, Avp, V, Acc) -> - min(Mod:avp_arity(Name, Avp), Avp, V, Acc). - min(1, Avp, V, Acc) -> [{Avp, V} | Acc]; min({0,_}, _, _, Acc) -> -- cgit v1.2.3 From 742e83daafafd95b31643f9f2a702da725e1ec18 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 14:21:41 +0200 Subject: Adapt compiler suite to diameter_make It was originally written before this interface existed. --- lib/diameter/test/diameter_compiler_SUITE.erl | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 40d0bf7c63..66c671b52d 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -45,7 +45,7 @@ %% RE/Replacement (in the sense of re:replace/4) pairs for morphing %% base_rfc3588.dia. The key is 'ok' or the the expected error as %% returned in the first element of the error tuple returned by -%% diameter_dict_util:parse/2. +%% diameter_make:codec/2. -define(REPLACE, [{ok, "", @@ -361,10 +361,18 @@ format(Config) -> format(Mods, Bin) -> B = modify(Bin, Mods), - {ok, Dict} = diameter_dict_util:parse(B, []), - {ok, D} = diameter_dict_util:parse(diameter_dict_util:format(Dict), []), + {ok, Dict} = make(B, []), + {ok, D} = make(diameter_make:format(Dict), []), {Dict, Dict} = {Dict, D}. +make(File, Opts) -> + case diameter_make:codec(File, [return, debug | Opts]) of + {ok, [_E,_H,_F,[_Vsn|Dict]]} -> + {ok, Dict}; + {error, _} = E -> + E + end. + %% =========================================================================== %% replace/1 %% @@ -379,13 +387,10 @@ replace(Config) -> replace({E, Mods}, Bin) -> B = modify(Bin, Mods), - case {E, diameter_dict_util:parse(B, [{include, here()}]), Mods} of + case {E, make(B, [{include, here()}]), Mods} of {ok, {ok, Dict}, _} -> Dict; - {_, {error, {E,_} = T}, _} -> - S = diameter_dict_util:format_error(T), - true = nochar($", S, E), - true = nochar($', S, E), + {_, {error, S}, _} -> S end. @@ -407,7 +412,7 @@ generate(Config) -> generate(Mods, Bin, N, Mode) -> B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]), - {ok, Dict} = diameter_dict_util:parse(B, []), + {ok, Dict} = make(B, []), File = "dict" ++ integer_to_list(N), {_, ok} = {Dict, diameter_codegen:from_dict("dict", Dict, @@ -428,9 +433,6 @@ norm({E, RE, Repl}) -> norm({_,_} = T) -> T. -nochar(Char, Str, Err) -> - Err == parse orelse not lists:member(Char, Str) orelse Str. - here() -> filename:dirname(code:which(?MODULE)). -- cgit v1.2.3 From ec91114dc4f14d787eeb07d7332b8803298b575c Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 23 Sep 2013 16:49:44 +0200 Subject: Add diameter_make:flatten/1, remove reformat/1 The latter is now unnecessary given that codec/2 can return a parse and format/1 can return the dictionary format. --- lib/diameter/src/compiler/diameter_make.erl | 34 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index c883eb91a9..0d8cdec7f2 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -35,7 +35,7 @@ dict/1, dict/2, format/1, - reformat/1]). + flatten/1]). -export_type([opt/0]). @@ -144,23 +144,27 @@ is_path(Bin) -> format(Dict) -> diameter_dict_util:format(Dict). -%% reformat/1 +%% flatten/1 %% -%% Parse a dictionary file and return its formatted equivalent. +%% Reconstitute a dictionary without @inherits. --spec reformat(File) - -> {ok, iolist()} - | {error, Reason} - when File :: dict(), - Reason :: string(). +-spec flatten(orddict:orddict()) + -> orddict:orddict(). -reformat(File) -> - case dict(File) of - {ok, Dict} -> - {ok, format(Dict)}; - {error, _} = No -> - No - end. +flatten(Dict) -> + lists:foldl(fun flatten/2, Dict, [[avp_types, import_avps], + [grouped, import_groups], + [enum, import_enums]]). + +flatten([_,_] = Keys, Dict) -> + [Values, Imports] = [orddict:fetch(K, Dict) || K <- Keys], + Vs = lists:append([Values | [V || {_,V} <- Imports]]), + lists:foldl(fun store/2, + Dict, + lists:zip([inherits | Keys], [[], Vs, []])). + +store({Key, Value}, Dict) -> + orddict:store(Key, Value, Dict). %% =========================================================================== -- cgit v1.2.3 From 8e819a7960a256b6c3b7bf5856c3f81b8df9ca7e Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 25 Sep 2013 11:28:19 +0200 Subject: Simplify and extend diameter_make interface In particular, make codec/2 flexible as to what's generated, the formats (erl, hrl, parse, forms and beam) being passed in the options list and defaulting to [erl, hrl]. The 'parse' format is the internal format to which dictionaries are parsed, which can be manipulated by flatten/1 before being passed back to codec/2 or format/1. Remove the (undocumented) dict/1,2 since codec/2 now subsumes it with the 'parse' option. --- lib/diameter/bin/diameterc | 25 ++-- lib/diameter/src/compiler/diameter_codegen.erl | 120 +++++++++++++----- lib/diameter/src/compiler/diameter_make.erl | 166 ++++++++++++------------- lib/diameter/test/diameter_compiler_SUITE.erl | 32 +++-- 4 files changed, 200 insertions(+), 143 deletions(-) (limited to 'lib') diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc index d4dd3153c5..d31f341c36 100755 --- a/lib/diameter/bin/diameterc +++ b/lib/diameter/bin/diameterc @@ -54,9 +54,6 @@ usage() -> [?MODULE]). main(Args) -> - %% Add the ebin directory relative to the script path. - BinDir = filename:dirname(escript:script_name()), - code:add_path(filename:join([BinDir, "..", "ebin"])), halt(gen(Args)). gen(Args) -> @@ -72,15 +69,12 @@ gen(Args) -> 1 end. -compile(#argv{file = File, options = Opts} = A) -> - try diameter_dict_util:parse({path, File}, Opts) of - {ok, Dict} -> - maybe_output(A, Dict, Opts, dict), %% parsed dictionary - maybe_output(A, Dict, Opts, erl), %% the erl file - maybe_output(A, Dict, Opts, hrl), %% The hrl file +compile(#argv{file = File, options = Opts, output = Out}) -> + try diameter_make:codec({path, File}, Opts ++ Out) of + ok -> 0; {error, Reason} -> - error_msg(diameter_dict_util:format_error(Reason), []), + error_msg(Reason, []), 1 catch error: Reason -> @@ -88,10 +82,6 @@ compile(#argv{file = File, options = Opts} = A) -> 2 end. -maybe_output(#argv{file = File, output = Output}, Spec, Opts, Mode) -> - lists:member(Mode, Output) - andalso diameter_codegen:from_dict(File, Spec, Opts, Mode). - error_msg({Fmt, Args}) -> error_msg(Fmt, Args). @@ -119,8 +109,9 @@ arg(["-o", Dir | Args], #argv{options = Opts} = A) -> true = dir_exists(Dir), arg(Args, A#argv{options = [{outdir, Dir} | Opts]}); -arg(["-i", Dir | Args], #argv{options = Opts} = A) -> - arg(Args, A#argv{options = Opts ++ [{include, Dir}]}); +arg(["-i", Dir | Args], #argv{} = A) -> + code:add_patha(Dir), %% Set path here instead of passing an include + arg(Args, A); %% option so it's set before calling diameter_make. arg(["--name", Name | Args], #argv{options = Opts} = A) -> arg(Args, A#argv{options = [{name, Name} | Opts]}); @@ -138,7 +129,7 @@ arg(["-H" | Args], #argv{output = Output} = A) -> arg(Args, A#argv{output = lists:delete(hrl, Output)}); arg(["-d" | Args], #argv{output = Output} = A) -> - arg(Args, A#argv{output = [dict, forms | Output]}); + arg(Args, A#argv{output = [parse, forms | Output -- [parse, forms]]}); arg([[$- = M, C, H | T] | Args], A) %% clustered options when C /= $i, C /= $o, C /= $- -> diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index 91bab2205c..47da193457 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -33,11 +33,6 @@ -export([from_dict/4]). -%% Internal exports (for test). --export([file/1, - file/2, - file/3]). - -include("diameter_forms.hrl"). -include("diameter_vsn.hrl"). @@ -50,11 +45,11 @@ -spec from_dict(File, ParseD, Opts, Mode) -> ok - | list() + | term() when File :: string(), ParseD :: orddict:orddict(), Opts :: list(), - Mode :: dict | forms | erl | hrl. + Mode :: parse | forms | erl | hrl | beam. from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), @@ -74,11 +69,12 @@ mod(_, {ok, Mod}) -> maybe_write(true, _, _, _, T) -> T; + maybe_write(_, Mode, Outdir, Mod, T) -> Path = filename:join(Outdir, Mod), %% minus extension do_write(Mode, [Path, $., ext(Mode)], T). -ext(dict) -> +ext(parse) -> "D"; ext(forms) -> "F"; @@ -86,9 +82,11 @@ ext(T) -> ?S(T). do_write(M, Path, T) - when M == dict; + when M == parse; M == forms -> write_term(Path, T); +do_write(beam, Path, {_Mod, Beam}) -> + write(Path, Beam); do_write(_, Path, T) -> write(Path, T). @@ -125,36 +123,35 @@ eraser(Key) -> %% =========================================================================== %% =========================================================================== -%% Generate from parsed dictionary in a file. - -file(F) -> - file(F, dict). - -file(F, Mode) -> - file(F, ".", Mode). - -file(F, Outdir, Mode) -> - {ok, [ParseD]} = file:consult(F), - from_dict(F, ParseD, Outdir, Mode). - -%% =========================================================================== -%% =========================================================================== - get_value(Key, Plist) -> proplists:get_value(Key, Plist, []). -gen(dict, ParseD, _Mod) -> +gen(parse, ParseD, _Mod) -> [?VERSION | ParseD]; -gen(hrl, ParseD, Mod) -> - gen_hrl(Mod, ParseD); - gen(forms, ParseD, Mod) -> erl_forms(Mod, ParseD); +gen(beam, ParseD, Mod) -> + compile(pp(erl_forms(Mod, ParseD))); + +gen(hrl, ParseD, Mod) -> + gen_hrl(Mod, ParseD); + gen(erl, ParseD, Mod) -> [header(), prettypr(erl_forms(Mod, ParseD)), $\n]. +compile({ok, Forms}) -> + case compile:forms(Forms, [debug_info, return]) of + {ok, Mod, Beam, _Warnings} -> + {Mod, Beam}; + {error, Errors, _Warnings} -> + erlang:error({compile, Errors}) + end; + +compile({error, Reason}) -> + erlang:error(Reason). + erl_forms(Mod, ParseD) -> Forms = [[{?attribute, module, Mod}, {?attribute, compile, {parse_transform, diameter_exprecs}}, @@ -851,3 +848,70 @@ prefix(ParseD) -> rec_name(Name, Prefix) -> Prefix ++ Name. + +%% =========================================================================== +%% pp/1 +%% +%% 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 +%% a forms list). + +pp(Forms) -> + {_, Beam, _} = code:get_object_code(diameter_gen_relay), + pp(Forms, abstract_code(Beam)). + +pp(Forms, {ok, Code}) -> + Files = files(Code, []), + {ok, lists:flatmap(fun(T) -> include(T, Files) end, Forms)}; + +pp(_, {error, _} = No) -> + No. + +include({attribute, _, include_lib, Path}, Files) -> + Inc = filename:basename(Path), + [{Inc, Forms}] = [T || {F, _} = T <- Files, F == Inc], %% expect one + lists:flatmap(fun filter/1, Forms); + +include(T, _) -> + [T]. + +abstract_code(Beam) -> + case beam_lib:chunks(Beam, [abstract_code]) of + {ok, {_Mod, [{abstract_code, {_Vsn, Code}}]}} -> + {ok, Code}; + {ok, {_Mod, [{abstract_code, no_abstract_code = No}]}} -> + {error, No}; + {error = E, beam_lib, Reason} -> + {E, Reason} + end. + +files([{attribute, _, file, {Path, _}} | T], Acc) -> + {Body, Rest} = lists:splitwith(fun({attribute, _, file, _}) -> false; + (_) -> true + end, + T), + files(Rest, [{filename:basename(Path), Body} | Acc]); + +files([], Acc) -> + Acc. + +%% Only retain record diameter_avp and functions not generated by +%% diameter_exprecs. + +filter({attribute, _, record, {diameter_avp, _}} = T) -> + [T]; + +filter({function, _, Name, _, _} = T) -> + case ?S(Name) of + [$#|_] -> %% generated by diameter_exprecs + []; + _ -> + [T] + end; + +filter(_) -> + []. diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index 0d8cdec7f2..bf337544a6 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -30,27 +30,35 @@ -module(diameter_make). --export([codec/1, - codec/2, - dict/1, - dict/2, +-export([codec/2, + codec/1, format/1, flatten/1]). -export_type([opt/0]). +-include("diameter_vsn.hrl"). + %% Options passed to codec/2. -type opt() :: {include|outdir|name|prefix|inherits, string()} | return | verbose - | debug. + | parse %% internal parsed form + | forms %% abstract format from which erl is generated + | beam %% compiled directly from preprocessed forms + | erl + | hrl. + +%% Internal parsed format with a version tag. +-type parsed() :: maybe_improper_list(integer(), orddict:orddict()). %% Literal dictionary or path. A NL of CR identifies the former. -type dict() :: iolist() - | binary(). + | binary() + | parsed(). %% as returned by codec/2 %% Name of a literal dictionary if otherwise unspecified. --define(DEFAULT_DICT_NAME, "dictionary.dia"). +-define(DEFAULT_DICT_FILE, "dictionary.dia"). %% =========================================================================== @@ -63,98 +71,45 @@ -spec codec(File, [opt()]) -> ok - | {ok, Ret} + | {ok, list()} %% with option 'return', one element for each output | {error, Reason} - when File :: dict(), - Ret :: list(), %% [Erl, Hrl | Debug], Debug = [] | [ParseD, Forms] + when File :: dict() + | {path, file:name_all()}, Reason :: string(). codec(File, Opts) -> - case to_dict(File, Opts) of - {ok, {Dict, Dictish}} -> - make(file(Dictish), Opts, Dict); - {error, _} = E -> - E - end. - -codec(File) -> - codec(File, []). - -file({path, Path}) -> - Path; -file(_) -> - ?DEFAULT_DICT_NAME. - -%% dict/2 -%% -%% Parse a dictionary file and return the orddict that a codec module -%% returns from dict/0. - --spec dict(File, [opt()]) - -> {ok, orddict:orddict()} - | {error, string()} - when File :: dict(). - -dict(File, Opts) -> - case to_dict(File, Opts) of - {ok, {Dict, _}} -> - {ok, Dict}; - {error, _} = E -> - E - end. - -dict(File) -> - dict(File, []). - -%% to_dict/2 - -to_dict(File, Opts) -> - Dictish = maybe_path(File), - case diameter_dict_util:parse(Dictish, Opts) of - {ok, Dict} -> - {ok, {Dict, Dictish}}; + {Dict, Path} = identify(File), + case parse(Dict, Opts) of + {ok, ParseD} -> + make(Path, default(Opts), ParseD); {error = E, Reason} -> {E, diameter_dict_util:format_error(Reason)} end. -maybe_path(File) -> - Bin = iolist_to_binary([File]), - case is_path(Bin) of - true -> {path, File}; - false -> Bin - end. - -%% Interpret anything containing \n or \r as a literal dictionary, -%% otherwise a path. (Which might be the wrong guess in the worst case.) -is_path(Bin) -> - try - [throw(C) || <> <= Bin, $\n == C orelse $\r == C], - true - catch - throw:_ -> false - end. +codec(File) -> + codec(File, []). %% format/1 %% %% Turn an orddict returned by dict/1-2 back into a dictionary. --spec format(orddict:orddict()) +-spec format(parsed()) -> iolist(). -format(Dict) -> +format([?VERSION | Dict]) -> diameter_dict_util:format(Dict). %% flatten/1 %% %% Reconstitute a dictionary without @inherits. --spec flatten(orddict:orddict()) - -> orddict:orddict(). +-spec flatten(parsed()) + -> parsed(). -flatten(Dict) -> - lists:foldl(fun flatten/2, Dict, [[avp_types, import_avps], - [grouped, import_groups], - [enum, import_enums]]). +flatten([?VERSION = V | Dict]) -> + [V | lists:foldl(fun flatten/2, Dict, [[avp_types, import_avps], + [grouped, import_groups], + [enum, import_enums]])]. flatten([_,_] = Keys, Dict) -> [Values, Imports] = [orddict:fetch(K, Dict) || K <- Keys], @@ -168,20 +123,57 @@ store({Key, Value}, Dict) -> %% =========================================================================== +parse({dict, ParseD}, _) -> + {ok, ParseD}; +parse(File, Opts) -> + diameter_dict_util:parse(File, Opts). + +default(Opts) -> + def(modes(Opts), Opts). + +def([], Opts) -> + [erl, hrl | Opts]; +def(_, Opts) -> + Opts. + +modes(Opts) -> + lists:filter(fun is_mode/1, Opts). + +is_mode(T) -> + lists:member(T, [erl, hrl, parse, forms, beam]). + +identify([Vsn | [T|_] = ParseD]) + when is_tuple(T) -> + ?VERSION == Vsn orelse erlang:error({version, {Vsn, ?VERSION}}), + {{dict, ParseD}, ?DEFAULT_DICT_FILE}; +identify({path, File} = T) -> + {T, File}; +identify(File) -> + Bin = iolist_to_binary([File]), + case is_path(Bin) of + true -> {{path, File}, File}; + false -> {Bin, ?DEFAULT_DICT_FILE} + end. + +%% Interpret anything containing \n or \r as a literal dictionary, +%% otherwise a path. (Which might be the wrong guess in the worst case.) +is_path(Bin) -> + try + [throw(C) || <> <= Bin, $\n == C orelse $\r == C], + true + catch + throw:_ -> false + end. + make(File, Opts, Dict) -> ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end, [], - lists:append([[dict, forms] || lists:member(debug, Opts)]) - ++ [erl, hrl])). -%% The order in which results are generated (dict/forms/erl/hrl) is -%% intentional, in order of more processing (except for hrl, which -%% isn't needed by diameter itself), since an error raises an -%% exception. The order of return results is the reverse. - -ok([ok,_|_]) -> + modes(Opts))). + +ok([ok|_]) -> ok; -ok([_,_|_] = L) -> - {ok, L}. +ok([_|_] = L) -> + {ok, lists:reverse(L)}. make(File, Opts, Dict, Mode) -> try diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 66c671b52d..943cac1446 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -366,8 +366,8 @@ format(Mods, Bin) -> {Dict, Dict} = {Dict, D}. make(File, Opts) -> - case diameter_make:codec(File, [return, debug | Opts]) of - {ok, [_E,_H,_F,[_Vsn|Dict]]} -> + case diameter_make:codec(File, [parse, hrl, return | Opts]) of + {ok, [Dict, _]} -> {ok, Dict}; {error, _} = E -> E @@ -408,20 +408,30 @@ generate(Config) -> [] = ?util:run([{?MODULE, [generate, M, Bin, N, T]} || {E,N} <- Rs, {ok, M} <- [norm(E)], - T <- [erl, hrl, dict]]). + T <- [erl, hrl, parse, forms]]). generate(Mods, Bin, N, Mode) -> B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]), {ok, Dict} = make(B, []), File = "dict" ++ integer_to_list(N), - {_, ok} = {Dict, diameter_codegen:from_dict("dict", - Dict, - [{name, File}, - {prefix, "base"}, - debug], - Mode)}, - Mode == erl - andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])). + {_, ok} = {Dict, diameter_make:codec(Dict, + [{name, File}, + {prefix, "base"}, + Mode])}, + generate(Mode, File, Dict). + +generate(erl, File, _) -> + {ok, _} = compile:file(File ++ ".erl", [return_errors]); + +generate(forms, File, _) -> + {ok, [_]} = file:consult(File ++ ".F"); + +generate(parse, File, Dict) -> + {ok, [Dict]} = file:consult(File ++ ".D"), %% assert + {ok, [_]} = diameter_make:codec(Dict, [beam, return]); + +generate(hrl, _, _) -> + ok. %% =========================================================================== -- cgit v1.2.3 From 350e7e93696c4a2f553a64232b5a52f256b5c0e7 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 2 Oct 2013 14:58:26 +0200 Subject: Modify type that currently causes dialyzer woe The intention was that the type would represent an improper list whose head was an integer and whose tail was an orddict but that doesn't seem to be dialyzer's interpretation anyway. --- lib/diameter/src/compiler/diameter_make.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index bf337544a6..411d71ba3b 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -50,7 +50,7 @@ | hrl. %% Internal parsed format with a version tag. --type parsed() :: maybe_improper_list(integer(), orddict:orddict()). +-type parsed() :: list(). %% Literal dictionary or path. A NL of CR identifies the former. -type dict() :: iolist() -- cgit v1.2.3 From b4b8a2130348d8828a53303d7003e24abfc692f2 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Fri, 4 Oct 2013 10:57:07 +0200 Subject: Fix diameter_make:flatten/1 To set @avp_vendor_id, @codecs and @custom_types as required for imported avps. --- lib/diameter/src/compiler/diameter_dict_util.erl | 5 +- lib/diameter/src/compiler/diameter_make.erl | 96 ++++++++++++++++-- lib/diameter/test/diameter_compiler_SUITE.erl | 119 +++++++++++++++++++++-- 3 files changed, 203 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl index eef0cb26d4..3941f30e03 100644 --- a/lib/diameter/src/compiler/diameter_dict_util.erl +++ b/lib/diameter/src/compiler/diameter_dict_util.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -265,6 +265,9 @@ io(K, Id) io(vendor = K, {Id, Name}) -> [?NL, section(K) | [[?SP, tok(X)] || X <- [Id, Name]]]; +io(_, []) -> + []; + io(avp_types = K, Body) -> [?NL, ?NL, section(K), ?NL, [body(K,A) || A <- Body]]; diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index 411d71ba3b..99034734c5 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -107,19 +107,97 @@ format([?VERSION | Dict]) -> -> parsed(). flatten([?VERSION = V | Dict]) -> - [V | lists:foldl(fun flatten/2, Dict, [[avp_types, import_avps], - [grouped, import_groups], - [enum, import_enums]])]. + [V | lists:foldl(fun flatten/2, + Dict, + [avp_vendor_id, + custom_types, + codecs, + [avp_types, import_avps], + [grouped, import_groups], + [enum, import_enums]])]. + +%% =========================================================================== + +%% flatten/2 flatten([_,_] = Keys, Dict) -> [Values, Imports] = [orddict:fetch(K, Dict) || K <- Keys], - Vs = lists:append([Values | [V || {_,V} <- Imports]]), - lists:foldl(fun store/2, + Vs = lists:append([Values | [V || {_Mod, V} <- Imports]]), + lists:foldl(fun({K,V},D) -> orddict:store(K,V,D) end, Dict, - lists:zip([inherits | Keys], [[], Vs, []])). - -store({Key, Value}, Dict) -> - orddict:store(Key, Value, Dict). + lists:zip([inherits | Keys], [[], Vs, []])); + +%% Inherited avp's setting the 'V' flag get their value either from +%% @avp_vendor_id in the inheriting dictionary or from @vendor in the +%% *inherited* (not inheriting) dictionary: add the latter to +%% @avp_vendor_id as required. +flatten(avp_vendor_id = Key, Dict) -> + Def = orddict:find(vendor, Dict), + ModD = imports(Dict), + Vids = orddict:fetch(Key, Dict), + Avps = lists:append([As || {_,As} <- Vids]), + orddict:store(Key, + dict:fold(fun(M, As, A) -> vid(M, As -- Avps, Def, A) end, + Vids, + ModD), + Dict); + +%% Import @codecs and @custom_types from inherited dictionaries as +%% required. +flatten(Key, Dict) -> + ImportAvps = orddict:fetch(import_avps, Dict), + ImportItems = [{M, As} + || {Mod, Avps} <- ImportAvps, + [_|D] <- [Mod:dict()], + {M,As0} <- orddict:fetch(Key, D), + F <- [fun(A) -> lists:keymember(A, 1, Avps) end], + [_|_] = As <- [lists:filter(F, As0)]], + orddict:store(Key, + lists:foldl(fun merge/2, + orddict:fetch(Key, Dict), + ImportItems), + Dict). + +%% merge/2 + +merge({Mod, _Avps} = T, Acc) -> + merge(lists:keyfind(Mod, 1, Acc), T, Acc). + +merge({Mod, Avps}, {Mod, As}, Acc) -> + lists:keyreplace(Mod, 1, Acc, {Mod, Avps ++ As}); +merge(false, T, Acc) -> + [T | Acc]. + +%% imports/1 +%% +%% Return a module() -> [AVP] dict of inherited AVP's setting the V flag. + +imports(Dict) -> + lists:foldl(fun imports/2, + dict:new(), + orddict:fetch(import_avps, Dict)). + +imports({Mod, Avps}, Dict) -> + dict:store(Mod, + [A || {A,_,_,Fs} <- Avps, lists:member($V, Fs)], + Dict). + +%% vid/4 + +vid(_, [], _, Acc) -> + Acc; +vid(Mod, Avps, Def, Acc) -> + v(Mod:vendor_id(), Avps, Def, Acc). + +v(Vid, _, {ok, {Vid, _}}, Acc) -> %% same id as inheriting dictionary's + Acc; +v(Vid, Avps, _, Acc) -> + case lists:keyfind(Vid, 1, Acc) of + {Vid, As} -> + lists:keyreplace(Vid, 1, Acc, {Vid, As ++ Avps}); + false -> + [{Vid, Avps} | Acc] + end. %% =========================================================================== diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 943cac1446..a37f52a2c5 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -31,10 +31,15 @@ %% testcases -export([format/1, format/2, replace/1, replace/2, - generate/1, generate/4]). + generate/1, generate/4, + flatten1/1, flatten1/3, + flatten2/1]). -export([dict/0]). %% fake dictionary module +%% dictionary callbacks for flatten2/1 +-export(['A1'/3, 'Unsigned32'/3]). + -define(base, "base_rfc3588.dia"). -define(util, diameter_util). -define(S, atom_to_list). @@ -335,7 +340,9 @@ suite() -> all() -> [format, replace, - generate]. + generate, + flatten1, + flatten2]. %% Error handling testcases will make an erroneous dictionary out of %% the base dictionary and check that the expected error results. @@ -361,11 +368,11 @@ format(Config) -> format(Mods, Bin) -> B = modify(Bin, Mods), - {ok, Dict} = make(B, []), - {ok, D} = make(diameter_make:format(Dict), []), + {ok, Dict} = parse(B, []), + {ok, D} = parse(diameter_make:format(Dict), []), {Dict, Dict} = {Dict, D}. -make(File, Opts) -> +parse(File, Opts) -> case diameter_make:codec(File, [parse, hrl, return | Opts]) of {ok, [Dict, _]} -> {ok, Dict}; @@ -387,7 +394,7 @@ replace(Config) -> replace({E, Mods}, Bin) -> B = modify(Bin, Mods), - case {E, make(B, [{include, here()}]), Mods} of + case {E, parse(B, [{include, here()}]), Mods} of {ok, {ok, Dict}, _} -> Dict; {_, {error, S}, _} -> @@ -412,7 +419,7 @@ generate(Config) -> generate(Mods, Bin, N, Mode) -> B = modify(Bin, Mods ++ [{"@name .*", "@name dict" ++ ?L(N)}]), - {ok, Dict} = make(B, []), + {ok, Dict} = parse(B, []), File = "dict" ++ integer_to_list(N), {_, ok} = {Dict, diameter_make:codec(Dict, [{name, File}, @@ -433,6 +440,104 @@ generate(parse, File, Dict) -> generate(hrl, _, _) -> ok. +%% =========================================================================== +%% flatten1/1 + +flatten1(_Config) -> + [Vsn | BaseD] = diameter_gen_base_rfc6733:dict(), + {ok, I} = parse("@inherits diameter_gen_base_rfc6733\n", []), + [Vsn | FlatD] = diameter_make:flatten(I), + [] = ?util:run([{?MODULE, [flatten1, K, BaseD, FlatD]} + || K <- [avp_types, grouped, enum]]). + +flatten1(Key, BaseD, FlatD) -> + Vs = orddict:fetch(Key, BaseD), + Vs = orddict:fetch(Key, FlatD). + +%% =========================================================================== +%% flatten2/1 + +flatten2(_Config) -> + Dict1 = + "@name diameter_test1\n" + "@prefix diameter_test1\n" + "@vendor 666 test\n" + "@avp_vendor_id 111 A1 A3\n" + "@avp_vendor_id 222 A4 A6\n" + "@custom_types " ++ ?S(?MODULE) ++ " A1 A4\n" + "@codecs " ++ ?S(?MODULE) ++ " A3 A6\n" + "@avp_types\n" + "A1 1001 Unsigned32 V\n" + "A2 1002 Unsigned32 V\n" + "A3 1003 Unsigned32 V\n" + "A4 1004 Unsigned32 V\n" + "A5 1005 Unsigned32 V\n" + "A6 1006 Unsigned32 V\n" + "@end ignored\n", + Dict2 = + "@name diameter_test2\n" + "@prefix diameter_test2\n" + "@vendor 777 test\n" + "@inherits diameter_test1 A1 A2 A3\n" + "@inherits diameter_gen_base_rfc6733\n" + "@avp_vendor_id 333 A1\n", + + {ok, [E1, {_,B1}]} + = diameter_make:codec(Dict1, [erl, beam, return]), + ct:pal("~s", [E1]), + {module, diameter_test1} + = code:load_binary(diameter_test1, "diameter_test1", B1), + + + {ok, [D2, E2, {_,B2}]} + = diameter_make:codec(Dict2, [parse, erl, beam, return]), + ct:pal("~s", [E2]), + {module, diameter_test2} + = code:load_binary(diameter_test2, "diameter_test2", B2), + + + Flat = lists:flatten(diameter_make:format(diameter_make:flatten(D2))), + ct:pal("~s", [Flat]), + {ok, [E3, {_,B3}]} + = diameter_make:codec(Flat, [erl, beam, return, + {name, "diameter_test3"}]), + ct:pal("~s", [E3]), + {module, diameter_test3} + = code:load_binary(diameter_test3, "diameter_test3", B3), + + {M1, M2, M3} = {diameter_test1, diameter_test2, diameter_test3}, + + [{1001, 111, M1, 'A1'}, %% @avp_vendor_id + {1002, 666, M1, 'A2'}, %% @vendor + {1003, 111, M1, 'A3'}, %% @avp_vendor_id + {1004, 222, M1, 'A4'}, %% @avp_vendor_id + {1005, 666, M1, 'A5'}, %% @vendor + {1006, 222, M1, 'A6'}, %% @avp_vendor_id + {1001, 333, M2, 'A1'}, %% M2 @avp_vendor_id + {1002, 666, M2, 'A2'}, %% M1 @vendor + {1003, 666, M2, 'A3'}, %% M1 @vendor + {1001, 333, M3, 'A1'}, %% (as for M2) + {1002, 666, M3, 'A2'}, %% " + {1003, 666, M3, 'A3'}] %% " + = [{Code, Vid, Mod, Name} + || Mod <- [M1, M2, M3], + Code <- lists:seq(1001, 1006), + Vid <- [666, 111, 222, 777, 333], + {Name, 'Unsigned32'} <- [Mod:avp_name(Code, Vid)]], + + [] = [{A,T,M,RC} || A <- ['A1', 'A3'], + T <- [encode, decode], + M <- [M2, M3], + Ref <- [make_ref()], + RC <- [M:avp(T, Ref, A)], + RC /= {T, Ref}]. + +'A1'(T, 'Unsigned32', Ref) -> + {T, Ref}. + +'Unsigned32'(T, 'A3', Ref) -> + {T, Ref}. + %% =========================================================================== modify(Bin, Mods) -> -- cgit v1.2.3 From 743773a87e24db2ba0f0222bcf4dcaba7ae7adcf Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 10 Oct 2013 10:47:45 +0200 Subject: Document diameter_make:format/1 and diameter_make:flatten/1 --- lib/diameter/doc/src/diameter_make.xml | 78 ++++++++++++++++++++++++++++------ lib/diameter/doc/src/seealso.ent | 2 + 2 files changed, 68 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml index 2e69fca1ae..c8c0f2fbc7 100644 --- a/lib/diameter/doc/src/diameter_make.xml +++ b/lib/diameter/doc/src/diameter_make.xml @@ -64,19 +64,48 @@ interface.

-codec(File :: iolist() | binary(), [Opt]) -> ok | {ok, Ret} | {error, Reason} +codec(File :: iolist() | binary(), [Opt]) -> ok + | {ok, [Out]} + | {error, Reason} Compile a dictionary file into Erlang source.

-Compile a single dictionary file to Erlang source. +Compile a single dictionary file. The input File can be either a path or a literal dictionary, the occurrence of newline (ascii NL) or carriage return (ascii CR) identifying the latter. -Opt can have the following types.

+Opt determines the format of the results and whether they are +written to file or returned, and can have the following types.

+parse | forms | erl | hrl | beam + +

+Specifies an output format. +Whether the output is returned or written to file depends on whether +or not option return is specified. +When written to file, the resulting file(s) will have extensions +.D, .F, .erl, .hrl and .beam +respectively, basenames defaulting to dictionary if the input +dictionary is literal and does not specify &dict_name;. +When returned, results are returned in the Out list in the +order specified. +Format options default to erl and hrl (in this order) if +unspecified.

+ +

+The parsed format is an internal representation that can be +passed to &format; and &flatten;, while the forms format is +only intended for debugging purposes. +Output for the erl and hrl formats are returned as +iolists, while the beam format returns a {module(), +binary()} tuple.

+ +
+ {include, string()}

@@ -93,14 +122,15 @@ Multiple include options can be specified.

Write generated source to the specified directory. -Defaults to the current working directory.

+Defaults to the current working directory. +Has no effect if option return is specified.

return

-Return erl and hrl source as two iolists rather than writing them to -the filesystem.

+Return results in a {ok, [Out]} tuple instead of writing to +file and returning ok.

{name|prefix, string()} @@ -118,7 +148,7 @@ Transform the input dictionary before compilation, appending &dict_inherits; of the specified string.

-Two forms of @inherits have special meaning:

+Two forms have special meaning:

 {inherits, "-"}
@@ -147,6 +177,34 @@ The &dict_name; of a literal input dictionary defaults to
 
 
 
+
+
+
+format(Parsed) -> iolist()
+Format a parsed dictionary.
+
+

+Turns a parsed dictionary, as returned by &codec;, back into the +dictionary format.

+
+
+ + + + +flatten(Parsed) -> term() +Flatten a parsed dictionary. + + +

+Reconstitute a parsed dictionary, as returned by &codec;, without +using &dict_inherits;. +That is, construct an equivalent dictionary in which all AVP's are +definined in the dictionary itself. +The return value is also a parsed dictionary.

+
+
+ @@ -155,11 +213,7 @@ The &dict_name; of a literal input dictionary defaults to BUGS

-All options are string-valued. -In particular, it is not currently possible to specify -an &dict_inherits; module as an atom(), or a path as an arbitrary -&filename;

- +Unrecognized options are silently ignored.

diff --git a/lib/diameter/doc/src/seealso.ent b/lib/diameter/doc/src/seealso.ent index 76b9823f79..d3305853af 100644 --- a/lib/diameter/doc/src/seealso.ent +++ b/lib/diameter/doc/src/seealso.ent @@ -115,6 +115,8 @@ significant. diameter_make:codec/2'> +diameter_make:format/1'> +diameter_make:flatten/1'> -- cgit v1.2.3 From 2eb76ba556b8775cffc94eac26b448eac70af267 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Sun, 1 Dec 2013 14:19:27 +0100 Subject: Return compilable forms instead of beam That is, preprocessed forms that can be passed to compile:forms/1,2. --- lib/diameter/doc/src/diameter_make.xml | 21 ++++++++-------- lib/diameter/src/compiler/diameter_codegen.erl | 26 ++++---------------- lib/diameter/src/compiler/diameter_make.erl | 5 ++-- lib/diameter/test/diameter_compiler_SUITE.erl | 33 +++++++++++++------------- 4 files changed, 34 insertions(+), 51 deletions(-) (limited to 'lib') diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml index c8c0f2fbc7..68780b1e05 100644 --- a/lib/diameter/doc/src/diameter_make.xml +++ b/lib/diameter/doc/src/diameter_make.xml @@ -1,5 +1,7 @@ compile:forms/2'> file:name()'> -parse | forms | erl | hrl | beam +parse | forms | erl | hrl

Specifies an output format. Whether the output is returned or written to file depends on whether or not option return is specified. When written to file, the resulting file(s) will have extensions -.D, .F, .erl, .hrl and .beam +.D, .F, .erl, and .hrl respectively, basenames defaulting to dictionary if the input dictionary is literal and does not specify &dict_name;. -When returned, results are returned in the Out list in the -order specified. +When returned, results are in the order of the corresponding format +options. Format options default to erl and hrl (in this order) if unspecified.

-The parsed format is an internal representation that can be -passed to &format; and &flatten;, while the forms format is -only intended for debugging purposes. -Output for the erl and hrl formats are returned as -iolists, while the beam format returns a {module(), -binary()} tuple.

+The parse format is an internal representation that can be +passed to &flatten; and &format;, while the forms format can be +passed to &compile_forms2;. +The erl and hrl formats are returned as +iolists.

diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl index 47da193457..22422f2ef2 100644 --- a/lib/diameter/src/compiler/diameter_codegen.erl +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -49,7 +49,7 @@ when File :: string(), ParseD :: orddict:orddict(), Opts :: list(), - Mode :: parse | forms | erl | hrl | beam. + Mode :: parse | forms | erl | hrl. from_dict(File, ParseD, Opts, Mode) -> Outdir = proplists:get_value(outdir, Opts, "."), @@ -85,8 +85,6 @@ do_write(M, Path, T) when M == parse; M == forms -> write_term(Path, T); -do_write(beam, Path, {_Mod, Beam}) -> - write(Path, Beam); do_write(_, Path, T) -> write(Path, T). @@ -130,10 +128,7 @@ gen(parse, ParseD, _Mod) -> [?VERSION | ParseD]; gen(forms, ParseD, Mod) -> - erl_forms(Mod, ParseD); - -gen(beam, ParseD, Mod) -> - compile(pp(erl_forms(Mod, ParseD))); + pp(erl_forms(Mod, ParseD)); gen(hrl, ParseD, Mod) -> gen_hrl(Mod, ParseD); @@ -141,17 +136,6 @@ gen(hrl, ParseD, Mod) -> gen(erl, ParseD, Mod) -> [header(), prettypr(erl_forms(Mod, ParseD)), $\n]. -compile({ok, Forms}) -> - case compile:forms(Forms, [debug_info, return]) of - {ok, Mod, Beam, _Warnings} -> - {Mod, Beam}; - {error, Errors, _Warnings} -> - erlang:error({compile, Errors}) - end; - -compile({error, Reason}) -> - erlang:error(Reason). - erl_forms(Mod, ParseD) -> Forms = [[{?attribute, module, Mod}, {?attribute, compile, {parse_transform, diameter_exprecs}}, @@ -866,10 +850,10 @@ pp(Forms) -> pp(Forms, {ok, Code}) -> Files = files(Code, []), - {ok, lists:flatmap(fun(T) -> include(T, Files) end, Forms)}; + lists:flatmap(fun(T) -> include(T, Files) end, Forms); -pp(_, {error, _} = No) -> - No. +pp(Forms, {error, Reason}) -> + erlang:error({forms, Reason, Forms}). include({attribute, _, include_lib, Path}, Files) -> Inc = filename:basename(Path), diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index 99034734c5..2f314b7e57 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -44,8 +44,7 @@ | return | verbose | parse %% internal parsed form - | forms %% abstract format from which erl is generated - | beam %% compiled directly from preprocessed forms + | forms %% abstract format for compile:forms/1,2 | erl | hrl. @@ -218,7 +217,7 @@ modes(Opts) -> lists:filter(fun is_mode/1, Opts). is_mode(T) -> - lists:member(T, [erl, hrl, parse, forms, beam]). + lists:member(T, [erl, hrl, parse, forms]). identify([Vsn | [T|_] = ParseD]) when is_tuple(T) -> diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index a37f52a2c5..ed369e8af3 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -435,7 +435,8 @@ generate(forms, File, _) -> generate(parse, File, Dict) -> {ok, [Dict]} = file:consult(File ++ ".D"), %% assert - {ok, [_]} = diameter_make:codec(Dict, [beam, return]); + {ok, [F]} = diameter_make:codec(Dict, [forms, return]), + {ok, _, _, _} = compile:forms(F, [return]); generate(hrl, _, _) -> ok. @@ -482,30 +483,23 @@ flatten2(_Config) -> "@inherits diameter_gen_base_rfc6733\n" "@avp_vendor_id 333 A1\n", - {ok, [E1, {_,B1}]} - = diameter_make:codec(Dict1, [erl, beam, return]), + {ok, [E1, F1]} + = diameter_make:codec(Dict1, [erl, forms, return]), ct:pal("~s", [E1]), - {module, diameter_test1} - = code:load_binary(diameter_test1, "diameter_test1", B1), + diameter_test1 = M1 = load_forms(F1), - - {ok, [D2, E2, {_,B2}]} - = diameter_make:codec(Dict2, [parse, erl, beam, return]), + {ok, [D2, E2, F2]} + = diameter_make:codec(Dict2, [parse, erl, forms, return]), ct:pal("~s", [E2]), - {module, diameter_test2} - = code:load_binary(diameter_test2, "diameter_test2", B2), - + diameter_test2 = M2 = load_forms(F2), Flat = lists:flatten(diameter_make:format(diameter_make:flatten(D2))), ct:pal("~s", [Flat]), - {ok, [E3, {_,B3}]} - = diameter_make:codec(Flat, [erl, beam, return, + {ok, [E3, F3]} + = diameter_make:codec(Flat, [erl, forms, return, {name, "diameter_test3"}]), ct:pal("~s", [E3]), - {module, diameter_test3} - = code:load_binary(diameter_test3, "diameter_test3", B3), - - {M1, M2, M3} = {diameter_test1, diameter_test2, diameter_test3}, + diameter_test3 = M3 = load_forms(F3), [{1001, 111, M1, 'A1'}, %% @avp_vendor_id {1002, 666, M1, 'A2'}, %% @vendor @@ -538,6 +532,11 @@ flatten2(_Config) -> 'Unsigned32'(T, 'A3', Ref) -> {T, Ref}. +load_forms(Forms) -> + {ok, Mod, Bin, _} = compile:forms(Forms, [return]), + {module, Mod} = code:load_binary(Mod, ?S(Mod), Bin), + Mod. + %% =========================================================================== modify(Bin, Mods) -> -- cgit v1.2.3