PageRenderTime 71ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/syntax_tools/src/igor.erl

http://github.com/gebi/jungerl
Erlang | 3033 lines | 1739 code | 281 blank | 1013 comment | 56 complexity | ff484948db07f89ac55ea1732e1dd4a7 MD5 | raw file
Possible License(s): AGPL-1.0, JSON, LGPL-2.1, BSD-3-Clause
  1. %% =====================================================================
  2. %% Igor, the Module Merger
  3. %%
  4. %% Copyright (C) 1998-2001 Richard Carlsson
  5. %%
  6. %% This library is free software; you can redistribute it and/or modify
  7. %% it under the terms of the GNU Lesser General Public License as
  8. %% published by the Free Software Foundation; either version 2 of the
  9. %% License, or (at your option) any later version.
  10. %%
  11. %% This library is distributed in the hope that it will be useful, but
  12. %% WITHOUT ANY WARRANTY; without even the implied warranty of
  13. %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. %% Lesser General Public License for more details.
  15. %%
  16. %% You should have received a copy of the GNU Lesser General Public
  17. %% License along with this library; if not, write to the Free Software
  18. %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  19. %% USA
  20. %%
  21. %% Author contact: richardc@csd.uu.se
  22. %%
  23. %% $Id$
  24. %%
  25. %% =====================================================================
  26. %%
  27. %% @doc Igor: the Module Merger and Renamer.
  28. %%
  29. %% <p>The program Igor merges the source code of one or more Erlang
  30. %% modules into a single module, which can then replace the original set
  31. %% of modules. Igor is also able to rename a set of (possibly
  32. %% interdependent) modules, without joining them into a single
  33. %% module.</p>
  34. %%
  35. %% <p>The main user interface consists of the functions <a
  36. %% href="#merge-3"><code>merge</code></a> and <a
  37. %% href="#rename-3"><code>rename</code></a>. See also the <a
  38. %% href="#parse_transform-2"><code>parse_transform</code></a>
  39. %% function</p>
  40. %%
  41. %% <p>A note of warning: Igor cannot do anything about the case when the
  42. %% name of a remote function is passed to the built-in functions
  43. %% <code>apply</code> and <code>spawn</code> <em>unless</em> the module
  44. %% and function names are explicitly stated in the call, as in e.g.
  45. %% <code>apply(lists, reverse, [Xs])</code>. In all other cases, Igor
  46. %% leaves such calls unchanged, and warns the user that manual editing
  47. %% might be necessary.</p>
  48. %%
  49. %% <p>Also note that Erlang records will be renamed as necessary to
  50. %% avoid non-equivalent definitions using the same record name. This
  51. %% does not work if the source code accesses the name field of such
  52. %% record tuples by <code>element/2</code> or similar methods. Always
  53. %% use the record syntax to handle record tuples, if possible.</p>
  54. %%
  55. %% <p>Disclaimer: the author of this program takes no responsibility for
  56. %% the correctness of the produced output, or for any effects of its
  57. %% execution. In particular, the author may not be held responsible
  58. %% should Igor include the code of a deceased madman in the result.</p>
  59. %%
  60. %% <p>For further information on Igors in general, see e.g. "Young
  61. %% Frankenstein", Mel Brooks, 1974, and "The Fifth Elephant", Terry
  62. %% Pratchett, 1999.</p>
  63. %% @end
  64. %%
  65. %% =====================================================================
  66. %%
  67. %% This program is named after the character Igor, assistant to Dr.
  68. %% Frankenstein, in the 1939 film "Son of Frankenstein" (with Boris
  69. %% Karloff playing The Monster for the last time; Igor was played by
  70. %% Bela Lugosi). Igor's job (in the film) was mainly to bring reasonably
  71. %% fresh parts of various human corpses to the good Doctor, for his
  72. %% purpose of reanimating them in the shape of a new formidable, living
  73. %% creature.
  74. %%
  75. %% Merging code is done by joining the sources, possibly changing the
  76. %% order of declarations as necessary, renaming functions and records to
  77. %% avoid name clashes, and changing remote calls to local calls where
  78. %% possible. Stub modules may be automatically generated to redirect any
  79. %% calls that still use the old names. Indirectly, code merging can be
  80. %% used to simply rename a set of modules.
  81. %%
  82. %% What Igor does not do is to optimise the resulting code, which
  83. %% typically can benefit from techniques such as inlining, constant
  84. %% folding, specialisation, etc. This task is left to the Doctor.
  85. %% (Luckily, Igor can call on Inga to do some cleanup; cf. 'erl_tidy'.)
  86. %% FIXME: don't remove module qualifier if name is (auto-)imported!
  87. %% TODO: handle merging of parameterized modules (somehow).
  88. %% TODO: check for redefinition of macros; check equivalence; comment out.
  89. %% TODO: {export, [E]}, E = atom() | {atom(), atom(), integer()}.
  90. %% TODO: improve documentation.
  91. %% TODO: optionally rename all functions from specified (or all) modules.
  92. -module(igor).
  93. -export([create_stubs/2, merge/2, merge/3, merge_files/3, merge_files/4,
  94. merge_sources/3, parse_transform/2, rename/2, rename/3]).
  95. -include_lib("kernel/include/file.hrl").
  96. %% =====================================================================
  97. %% Global Constants
  98. -define(NOTE_HEADER, "Note from Igor: ").
  99. -define(COMMENT_PREFIX, "% ").
  100. -define(COMMENT_BAR,
  101. "======================="
  102. "======================="
  103. "=======================").
  104. -define(NOTE_PREFIX, "%! ").
  105. -define(KILL_PREFIX, "%<<< ").
  106. -define(DEFAULT_INCLUDES, ["."]).
  107. -define(DEFAULT_MACROS, []).
  108. -define(DEFAULT_SUFFIX, ".erl").
  109. -define(DEFAULT_BACKUP_SUFFIX, ".bak").
  110. -define(DEFAULT_DIR, "").
  111. -define(DEFAULT_STUB_DIR, "stubs").
  112. -define(TIDY_OPTS, [quiet]).
  113. %% This may also be used in patterns. R must not be an integer, i.e.,
  114. %% the structure must be distinct from function names.
  115. -define(record_name(R), {record, R}).
  116. %% Data structure for module information
  117. -record(module, {name, % = atom()
  118. vars = none, % = [atom()] | none
  119. functions, % = ordset({atom(), int()})
  120. exports, % = ordset({atom(), int()})
  121. % | ordset({{atom(), int()},
  122. % term()})
  123. aliases, % = ordset({{atom(), int()},
  124. % {atom(),
  125. % {atom(), int()}}})
  126. attributes, % = ordset({atom(), term()})
  127. records % = [{atom(), [{atom(), term()}]}]
  128. }).
  129. %% The default pretty-printing function.
  130. default_printer(Tree, Options) ->
  131. erl_prettypr:format(Tree, Options).
  132. %% =====================================================================
  133. %% @spec parse_transform(Forms::[syntaxTree()], Options::[term()]) ->
  134. %% [syntaxTree()]
  135. %%
  136. %% syntaxTree() = erl_syntax:syntaxTree()
  137. %%
  138. %% @doc Allows Igor to work as a component of the Erlang compiler.
  139. %% Including the term <code>{parse_transform, igor}</code> in the
  140. %% compile options when compiling an Erlang module (cf.
  141. %% <code>compile:file/2</code>), will call upon Igor to process the
  142. %% source code, allowing automatic inclusion of other source files. No
  143. %% files are created or overwritten when this function is used.
  144. %%
  145. %% <p>Igor will look for terms <code>{igor, List}</code> in the compile
  146. %% options, where <code>List</code> is a list of Igor-specific options,
  147. %% as follows:
  148. %% <dl>
  149. %% <dt><code>{files, [filename()]}</code></dt>
  150. %% <dd>The value specifies a list of source files to be merged with
  151. %% the file being compiled; cf. <code>merge_files/4</code>.</dd>
  152. %% </dl>
  153. %%
  154. %% See <code>merge_files/4</code> for further options. Note, however,
  155. %% that some options are preset by this function and cannot be
  156. %% overridden by the user; in particular, all cosmetic features are
  157. %% turned off, for efficiency. Preprocessing is turned on.</p>
  158. %%
  159. %% @see merge_files/4
  160. %% @see compile:file/2
  161. parse_transform(Forms, Options) ->
  162. M = get_module_info(Forms),
  163. Name = M#module.name,
  164. Opts = proplists:append_values(igor, Options),
  165. Files = proplists:append_values(files, Opts),
  166. %% We turn off all features that are only cosmetic, and make sure to
  167. %% turn on preservation of `file' attributes.
  168. Opts1 = [{comments, false},
  169. {notes, no},
  170. {no_imports, true},
  171. {file_attributes, yes},
  172. {preprocess, true},
  173. {export, [Name]}
  174. | Opts],
  175. {T, _} = merge_files(Name, [Forms], Files, Opts1),
  176. verbose("done.", Opts1),
  177. erl_syntax:revert_forms(T).
  178. %% =====================================================================
  179. %% @spec merge(Name::atom(), Files::[filename()]) -> [filename()]
  180. %% @equiv merge(Name, Files, [])
  181. merge(Name, Files) ->
  182. merge(Name, Files, []).
  183. %% =====================================================================
  184. %% @spec merge(Name::atom(), Files::[filename()], Options::[term()]) ->
  185. %% [filename()]
  186. %%
  187. %% filename() = file:filename()
  188. %%
  189. %% @doc Merges source code files to a single file. <code>Name</code>
  190. %% specifies the name of the resulting module - not the name of the
  191. %% output file. <code>Files</code> is a list of file names and/or module
  192. %% names of source modules to be read and merged (see
  193. %% <code>merge_files/4</code> for details). All the input modules must
  194. %% be distinctly named.
  195. %%
  196. %% <p>The resulting source code is written to a file named
  197. %% "<code><em>Name</em>.erl</code>" in the current directory, unless
  198. %% otherwise specified by the options <code>dir</code> and
  199. %% <code>outfile</code> described below.</p>
  200. %%
  201. %% <p>Examples:
  202. %% <ul>
  203. %% <li>given a module <code>m</code> in file "<code>m.erl</code>"
  204. %% which uses the standard library module <code>lists</code>, calling
  205. %% <code>igor:merge(m, [m, lists])</code> will create a new file
  206. %% "<code>m.erl</code> which contains the code from <code>m</code> and
  207. %% exports the same functions, and which includes the referenced code
  208. %% from the <code>lists</code> module. The original file will be
  209. %% renamed to "<code>m.erl.bak</code>".</li>
  210. %%
  211. %% <li>given modules <code>m1</code> and <code>m2</code>, in
  212. %% corresponding files, calling <code>igor:merge(m, [m1, m2])</code>
  213. %% will create a file "<code>m.erl</code>" which contains the code
  214. %% from <code>m1</code> and <code>m2</code> and exports the functions
  215. %% of <code>m1</code>.</li>
  216. %% </ul></p>
  217. %%
  218. %% <p>Stub module files are created for those modules that are to be
  219. %% exported by the target module (see options <code>export</code>,
  220. %% <code>stubs</code> and <code>stub_dir</code>).</p>
  221. %%
  222. %% <p>The function returns the list of file names of all created
  223. %% modules, including any automatically created stub modules. The file
  224. %% name of the target module is always first in the list.</p>
  225. %%
  226. %% <p>Note: If you get a "syntax error" message when trying to merge
  227. %% files (and you know those files to be correct), then try the
  228. %% <code>preprocess</code> option. It typically means that your code
  229. %% contains too strange macros to be handled without actually performing
  230. %% the preprocessor expansions.</p>
  231. %%
  232. %% <p>Options:
  233. %% <dl>
  234. %% <dt><code>{backup_suffix, string()}</code></dt>
  235. %%
  236. %% <dd>Specifies the file name suffix to be used when a backup file
  237. %% is created; the default value is <code>".bak"</code>.</dd>
  238. %%
  239. %% <dt><code>{backups, bool()}</code></dt>
  240. %%
  241. %% <dd>If the value is <code>true</code>, existing files will be
  242. %% renamed before new files are opened for writing. The new names
  243. %% are formed by appending the string given by the
  244. %% <code>backup_suffix</code> option to the original name. The
  245. %% default value is <code>true</code>.</dd>
  246. %%
  247. %% <dt><code>{dir, filename()}</code></dt>
  248. %%
  249. %% <dd>Specifies the name of the directory in which the output file
  250. %% is to be written. An empty string is interpreted as the current
  251. %% directory. By default, the current directory is used.</dd>
  252. %%
  253. %% <dt><code>{outfile, filename()}</code></dt>
  254. %%
  255. %% <dd>Specifies the name of the file (without suffix) to which the
  256. %% resulting source code is to be written. By default, this is the
  257. %% same as the <code>Name</code> argument.</dd>
  258. %%
  259. %% <dt><code>{preprocess, bool()}</code></dt>
  260. %%
  261. %% <dd>If the value is <code>true</code>, preprocessing will be done
  262. %% when reading the source code. See <code>merge_files/4</code> for
  263. %% details.</dd>
  264. %%
  265. %% <dt><code>{printer, Function}</code></dt>
  266. %% <dd><ul>
  267. %% <li><code>Function = (syntaxTree()) -> string()</code></li>
  268. %% </ul>
  269. %% Specifies a function for prettyprinting Erlang syntax trees.
  270. %% This is used for outputting the resulting module definition, as
  271. %% well as for creating stub files. The function is assumed to
  272. %% return formatted text for the given syntax tree, and should raise
  273. %% an exception if an error occurs. The default formatting function
  274. %% calls <code>erl_prettypr:format/2</code>.</dd>
  275. %%
  276. %% <dt><code>{stub_dir, filename()}</code></dt>
  277. %%
  278. %% <dd>Specifies the name of the directory to which any generated
  279. %% stub module files are written. The default value is
  280. %% <code>"stubs"</code>.</dd>
  281. %%
  282. %% <dt><code>{stubs, bool()}</code></dt>
  283. %%
  284. %% <dd>If the value is <code>true</code>, stub module files will be
  285. %% automatically generated for all exported modules that do not have
  286. %% the same name as the target module. The default value is
  287. %% <code>true</code>.</dd>
  288. %%
  289. %% <dt><code>{suffix, string()}</code></dt>
  290. %%
  291. %% <dd>Specifies the suffix to be used for the output file names;
  292. %% the default value is <code>".erl"</code>.</dd>
  293. %% </dl>
  294. %%
  295. %% See <code>merge_files/4</code> for further options.</p>
  296. %%
  297. %% @see merge/2
  298. %% @see merge_files/4
  299. %% The defaults for 'merge' are also used for 'create_stubs'.
  300. -define(DEFAULT_MERGE_OPTS,
  301. [{backup_suffix, ?DEFAULT_BACKUP_SUFFIX},
  302. backups,
  303. {dir, ?DEFAULT_DIR},
  304. {printer, fun default_printer/2},
  305. {stub_dir, ?DEFAULT_STUB_DIR},
  306. stubs,
  307. {suffix, ?DEFAULT_SUFFIX},
  308. {verbose, false}]).
  309. merge(Name, Files, Opts) ->
  310. Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
  311. {Tree, Stubs} = merge_files(Name, Files, Opts1),
  312. Dir = proplists:get_value(dir, Opts1, ""),
  313. Filename = proplists:get_value(outfile, Opts1, Name),
  314. File = write_module(Tree, Filename, Dir, Opts1),
  315. [File | maybe_create_stubs(Stubs, Opts1)].
  316. %% =====================================================================
  317. %% @spec merge_files(Name::atom(), Files::[filename()],
  318. %% Options::[term()]) ->
  319. %% {syntaxTree(), [stubDescriptor()]}
  320. %% @equiv merge_files(Name, [], Files, Options)
  321. merge_files(Name, Files, Options) ->
  322. merge_files(Name, [], Files, Options).
  323. %% =====================================================================
  324. %% @spec merge_files(Name::atom(), Sources::[Forms],
  325. %% Files::[filename()], Options::[term()]) ->
  326. %% {syntaxTree(), [stubDescriptor()]}
  327. %% Forms = syntaxTree() | [syntaxTree()]
  328. %%
  329. %% @doc Merges source code files and syntax trees to a single syntax
  330. %% tree. This is a file-reading front end to
  331. %% <code>merge_sources/3</code>. <code>Name</code> specifies the name of
  332. %% the resulting module - not the name of the output file.
  333. %% <code>Sources</code> is a list of syntax trees and/or lists of
  334. %% "source code form" syntax trees, each entry representing a module
  335. %% definition. <code>Files</code> is a list of file names and/or module
  336. %% names of source modules to be read and included. All the input
  337. %% modules must be distinctly named.
  338. %%
  339. %% <p>If a name in <code>Files</code> is not the name of an existing
  340. %% file, Igor assumes it represents a module name, and tries to locate
  341. %% and read the corresponding source file. The parsed files are appended
  342. %% to <code>Sources</code> and passed on to
  343. %% <code>merge_sources/3</code>, i.e., entries in <code>Sources</code>
  344. %% are listed before entries read from files.</p>
  345. %%
  346. %% <p>If no exports are listed by an <code>export</code> option (see
  347. %% <code>merge_sources/3</code> for details), then if <code>Name</code>
  348. %% is also the name of one of the input modules, that module will be
  349. %% exported; otherwise, the first listed module will be exported. Cf.
  350. %% the examples under <code>merge/3</code>.</p>
  351. %%
  352. %% <p>The result is a pair <code>{Tree, Stubs}</code>, where
  353. %% <code>Tree</code> represents the source code that is the result of
  354. %% merging all the code in <code>Sources</code> and <code>Files</code>,
  355. %% and <code>Stubs</code> is a list of stub module descriptors (see
  356. %% <code>merge_sources/3</code> for details).</p>
  357. %%
  358. %% <p>Options:
  359. %% <dl>
  360. %% <dt><code>{comments, bool()}</code></dt>
  361. %%
  362. %% <dd>If the value is <code>true</code>, source code comments in
  363. %% the original files will be preserved in the output. The default
  364. %% value is <code>true</code>.</dd>
  365. %%
  366. %% <dt><code>{find_src_rules, [{string(), string()}]}</code></dt>
  367. %%
  368. %% <dd>Specifies a list of rules for associating object files with
  369. %% source files, to be passed to the function
  370. %% <code>filename:find_src/2</code>. This can be used to change the
  371. %% way Igor looks for source files. If this option is not specified,
  372. %% the default system rules are used. The first occurrence of this
  373. %% option completely overrides any later in the option list.</dd>
  374. %%
  375. %% <dt><code>{includes, [filename()]}</code></dt>
  376. %%
  377. %% <dd>Specifies a list of directory names for the Erlang
  378. %% preprocessor, if used, to search for include files (cf. the
  379. %% <code>preprocess</code> option). The default value is the empty
  380. %% list. The directory of the source file and the current directory
  381. %% are automatically appended to the list.</dd>
  382. %%
  383. %% <dt><code>{macros, [{atom(), term()}]}</code></dt>
  384. %%
  385. %% <dd>Specifies a list of "pre-defined" macro definitions for the
  386. %% Erlang preprocessor, if used (cf. the <code>preprocess</code>
  387. %% option). The default value is the empty list.</dd>
  388. %%
  389. %% <dt><code>{preprocess, bool()}</code></dt>
  390. %%
  391. %% <dd>If the value is <code>false</code>, Igor will read source
  392. %% files without passing them through the Erlang preprocessor
  393. %% (<code>epp</code>), in order to avoid expansion of preprocessor
  394. %% directives such as <code>-include(...).</code>,
  395. %% <code>-define(...).</code> and <code>-ifdef(...)</code>, and
  396. %% macro calls such as <code>?LINE</code> and <code>?MY_MACRO(x,
  397. %% y)</code>. The default value is <code>false</code>, i.e.,
  398. %% preprocessing is not done. (See the module
  399. %% <code>epp_dodger</code> for details.)
  400. %%
  401. %% <p>Notes: If a file contains too exotic definitions or uses of
  402. %% macros, it will not be possible to read it without preprocessing.
  403. %% Furthermore, Igor does not currently try to sort out multiple
  404. %% inclusions of the same file, or redefinitions of the same macro
  405. %% name. Therefore, when preprocessing is turned off, it may become
  406. %% necessary to edit the resulting source code, removing such
  407. %% re-inclusions and redefinitions.</p></dd>
  408. %% </dl>
  409. %%
  410. %% See <code>merge_sources/3</code> for further options.</p>
  411. %%
  412. %% @see merge/3
  413. %% @see merge_files/3
  414. %% @see merge_sources/3
  415. %% @see filename:find_src/2
  416. %% @see epp_dodger
  417. merge_files(_, _Trees, [], _) ->
  418. report_error("no files to merge."),
  419. exit(badarg);
  420. merge_files(Name, Trees, Files, Opts) ->
  421. Opts1 = Opts ++ [{includes, ?DEFAULT_INCLUDES},
  422. {macros, ?DEFAULT_MACROS},
  423. {preprocess, false},
  424. comments],
  425. Sources = [read_module(F, Opts1) || F <- Files],
  426. merge_sources(Name, Trees ++ Sources, Opts1).
  427. %% =====================================================================
  428. %% @spec merge_sources(Name::atom(), Sources::[Forms],
  429. %% Options::[term()]) ->
  430. %% {syntaxTree(), [stubDescriptor()]}
  431. %%
  432. %% Forms = syntaxTree() | [syntaxTree()]
  433. %%
  434. %% @type stubDescriptor() = [{ModuleName, Functions, [Attribute]}]
  435. %% ModuleName = atom()
  436. %% Functions = [{FunctionName, {ModuleName, FunctionName}}]
  437. %% FunctionName = {atom(), integer()}
  438. %% Attribute = {atom(), term()}.
  439. %%
  440. %% A stub module descriptor contains the module name, a list of
  441. %% exported functions, and a list of module attributes. Each
  442. %% function is described by its name (which includes its arity),
  443. %% and the corresponding module and function that it calls. (The
  444. %% arities should always match.) The attributes are simply
  445. %% described by key-value pairs.
  446. %%
  447. %% @doc Merges syntax trees to a single syntax tree. This is the main
  448. %% code merging "engine". <code>Name</code> specifies the name of the
  449. %% resulting module. <code>Sources</code> is a list of syntax trees of
  450. %% type <code>form_list</code> and/or lists of "source code form" syntax
  451. %% trees, each entry representing a module definition. All the input
  452. %% modules must be distinctly named.
  453. %%
  454. %% <p>Unless otherwise specified by the options, all modules are assumed
  455. %% to be at least "static", and all except the target module are assumed
  456. %% to be "safe". See the <code>static</code> and <code>safe</code>
  457. %% options for details.</p>
  458. %%
  459. %% <p>If <code>Name</code> is also the name of one of the input modules,
  460. %% the code from that module will occur at the top of the resulting
  461. %% code, and no extra "header" comments will be added. In other words,
  462. %% the look of that module will be preserved.</p>
  463. %%
  464. %% <p>The result is a pair <code>{Tree, Stubs}</code>, where
  465. %% <code>Tree</code> represents the source code that is the result of
  466. %% merging all the code in <code>Sources</code>, and <code>Stubs</code>
  467. %% is a list of stub module descriptors (see below).</p>
  468. %%
  469. %% <p><code>Stubs</code> contains one entry for each exported input
  470. %% module (cf. the <code>export</code> option), each entry describing a
  471. %% stub module that redirects calls of functions in the original module
  472. %% to the corresponding (possibly renamed) functions in the new module.
  473. %% The stub descriptors can be used to automatically generate stub
  474. %% modules; see <code>create_stubs/2</code>.</p>
  475. %%
  476. %% <p>Options:
  477. %% <dl>
  478. %% <dt><code>{export, [atom()]}</code></dt>
  479. %%
  480. %% <dd>Specifies a list of names of input modules whose interfaces
  481. %% should be exported by the output module. A stub descriptor is
  482. %% generated for each specified module, unless its name is
  483. %% <code>Name</code>. If no modules are specified, then if
  484. %% <code>Name</code> is also the name of an input module, that
  485. %% module will be exported; otherwise the first listed module in
  486. %% <code>Sources</code> will be exported. The default value is the
  487. %% empty list.</dd>
  488. %%
  489. %% <dt><code>{export_all, bool()}</code></dt>
  490. %%
  491. %% <dd>If the value is <code>true</code>, this is equivalent to
  492. %% listing all of the input modules in the <code>export</code>
  493. %% option. The default value is <code>false</code>.</dd>
  494. %%
  495. %% <dt><code>{file_attributes, Preserve}</code></dt>
  496. %% <dd><ul>
  497. %% <li><code>Preserve = yes | comment | no</code></li>
  498. %% </ul>
  499. %% If the value is <code>yes</code>, all file attributes
  500. %% <code>-file(...)</code> in the input sources will be preserved in
  501. %% the resulting code. If the value is <code>comment</code>, they
  502. %% will be turned into comments, but remain in their original
  503. %% positions in the code relative to the other source code forms. If
  504. %% the value is <code>no</code>, all file attributes will be removed
  505. %% from the code, unless they have attached comments, in which case
  506. %% they will be handled as in the <code>comment</code> case. The
  507. %% default value is <code>no</code>.</dd>
  508. %%
  509. %% <dt><code>{no_banner, bool()}</code></dt>
  510. %%
  511. %% <dd>If the value is <code>true</code>, no banner comment will be
  512. %% added at the top of the resulting module, even if the target
  513. %% module does not have the same name as any of the input modules.
  514. %% Instead, Igor will try to preserve the look of the module whose
  515. %% code is at the top of the output. The default value is
  516. %% <code>false</code>.</dd>
  517. %%
  518. %% <dt><code>{no_headers, bool()}</code></dt>
  519. %%
  520. %% <dd>If the value is <code>true</code>, no header comments will be
  521. %% added to the resulting module at the beginning of each section of
  522. %% code that originates from a particular input module. The default
  523. %% value is <code>false</code>, which means that section headers are
  524. %% normally added whenever more than two or more modules are
  525. %% merged.</dd>
  526. %%
  527. %% <dt><code>{no_imports, bool()}</code></dt>
  528. %%
  529. %% <dd>If the value is <code>true</code>, all
  530. %% <code>-import(...)</code> declarations in the original code will
  531. %% be expanded in the result; otherwise, as much as possible of the
  532. %% original import declarations will be preserved. The default value
  533. %% is <code>false</code>.</dd>
  534. %%
  535. %% <dt><code>{notes, Notes}</code></dt>
  536. %% <dd><ul>
  537. %% <li><code>Notes = always | yes | no</code></li>
  538. %% </ul>
  539. %% If the value is <code>yes</code>, comments will be inserted where
  540. %% important changes have been made in the code. If the value is
  541. %% <code>always</code>, <em>all</em> changes to the code will be
  542. %% commented. If the value is <code>no</code>, changes will be made
  543. %% without comments. The default value is <code>yes</code>.</dd>
  544. %%
  545. %% <dt><code>{redirect, [{atom(), atom()}]}</code></dt>
  546. %%
  547. %% <dd>Specifies a list of pairs of module names, representing a
  548. %% mapping from old names to new. <em>The set of old names may not
  549. %% include any of the names of the input modules.</em> All calls to
  550. %% the listed old modules will be rewritten to refer to the
  551. %% corresponding new modules. <em>The redirected calls will not be
  552. %% further processed, even if the new destination is in one of the
  553. %% input modules.</em> This option mainly exists to support module
  554. %% renaming; cf. <code>rename/3</code>. The default value is the
  555. %% empty list.</dd>
  556. %%
  557. %% <dt><code>{safe, [atom()]}</code></dt>
  558. %%
  559. %% <dd>Specifies a list of names of input modules such that calls to
  560. %% these "safe" modules may be turned into direct local calls, that
  561. %% do not test for code replacement. Typically, this can be done for
  562. %% e.g. standard library modules. If a module is "safe", it is per
  563. %% definition also "static" (cf. below). The list may be empty. By
  564. %% default, all involved modules <em>except the target module</em>
  565. %% are considered "safe".</dd>
  566. %%
  567. %% <dt><code>{static, [atom()]}</code></dt>
  568. %%
  569. %% <dd>Specifies a list of names of input modules which will be
  570. %% assumed never to be replaced (reloaded) unless the target module
  571. %% is also first replaced. The list may be empty. The target module
  572. %% itself (which may also be one of the input modules) is always
  573. %% regarded as "static", regardless of the value of this option. By
  574. %% default, all involved modules are assumed to be static.</dd>
  575. %%
  576. %% <dt><code>{tidy, bool()}</code></dt>
  577. %%
  578. %% <dd>If the value is <code>true</code>, the resulting code will be
  579. %% processed using the <code>erl_tidy</code> module, which removes
  580. %% unused functions and does general code cleanup. (See
  581. %% <code>erl_tidy:module/2</code> for additional options.) The
  582. %% default value is <code>true</code>.</dd>
  583. %%
  584. %% <dt><code>{verbose, bool()}</code></dt>
  585. %%
  586. %% <dd>If the value is <code>true</code>, progress messages will be
  587. %% output while the program is running; the default value is
  588. %% <code>false</code>.</dd>
  589. %% </dl></p>
  590. %%
  591. %% <p>Note: The distinction between "static" and "safe" modules is
  592. %% necessary in order not to break the semantics of dynamic code
  593. %% replacement. A "static" source module will not be replaced unless the
  594. %% target module also is. Now imagine a state machine implemented by
  595. %% placing the code for each state in a separate module, and suppose
  596. %% that we want to merge this into a single target module, marking all
  597. %% source modules as static. At each point in the original code where a
  598. %% call is made from one of the modules to another (i.e., the state
  599. %% transitions), code replacement is expected to be detected. Then, if
  600. %% we in the merged code do not check at these points if the
  601. %% <em>target</em> module (the result of the merge) has been replaced,
  602. %% we can not be sure in general that we will be able to do code
  603. %% replacement of the merged state machine - it could run forever
  604. %% without detecting the code change. Therefore, all such calls must
  605. %% remain remote-calls (detecting code changes), but may call the target
  606. %% module directly.</p>
  607. %%
  608. %% <p>If we are sure that this kind of situation cannot ensue, we may
  609. %% specify the involved modules as "safe", and all calls between them
  610. %% will become local. Note that if the target module itself is specified
  611. %% as safe, "remote" calls to itself will be turned into local calls.
  612. %% This would destroy the code replacement properties of e.g. a typical
  613. %% server loop.</p>
  614. %%
  615. %% @see create_stubs/2
  616. %% @see rename/3
  617. %% @see erl_tidy:module/2
  618. %% Currently, there is no run-time support in Erlang for detecting
  619. %% whether some module has been changed since the current module was
  620. %% loaded. Therefore, if a source module is specified as non-static, not
  621. %% much will be gained from merging: a call to a non-static module will
  622. %% remain a remote call using the old module name, even when it is
  623. %% performed from within the merged code. If that module is specified as
  624. %% exported, the old name could then refer to an auto-generated stub,
  625. %% redirecting the call back to the corresponding function in the target
  626. %% module. This could possibly be useful in some cases, but efficiency
  627. %% is not improved by such a transformation. If support for efficient
  628. %% testing for module updates is added to Erlang in future versions,
  629. %% code merging will be able to use local calls even for non-static
  630. %% source modules, opening the way for compiler optimisations over the
  631. %% module boundaries.
  632. %% Data structure for merging environment.
  633. -record(merge, {target, % = atom()
  634. sources, % = ordset(atom())
  635. export, % = ordset(atom())
  636. static, % = ordset(atom())
  637. safe, % = ordset(atom())
  638. preserved, % = bool()
  639. no_headers, % = bool()
  640. notes, % = bool()
  641. redirect, % = dict(atom(), atom())
  642. no_imports, % = ordset(atom())
  643. options % = [term()]
  644. }).
  645. merge_sources(Name, Sources, Opts) ->
  646. %% Prepare the options and the inputs.
  647. Opts1 = Opts ++ [{export_all, false},
  648. {file_attributes, no},
  649. {no_imports, false},
  650. {notes, yes},
  651. tidy,
  652. {verbose, false}],
  653. Trees = case Sources of
  654. [] ->
  655. report_error("no sources to merge."),
  656. exit(badarg);
  657. _ ->
  658. [if list(M) -> erl_syntax:form_list(M);
  659. true -> M
  660. end
  661. || M <- Sources]
  662. end,
  663. %% There must be at least one module to work with.
  664. Modules = [get_module_info(T) || T <- Trees],
  665. merge_sources_1(Name, Modules, Trees, Opts1).
  666. %% Data structure for keeping state during transformation.
  667. -record(state, {export}).
  668. state__add_export(Name, Arity, S) ->
  669. S#state{export = sets:add_element({Name, Arity},
  670. S#state.export)}.
  671. merge_sources_1(Name, Modules, Trees, Opts) ->
  672. %% Get the (nonempty) list of source module names, in the given
  673. %% order. Multiple occurrences of the same source module name are
  674. %% not accepted.
  675. Ns = [M#module.name || M <- Modules],
  676. case duplicates(Ns) of
  677. [] ->
  678. ok;
  679. Ns1 ->
  680. report_error("same module names repeated in input: ~p.",
  681. [Ns1]),
  682. exit(error)
  683. end,
  684. Sources = ordsets:from_list(Ns),
  685. All = ordsets:add_element(Name, Sources),
  686. %% Initialise the merging environment from the given options.
  687. %%
  688. %% If the `export' option is the empty list, then if the target
  689. %% module is the same as one of the sources, that module will be
  690. %% exported; otherwise the first listed source module is exported.
  691. %% This simplifies use in most cases, and guarantees that the
  692. %% generated module has a well-defined interface. If `export_all' is
  693. %% `true', we expand it here by including the set of source module
  694. %% names.
  695. Es = case proplists:append_values(export, Opts) of
  696. [] ->
  697. case ordsets:is_element(Name, Sources) of
  698. true ->
  699. [Name];
  700. false ->
  701. [hd(Ns)]
  702. end;
  703. Es1 when list(Es1) ->
  704. ordsets:from_list(Es1);
  705. Es1 ->
  706. report_error("bad value for `export' option: ~P.",
  707. [Es1, 5])
  708. end,
  709. Export = case proplists:get_bool(export_all, Opts) of
  710. false ->
  711. Es;
  712. true ->
  713. ordsets:union(Sources, Es)
  714. end,
  715. check_module_names(Export, Sources, "declared as exported"),
  716. verbose("modules exported from `~w': ~p.", [Name, Export], Opts),
  717. %% The target module is always "static". (Particularly useful when
  718. %% the target is the same as one of the source modules). It is
  719. %% however not "safe" by default. If no modules are explicitly
  720. %% specified as static, it is assumed that *all* are static.
  721. Static0 = ordsets:from_list(proplists:append_values(static, Opts)),
  722. case proplists:is_defined(static, Opts) of
  723. false ->
  724. Static = All;
  725. true ->
  726. Static = ordsets:add_element(Name, Static0)
  727. end,
  728. check_module_names(Static, All, "declared 'static'"),
  729. verbose("static modules: ~p.", [Static], Opts),
  730. %% If no modules are explicitly specified as "safe", it is assumed
  731. %% that *all* source modules are "safe" except the target module and
  732. %% those explicitly specified as "static".
  733. Safe = case proplists:is_defined(safe, Opts) of
  734. false ->
  735. ordsets:subtract(Sources,
  736. ordsets:add_element(Name, Static0));
  737. true ->
  738. ordsets:from_list(
  739. proplists:append_values(safe, Opts))
  740. end,
  741. check_module_names(Safe, All, "declared 'safe'"),
  742. verbose("safe modules: ~p.", [Safe], Opts),
  743. Preserved = (ordsets:is_element(Name, Sources)
  744. and ordsets:is_element(Name, Export))
  745. or proplists:get_bool(no_banner, Opts),
  746. NoHeaders = proplists:get_bool(no_headers, Opts),
  747. Notes = proplists:get_value(notes, Opts, always),
  748. Rs = proplists:append_values(redirect, Opts),
  749. Redirect = case is_atom_map(Rs) of
  750. true ->
  751. Ms = ordsets:from_list([M || {M, _} <- Rs]),
  752. case ordsets:intersection(Sources, Ms) of
  753. [] ->
  754. ok;
  755. Ms1 ->
  756. report_error("cannot redirect calls to "
  757. "modules in input set: ~p.",
  758. [Ms1]),
  759. exit(error)
  760. end,
  761. dict:from_list(Rs);
  762. false ->
  763. report_error("bad value for `redirect' option: "
  764. "~P.",
  765. [Rs, 10]),
  766. exit(error)
  767. end,
  768. NoImports = case proplists:get_bool(no_imports, Opts) of
  769. true ->
  770. ordsets:from_list(Sources ++
  771. dict:fetch_keys(Redirect));
  772. false ->
  773. ordsets:from_list(dict:fetch_keys(Redirect))
  774. end,
  775. Env = #merge{target = Name,
  776. sources = Sources,
  777. export = Export,
  778. safe = Safe,
  779. static = Static,
  780. preserved = Preserved,
  781. no_headers = NoHeaders,
  782. notes = Notes,
  783. redirect = Redirect,
  784. no_imports = NoImports,
  785. options = Opts},
  786. merge_sources_2(Env, Modules, Trees, Opts).
  787. is_atom_map([{A1, A2} | As]) when atom(A1), atom(A2) ->
  788. is_atom_map(As);
  789. is_atom_map([]) ->
  790. true;
  791. is_atom_map(_) ->
  792. false.
  793. check_module_names(Names, Sources, Txt) ->
  794. case Names -- Sources of
  795. [] ->
  796. ok;
  797. Xs ->
  798. report_error("unknown modules ~s: ~p.", [Txt, Xs]),
  799. exit(error)
  800. end.
  801. %% This function performs all the stages of the actual merge:
  802. merge_sources_2(Env, Modules, Trees, Opts) ->
  803. %% Compute the merged name space and the list of renamings.
  804. {Names, Renaming} = merge_namespaces(Modules, Env),
  805. %% Merge the source module descriptions, computing a structure
  806. %% describing the resulting module, and a table of aliases which
  807. %% must be expanded.
  808. {Module, Expansions} = merge_info(Modules, Names, Renaming,
  809. Env),
  810. %% Merge the actual source code, also returning the "original
  811. %% header" (for the first code section in the output).
  812. St = #state{export = sets:new()},
  813. {Tree, Header, St1} = merge_code(Trees, Modules, Expansions,
  814. Renaming, Env, St),
  815. %% Filter out unwanted program forms and add a preamble to the code,
  816. %% making a complete module.
  817. Tree1 = erl_syntax:form_list([make_preamble(Module, Header,
  818. Env, St1),
  819. filter_forms(Tree, Env)]),
  820. %% Tidy the final syntax tree (removing unused functions) and return
  821. %% it together with the list of stub descriptors.
  822. {tidy(Tree1, Opts), make_stubs(Modules, Renaming, Env)}.
  823. make_preamble(Module, Header, Env, St) ->
  824. Name = Module#module.name,
  825. Vars = Module#module.vars,
  826. Extras = ordsets:from_list(sets:to_list(St#state.export)),
  827. Exports = make_exports(Module#module.exports, Extras),
  828. Imports = make_imports(Module#module.aliases),
  829. Attributes = make_attributes(Module#module.attributes),
  830. erl_syntax:form_list(module_header(Header, Name, Vars, Env)
  831. ++ Exports
  832. ++ Imports
  833. ++ Attributes).
  834. %% If the target preserves one of the source modules, we do not generate
  835. %% a new header, but use the original.
  836. module_header(Forms, Name, Vars, Env) ->
  837. case Env#merge.preserved of
  838. true ->
  839. update_header(Forms, Name, Vars);
  840. false ->
  841. [comment([?COMMENT_BAR,
  842. "This module was formed by merging "
  843. "the following modules:",
  844. ""]
  845. ++ [lists:flatten(io_lib:fwrite("\t\t`~w'",
  846. [M]))
  847. || M <- Env#merge.sources]
  848. ++ ["",
  849. timestamp(),
  850. ""]),
  851. erl_syntax:attribute(erl_syntax:atom('module'),
  852. [erl_syntax:atom(Name)])]
  853. end.
  854. update_header(Fs, Name, Vars) ->
  855. [M | Fs1] = lists:reverse(Fs),
  856. Ps = if Vars == none -> [];
  857. true -> [erl_syntax:list([erl_syntax:variable(V)
  858. || V <- Vars])]
  859. end,
  860. M1 = rewrite(M, erl_syntax:attribute(erl_syntax:atom('module'),
  861. [erl_syntax:atom(Name) | Ps])),
  862. lists:reverse([M1 | Fs1]).
  863. %% Some functions may have been noted as necessary to export (because of
  864. %% how they are called) even though the user did not specify that the
  865. %% modules in which these functions originated should be part of the
  866. %% interface of the resulting module.
  867. make_exports(Exports, Extras) ->
  868. case ordsets:subtract(Extras, Exports) of
  869. [] ->
  870. [make_export(Exports)];
  871. Es ->
  872. [make_export(Exports),
  873. comment(["** The following exports "
  874. "are not official: **"]),
  875. make_export(Es)]
  876. end.
  877. make_export(Names) ->
  878. Es = [erl_syntax:arity_qualifier(erl_syntax:atom(F),
  879. erl_syntax:integer(A))
  880. || {F, A} <- Names],
  881. if Es == [] ->
  882. comment(["** Nothing is officially exported "
  883. "from this module! **"]);
  884. true ->
  885. erl_syntax:attribute(erl_syntax:atom('export'),
  886. [erl_syntax:list(Es)])
  887. end.
  888. %% Any aliases that cannot be expressed using `import' (i.e. those not
  889. %% on the form `{F, {M, F}}') are ignored.
  890. make_imports(As) ->
  891. %% First remove any auto-imports and "non-proper" imports from
  892. %% the list.
  893. As1 = [A || {F, {_M, F}} = A <- As, not is_auto_import(F)],
  894. [make_import(M, Fs) || {M, Fs} <- group_imports(As1)].
  895. make_import(Module, Names) ->
  896. Is = [erl_syntax:arity_qualifier(erl_syntax:atom(F),
  897. erl_syntax:integer(A))
  898. || {F, A} <- Names],
  899. erl_syntax:attribute(erl_syntax:atom('import'),
  900. [erl_syntax:atom(Module),
  901. erl_syntax:list(Is)]).
  902. %% Group aliases by module.
  903. group_imports(Imports) ->
  904. dict:to_list(
  905. lists:foldl(
  906. fun ({F, {M, F}}, D) ->
  907. case dict:find(M, D) of
  908. {ok, V} ->
  909. V1 = ordsets:add_element(F, V),
  910. dict:store(M, V1, D);
  911. error ->
  912. dict:store(M, [F], D)
  913. end
  914. end,
  915. dict:new(), Imports)).
  916. %% ---------------------------------------------------------------------
  917. %% Making stub descriptors
  918. %%
  919. %% These are generated for all exported modules that are not the target
  920. %% module.
  921. make_stubs(Modules, Renaming, Env) ->
  922. make_stubs_1(Modules, Renaming, Env).
  923. make_stubs_1([M | Ms], Renaming, Env) ->
  924. Name = M#module.name,
  925. if Name /= Env#merge.target ->
  926. case ordsets:is_element(Name, Env#merge.export) of
  927. true ->
  928. [make_stub(M, Renaming(Name), Env)
  929. | make_stubs_1(Ms, Renaming, Env)];
  930. false ->
  931. make_stubs_1(Ms, Renaming, Env)
  932. end;
  933. true ->
  934. make_stubs_1(Ms, Renaming, Env)
  935. end;
  936. make_stubs_1([], _, _) ->
  937. [].
  938. make_stub(M, Map, Env) ->
  939. Target = Env#merge.target,
  940. Es = [{F, {Target, Map(F)}} || F <- M#module.exports],
  941. {M#module.name, Es, M#module.attributes}.
  942. %% ---------------------------------------------------------------------
  943. %% Removing and/or out-commenting program forms. The returned form
  944. %% sequence tree is not necessarily flat.
  945. -record(filter, {records, file_attributes, attributes}).
  946. filter_forms(Tree, Env) ->
  947. Forms = erl_syntax:form_list_elements(
  948. erl_syntax:flatten_form_list(Tree)),
  949. erl_syntax:form_list(filter_forms_1(Forms, Env)).
  950. filter_forms_1(Forms, Env) ->
  951. {Fs, _} = filter_forms_2(Forms, Env),
  952. lists:reverse(Fs).
  953. filter_forms_2(Forms, Env) ->
  954. FileAttrsOpt = proplists:get_value(file_attributes,
  955. Env#merge.options, comment),
  956. %% Sanity check and translation of option value:
  957. FileAttrs = case FileAttrsOpt of
  958. yes -> keep;
  959. no -> delete;
  960. comment -> kill;
  961. _ ->
  962. report_error("invalid value for option "
  963. "`file_attributes': ~w.",
  964. [FileAttrsOpt]),
  965. exit(error)
  966. end,
  967. Attrs = if length(Env#merge.sources) == 1 ->
  968. delete; %% keeping the originals looks weird
  969. true ->
  970. kill
  971. end,
  972. S = #filter{records = sets:new(),
  973. file_attributes = FileAttrs,
  974. attributes = Attrs},
  975. lists:foldl(
  976. fun (F, {Fs, S0}) ->
  977. case filter_form(F, S0) of
  978. {keep, S1} ->
  979. {[F | Fs], S1}; % keep
  980. {kill, S1} ->
  981. {[kill_form(F) | Fs], S1}; % kill
  982. {delete, S1} ->
  983. %% Remove, or kill if it has comments (only
  984. %% top-level comments are examined).
  985. case erl_syntax:has_comments(F) of
  986. false ->
  987. {Fs, S1};
  988. true ->
  989. {[kill_form(F) | Fs], S1}
  990. end
  991. end
  992. end,
  993. {[], S}, Forms).
  994. filter_form(F, S) ->
  995. case erl_syntax_lib:analyze_form(F) of
  996. {attribute, {'file', _}} ->
  997. {S#filter.file_attributes, S};
  998. {attribute, {'module', _}} ->
  999. {delete, S};
  1000. {attribute, {'export', _}} ->
  1001. {delete, S};
  1002. {attribute, {'import', _}} ->
  1003. {delete, S};
  1004. {attribute, {'record', {R, _}}} ->
  1005. Records = S#filter.records,
  1006. case sets:is_element(R, Records) of
  1007. true ->
  1008. {kill, S}; % already defined above
  1009. false ->
  1010. S1 = S#filter{records =
  1011. sets:add_element(R, Records)},
  1012. {keep, S1}
  1013. end;
  1014. {attribute, preprocessor} ->
  1015. {keep, S}; %% keep all preprocessor attributes
  1016. {attribute, _} ->
  1017. {S#filter.attributes, S}; %% handle all other attributes
  1018. {error_marker, _} ->
  1019. {delete, S};
  1020. {warning_marker, _} ->
  1021. {delete, S};
  1022. eof_marker ->
  1023. {delete, S}; % these must be deleted!
  1024. _ ->
  1025. {keep, S} % keep all other Erlang forms
  1026. end.
  1027. %% This out-comments (kills) a program form. Any top-level pre-comments
  1028. %% are moved out, to avoid "nested" comments.
  1029. kill_form(F) ->
  1030. F1 = erl_syntax:set_precomments(F, []),
  1031. F2 = erl_syntax_lib:to_comment(F1, ?KILL_PREFIX),
  1032. erl_syntax:set_precomments(F2,
  1033. erl_syntax:get_precomments(F)).
  1034. %% ---------------------------------------------------------------------
  1035. %% Merging the name spaces of a set of modules. Returns the final set
  1036. %% (see module `sets') of names and a total renaming function (atom())
  1037. %% -> ({atom(), integer()}) -> {atom(), integer()}.
  1038. %%
  1039. %% Names are added in two passes, in order to avoid renaming the
  1040. %% interface functions whenever possible: all exported functions are
  1041. %% added to the name space before any nonexported are added, and
  1042. %% "exported" modules are taken before any other. Thus, the order is:
  1043. %%
  1044. %% - exported functions of exported modules
  1045. %% - exported functions of nonexported modules
  1046. %% - internal functions of exported modules
  1047. %% - internal functions of nonexported modules
  1048. %%
  1049. %% In fact, only the first group is important, but there might be some
  1050. %% point in establishing the above order, for better readability of the
  1051. %% final code.
  1052. merge_namespaces(Modules, Env) ->
  1053. Export = Env#merge.export,
  1054. Split = fun (M) ->
  1055. ordsets:is_element(M#module.name, Export)
  1056. end,
  1057. {M1, M2} = split_list(Split, Modules),
  1058. R = dict:new(),
  1059. Acc = {sets:new(), R},
  1060. {M3, Acc1} = merge_namespaces_1(M1, Acc),
  1061. %% Detect and warn about renamed interface functions
  1062. {_, Maps0} = Acc1,
  1063. case [{M, dict:to_list(Map)}
  1064. || {M, Map} <- dict:to_list(Maps0), dict:size(Map) /= 0] of
  1065. [] ->
  1066. ok;
  1067. Fs ->
  1068. report_warning("interface functions renamed:\n\t~p.",
  1069. [Fs])
  1070. end,
  1071. {M4, Acc2} = merge_namespaces_1(M2, Acc1),
  1072. Ms = M3 ++ M4,
  1073. Acc3 = merge_namespaces_2(Ms, Acc2),
  1074. {{Names, Maps}, _} = merge_namespaces_3(Ms, Acc3),
  1075. {Names, make_renaming_function(Maps)}.
  1076. %% Adding exported names. (Note that the list gets a new temporary
  1077. %% format also containing the exports.) This first step initialises the
  1078. %% Maps "dict-of-dicts" structure.
  1079. merge_namespaces_1(Modules, Acc) ->
  1080. lists:mapfoldl(
  1081. fun (Module, {Names, Maps}) ->
  1082. Exports = sets:from_list(Module#module.exports),
  1083. M = Module#module.name,
  1084. {Names1, Map} = add_function_renamings(M, Exports, Names,
  1085. dict:new()),
  1086. Maps1 = dict:store(M, Map, Maps),
  1087. {{Module, Exports}, {Names1, Maps1}}
  1088. end,
  1089. Acc, Modules).
  1090. %% Adding nonexported names.
  1091. merge_namespaces_2(Modules, Acc) ->
  1092. lists:foldl(
  1093. fun ({Module, Exports}, {Names, Maps}) ->
  1094. Other = sets:subtract(
  1095. sets:from_list(Module#module.functions),
  1096. Exports),
  1097. M = Module#module.name,
  1098. Map = dict:fetch(M, Maps),
  1099. {Names1, Map1} = add_function_renamings(M, Other, Names,
  1100. Map),
  1101. Maps1 = dict:store(M, Map1, Maps),
  1102. {Names1, Maps1}
  1103. end,
  1104. Acc, Modules).
  1105. %% Adding record names. We need to keep a global
  1106. %% "record-definition-to-new-record-name" mapping RMap while doing this.
  1107. merge_namespaces_3(Modules, Acc) ->
  1108. lists:foldl(
  1109. fun ({Module, _Exports}, {{Names, Maps}, RMap}) ->
  1110. Records = Module#module.records,
  1111. M = Module#module.name,
  1112. Map = dict:fetch(M, Maps),
  1113. {Names1, Map1, RMap1} = add_record_renamings(M, Records,
  1114. Names, Map,
  1115. RMap),
  1116. Maps1 = dict:store(M, Map1, Maps),
  1117. {{Names1, Maps1}, RMap1}
  1118. end,
  1119. {Acc, dict:new()}, Modules).
  1120. %% This takes the set of added function names together with the existing
  1121. %% name set, creates new function names where necessary, and returns the
  1122. %% final name set together with the list of renamings.
  1123. add_function_renamings(Module, New, Names, Map) ->
  1124. Clashes = sets:to_list(sets:intersection(New, Names)),
  1125. lists:foldl(
  1126. fun (F = {_, A}, {Names, Map}) when integer(A) ->
  1127. F1 = new_function_name(Module, F, Names),
  1128. {sets:add_element(F1, Names), dict:store(F, F1, Map)}
  1129. end,
  1130. {sets:union(New, Names), Map}, Clashes).
  1131. %% This is similar to the above, but for record names. Note that we add
  1132. %% both the record name and the whole definition to the namespace.
  1133. add_record_renamings(Module, Records, Names, Map, RMap) ->
  1134. lists:foldl(
  1135. fun (N = {R, Fs}, {Names, Map, RMap}) ->
  1136. case sets:is_element(?record_name(R), Names) of
  1137. true ->
  1138. %% The name is already in use.
  1139. case sets:is_element(?record_name(N), Names) of
  1140. true ->
  1141. %% We have seen this definition before;
  1142. %% make sure we use the same name.
  1143. {R1, _} = remap_record_name(N, RMap),
  1144. Map1 = dict:store(?record_name(R),
  1145. ?record_name(R1), Map),
  1146. {Names, Map1, RMap};
  1147. false ->
  1148. %% Redefinition of existing name. Create
  1149. %% new name and set up renamings.
  1150. N1 = {R1, _} = new_record_name(Module, R,
  1151. Fs, Names),
  1152. Map1 = dict:store(?record_name(R),
  1153. ?record_name(R1), Map),
  1154. RMap1 = dict:store(N, N1, RMap),
  1155. Names1 = sets:add_element(?record_name(N1),
  1156. Names),
  1157. {Names1, Map1, RMap1}
  1158. end;
  1159. false ->
  1160. %% A previously unused record name.
  1161. Names1 = sets:add_element(?record_name(R), Names),
  1162. Names2 = sets:add_element(?record_name(N), Names1),
  1163. {Names2, Map, RMap}
  1164. end
  1165. end,
  1166. {Names, Map, RMap}, Records).
  1167. remap_record_name(N, Map) ->
  1168. case dict:find(N, Map) of
  1169. {ok, N1} -> N1;
  1170. error -> N
  1171. end.
  1172. %% This hides the implementation of the record namespace. Since Map
  1173. %% yields identity for non-remapped names, the remapped names must be
  1174. %% stored in wrapped form.
  1175. map_record_name(R, Map) ->
  1176. ?record_name(R1) = Map(?record_name(R)),
  1177. R1.
  1178. %% When we rename a function, we want the new name to be as close as
  1179. %% possible to the old, and as informative as possible. Therefore, we
  1180. %% first prefix it with the name of the originating module, followed by
  1181. %% two underscore characters, and then if there still is a name clash,
  1182. %% we suffix the name by "_N", where N is the smallest possible positive
  1183. %% integer that does not cause a clash.
  1184. new_function_name(M, {F, A}, Names) ->
  1185. Base = atom_to_list(M) ++ "__" ++ atom_to_list(F),
  1186. Name = {list_to_atom(Base), A},
  1187. case sets:is_element(Name, Names) of
  1188. false ->
  1189. Name;
  1190. true ->
  1191. new_function_name(1, A, Base, Names)
  1192. end.
  1193. new_function_name(N, Arity, Base, Names) ->
  1194. Name = {list_to_atom(Base ++ "_" ++ integer_to_list(N)),
  1195. Arity},
  1196. case sets:is_element(Name, Names) of
  1197. false ->
  1198. Name;
  1199. true ->
  1200. %% Increment counter and try again.
  1201. new_function_name(N + 1, Arity, Base, Names)
  1202. end.
  1203. %% This is pretty much the same as new_function_name, for now.
  1204. new_record_name(M, R, Fs, Names) ->
  1205. Base = atom_to_list(M) ++ "__" ++ atom_to_list(R),
  1206. Name = {list_to_atom(Base), Fs},
  1207. case sets:is_element(?record_name(Name), Names) of
  1208. false ->
  1209. Name;
  1210. true ->
  1211. new_record_name_1(1, Base, Fs, Names)
  1212. end.
  1213. new_record_name_1(N, Base, Fs, Names) ->
  1214. Name = {list_to_atom(Base ++ "_" ++ integer_to_list(N)), Fs},
  1215. case sets:is_element(?record_name(Name), Names) of
  1216. false ->
  1217. Name;
  1218. true ->
  1219. %% Increment counter and try again.
  1220. new_record_name_1(N + 1, Base, Fs, Names)
  1221. end.
  1222. %% This returns a *total* function from the set of module names to the
  1223. %% set of *total* operators on function names, yielding identity for all
  1224. %% function names that are not specified in the given partial map
  1225. %% (ModuleName -> (Name -> Name)).
  1226. make_renaming_function(Maps) ->
  1227. fun (Module) ->
  1228. case dict:find(Module, Maps) of
  1229. {ok, Map} ->
  1230. fun (Name) ->
  1231. case dict:find(Name, Map) of
  1232. {ok, Name1} ->
  1233. Name1; % renamed
  1234. error ->
  1235. Name % identity
  1236. end
  1237. end;
  1238. error ->
  1239. %% Other module - yield identity map.
  1240. fun (Name) -> Name end
  1241. end
  1242. end.
  1243. %% ---------------------------------------------------------------------
  1244. %% Merging module info records into a target module record, and finding
  1245. %% necessary alias expansions. Returns `{Module, Expansions}' where
  1246. %% `Expansions' has type `dict(ModuleName, dict(Alias, FullName))'
  1247. merge_info(Modules, Names, Renaming, Env) ->
  1248. Forbid = sets:from_list(Env#merge.no_imports),
  1249. Expansions = alias_expansions(Modules, Names, Forbid),
  1250. Module = merge_info_1(Modules, Renaming, Expansions, Env),
  1251. {Module, Expansions}.
  1252. merge_info_1(Modules, Renaming, Expansions, Env) ->
  1253. lists:foldl(
  1254. fun (M, A) ->
  1255. Name = M#module.name,
  1256. Map = Renaming(Name),
  1257. Functions = join_functions(Map,
  1258. M#module.functions,
  1259. A#module.functions),
  1260. Exports = join_exports(Env, Name, Map,
  1261. M#module.exports,
  1262. A#module.exports),
  1263. Aliases = join_aliases(Name, Expansions,
  1264. M#module.aliases,
  1265. A#module.aliases),
  1266. Attributes = join_attributes(Env, Name,
  1267. M#module.attributes,
  1268. A#module.attributes),
  1269. Records = join_records(Map,
  1270. M#module.records,
  1271. A#module.records),
  1272. A#module{functions = Functions,
  1273. exports = Exports,
  1274. aliases = Aliases,
  1275. attributes = Attributes,
  1276. records = Records}
  1277. end,
  1278. #module{name = Env#merge.target,
  1279. functions = ordsets:new(),
  1280. exports = ordsets:new(),
  1281. aliases = ordsets:new(),
  1282. attributes = ordsets:new(),
  1283. records = ordsets:new()},
  1284. Modules).
  1285. %% Functions must be renamed before including.
  1286. join_functions(Map, Source, Target) ->
  1287. ordsets:union(ordsets:from_list([Map(A) || A <- Source]),
  1288. Target).
  1289. %% Exports also need renaming, and are kept only if their originating
  1290. %% modules are exported.
  1291. join_exports(Env, Name, Map, Source, Target) ->
  1292. case ordsets:is_element(Name, Env#merge.export) of
  1293. true ->
  1294. ordsets:union(ordsets:from_list([Map(F)
  1295. || F <- Source]),
  1296. Target);
  1297. false ->
  1298. Target
  1299. end.
  1300. %% Aliases never need renaming; instead we always expand uses which
  1301. %% could cause name clashes. We must then remove the expanded names from
  1302. %% the imports of the target.
  1303. join_aliases(Name, Expansions, Source, Target) ->
  1304. As = case dict:find(Name, Expansions) of
  1305. {ok, As1} ->
  1306. ordsets:from_list(dict:to_list(As1));
  1307. error ->
  1308. []
  1309. end,
  1310. ordsets:union(ordsets:subtract(Source, As), Target).
  1311. %% We only propagate attributes if the number of source modules is 1 or
  1312. %% the source module has the same name as the resulting module.
  1313. join_attributes(Env, Name, Source, Target) ->
  1314. if Env#merge.target == Name ->
  1315. ordsets:union(Source, Target);
  1316. true ->
  1317. if length(Env#merge.sources) == 1 ->
  1318. ordsets:union(Source, Target);
  1319. true ->
  1320. Target
  1321. end
  1322. end.
  1323. %% The final record info in itself is not used at present, but we
  1324. %% compute the join anyway. We apply renaming to records much like we do
  1325. %% to functions, but records have a separate namespace.
  1326. join_records(Map, Source, Target) ->
  1327. Renamed = [{map_record_name(R, Map), Fs} || {R, Fs} <- Source],
  1328. ordsets:union(ordsets:from_list(Renamed), Target).
  1329. %% This finds aliases that are in conflict or are for other reasons
  1330. %% necessary to expand while transforming the code later. It is assumed
  1331. %% that each module is in itself correct, and thus does not contain
  1332. %% conflicting definitions of the same alias.
  1333. %%
  1334. %% We could of course simply say that *all* aliases, without exception,
  1335. %% should be expanded, but such a big change in the style of the code
  1336. %% should not be done unless the user explicitly specifies it.
  1337. %%
  1338. %% The returned `Expansions' is a dictionary (module `dict') mapping
  1339. %% each module name in `Modules' to a dictionary which maps those
  1340. %% aliases to be expanded for that module to their corresponding full
  1341. %% names.
  1342. %%
  1343. %% Aliases are filtered according to the following rules:
  1344. %%
  1345. %% 1. If a name is defined (in some source module) as an alias of a
  1346. %% name `M:...', where `M' is any of the source modules(*), then
  1347. %% the definition of that alias should be removed, and all its uses
  1348. %% (in the same module as the definition) be expanded.
  1349. %%
  1350. %% 2. Then, if a name is defined (in some source module) as an
  1351. %% alias, but the name occurs in the name space of the resulting
  1352. %% module, then the definition should be removed and all uses (in
  1353. %% the same module) expanded.
  1354. %%
  1355. %% 3. Finally, if a name has two or more distinct alias definitions
  1356. %% in the source modules, then all definitions of that alias should
  1357. %% be removed and all uses (in all modules) expanded. (We remove
  1358. %% all definitions mainly for symmetry.)
  1359. %%
  1360. %% (*) It is actually possible for an alias to refer to the module
  1361. %% in which it is itself defined. However, since we also in this
  1362. %% case want to expand all uses, we don't have to do any extra work
  1363. %% to handle it.
  1364. %% The filtering is done in two stages.
  1365. alias_expansions(Modules, Names, Forbid) ->
  1366. Table = alias_expansions_1(Modules, Forbid, Names),
  1367. alias_expansions_2(Modules, Table).
  1368. %% First consider each alias in isolation.
  1369. alias_expansions_1(Modules, Forbid, Names) ->
  1370. lists:foldl(
  1371. fun (M, T) ->
  1372. Map = lists:foldl(
  1373. fun ({A, F}, T1) ->
  1374. case keep_alias(A, F, Forbid, Names)
  1375. of
  1376. true ->
  1377. T1;
  1378. false ->
  1379. dict:store(A, F, T1)
  1380. end
  1381. end,
  1382. dict:new(), M#module.aliases),
  1383. dict:store(M#module.name, Map, T)
  1384. end,
  1385. dict:new(), Modules).
  1386. keep_alias(A, {M, _}, Forbid, Names) ->
  1387. case sets:is_element(M, Forbid) of
  1388. true ->
  1389. false;
  1390. false ->
  1391. not sets:is_element(A, Names)
  1392. end.
  1393. %% In this second stage, we resolve any conflicts that may remain
  1394. %% because of distinct source modules still containing distinct alias
  1395. %% definitions of the same name - in that case we remove *all* of them
  1396. %% (mainly for symmetry).
  1397. alias_expansions_2(Modules, Table) ->
  1398. %% Get the set of all alias definitions in all modules (collapsing
  1399. %% duplicated but equivalent definitions).
  1400. Aliases = lists:foldl(
  1401. fun (M, A) ->
  1402. ordsets:union(A, M#module.aliases)
  1403. end,
  1404. ordsets:new(), Modules),
  1405. %% Get the set of names with multiple (distinct) definitions.
  1406. Names = duplicates([F || {F, _} <- Aliases]),
  1407. %% Go through all aliases in all source modules and add necessary
  1408. %% entries to the expansion-table. We expect that there is an entry
  1409. %% in the table here for each module.
  1410. lists:foldl(
  1411. fun (M, T) ->
  1412. N = M#module.name,
  1413. lists:foldl(
  1414. fun ({A, F}, T1) ->
  1415. case ordsets:is_element(A, Names) of
  1416. true ->
  1417. T2 = dict:fetch(N, T1),
  1418. dict:store(N,
  1419. dict:store(A, F, T2),
  1420. T1);
  1421. false ->
  1422. T1
  1423. end
  1424. end,
  1425. T, M#module.aliases)
  1426. end,
  1427. Table, Modules).
  1428. %% ---------------------------------------------------------------------
  1429. %% Merging the source code.
  1430. %% Data structure for code transformation environment.
  1431. -record(code, {module, % = atom()
  1432. target, % = atom()
  1433. sources, % = ordset(atom())
  1434. static, % = ordset(atom())
  1435. safe, % = ordset(atom())
  1436. preserved, % = bool()
  1437. no_headers, % = bool()
  1438. notes, % = bool()
  1439. map, % = ({atom(), int()}) -> {atom(), int()}
  1440. renaming, % = (atom()) -> ({atom(), int()}) ->
  1441. % {atom(), int()}
  1442. expand, % = dict({atom(), int()},
  1443. % {atom(), {atom(), int()}})
  1444. redirect % = dict(atom(), atom())
  1445. }).
  1446. %% `Trees' must be a list of syntax trees of type `form_list'. The
  1447. %% result is a pair `{Result, Header}' where `Result' is a `form_list'
  1448. %% tree representing the merged code, and if the `preserved' flag is
  1449. %% set, `Header' is the list of forms up to and including the first
  1450. %% `-module(...)' declaration, but stripped of any `-file(...)'
  1451. %% attributes - otherwise `Header' is an empty list.
  1452. merge_code(Trees, Modules, Expansions, Renaming, Env, St) ->
  1453. Env1 = #code{target = Env#merge.target,
  1454. sources = sets:from_list(Env#merge.sources),
  1455. static = sets:from_list(Env#merge.static),
  1456. safe = sets:from_list(Env#merge.safe),
  1457. preserved = Env#merge.preserved,
  1458. no_headers = Env#merge.no_headers,
  1459. notes = Env#merge.notes,
  1460. redirect = Env#merge.redirect,
  1461. renaming = Renaming},
  1462. Code = order_code(Modules, Trees, Env1),
  1463. {Code1, Header} = case Env1#code.preserved of
  1464. true ->
  1465. take_header(Code);
  1466. false ->
  1467. {Code, erl_syntax:form_list([])}
  1468. end,
  1469. {Forms, St1} = merge_code_1(Code1, Expansions, Env1, St),
  1470. Tree = erl_syntax:form_list(Forms),
  1471. {Tree, Header, St1}.
  1472. merge_code_1(Code, Expansions, Env, St) ->
  1473. lists:foldr(
  1474. fun ({Module, T}, {Acc, St0}) ->
  1475. M = Module#module.name,
  1476. Expand = case dict:find(M, Expansions) of
  1477. {ok, Dict} -> Dict;
  1478. error -> dict:new()
  1479. end,
  1480. Env1 = Env#code{module = M,
  1481. map = (Env#code.renaming)(M),
  1482. expand = Expand},
  1483. {T1, St1} = transform(T, Env1, St0),
  1484. {[section_header(M, T1, Env1) | Acc], St1}
  1485. end,
  1486. {[], St}, Code).
  1487. %% Pair module info and source code, in the order we want, and flatten
  1488. %% the form lists. If the name of the target is the same as one of the
  1489. %% source modules, and the result should preserve the original module,
  1490. %% the code for that module should be first in the output.
  1491. order_code(Modules, Trees, Env) ->
  1492. order_code(Modules, Trees, {}, [], Env).
  1493. order_code([M | Ms], [T | Ts], First, Rest, Env) ->
  1494. T1 = erl_syntax:flatten_form_list(T),
  1495. case (M#module.name == Env#code.target) and
  1496. Env#code.preserved of
  1497. true ->
  1498. order_code(Ms, Ts, {M, T1}, Rest, Env);
  1499. false ->
  1500. order_code(Ms, Ts, First, [{M, T1} | Rest], Env)
  1501. end;
  1502. order_code([], [], First, Rest, _Env) ->
  1503. Rest1 = lists:reverse(Rest),
  1504. case First of
  1505. {} ->
  1506. Rest1;
  1507. M ->
  1508. [M | Rest1]
  1509. end.
  1510. %% Extracting the "original" header (the `-module(...)' declaration is
  1511. %% sure to exist).
  1512. take_header([{M, T} | Ms]) ->
  1513. Fs = erl_syntax:form_list_elements(T),
  1514. {Header, Fs1} = take_header_1(Fs, []),
  1515. T1 = erl_syntax:form_list(Fs1),
  1516. {[{M, T1} | Ms], Header}.
  1517. take_header_1([F | Fs], As) ->
  1518. case erl_syntax_lib:analyze_form(F) of
  1519. {'attribute', {'module', _}} ->
  1520. {lists:reverse([F | As]), Fs}; % done
  1521. {'attribute', {'file', _}} ->
  1522. take_header_1(Fs, As); % discard
  1523. _ ->
  1524. take_header_1(Fs, [F | As]) % keep
  1525. end.
  1526. section_header(Name, Tree, Env) ->
  1527. N = sets:size(Env#code.sources),
  1528. if N > 1, Name /= Env#code.target, Env#code.notes /= no,
  1529. Env#code.no_headers /= true ->
  1530. Text = io_lib:fwrite("The following code stems "
  1531. "from module `~w'.", [Name]),
  1532. Header = comment([?COMMENT_BAR, "",
  1533. lists:flatten(Text), ""]),
  1534. erl_syntax:form_list([Header, Tree]);
  1535. true ->
  1536. Tree
  1537. end.
  1538. transform(Tree, Env, St) ->
  1539. case erl_syntax:type(Tree) of
  1540. application ->
  1541. transform_application(Tree, Env, St);
  1542. attribute ->
  1543. transform_attribute(Tree, Env, St);
  1544. function ->
  1545. transform_function(Tree, Env, St);
  1546. implicit_fun ->
  1547. transform_implicit_fun(Tree, Env, St);
  1548. rule ->
  1549. transform_rule(Tree, Env, St);
  1550. record_expr ->
  1551. transform_record(Tree, Env, St);
  1552. record_index_expr ->
  1553. transform_record(Tree, Env, St);
  1554. record_access ->
  1555. transform_record(Tree, Env, St);
  1556. _ ->
  1557. default_transform(Tree, Env, St)
  1558. end.
  1559. default_transform(Tree, Env, St) ->
  1560. case erl_syntax:subtrees(Tree) of
  1561. [] ->
  1562. {Tree, St};
  1563. Gs ->
  1564. {Gs1, St1} = transform_1(Gs, Env, St),
  1565. Tree1 = rewrite(Tree, erl_syntax:make_tree(
  1566. erl_syntax:type(Tree),
  1567. Gs1)),
  1568. {Tree1, St1}
  1569. end.
  1570. transform_1([G | Gs], Env, St) ->
  1571. {G1, St1} = transform_list(G, Env, St),
  1572. {Gs1, St2} = transform_1(Gs, Env, St1),
  1573. {[G1 | Gs1], St2};
  1574. transform_1([], _Env, St) ->
  1575. {[], St}.
  1576. transform_list([T | Ts], Env, St) ->
  1577. {T1, St1} = transform(T, Env, St),
  1578. {Ts1, St2} = transform_list(Ts, Env, St1),
  1579. {[T1 | Ts1], St2};
  1580. transform_list([], _Env, St) ->
  1581. {[], St}.
  1582. %% Renaming function definitions
  1583. transform_function(T, Env, St) ->
  1584. {T1, St1} = default_transform(T, Env, St),
  1585. F = erl_syntax_lib:analyze_function(T1),
  1586. {V, Text} = case (Env#code.map)(F) of
  1587. F ->
  1588. %% Not renamed
  1589. {none, []};
  1590. {Atom, _Arity} ->
  1591. %% Renamed
  1592. Cs = erl_syntax:function_clauses(T1),
  1593. N = rename_atom(
  1594. erl_syntax:function_name(T1),
  1595. Atom),
  1596. T2 = erl_syntax:function(N, Cs),
  1597. {{value, T2}, renaming_note(Atom)}
  1598. end,
  1599. {maybe_modified(V, T1, 2, Text, Env), St1}.
  1600. renaming_note(Name) ->
  1601. [lists:flatten(io_lib:fwrite("renamed function to `~w'",
  1602. [Name]))].
  1603. rename_atom(Node, Atom) ->
  1604. rewrite(Node, erl_syntax:atom(Atom)).
  1605. %% Renaming Mnemosyne rules (just like function definitions)
  1606. transform_rule(T, Env, St) ->
  1607. {T1, St1} = default_transform(T, Env, St),
  1608. F = erl_syntax_lib:analyze_rule(T1),
  1609. {V, Text} = case (Env#code.map)(F) of
  1610. F ->
  1611. %% Not renamed
  1612. {none, []};
  1613. {Atom, _Arity} ->
  1614. %% Renamed
  1615. Cs = erl_syntax:rule_clauses(T1),
  1616. N = rename_atom(
  1617. erl_syntax:rule_name(T1),
  1618. Atom),
  1619. T2 = rewrite(T1,
  1620. erl_syntax:rule(N, Cs)),
  1621. {{value, T2}, renaming_note(Atom)}
  1622. end,
  1623. {maybe_modified(V, T1, 2, Text, Env), St1}.
  1624. %% Renaming "implicit fun" expressions (done quietly).
  1625. transform_implicit_fun(T, Env, St) ->
  1626. {T1, St1} = default_transform(T, Env, St),
  1627. F = erl_syntax_lib:analyze_implicit_fun(T1),
  1628. {V, Text} = case (Env#code.map)(F) of
  1629. F ->
  1630. %% Not renamed
  1631. {none, []};
  1632. {Atom, Arity} ->
  1633. %% Renamed
  1634. N = rewrite(
  1635. erl_syntax:implicit_fun_name(T1),
  1636. erl_syntax:arity_qualifier(
  1637. erl_syntax:atom(Atom),
  1638. erl_syntax:integer(Arity))),
  1639. T2 = erl_syntax:implicit_fun(N),
  1640. {{value, T2}, ["function was renamed"]}
  1641. end,
  1642. {maybe_modified_quiet(V, T1, 2, Text, Env), St1}.
  1643. %% Transforming function applications
  1644. transform_application(T, Env, St) ->
  1645. %% We transform the arguments first, so we can concentrate on the
  1646. %% application itself after that point.
  1647. {As, St1} = transform_list(
  1648. erl_syntax:application_arguments(T),
  1649. Env, St),
  1650. F = erl_syntax:application_operator(T),
  1651. %% See if the operator is an explicit function name.
  1652. %% (Usually, this will be the case.)
  1653. case catch {ok, erl_syntax_lib:analyze_function_name(F)} of
  1654. {ok, Name} ->
  1655. transform_application_1(Name, F, As, T, Env, St1);
  1656. syntax_error ->
  1657. %% Oper is not a function name, but might be any other
  1658. %% expression - we just visit it and reassemble the
  1659. %% application.
  1660. %% We do not handle applications of tuples `{M, F}'.
  1661. {F1, St2} = transform(F, Env, St1),
  1662. {rewrite(T, erl_syntax:application(F1, As)), St2};
  1663. {'EXIT', R} ->
  1664. exit(R);
  1665. R ->
  1666. throw(R)
  1667. end.
  1668. %% At this point we should have an explicit function name, which might
  1669. %% or might not be qualified by a module name.
  1670. transform_application_1(Name, F, As, T, Env, St) ->
  1671. %% Before doing anything else, we must unfold any uses of aliases
  1672. %% whose definitions have been killed.
  1673. Arity = length(As),
  1674. {Name1, F1} = expand_operator(Name, Arity, F, Env),
  1675. F2 = maybe_modified_quiet(F1, F, 7, ["unfolded alias"], Env),
  1676. {V, St1} = transform_application_2(Name1, Arity, F2, As, Env,
  1677. St),
  1678. T1 = rewrite(T, erl_syntax:application(F2, As)),
  1679. T3 = case V of
  1680. none ->
  1681. T1;
  1682. {value, {T2, Depth, Message}} ->
  1683. maybe_modified_quiet({value, T2}, T1, Depth,
  1684. Message, Env)
  1685. end,
  1686. {T3, St1}.
  1687. %% Here, Name has been expanded if necessary (if so, this is also
  1688. %% reflected by F), and As have been transformed. We should return
  1689. %% `{none, State}' if no further rewriting is necessary, and otherwise
  1690. %% `{{value, {Tree, Depth, Message}}, State}', where `Depth' and
  1691. %% `Message' are to be passed to `maybe_modified'.
  1692. transform_application_2(Name, Arity, F, As, Env, St)
  1693. when atom(Name) ->
  1694. transform_atom_application(Name, Arity, F, As, Env, St);
  1695. transform_application_2({M, N}, Arity, F, As, Env, St)
  1696. when atom(M), atom(N) ->
  1697. transform_qualified_application(M, N, Arity, F, As, Env, St);
  1698. transform_application_2(_Name, _Arity, _F, _As, _Env, St) ->
  1699. {none, St}. % strange name - do nothing.
  1700. expand_operator(Name, Arity, _F, Env) when atom(Name) ->
  1701. %% An unqualified function name - must be looked up. However, we
  1702. %% must first check that it is not an auto-imported name - these
  1703. %% have precedence over normal imports. We do a sanity check on the
  1704. %% found arity.
  1705. case is_auto_import({Name, Arity}) of
  1706. true ->
  1707. {Name, none}; % auto-import - never expand.
  1708. false ->
  1709. case dict:find({Name, Arity}, Env#code.expand) of
  1710. {ok, {M, {N, A}}} when A == Arity ->
  1711. %% Expand to a qualified name.
  1712. F1 = erl_syntax:module_qualifier(
  1713. erl_syntax:atom(M),
  1714. erl_syntax:atom(N)),
  1715. {{M, N}, {value, F1}};
  1716. error ->
  1717. %% Not in the table - leave it unchanged
  1718. {Name, none}
  1719. end
  1720. end;
  1721. expand_operator(Name, _Arity, _F, _Env) ->
  1722. %% Qualified function name - leave it unchanged
  1723. {Name, none}.
  1724. %% Transforming an application of a named function without module
  1725. %% qualifier (often misleadingly called "local" applications). Note that
  1726. %% since the `apply', `spawn' and `spawn_link' functions are implicitly
  1727. %% imported (from module `erlang'), applications of these names cannot
  1728. %% refer to functions defined in the source code.
  1729. transform_atom_application(Name, Arity, F, As, Env, St) ->
  1730. %% Catch applications of `apply' and `spawn'.
  1731. case {Name, Arity} of
  1732. {'apply', 2} ->
  1733. warning_apply_2(Env#code.module, Env#code.target),
  1734. {none, St};
  1735. {'apply', 3} ->
  1736. transform_apply_call(F, As, Env, St);
  1737. {'spawn', 3} ->
  1738. transform_spawn_call(F, As, Env, St);
  1739. {'spawn', 4} ->
  1740. transform_spawn_call(F, As, Env, St);
  1741. {'spawn_link', 3} ->
  1742. transform_spawn_call(F, As, Env, St);
  1743. {'spawn_link', 4} ->
  1744. transform_spawn_call(F, As, Env, St);
  1745. _ ->
  1746. %% A simple call of an unqualified function name - just
  1747. %% remap the name as necessary. Auto-imported names may not
  1748. %% be changed - the call never refers to a local function.
  1749. %% We do a sanity check on the arity.
  1750. case is_auto_import({Name, Arity}) of
  1751. true ->
  1752. {none, St}; % auto-import - do not change.
  1753. false ->
  1754. case (Env#code.map)({Name, Arity}) of
  1755. {N, A} when N == Name, A == Arity ->
  1756. %% Not changed.
  1757. {none, St};
  1758. {N, A} when A == Arity ->
  1759. %% The callee (in the current module)
  1760. %% was renamed.
  1761. F1 = rewrite(F, erl_syntax:atom(N)),
  1762. T = erl_syntax:application(F1, As),
  1763. V = {T, 2, ["callee was renamed"]},
  1764. {{value, V}, St}
  1765. end
  1766. end
  1767. end.
  1768. %% Transforming an application of an explicitly named function qualified
  1769. %% with an (also explicit) module name. (Often called "remote"
  1770. %% applications.)
  1771. transform_qualified_application(Module, Name, Arity, F, As, Env, St) ->
  1772. %% Catch applications of `apply' and `spawn'.
  1773. case {Module, Name, Arity} of
  1774. {'erlang', 'apply', 2} ->
  1775. warning_apply_2(Env#code.module, Env#code.target),
  1776. {none, St};
  1777. {'erlang', 'apply', 3} ->
  1778. transform_apply_call(F, As, Env, St);
  1779. {'erlang', 'spawn', 3} ->
  1780. transform_spawn_call(F, As, Env, St);
  1781. {'erlang', 'spawn', 4} ->
  1782. transform_spawn_call(F, As, Env, St);
  1783. {'erlang', 'spawn_link', 3} ->
  1784. transform_spawn_call(F, As, Env, St);
  1785. {'erlang', 'spawn_link', 4} ->
  1786. transform_spawn_call(F, As, Env, St);
  1787. _ ->
  1788. case erlang:is_builtin(Module, Name, Arity) of
  1789. false ->
  1790. transform_qualified_application_1(
  1791. Module, Name, Arity, F, As, Env, St);
  1792. true ->
  1793. {none, St}
  1794. end
  1795. end.
  1796. transform_qualified_application_1(Module, Name, Arity, F, As, Env,
  1797. St) ->
  1798. MakeLocal = fun (N) ->
  1799. F1 = rewrite(F, erl_syntax:atom(N)),
  1800. erl_syntax:application(F1, As)
  1801. end,
  1802. MakeRemote = fun () ->
  1803. erl_syntax:application(F, As)
  1804. end,
  1805. MakeDynamic = fun(M, N) ->
  1806. F1 = erl_syntax:module_qualifier(
  1807. erl_syntax:atom(M),
  1808. erl_syntax:atom(N)),
  1809. F2 = rewrite(F, F1),
  1810. erl_syntax:application(F2, As)
  1811. end,
  1812. localise(Module, Name, Arity, MakeLocal, MakeRemote,
  1813. MakeDynamic, 3, Env, St).
  1814. %% For an `apply/3' call, if we know the called module and function
  1815. %% names, and the number of arguments, then we can rewrite it to a
  1816. %% direct remote call - and if we do not, there is nothing we can
  1817. %% change.
  1818. transform_apply_call(F, As, Env, St) ->
  1819. case As of
  1820. [Module, Name, List] ->
  1821. case (erl_syntax:type(Module) == atom)
  1822. and (erl_syntax:type(Name) == atom)
  1823. and erl_syntax:is_proper_list(List) of
  1824. true ->
  1825. transform_apply_call_1(Module, Name, List, F,
  1826. As, Env, St);
  1827. false ->
  1828. %% We can't get enough information about the
  1829. %% arguments to the `apply' call, so we do nothing
  1830. %% but warn.
  1831. warning_unsafe_call(apply, Env#code.module,
  1832. Env#code.target),
  1833. {none, St}
  1834. end
  1835. end.
  1836. %% Rewrite the apply-call to a static qualified call and handle that
  1837. %% instead.
  1838. transform_apply_call_1(Module, Name, List, F, _As, Env, St) ->
  1839. F1 = rewrite(F, erl_syntax:module_qualifier( Module, Name)),
  1840. As1 = erl_syntax:list_elements(List),
  1841. M = erl_syntax:atom_value(Module),
  1842. N = erl_syntax:atom_value(Name),
  1843. A = length(As1),
  1844. transform_qualified_application_1(M, N, A, F1, As1, Env, St).
  1845. %% `spawn' and `spawn_link' (with arity 3 or 4) are very much like
  1846. %% `apply/3', but there could be an extra `Node' argument. Note that `F'
  1847. %% below can represent both `spawn' and `spawn_link'.
  1848. transform_spawn_call(F, As, Env, St) ->
  1849. case As of
  1850. [Module, Name, List] ->
  1851. MakeSpawn = fun (As1) ->
  1852. erl_syntax:application(F, As1)
  1853. end,
  1854. transform_spawn_call_1(Module, Name, List, MakeSpawn,
  1855. Env, St);
  1856. [Node, Module, Name, List] ->
  1857. MakeSpawn = fun (As1) ->
  1858. erl_syntax:application(
  1859. F, [Node | As1])
  1860. end,
  1861. transform_spawn_call_1(Module, Name, List, MakeSpawn,
  1862. Env, St)
  1863. end.
  1864. %% Here, we can treat all dynamic-lookup spawns like `spawn/3'.
  1865. transform_spawn_call_1(Module, Name, List, MakeSpawn, Env, St) ->
  1866. case (erl_syntax:type(Module) == atom)
  1867. and (erl_syntax:type(Name) == atom)
  1868. and erl_syntax:is_proper_list(List)
  1869. of
  1870. true ->
  1871. transform_spawn_call_2(Module, Name, List, MakeSpawn,
  1872. Env, St);
  1873. _ ->
  1874. %% We can't get enough information about the arguments to
  1875. %% the `spawn' call, so we do nothing but warn.
  1876. warning_unsafe_call(spawn, Env#code.module,
  1877. Env#code.target),
  1878. {none, St}
  1879. end.
  1880. transform_spawn_call_2(Module, Name, List, MakeSpawn, Env, St) ->
  1881. As = erl_syntax:list_elements(List),
  1882. Arity = length(As),
  1883. MakeLocal = fun (N) ->
  1884. %% By using `spawn-a-fun', we do not have to
  1885. %% force the callee to be exported.
  1886. A = rewrite(Name, erl_syntax:atom(N)),
  1887. B = erl_syntax:application(A, As),
  1888. C = erl_syntax:clause([], [B]),
  1889. F = erl_syntax:fun_expr([C]),
  1890. MakeSpawn([F])
  1891. end,
  1892. MakeRemote = fun () ->
  1893. MakeSpawn([Module, Name, List])
  1894. end,
  1895. MakeDynamic = fun (M, N) ->
  1896. F = rewrite(Name, erl_syntax:atom(N)),
  1897. MakeSpawn([erl_syntax:atom(M), F, List])
  1898. end,
  1899. localise(erl_syntax:atom_value(Module),
  1900. erl_syntax:atom_value(Name),
  1901. Arity, MakeLocal, MakeRemote, MakeDynamic,
  1902. 4, Env, St).
  1903. %% MakeLocal = (atom()) -> syntaxTree()
  1904. %% MakeRemote = () -> syntaxTree()
  1905. %% MakeDynamic = (atom(), atom()) -> syntaxTree()
  1906. %% localise(...) -> {none, state()} | {{value, V}, State}
  1907. localise(Module, Name, Arity, MakeLocal, MakeRemote, MakeDynamic,
  1908. Depth, Env, St) ->
  1909. %% Is the callee in one of the source modules?
  1910. case sets:is_element(Module, Env#code.sources) of
  1911. false ->
  1912. case dict:find(Module, Env#code.redirect) of
  1913. {ok, Module1} ->
  1914. T = MakeDynamic(Module1, Name),
  1915. V = {T, Depth, ["redirected call"]},
  1916. {{value, V}, St};
  1917. error ->
  1918. {none, St} % Nothing needs doing.
  1919. end;
  1920. true ->
  1921. %% Remap the name of the callee, as necessary. Do a sanity
  1922. %% check on the arity.
  1923. Map = (Env#code.renaming)(Module),
  1924. Name1 = case Map({Name, Arity}) of
  1925. {N, A} when A == Arity ->
  1926. N
  1927. end,
  1928. %% See if the callee module is "safe" and/or "static".
  1929. Safe = sets:is_element(Module, Env#code.safe),
  1930. Static = (sets:is_element(Module, Env#code.static)
  1931. or Safe),
  1932. %% Select what kind of code to generate for the call:
  1933. case Static of
  1934. false ->
  1935. %% (This also implies that the called module is not
  1936. %% the target module - which is always "static" -
  1937. %% and that it is not "safe".) The called module
  1938. %% could be replaced dynamically, independent of the
  1939. %% target module, so we must protect the localised
  1940. %% call. We strip all comments from the localised
  1941. %% code, to avoid getting the same comments twice.
  1942. L = MakeLocal(Name1),
  1943. L1 = erl_syntax_lib:strip_comments(L),
  1944. R = MakeRemote(),
  1945. {T, Text} = protect_call(Module, L1, R),
  1946. V = {T, Depth, Text},
  1947. {{value, V}, St};
  1948. true ->
  1949. %% In this case, the called module is never replaced
  1950. %% unless the target module also is. (N.B.: These
  1951. %% might be the same module.)
  1952. case Safe of
  1953. false ->
  1954. %% The normal code replacement semantics
  1955. %% must be preserved here, so the generated
  1956. %% call must be qualified with the name of
  1957. %% the target module. (We assume this is
  1958. %% efficiently compiled even if we do not
  1959. %% insert an explicit "latest version"
  1960. %% test.)
  1961. Target = Env#code.target,
  1962. case Module == Target of
  1963. true ->
  1964. %% Already calling the target module
  1965. %% - do not insert irritating notes.
  1966. {none, St};
  1967. false ->
  1968. %% We must ensure that the function
  1969. %% is exported.
  1970. St1 = state__add_export(Name1,
  1971. Arity, St),
  1972. T = MakeDynamic(Target, Name1),
  1973. Text = ["localised call"],
  1974. V = {T, Depth, Text},
  1975. {{value, V}, St1}
  1976. end;
  1977. true ->
  1978. %% The call is regarded as safe to localise
  1979. %% completely. Code replacement will in
  1980. %% general not be detected (except for
  1981. %% spawn/apply).
  1982. T = MakeLocal(Name1),
  1983. Text = ["localised safe call"],
  1984. V = {T, Depth, Text},
  1985. {{value, V}, St}
  1986. end
  1987. end
  1988. end.
  1989. %%% %% This creates a test on whether there is a later loaded version of
  1990. %%% %% Module: if not, select the `Local' expression, otherwise the `Remote'
  1991. %%% %% expression. We knowingly duplicate code here, to allow better
  1992. %%% %% optimisations, but we never duplicate work.
  1993. %%%
  1994. %%% protect_call(Module, Local, Remote) ->
  1995. %%% T = erl_syntax:if_expr(
  1996. %%% [erl_syntax:clause([erl_syntax:application(
  1997. %%% erl_syntax:atom('not_replaced'),
  1998. %%% [erl_syntax:atom(Module)])],
  1999. %%% [Local]),
  2000. %%% erl_syntax:clause([erl_syntax:atom('true')],
  2001. %%% [Remote])]),
  2002. %%% {T, ["localised dynamic call"]}.
  2003. %% This "protects" a localised call by letting it remain a remote call.
  2004. protect_call(_Module, _Local, Remote) ->
  2005. {Remote, ["dynamic call"]}.
  2006. %% Renaming record declarations
  2007. transform_attribute(T, Env, St) ->
  2008. {T1, St1} = default_transform(T, Env, St),
  2009. case erl_syntax_lib:analyze_attribute(T1) of
  2010. {record, {R, _}} ->
  2011. F = fun(R) ->
  2012. [_ | As] = erl_syntax:attribute_arguments(T1),
  2013. erl_syntax:attribute(
  2014. erl_syntax:attribute_name(T1),
  2015. [erl_syntax:atom(R) | As])
  2016. end,
  2017. {V, Text} = rename_record(R, F, Env),
  2018. {maybe_modified(V, T1, 2, Text, Env), St1};
  2019. _ ->
  2020. {T1, St1}
  2021. end.
  2022. %% This handles renaming of records.
  2023. transform_record(T, Env, St) ->
  2024. {T1, St1} = default_transform(T, Env, St),
  2025. X = case catch erl_syntax_lib:analyze_record_expr(T1) of
  2026. {record_expr, {R, _}} ->
  2027. F = fun (R) ->
  2028. erl_syntax:record_expr(
  2029. erl_syntax:record_expr_argument(T1),
  2030. erl_syntax:atom(R),
  2031. erl_syntax:record_expr_fields(T1))
  2032. end,
  2033. {R, F};
  2034. {record_index_expr, {R, _}} ->
  2035. F = fun (R) ->
  2036. erl_syntax:record_index_expr(
  2037. erl_syntax:atom(R),
  2038. erl_syntax:record_index_expr_field(T1))
  2039. end,
  2040. {R, F};
  2041. {record_access, {R, _}} ->
  2042. F = fun (R) ->
  2043. erl_syntax:record_access(
  2044. erl_syntax:record_access_argument(T1),
  2045. erl_syntax:atom(R),
  2046. erl_syntax:record_access_field(T1))
  2047. end,
  2048. {R, F};
  2049. _Type ->
  2050. false
  2051. end,
  2052. case X of
  2053. {R1, F1} ->
  2054. {V, Text} = rename_record(R1, F1, Env),
  2055. {maybe_modified(V, T1, 1, Text, Env), St1};
  2056. false ->
  2057. {T1, St1}
  2058. end.
  2059. rename_record(R, F, Env) ->
  2060. case map_record_name(R, Env#code.map) of
  2061. R ->
  2062. %% Not renamed
  2063. {none, []};
  2064. R1 ->
  2065. %% Renamed
  2066. {{value, F(R1)}, ["record was renamed"]}
  2067. end.
  2068. %% Maybe-rewriting Node, adding modification notes.
  2069. %% This is for non-primary modifications; they are not commented unless
  2070. %% the `notes' option is set to `always'.
  2071. maybe_modified_quiet(V, Node, Depth, Message, Env) ->
  2072. case Env#code.notes of
  2073. always ->
  2074. maybe_modified_1(V, Node, Depth, Message, yes);
  2075. _ ->
  2076. maybe_modified_1(V, Node, Depth, Message, no)
  2077. end.
  2078. %% This is for important notes; they are only disabled if the `notes'
  2079. %% option is set to `no'.
  2080. maybe_modified(V, Node, Depth, Message, Env) ->
  2081. maybe_modified_1(V, Node, Depth, Message, Env#code.notes).
  2082. maybe_modified_1(none, Node, _Depth, _Message, _Notes) ->
  2083. Node;
  2084. maybe_modified_1({value, Node1}, Node, Depth, Message, Notes) ->
  2085. case Notes of
  2086. no ->
  2087. rewrite(Node, Node1);
  2088. _ ->
  2089. Code = erl_syntax:comment_text(
  2090. erl_syntax_lib:to_comment(
  2091. erl_syntax_lib:strip_comments(
  2092. erl_syntax_lib:limit(Node, Depth)),
  2093. "\040\040")),
  2094. erl_syntax:add_precomments(
  2095. [comment_note(Message ++
  2096. ["Original code:" | Code])],
  2097. rewrite(Node, Node1))
  2098. end.
  2099. %% =====================================================================
  2100. %% @spec create_stubs(Stubs::[stubDescriptor()], Options::[term()]) ->
  2101. %% [string()]
  2102. %%
  2103. %% @doc Creates stub module source files corresponding to the given stub
  2104. %% descriptors. The returned value is the list of names of the created
  2105. %% files. See <code>merge_sources/3</code> for more information about
  2106. %% stub descriptors.
  2107. %%
  2108. %% <p>Options:
  2109. %% <dl>
  2110. %% <dt><code>{backup_suffix, string()}</code></dt>
  2111. %% <dt><code>{backups, bool()}</code></dt>
  2112. %% <dt><code>{printer, Function}</code></dt>
  2113. %% <dt><code>{stub_dir, filename()}</code></dt>
  2114. %% <dt><code>{suffix, string()}</code></dt>
  2115. %% <dt><code>{verbose, bool()}</code></dt>
  2116. %% </dl>
  2117. %% See <code>merge/3</code> for details on these options.</p>
  2118. %%
  2119. %% @see merge/3
  2120. %% @see merge_sources/3
  2121. create_stubs(Stubs, Opts) ->
  2122. Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
  2123. lists:foldl(fun (S, Fs) ->
  2124. F = create_stub(S, Opts1),
  2125. [F | Fs]
  2126. end,
  2127. [], Stubs).
  2128. maybe_create_stubs(Stubs, Opts) ->
  2129. case proplists:get_bool(stubs, Opts) of
  2130. true ->
  2131. create_stubs(Stubs, Opts);
  2132. false ->
  2133. []
  2134. end.
  2135. create_stub({Name, Fs, Attrs}, Opts) ->
  2136. Defs = [stub_function(F) || F <- Fs],
  2137. Exports = [F || {F, _} <- Fs],
  2138. Forms = stub_header(Name, Exports, Attrs) ++ Defs,
  2139. Dir = proplists:get_value(stub_dir, Opts, ""),
  2140. verbose("creating stub file for module `~w'.", [Name], Opts),
  2141. write_module(erl_syntax:form_list(Forms), Name, Dir, Opts).
  2142. %% We just follow the arity specifications naively when we create the
  2143. %% stub funcion - it is not our responsibility to check them.
  2144. stub_function({{F, A}, {M, {F1, A1}}}) ->
  2145. Vs = var_list(A),
  2146. Vs1 = var_list(A1),
  2147. R = erl_syntax:module_qualifier(erl_syntax:atom(M),
  2148. erl_syntax:atom(F1)),
  2149. Call = erl_syntax:application(R, Vs1),
  2150. erl_syntax:function(erl_syntax:atom(F),
  2151. [erl_syntax:clause(Vs, [], [Call])]).
  2152. var_list(N) ->
  2153. var_list(N, 1).
  2154. var_list(N, I) when N > 0 ->
  2155. [erl_syntax:variable("X" ++ integer_to_list(I))
  2156. | var_list(N - 1, I + 1)];
  2157. var_list(0, _) ->
  2158. [].
  2159. stub_header(Name, Exports, Attrs) ->
  2160. [comment([?COMMENT_BAR,
  2161. io_lib:fwrite("This is an automatically "
  2162. "generated stub interface\n"
  2163. "for the module `~w'.",
  2164. [Name]),
  2165. "",
  2166. timestamp(),
  2167. ""]),
  2168. erl_syntax:attribute(erl_syntax:atom('module'),
  2169. [erl_syntax:atom(Name)]),
  2170. make_export(Exports)]
  2171. ++ make_attributes(Attrs).
  2172. %% =====================================================================
  2173. %% @spec rename(Files::[filename()], Renamings) -> [string()]
  2174. %% @equiv rename(Files, Renamings, [])
  2175. rename(Files, Renamings) ->
  2176. rename(Files, Renamings, []).
  2177. %% =====================================================================
  2178. %% @spec rename(Files::[filename()], Renamings, Options::[term()]) ->
  2179. %% [string()]
  2180. %%
  2181. %% Renamings = [{atom(), atom()}]
  2182. %%
  2183. %% @doc Renames a set of possibly interdependent source code modules.
  2184. %% <code>Files</code> is a list of file names of source modules to be
  2185. %% processed. <code>Renamings</code> is a list of pairs of <em>module
  2186. %% names</em>, representing a mapping from old names to new. The
  2187. %% returned value is the list of output file names.
  2188. %%
  2189. %% <p>Each file in the list will be read and processed separately. For
  2190. %% every file, each reference to some module M, such that there is an
  2191. %% entry <code>{<em>M</em>, <em>M1</em>}</code> in
  2192. %% <code>Renamings</code>, will be changed to the corresponding M1.
  2193. %% Furthermore, if a file F defines module M, and there is an entry
  2194. %% <code>{<em>M</em>, <em>M1</em>}</code> in <code>Renamings</code>, a
  2195. %% new file named <code><em>M1</em>.erl</code> will be created in the
  2196. %% same directory as F, containing the source code for module M, renamed
  2197. %% to M1. If M does not have an entry in <code>Renamings</code>, the
  2198. %% module is not renamed, only updated, and the resulting source code is
  2199. %% written to <code><em>M</em>.erl</code> (typically, this overwrites
  2200. %% the original file). The <code>suffix</code> option (see below) can be
  2201. %% used to change the default "<code>.erl</code>" suffix for the
  2202. %% generated files.</p>
  2203. %%
  2204. %% <p>Stub modules will automatically be created (see the
  2205. %% <code>stubs</code> and <code>stub_dir</code> options below) for each
  2206. %% module that is renamed. These can be used to redirect any calls still
  2207. %% using the old module names. The stub files are created in the same
  2208. %% directory as the source file (typically overwriting the original
  2209. %% file).</p>
  2210. %%
  2211. %% <p>Options:
  2212. %% <dl>
  2213. %% <dt><code>{backup_suffix, string()}</code></dt>
  2214. %% <dt><code>{backups, bool()}</code></dt>
  2215. %% <dt><code>{printer, Function}</code></dt>
  2216. %% <dt><code>{stubs, bool()}</code></dt>
  2217. %% <dt><code>{suffix, string()}</code></dt>
  2218. %% </dl>
  2219. %% See <code>merge/3</code> for details on these options.</p>
  2220. %%
  2221. %% <p><dl>
  2222. %% <dt><code>{comments, bool()}</code></dt>
  2223. %% <dt><code>{preprocess, bool()}</code></dt>
  2224. %% </dl>
  2225. %% See <code>merge_files/4</code> for details on these options.</p>
  2226. %%
  2227. %% <p><dl>
  2228. %% <dt><code>{no_banner, bool()}</code></dt>
  2229. %% </dl>
  2230. %% For the <code>rename</code> function, this option is
  2231. %% <code>true</code> by default. See <code>merge_sources/3</code> for
  2232. %% details.</p>
  2233. %%
  2234. %% <p><dl>
  2235. %% <dt><code>{tidy, bool()}</code></dt>
  2236. %% </dl>
  2237. %% For the <code>rename</code> function, this option is
  2238. %% <code>false</code> by default. See <code>merge_sources/3</code> for
  2239. %% details.</p>
  2240. %%
  2241. %% <p><dl>
  2242. %% <dt><code>{no_headers, bool()}</code></dt>
  2243. %% <dt><code>{stub_dir, filename()}</code></dt>
  2244. %% </dl>
  2245. %% These options are preset by the <code>rename</code> function and
  2246. %% cannot be overridden by the user.</p>
  2247. %%
  2248. %% <p>See <code>merge_sources/3</code> for further options.</p>
  2249. %%
  2250. %% @see merge/3
  2251. %% @see merge_sources/3
  2252. %% @see merge_files/4
  2253. rename(Files, Renamings, Opts) ->
  2254. Dict = case is_atom_map(Renamings) of
  2255. true ->
  2256. dict:from_list(Renamings);
  2257. false ->
  2258. report_error("bad module renaming: ~P.",
  2259. [Renamings, 10]),
  2260. exit(error)
  2261. end,
  2262. %% We disable *all* automatic source code lookup, for safety: you
  2263. %% are only allowed to do renaming on a module if you give its path.
  2264. Opts1 = [{find_src_rules, []}]
  2265. ++ Opts ++ [{backup_suffix, ?DEFAULT_BACKUP_SUFFIX},
  2266. backups,
  2267. {printer, fun default_printer/2},
  2268. stubs,
  2269. {suffix, ?DEFAULT_SUFFIX},
  2270. comments,
  2271. {preprocess, false},
  2272. {tidy, false},
  2273. no_banner,
  2274. {notes, no},
  2275. {verbose, false}],
  2276. lists:flatmap(fun (F) -> rename_file(F, Dict, Opts1) end, Files).
  2277. rename_file(File, Dict, Opts) ->
  2278. S = read_module(File, Opts),
  2279. M = get_module_info(S),
  2280. Name = M#module.name,
  2281. Name1 = case dict:find(Name, Dict) of
  2282. {ok, N} -> N;
  2283. error -> Name
  2284. end,
  2285. %% We convert the dictionary to a new list to ensure that we use the
  2286. %% exact same renaming for redirections. We must remove the current
  2287. %% module from the redirection set.
  2288. Dict1 = dict:erase(Name, Dict),
  2289. Opts1 = [no_headers,
  2290. {export, [Name]},
  2291. {static, [Name]},
  2292. {redirect, dict:to_list(Dict1)}] ++ Opts,
  2293. {Tree, Stubs} = merge_sources(Name1, [S], Opts1),
  2294. Dir = filename:dirname(filename(File)),
  2295. File1 = write_module(Tree, Name1, Dir, Opts),
  2296. %% We create the stub file in the same directory as the source file
  2297. %% and the target file.
  2298. [File1 | maybe_create_stubs(Stubs, [{stub_dir, Dir} | Opts1])].
  2299. %% ---------------------------------------------------------------------
  2300. %% Initialise a module-info record with data about the module
  2301. %% represented by the syntax tree (or list of "forms"). Listed exports
  2302. %% are guaranteed to be in the set of function names.
  2303. get_module_info(Forms) ->
  2304. L = case catch {ok, erl_syntax_lib:analyze_forms(Forms)} of
  2305. {ok, L1} ->
  2306. L1;
  2307. syntax_error ->
  2308. report_error("syntax error in input."),
  2309. erlang:fault(badarg);
  2310. {'EXIT', R} ->
  2311. exit(R);
  2312. R ->
  2313. throw(R)
  2314. end,
  2315. {Name, Vars} =
  2316. case lists:keysearch(module, 1, L) of
  2317. {value, {module, {N, Vs}}} ->
  2318. {N, Vs};
  2319. {value, {module, N}} ->
  2320. {N, none};
  2321. _ ->
  2322. report_error("in source code: module name missing."),
  2323. exit(error)
  2324. end,
  2325. case lists:keysearch(errors, 1, L) of
  2326. {value, {errors, Ds}} when Ds /= [] ->
  2327. report_errors(Ds, Name),
  2328. exit(error);
  2329. _ ->
  2330. ok
  2331. end,
  2332. case lists:keysearch(warnings, 1, L) of
  2333. {value, {warnings, Ds1}} when Ds1 /= [] ->
  2334. report_warnings(Ds1, Name);
  2335. _ ->
  2336. ok
  2337. end,
  2338. Functions = case lists:keysearch(functions, 1, L) of
  2339. {value, {functions, Fs}} ->
  2340. ordsets:from_list(Fs);
  2341. _ ->
  2342. []
  2343. end,
  2344. Exports = case lists:keysearch(exports, 1, L) of
  2345. {value, {exports, Es}} ->
  2346. ordsets:from_list(Es);
  2347. _ ->
  2348. []
  2349. end,
  2350. Imports = case lists:keysearch(imports, 1, L) of
  2351. {value, {imports, Is}} ->
  2352. expand_imports(Is, Name);
  2353. _ ->
  2354. []
  2355. end,
  2356. Attributes = case lists:keysearch(attributes, 1, L) of
  2357. {value, {attributes, As}} ->
  2358. ordsets:from_list(As);
  2359. _ ->
  2360. []
  2361. end,
  2362. Records = case lists:keysearch(records, 1, L) of
  2363. {value, {records, Rs}} ->
  2364. fold_record_fields(Rs);
  2365. _ ->
  2366. []
  2367. end,
  2368. check_records(Records, Name),
  2369. #module{name = Name,
  2370. vars = Vars,
  2371. functions = Functions,
  2372. exports = ordsets:intersection(Exports, Functions),
  2373. aliases = Imports,
  2374. attributes = Attributes,
  2375. records = Records}.
  2376. fold_record_fields(Rs) ->
  2377. [{N, [fold_record_field(F) || F <- Fs]} || {N, Fs} <- Rs].
  2378. fold_record_field({Name, none}) ->
  2379. {Name, none};
  2380. fold_record_field({Name, F}) ->
  2381. case erl_syntax:is_literal(F) of
  2382. true ->
  2383. {Name, {value, erl_syntax:concrete(F)}};
  2384. false ->
  2385. %% The default value for the field is not a constant, so we
  2386. %% represent it by a hash value instead. (We don't want to
  2387. %% do this in the general case.)
  2388. {Name, {hash, erlang:phash(F, 16#ffffff)}}
  2389. end.
  2390. report_errors([D | Ds], Name) ->
  2391. report_error("error: " ++ error_text(D, Name)),
  2392. report_errors(Ds, Name);
  2393. report_errors([], _) ->
  2394. ok.
  2395. report_warnings([D | Ds], Name) ->
  2396. report_warning(error_text(D, Name)),
  2397. report_errors(Ds, Name);
  2398. report_warnings([], _) ->
  2399. ok.
  2400. error_text(D, Name) ->
  2401. case D of
  2402. {L, M, E} when integer(L), atom(M) ->
  2403. case catch M:format_error(E) of
  2404. S when list(S) ->
  2405. io_lib:fwrite("`~w', line ~w: ~s.",
  2406. [Name, L, S]);
  2407. _ ->
  2408. error_text_1(D, Name)
  2409. end;
  2410. _E ->
  2411. error_text_1(D, Name)
  2412. end.
  2413. error_text_1(D, Name) ->
  2414. io_lib:fwrite("error: `~w', ~P.", [Name, D, 15]).
  2415. check_records(Rs, Name) ->
  2416. case duplicates([N || {N, _} <- Rs]) of
  2417. [] ->
  2418. ok;
  2419. Ns ->
  2420. report_error("in module `~w': "
  2421. "multiply defined records: ~p.",
  2422. [Name, Ns]),
  2423. exit(error)
  2424. end.
  2425. expand_imports(Is, Name) ->
  2426. Fs = ordsets:from_list(lists:append([[{M, F} || F <- Fs]
  2427. || {M, Fs} <- Is])),
  2428. As = erl_syntax_lib:function_name_expansions(Fs),
  2429. case duplicates([N || {N, _} <- As]) of
  2430. [] ->
  2431. ordsets:from_list(As);
  2432. Ns ->
  2433. report_error("in module `~w': "
  2434. "multiply imported functions: ~p.",
  2435. [Name, Ns]),
  2436. exit(error)
  2437. end.
  2438. %% ---------------------------------------------------------------------
  2439. %% File handling
  2440. %% open_output_file(filename()) -> filedescriptor()
  2441. open_output_file(FName) ->
  2442. case catch file:open(FName, [write]) of
  2443. {ok, FD} ->
  2444. FD;
  2445. {error, R} ->
  2446. error_open_output(FName),
  2447. exit({error, R});
  2448. {'EXIT', R} ->
  2449. error_open_output(FName),
  2450. exit(R);
  2451. R ->
  2452. error_open_output(FName),
  2453. exit(R)
  2454. end.
  2455. %% read_module(Name, Options) -> syntaxTree()
  2456. %%
  2457. %% This also tries to locate the real source file, if "Name" does not
  2458. %% point directly to a particular file.
  2459. read_module(Name, Options) ->
  2460. case file_type(Name) of
  2461. {value, _} ->
  2462. read_module_1(Name, Options);
  2463. none ->
  2464. Rules = proplists:get_value(find_src_rules, Options),
  2465. case find_src(Name, Rules) of
  2466. {error, _} ->
  2467. %% It seems that we have no file - go on anyway,
  2468. %% just to get a decent error message.
  2469. read_module_1(Name, Options);
  2470. {Name1, _} ->
  2471. read_module_1(Name1 ++ ".erl", Options)
  2472. end
  2473. end.
  2474. read_module_1(Name, Options) ->
  2475. verbose("reading module `~s'.", [filename(Name)], Options),
  2476. Forms = read_module_2(Name, Options),
  2477. case proplists:get_bool(comments, Options) of
  2478. false ->
  2479. Forms;
  2480. true ->
  2481. Comments = erl_comment_scan:file(Name),
  2482. erl_recomment:recomment_forms(Forms, Comments)
  2483. end.
  2484. read_module_2(Name, Options) ->
  2485. case read_module_3(Name, Options) of
  2486. {ok, Forms} ->
  2487. check_forms(Forms, Name),
  2488. Forms;
  2489. {error, R} ->
  2490. error_read_file(Name),
  2491. exit({error, R})
  2492. end.
  2493. read_module_3(Name, Options) ->
  2494. case proplists:get_bool(preprocess, Options) of
  2495. false ->
  2496. epp_dodger:parse_file(Name);
  2497. true ->
  2498. read_module_4(Name, Options)
  2499. end.
  2500. read_module_4(Name, Options) ->
  2501. Includes = proplists:append_values(includes, Options)
  2502. ++ [filename:dirname(Name) | ?DEFAULT_INCLUDES],
  2503. Macros = proplists:append_values(macros, Options)
  2504. ++ ?DEFAULT_MACROS,
  2505. epp:parse_file(Name, Includes, Macros).
  2506. check_forms([F | Fs], File) ->
  2507. case erl_syntax:type(F) of
  2508. error_marker ->
  2509. S = case erl_syntax:error_marker_info(F) of
  2510. {_, M, D} ->
  2511. M:format_error(D);
  2512. _ ->
  2513. "unknown error"
  2514. end,
  2515. report_error("in file `~s' at line ~w:\n ~s",
  2516. [filename(File), erl_syntax:get_pos(F), S]),
  2517. exit(error);
  2518. _ ->
  2519. check_forms(Fs, File)
  2520. end;
  2521. check_forms([], _) ->
  2522. ok.
  2523. find_src(Name, undefined) ->
  2524. filename:find_src(filename(Name));
  2525. find_src(Name, Rules) ->
  2526. filename:find_src(filename(Name), Rules).
  2527. %% file_type(filename()) -> {value, Type} | none
  2528. file_type(Name) ->
  2529. case catch file:read_file_info(Name) of
  2530. {ok, Env} ->
  2531. {value, Env#file_info.type};
  2532. {error, enoent} ->
  2533. none;
  2534. {error, R} ->
  2535. error_read_file_info(Name),
  2536. exit({error, R});
  2537. {'EXIT', R} ->
  2538. error_read_file_info(Name),
  2539. exit(R);
  2540. R ->
  2541. error_read_file_info(Name),
  2542. throw(R)
  2543. end.
  2544. %% Create the target directory and make a backup file if necessary, then
  2545. %% open the file, output the text and close the file safely. Returns the
  2546. %% file name.
  2547. write_module(Tree, Name, Dir, Opts) ->
  2548. Name1 = filename(Name),
  2549. Dir1 = filename(Dir),
  2550. Base = if Dir1 == "" ->
  2551. Name1;
  2552. true ->
  2553. case file_type(Dir1) of
  2554. {value, directory} ->
  2555. ok;
  2556. {value, _} ->
  2557. report_error("`~s' is not a directory.",
  2558. [Dir1]),
  2559. exit(error);
  2560. none ->
  2561. case file:make_dir(Dir1) of
  2562. ok ->
  2563. verbose("created directory `~s'.",
  2564. [Dir1], Opts),
  2565. ok;
  2566. E ->
  2567. report_error("failed to create "
  2568. "directory `~s'.",
  2569. [Dir1]),
  2570. exit({make_dir, E})
  2571. end
  2572. end,
  2573. filename:join(Dir1, Name1)
  2574. end,
  2575. Suffix = proplists:get_value(suffix, Opts, ""),
  2576. File = Base ++ Suffix,
  2577. case proplists:get_bool(backups, Opts) of
  2578. true ->
  2579. backup_file(File, Opts);
  2580. false ->
  2581. ok
  2582. end,
  2583. Printer = proplists:get_value(printer, Opts),
  2584. FD = open_output_file(File),
  2585. verbose("writing to file `~s'.", [File], Opts),
  2586. V = (catch {ok, output(FD, Printer, Tree, Opts)}),
  2587. file:close(FD),
  2588. case V of
  2589. {ok, _} ->
  2590. File;
  2591. {'EXIT', R} ->
  2592. error_write_file(File),
  2593. exit(R);
  2594. R ->
  2595. error_write_file(File),
  2596. throw(R)
  2597. end.
  2598. output(FD, Printer, Tree, Opts) ->
  2599. io:put_chars(FD, Printer(Tree, Opts)),
  2600. io:nl(FD).
  2601. %% If the file exists, rename it by appending the given suffix to the
  2602. %% file name.
  2603. backup_file(Name, Opts) ->
  2604. case file_type(Name) of
  2605. {value, regular} ->
  2606. backup_file_1(Name, Opts);
  2607. {value, _} ->
  2608. error_backup_file(Name),
  2609. exit(error);
  2610. none ->
  2611. ok
  2612. end.
  2613. %% The file should exist and be a regular file here.
  2614. backup_file_1(Name, Opts) ->
  2615. Name1 = filename(Name),
  2616. Suffix = proplists:get_value(backup_suffix, Opts, ""),
  2617. Dest = filename:join(filename:dirname(Name1),
  2618. filename:basename(Name1) ++ Suffix),
  2619. case catch file:rename(Name1, Dest) of
  2620. ok ->
  2621. verbose("made backup of file `~s'.", [Name1], Opts);
  2622. {error, R} ->
  2623. error_backup_file(Name1),
  2624. exit({error, R});
  2625. {'EXIT', R} ->
  2626. error_backup_file(Name1),
  2627. exit(R);
  2628. R ->
  2629. error_backup_file(Name1),
  2630. throw(R)
  2631. end.
  2632. %% =====================================================================
  2633. %% Utility functions
  2634. %% The form sequence returned by 'erl_tidy:module' is flat, even if the
  2635. %% given tree is not.
  2636. tidy(Tree, Opts) ->
  2637. case proplists:get_bool(tidy, Opts) of
  2638. true ->
  2639. verbose("tidying final module.", Opts),
  2640. erl_tidy:module(Tree, ?TIDY_OPTS);
  2641. false ->
  2642. Tree
  2643. end.
  2644. make_attributes(As) ->
  2645. [make_attribute(A) || A <- As].
  2646. make_attribute({Name, Term}) ->
  2647. erl_syntax:attribute(erl_syntax:atom(Name),
  2648. [erl_syntax:abstract(Term)]).
  2649. is_auto_import({F, A}) ->
  2650. erl_internal:bif(F, A);
  2651. is_auto_import(_) ->
  2652. false.
  2653. timestamp() ->
  2654. {{Yr, Mth, Dy}, {Hr, Mt, Sc}} = erlang:localtime(),
  2655. lists:flatten(io_lib:fwrite("Created by Igor "
  2656. "~w-~2.2.0w-~2.2.0w, "
  2657. "~2.2.0w:~2.2.0w:~2.2.0w.",
  2658. [Yr, Mth, Dy, Hr, Mt, Sc])).
  2659. filename([C | T]) when integer(C), C > 0, C =< 255 ->
  2660. [C | filename(T)];
  2661. filename([H|T]) ->
  2662. filename(H) ++ filename(T);
  2663. filename([]) ->
  2664. [];
  2665. filename(N) when atom(N) ->
  2666. atom_to_list(N);
  2667. filename(N) ->
  2668. report_error("bad filename: `~P'.", [N, 25]),
  2669. exit(error).
  2670. duplicates(Xs) ->
  2671. ordsets:from_list(Xs -- ordsets:from_list(Xs)).
  2672. split_list(F, L) ->
  2673. split_list(L, F, [], []).
  2674. split_list([H | T], F, A1, A2) ->
  2675. case F(H) of
  2676. true ->
  2677. split_list(T, F, [H | A1], A2);
  2678. false ->
  2679. split_list(T, F, A1, [H | A2])
  2680. end;
  2681. split_list([], _, A1, A2) ->
  2682. {lists:reverse(A1), lists:reverse(A2)}.
  2683. rewrite(Source, Target) ->
  2684. erl_syntax:copy_attrs(Source, Target).
  2685. comment_note([L | Ls]) ->
  2686. comment([?NOTE_HEADER ++ L | Ls], ?NOTE_PREFIX).
  2687. comment(Txt) ->
  2688. comment(Txt, ?COMMENT_PREFIX).
  2689. comment(Txt, Prefix) ->
  2690. erl_syntax:comment(prefix_lines(split_lines(Txt), Prefix)).
  2691. prefix_lines([L | Ls], Prefix) ->
  2692. [Prefix ++ L | prefix_lines(Ls, Prefix)];
  2693. prefix_lines([], _) ->
  2694. [].
  2695. split_lines(Ls) ->
  2696. split_lines(Ls, []).
  2697. split_lines([L | Ls], Ls1) ->
  2698. split_lines(Ls, split_lines(L, [], Ls1));
  2699. split_lines([], Ls1) ->
  2700. lists:reverse(Ls1).
  2701. split_lines([$\r, $\n | Cs], Cs1, Ls) ->
  2702. split_lines_1(Cs, Cs1, Ls);
  2703. split_lines([$\r | Cs], Cs1, Ls) ->
  2704. split_lines_1(Cs, Cs1, Ls);
  2705. split_lines([$\n | Cs], Cs1, Ls) ->
  2706. split_lines_1(Cs, Cs1, Ls);
  2707. split_lines([C | Cs], Cs1, Ls) ->
  2708. split_lines(Cs, [C | Cs1], Ls);
  2709. split_lines([], Cs, Ls) ->
  2710. [lists:reverse(Cs) | Ls].
  2711. split_lines_1(Cs, Cs1, Ls) ->
  2712. split_lines(Cs, [], [lists:reverse(Cs1) | Ls]).
  2713. %% =====================================================================
  2714. %% Reporting
  2715. warning_unsafe_call(Name, Module, Target) ->
  2716. report_warning("call to `~w' in module `~w' "
  2717. "possibly unsafe in `~w'.", [Name, Module, Target]).
  2718. warning_apply_2(Module, Target) ->
  2719. report_warning("call to `apply/2' in module `~w' "
  2720. "possibly unsafe in `~w'.", [Module, Target]).
  2721. error_open_output(Name) ->
  2722. report_error("cannot open file `~s' for output.", [filename(Name)]).
  2723. error_read_file(Name) ->
  2724. report_error("error reading file `~s'.", [filename(Name)]).
  2725. error_read_file_info(Name) ->
  2726. report_error("error getting file info: `~s'.", [filename(Name)]).
  2727. error_write_file(Name) ->
  2728. report_error("error writing to file `~s'.", [filename(Name)]).
  2729. error_backup_file(Name) ->
  2730. report_error("could not create backup of file `~s'.",
  2731. [filename(Name)]).
  2732. verbose(S, Opts) ->
  2733. verbose(S, [], Opts).
  2734. verbose(S, Vs, Opts) ->
  2735. case proplists:get_bool(verbose, Opts) of
  2736. true ->
  2737. report(S, Vs);
  2738. false ->
  2739. ok
  2740. end.
  2741. report_error(S) ->
  2742. report_error(S, []).
  2743. report_error(S, Vs) ->
  2744. report(S, Vs).
  2745. report_warning(S) ->
  2746. report_warning(S, []).
  2747. report_warning(S, Vs) ->
  2748. report("warning: " ++ S, Vs).
  2749. % report(S) ->
  2750. % report(S, []).
  2751. report(S, Vs) ->
  2752. io:fwrite(lists:concat([?MODULE, ": ", S, "\n"]), Vs).