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_make.erl | 105 +++++++++++++++++++++------- 1 file changed, 80 insertions(+), 25 deletions(-) (limited to 'lib/diameter/src/compiler/diameter_make.erl') 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