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/src/compiler/diameter_codegen.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/diameter/src') 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/diameter/src') 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/src/compiler/diameter_codegen.erl | 250 ++++++++++++------------- lib/diameter/src/compiler/diameter_make.erl | 4 +- 2 files changed, 127 insertions(+), 127 deletions(-) (limited to 'lib/diameter/src') 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. -- 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/src/compiler/diameter_codegen.erl | 10 +++++----- lib/diameter/src/compiler/diameter_make.erl | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'lib/diameter/src') 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/diameter/src') 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/src/compiler/diameter_codegen.erl | 79 ++++++++++------- lib/diameter/src/compiler/diameter_dict_util.erl | 2 +- lib/diameter/src/compiler/diameter_make.erl | 105 +++++++++++++++++------ 3 files changed, 129 insertions(+), 57 deletions(-) (limited to 'lib/diameter/src') 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 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/diameter/src') 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/src/compiler/diameter_codegen.erl | 120 +++++++++++++----- lib/diameter/src/compiler/diameter_make.erl | 166 ++++++++++++------------- 2 files changed, 171 insertions(+), 115 deletions(-) (limited to 'lib/diameter/src') 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 -- 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/diameter/src') 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 +++++++++++++++++++++--- 2 files changed, 91 insertions(+), 10 deletions(-) (limited to 'lib/diameter/src') 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. %% =========================================================================== -- 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/src/compiler/diameter_codegen.erl | 26 +++++--------------------- lib/diameter/src/compiler/diameter_make.erl | 5 ++--- 2 files changed, 7 insertions(+), 24 deletions(-) (limited to 'lib/diameter/src') 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) -> -- cgit v1.2.3