aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/diameter/doc/src/diameter_make.xml19
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl79
-rw-r--r--lib/diameter/src/compiler/diameter_dict_util.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl105
4 files changed, 147 insertions, 58 deletions
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.</p>
<funcs>
<func>
-<name>codec(Path::string(), [Opt]) -> ok | {error, Reason}</name>
+<name>codec(File :: iolist() | binary(), [Opt]) -> ok | {ok, Ret} | {error, Reason}</name>
<fsummary>Compile a dictionary file into Erlang source.</fsummary>
<desc>
<p>
Compile a single dictionary file to Erlang source.
+The input <c>File</c> can be either a path or a literal dictionary,
+the occurrence of newline (ascii NL) or carriage return (ascii CR)
+identifying the latter.
<c>Opt</c> can have the following types.</p>
<taglist>
@@ -93,6 +96,13 @@ Write generated source to the specified directory.
Defaults to the current working directory.</p>
</item>
+<tag><c>return</c></tag>
+<item>
+<p>
+Return erl and hrl source as two iolists rather than writing them to
+the filesystem.</p>
+</item>
+
<tag><c>{name|prefix, string()}</c></tag>
<item>
<p>
@@ -127,6 +137,13 @@ Multiple <c>inherits</c> options can be specified.</p>
</taglist>
+<p>
+Note that a dictionary's <c>&dict_name;</c>, together with the
+<c>outdir</c> option, determine the output paths when the
+<c>return</c> option is not specified.
+The <c>&dict_name;</c> of a literal input dictionary defaults to
+<c>dictionary</c>.</p>
+
</desc>
</func>
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) || <<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()})