aboutsummaryrefslogtreecommitdiffstats
path: root/lib/syntax_tools/src/igor.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/syntax_tools/src/igor.erl')
-rw-r--r--lib/syntax_tools/src/igor.erl162
1 files changed, 100 insertions, 62 deletions
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 9e7b784170..e92e9593b6 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -117,20 +117,23 @@
-define(record_name(R), {record, R}).
+%% =====================================================================
+
+-type ordset(X) :: [X]. % XXX: TAKE ME OUT
+
+%% =====================================================================
%% Data structure for module information
--record(module, {name, % = atom()
- vars = none, % = [atom()] | none
- functions, % = ordset({atom(), int()})
- exports, % = ordset({atom(), int()})
- % | ordset({{atom(), int()},
- % term()})
- aliases, % = ordset({{atom(), int()},
- % {atom(),
- % {atom(), int()}}})
- attributes, % = ordset({atom(), term()})
- records % = [{atom(), [{atom(), term()}]}]
+-record(module, {name :: atom(),
+ vars = none :: [atom()] | 'none',
+ functions :: ordset({atom(), arity()}),
+ exports :: ordset({atom(), arity()})
+ | ordset({{atom(), arity()}, term()}),
+ aliases :: ordset({{atom(), arity()},
+ {atom(), {atom(), arity()}}}),
+ attributes :: ordset({atom(), term()}),
+ records :: [{atom(), [{atom(), term()}]}]
}).
%% The default pretty-printing function.
@@ -138,6 +141,17 @@
default_printer(Tree, Options) ->
erl_prettypr:format(Tree, Options).
+%% =====================================================================
+
+-type option() :: atom() | {atom(), term()}.
+
+-type attribute() :: {atom(), term()}.
+-type moduleName() :: atom().
+-type functionName() :: {atom(), arity()}.
+-type functionPair() :: {functionName(), {moduleName(), functionName()}}.
+-type stubDescriptor() :: [{moduleName(), [functionPair()], [attribute()]}].
+
+-type notes() :: 'always' | 'yes' | 'no'.
%% =====================================================================
%% @spec parse_transform(Forms::[syntaxTree()], Options::[term()]) ->
@@ -169,6 +183,9 @@ default_printer(Tree, Options) ->
%% @see merge_files/4
%% @see //compiler/compile:file/2
+-spec parse_transform(erl_syntax:forms(), [option()]) ->
+ [erl_syntax:syntaxTree()].
+
parse_transform(Forms, Options) ->
M = get_module_info(Forms),
Name = M#module.name,
@@ -192,6 +209,8 @@ parse_transform(Forms, Options) ->
%% @spec merge(Name::atom(), Files::[filename()]) -> [filename()]
%% @equiv merge(Name, Files, [])
+-spec merge(atom(), [file:filename()]) -> [file:filename()].
+
merge(Name, Files) ->
merge(Name, Files, []).
@@ -251,7 +270,7 @@ merge(Name, Files) ->
%% <dd>Specifies the file name suffix to be used when a backup file
%% is created; the default value is `".bak"'.</dd>
%%
-%% <dt>`{backups, bool()}'</dt>
+%% <dt>`{backups, boolean()}'</dt>
%%
%% <dd>If the value is `true', existing files will be
%% renamed before new files are opened for writing. The new names
@@ -271,7 +290,7 @@ merge(Name, Files) ->
%% resulting source code is to be written. By default, this is the
%% same as the `Name' argument.</dd>
%%
-%% <dt>`{preprocess, bool()}'</dt>
+%% <dt>`{preprocess, boolean()}'</dt>
%%
%% <dd>If the value is `true', preprocessing will be done
%% when reading the source code. See `merge_files/4' for
@@ -294,7 +313,7 @@ merge(Name, Files) ->
%% stub module files are written. The default value is
%% `"stubs"'.</dd>
%%
-%% <dt>`{stubs, bool()}'</dt>
+%% <dt>`{stubs, boolean()}'</dt>
%%
%% <dd>If the value is `true', stub module files will be
%% automatically generated for all exported modules that do not have
@@ -324,6 +343,8 @@ merge(Name, Files) ->
{suffix, ?DEFAULT_SUFFIX},
{verbose, false}]).
+-spec merge(atom(), [file:filename()], [option()]) -> [file:filename()].
+
merge(Name, Files, Opts) ->
Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
{Tree, Stubs} = merge_files(Name, Files, Opts1),
@@ -339,6 +360,9 @@ merge(Name, Files, Opts) ->
%% {syntaxTree(), [stubDescriptor()]}
%% @equiv merge_files(Name, [], Files, Options)
+-spec merge_files(atom(), [file:filename()], [option()]) ->
+ {erl_syntax:syntaxTree(), [stubDescriptor()]}.
+
merge_files(Name, Files, Options) ->
merge_files(Name, [], Files, Options).
@@ -380,7 +404,7 @@ merge_files(Name, Files, Options) ->
%%
%% Options:
%% <dl>
-%% <dt>`{comments, bool()}'</dt>
+%% <dt>`{comments, boolean()}'</dt>
%%
%% <dd>If the value is `true', source code comments in
%% the original files will be preserved in the output. The default
@@ -409,7 +433,7 @@ merge_files(Name, Files, Options) ->
%% Erlang preprocessor, if used (cf. the `preprocess'
%% option). The default value is the empty list.</dd>
%%
-%% <dt>`{preprocess, bool()}'</dt>
+%% <dt>`{preprocess, boolean()}'</dt>
%%
%% <dd>If the value is `false', Igor will read source
%% files without passing them through the Erlang preprocessor
@@ -438,6 +462,9 @@ merge_files(Name, Files, Options) ->
%% @see //stdlib/filename:find_src/2
%% @see epp_dodger
+-spec merge_files(atom(), erl_syntax:forms(), [file:filename()], [option()]) ->
+ {erl_syntax:syntaxTree(), [stubDescriptor()]}.
+
merge_files(_, _Trees, [], _) ->
report_error("no files to merge."),
exit(badarg);
@@ -512,7 +539,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% `Sources' will be exported. The default value is the
%% empty list.</dd>
%%
-%% <dt>`{export_all, bool()}'</dt>
+%% <dt>`{export_all, boolean()}'</dt>
%%
%% <dd>If the value is `true', this is equivalent to
%% listing all of the input modules in the `export'
@@ -532,7 +559,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% they will be handled as in the `comment' case. The
%% default value is `no'.</dd>
%%
-%% <dt>`{no_banner, bool()}'</dt>
+%% <dt>`{no_banner, boolean()}'</dt>
%%
%% <dd>If the value is `true', no banner comment will be
%% added at the top of the resulting module, even if the target
@@ -541,7 +568,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% code is at the top of the output. The default value is
%% `false'.</dd>
%%
-%% <dt>`{no_headers, bool()}'</dt>
+%% <dt>`{no_headers, boolean()}'</dt>
%%
%% <dd>If the value is `true', no header comments will be
%% added to the resulting module at the beginning of each section of
@@ -550,7 +577,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% normally added whenever more than two or more modules are
%% merged.</dd>
%%
-%% <dt>`{no_imports, bool()}'</dt>
+%% <dt>`{no_imports, boolean()}'</dt>
%%
%% <dd>If the value is `true', all
%% `-import(...)' declarations in the original code will
@@ -599,7 +626,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% regarded as "static", regardless of the value of this option. By
%% default, all involved modules are assumed to be static.</dd>
%%
-%% <dt>`{tidy, bool()}'</dt>
+%% <dt>`{tidy, boolean()}'</dt>
%%
%% <dd>If the value is `true', the resulting code will be
%% processed using the `erl_tidy' module, which removes
@@ -607,7 +634,7 @@ merge_files(Name, Trees, Files, Opts) ->
%% `erl_tidy:module/2' for additional options.) The
%% default value is `true'.</dd>
%%
-%% <dt>`{verbose, bool()}'</dt>
+%% <dt>`{verbose, boolean()}'</dt>
%%
%% <dd>If the value is `true', progress messages will be
%% output while the program is running; the default value is
@@ -659,19 +686,22 @@ merge_files(Name, Trees, Files, Opts) ->
%% Data structure for merging environment.
--record(merge, {target, % = atom()
- sources, % = ordset(atom())
- export, % = ordset(atom())
- static, % = ordset(atom())
- safe, % = ordset(atom())
- preserved, % = bool()
- no_headers, % = bool()
- notes, % = bool()
- redirect, % = dict(atom(), atom())
- no_imports, % = ordset(atom())
- options % = [term()]
+-record(merge, {target :: atom(),
+ sources :: ordset(atom()),
+ export :: ordset(atom()),
+ static :: ordset(atom()),
+ safe :: ordset(atom()),
+ preserved :: boolean(),
+ no_headers :: boolean(),
+ notes :: notes(),
+ redirect :: dict(), % = dict(atom(), atom())
+ no_imports :: ordset(atom()),
+ options :: [option()]
}).
+-spec merge_sources(atom(), erl_syntax:forms(), [option()]) ->
+ {erl_syntax:syntaxTree(), [stubDescriptor()]}.
+
merge_sources(Name, Sources, Opts) ->
%% Prepare the options and the inputs.
Opts1 = Opts ++ [{export_all, false},
@@ -696,7 +726,7 @@ merge_sources(Name, Sources, Opts) ->
%% Data structure for keeping state during transformation.
--record(state, {export}).
+-record(state, {export :: set()}).
state__add_export(Name, Arity, S) ->
S#state{export = sets:add_element({Name, Arity},
@@ -981,7 +1011,7 @@ make_stubs(Modules, Renaming, Env) ->
make_stubs_1([M | Ms], Renaming, Env) ->
Name = M#module.name,
- if Name /= Env#merge.target ->
+ if Name =/= Env#merge.target ->
case ordsets:is_element(Name, Env#merge.export) of
true ->
[make_stub(M, Renaming(Name), Env)
@@ -1005,7 +1035,7 @@ make_stub(M, Map, Env) ->
%% Removing and/or out-commenting program forms. The returned form
%% sequence tree is not necessarily flat.
--record(filter, {records, file_attributes, attributes}).
+-record(filter, {records :: set(), file_attributes, attributes}).
filter_forms(Tree, Env) ->
Forms = erl_syntax:form_list_elements(
@@ -1098,8 +1128,7 @@ filter_form(F, S) ->
kill_form(F) ->
F1 = erl_syntax:set_precomments(F, []),
F2 = erl_syntax_lib:to_comment(F1, ?KILL_PREFIX),
- erl_syntax:set_precomments(F2,
- erl_syntax:get_precomments(F)).
+ erl_syntax:set_precomments(F2, erl_syntax:get_precomments(F)).
%% ---------------------------------------------------------------------
@@ -1138,8 +1167,7 @@ merge_namespaces(Modules, Env) ->
[] ->
ok;
Fs ->
- report_warning("interface functions renamed:\n\t~p.",
- [Fs])
+ report_warning("interface functions renamed:\n\t~p.", [Fs])
end,
{M4, Acc2} = merge_namespaces_1(M2, Acc1),
Ms = M3 ++ M4,
@@ -1550,20 +1578,20 @@ alias_expansions_2(Modules, Table) ->
%% Data structure for code transformation environment.
--record(code, {module, % = atom()
- target, % = atom()
- sources, % = ordset(atom())
- static, % = ordset(atom())
- safe, % = ordset(atom())
- preserved, % = bool()
- no_headers, % = bool()
- notes, % = bool()
+-record(code, {module :: atom(),
+ target :: atom(),
+ sources :: set(), % set(atom()),
+ static :: set(), % set(atom()),
+ safe :: set(), % set(atom()),
+ preserved :: boolean(),
+ no_headers :: boolean(),
+ notes :: notes(),
map, % = ({atom(), int()}) -> {atom(), int()}
renaming, % = (atom()) -> ({atom(), int()}) ->
% {atom(), int()}
- expand, % = dict({atom(), int()},
- % {atom(), {atom(), int()}})
- redirect % = dict(atom(), atom())
+ expand :: dict(), % = dict({atom(), int()},
+ % {atom(), {atom(), int()}})
+ redirect :: dict() % = dict(atom(), atom())
}).
%% `Trees' must be a list of syntax trees of type `form_list'. The
@@ -1657,8 +1685,8 @@ take_header_1([F | Fs], As) ->
section_header(Name, Tree, Env) ->
N = sets:size(Env#code.sources),
- if N > 1, Name /= Env#code.target, Env#code.notes /= no,
- Env#code.no_headers /= true ->
+ if N > 1, Name =/= Env#code.target, Env#code.notes =/= no,
+ Env#code.no_headers =/= true ->
Text = io_lib:fwrite("The following code stems "
"from module `~w'.", [Name]),
Header = comment([?COMMENT_BAR, "",
@@ -2292,11 +2320,11 @@ maybe_modified_1({value, Node1}, Node, Depth, Message, Notes) ->
%% Options:
%% <dl>
%% <dt>`{backup_suffix, string()}'</dt>
-%% <dt>`{backups, bool()}'</dt>
+%% <dt>`{backups, boolean()}'</dt>
%% <dt>`{printer, Function}'</dt>
%% <dt>`{stub_dir, filename()}'</dt>
%% <dt>`{suffix, string()}'</dt>
-%% <dt>`{verbose, bool()}'</dt>
+%% <dt>`{verbose, boolean()}'</dt>
%% </dl>
%%
%% See `merge/3' for details on these options.
@@ -2304,6 +2332,8 @@ maybe_modified_1({value, Node1}, Node, Depth, Message, Notes) ->
%% @see merge/3
%% @see merge_sources/3
+-spec create_stubs([stubDescriptor()], [option()]) -> [string()].
+
create_stubs(Stubs, Opts) ->
Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
lists:foldl(fun (S, Fs) ->
@@ -2365,9 +2395,15 @@ stub_header(Name, Exports, Attrs) ->
%% =====================================================================
+
+-type renamings() :: [{atom(), atom()}].
+
+%% =====================================================================
%% @spec rename(Files::[filename()], Renamings) -> [string()]
%% @equiv rename(Files, Renamings, [])
+-spec rename([file:filename()], renamings()) -> [string()].
+
rename(Files, Renamings) ->
rename(Files, Renamings, []).
@@ -2408,35 +2444,35 @@ rename(Files, Renamings) ->
%% Options:
%% <dl>
%% <dt>`{backup_suffix, string()}'</dt>
-%% <dt>`{backups, bool()}'</dt>
+%% <dt>`{backups, boolean()}'</dt>
%% <dt>`{printer, Function}'</dt>
-%% <dt>`{stubs, bool()}'</dt>
+%% <dt>`{stubs, boolean()}'</dt>
%% <dt>`{suffix, string()}'</dt>
%% </dl>
%% See `merge/3' for details on these options.
%%
%% <dl>
-%% <dt>`{comments, bool()}'</dt>
-%% <dt>`{preprocess, bool()}'</dt>
+%% <dt>`{comments, boolean()}'</dt>
+%% <dt>`{preprocess, boolean()}'</dt>
%% </dl>
%% See `merge_files/4' for details on these options.
%%
%% <dl>
-%% <dt>`{no_banner, bool()}'</dt>
+%% <dt>`{no_banner, boolean()}'</dt>
%% </dl>
%% For the `rename' function, this option is
%% `true' by default. See `merge_sources/3' for
%% details.
%%
%% <dl>
-%% <dt>`{tidy, bool()}'</dt>
+%% <dt>`{tidy, boolean()}'</dt>
%% </dl>
%% For the `rename' function, this option is
%% `false' by default. See `merge_sources/3' for
%% details.
%%
%% <dl>
-%% <dt>`{no_headers, bool()}'</dt>
+%% <dt>`{no_headers, boolean()}'</dt>
%% <dt>`{stub_dir, filename()}'</dt>
%% </dl>
%% These options are preset by the `rename' function and
@@ -2448,6 +2484,8 @@ rename(Files, Renamings) ->
%% @see merge_sources/3
%% @see merge_files/4
+-spec rename([file:filename()], renamings(), [term()]) -> [string()].
+
rename(Files, Renamings, Opts) ->
Dict = case is_atom_map(Renamings) of
true ->