⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 igor.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
%% =====================================================================%% This library is free software; you can redistribute it and/or modify%% it under the terms of the GNU Lesser General Public License as%% published by the Free Software Foundation; either version 2 of the%% License, or (at your option) any later version.%%%% This library is distributed in the hope that it will be useful, but%% WITHOUT ANY WARRANTY; without even the implied warranty of%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU%% Lesser General Public License for more details.%%%% You should have received a copy of the GNU Lesser General Public%% License along with this library; if not, write to the Free Software%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307%% USA%%%% $Id$%%%% @copyright 1998-2006 Richard Carlsson%% @author Richard Carlsson <richardc@it.uu.se>%% @end%% =====================================================================%% @doc Igor: the Module Merger and Renamer.%%%% The program Igor merges the source code of one or more Erlang%% modules into a single module, which can then replace the original set%% of modules. Igor is also able to rename a set of (possibly%% interdependent) modules, without joining them into a single%% module.%%%% The main user interface consists of the functions {@link merge/3} and%% {@link rename/3}. See also the function {@link parse_transform/2}.%%%% A note of warning: Igor cannot do anything about the case when the%% name of a remote function is passed to the built-in functions%% `apply' and `spawn' <em>unless</em> the module%% and function names are explicitly stated in the call, as in e.g.%% `apply(lists, reverse, [Xs])'. In all other cases, Igor%% leaves such calls unchanged, and warns the user that manual editing%% might be necessary.%%%% Also note that Erlang records will be renamed as necessary to%% avoid non-equivalent definitions using the same record name. This%% does not work if the source code accesses the name field of such%% record tuples by `element/2' or similar methods. Always%% use the record syntax to handle record tuples, if possible.%%%% Disclaimer: the author of this program takes no responsibility for%% the correctness of the produced output, or for any effects of its%% execution. In particular, the author may not be held responsible%% should Igor include the code of a deceased madman in the result.%%%% For further information on Igors in general, see e.g. "Young%% Frankenstein", Mel Brooks, 1974, and "The Fifth Elephant", Terry%% Pratchett, 1999.%% @end%% =====================================================================%% This program is named after the character Igor, assistant to Dr.%% Frankenstein, in the 1939 film "Son of Frankenstein" (with Boris%% Karloff playing The Monster for the last time; Igor was played by%% Bela Lugosi). Igor's job (in the film) was mainly to bring reasonably%% fresh parts of various human corpses to the good Doctor, for his%% purpose of reanimating them in the shape of a new formidable, living%% creature.%%%% Merging code is done by joining the sources, possibly changing the%% order of declarations as necessary, renaming functions and records to%% avoid name clashes, and changing remote calls to local calls where%% possible. Stub modules may be automatically generated to redirect any%% calls that still use the old names. Indirectly, code merging can be%% used to simply rename a set of modules.%%%% What Igor does not do is to optimise the resulting code, which%% typically can benefit from techniques such as inlining, constant%% folding, specialisation, etc. This task is left to the Doctor.%% (Luckily, Igor can call on Inga to do some cleanup; cf. 'erl_tidy'.)%% TODO: FIXME: don't remove module qualifier if name is (auto-)imported!%% TODO: handle merging of parameterized modules (somehow).%% TODO: check for redefinition of macros; check equivalence; comment out.%% TODO: {export, [E]}, E = atom() | {atom(), atom(), integer()}.%% TODO: improve documentation. %% TODO: optionally rename all functions from specified (or all) modules.-module(igor).-export([create_stubs/2, merge/2, merge/3, merge_files/3, merge_files/4,	 merge_sources/3, parse_transform/2, rename/2, rename/3]).-include_lib("kernel/include/file.hrl").%% =====================================================================%% Global Constants-define(NOTE_HEADER, "Note from Igor: ").-define(COMMENT_PREFIX, "% ").-define(COMMENT_BAR,	"======================="	"======================="	"=======================").-define(NOTE_PREFIX, "%! ").-define(KILL_PREFIX, "%<<< ").-define(DEFAULT_INCLUDES, ["."]).-define(DEFAULT_MACROS, []).-define(DEFAULT_SUFFIX, ".erl").-define(DEFAULT_BACKUP_SUFFIX, ".bak").-define(DEFAULT_DIR, "").-define(DEFAULT_STUB_DIR, "stubs").-define(TIDY_OPTS, [quiet]).%% This may also be used in patterns. R must not be an integer, i.e.,%% the structure must be distinct from function names.-define(record_name(R), {record, R}).%% Data structure for module information-record(module, {name,		% = atom()		 vars = none,	% = [atom()] | none		 functions,	% = ordset({atom(), int()})		 exports,	% = ordset({atom(), int()})				% | ordset({{atom(), int()},				%	    term()})		 aliases,	% = ordset({{atom(), int()},				%	    {atom(),				%	     {atom(), int()}}})		 attributes,	% = ordset({atom(), term()})		 records	% = [{atom(), [{atom(), term()}]}]		}).%% The default pretty-printing function.default_printer(Tree, Options) ->    erl_prettypr:format(Tree, Options).%% =====================================================================%% @spec parse_transform(Forms::[syntaxTree()], Options::[term()]) ->%%           [syntaxTree()]%%%%         syntaxTree() = erl_syntax:syntaxTree()%%%% @doc Allows Igor to work as a component of the Erlang compiler.%% Including the term `{parse_transform, igor}' in the%% compile options when compiling an Erlang module (cf.%% `compile:file/2'), will call upon Igor to process the%% source code, allowing automatic inclusion of other source files. No%% files are created or overwritten when this function is used.%%%% Igor will look for terms `{igor, List}' in the compile%% options, where `List' is a list of Igor-specific options,%% as follows:%% <dl>%%  <dt>`{files, [filename()]}'</dt>%%    <dd>The value specifies a list of source files to be merged with%%    the file being compiled; cf. `merge_files/4'.</dd>%% </dl>%%%% See `merge_files/4' for further options. Note, however,%% that some options are preset by this function and cannot be%% overridden by the user; in particular, all cosmetic features are%% turned off, for efficiency. Preprocessing is turned on.%%%% @see merge_files/4%% @see //compiler/compile:file/2parse_transform(Forms, Options) ->    M = get_module_info(Forms),    Name = M#module.name,    Opts = proplists:append_values(igor, Options),    Files = proplists:append_values(files, Opts),    %% We turn off all features that are only cosmetic, and make sure to    %% turn on preservation of `file' attributes.    Opts1 = [{comments, false},	     {notes, no},	     {no_imports, true},	     {file_attributes, yes},	     {preprocess, true},	     {export, [Name]}	     | Opts],    {T, _} = merge_files(Name, [Forms], Files, Opts1),    verbose("done.", Opts1),    erl_syntax:revert_forms(T).%% =====================================================================%% @spec merge(Name::atom(), Files::[filename()]) -> [filename()]%% @equiv merge(Name, Files, [])merge(Name, Files) ->    merge(Name, Files, []).%% =====================================================================%% @spec merge(Name::atom(), Files::[filename()], Options::[term()]) ->%%           [filename()]%%%%	    filename() = file:filename()%%%% @doc Merges source code files to a single file. `Name'%% specifies the name of the resulting module - not the name of the%% output file. `Files' is a list of file names and/or module%% names of source modules to be read and merged (see%% `merge_files/4' for details). All the input modules must%% be distinctly named.%%%% The resulting source code is written to a file named%% "`<em>Name</em>.erl'" in the current directory, unless%% otherwise specified by the options `dir' and%% `outfile' described below.%%%% Examples:%% <ul>%%   <li>given a module `m' in file "`m.erl'"%%   which uses the standard library module `lists', calling%%   `igor:merge(m, [m, lists])' will create a new file%%   "`m.erl' which contains the code from `m' and%%   exports the same functions, and which includes the referenced code%%   from the `lists' module. The original file will be%%   renamed to "`m.erl.bak'".</li>%%%%   <li>given modules `m1' and `m2', in%%   corresponding files, calling `igor:merge(m, [m1, m2])'%%   will create a file "`m.erl'" which contains the code%%   from `m1' and `m2' and exports the functions%%   of `m1'.</li>%% </ul>%%%% Stub module files are created for those modules that are to be%% exported by the target module (see options `export',%% `stubs' and `stub_dir').%%%% The function returns the list of file names of all created%% modules, including any automatically created stub modules. The file%% name of the target module is always first in the list.%%%% Note: If you get a "syntax error" message when trying to merge%% files (and you know those files to be correct), then try the%% `preprocess' option. It typically means that your code%% contains too strange macros to be handled without actually performing%% the preprocessor expansions.%% %% Options:%% <dl>%%   <dt>`{backup_suffix, string()}'</dt>%%%%     <dd>Specifies the file name suffix to be used when a backup file%%     is created; the default value is `".bak"'.</dd>%%%%   <dt>`{backups, bool()}'</dt>%%%%     <dd>If the value is `true', existing files will be%%     renamed before new files are opened for writing. The new names%%     are formed by appending the string given by the%%     `backup_suffix' option to the original name. The%%     default value is `true'.</dd>%%%%   <dt>`{dir, filename()}'</dt>%%%%     <dd>Specifies the name of the directory in which the output file%%     is to be written. An empty string is interpreted as the current%%     directory. By default, the current directory is used.</dd>%%%%   <dt>`{outfile, filename()}'</dt>%%%%     <dd>Specifies the name of the file (without suffix) to which the%%     resulting source code is to be written. By default, this is the%%     same as the `Name' argument.</dd>%%%%   <dt>`{preprocess, bool()}'</dt>%%%%     <dd>If the value is `true', preprocessing will be done%%     when reading the source code. See `merge_files/4' for%%     details.</dd>%%%%   <dt>`{printer, Function}'</dt>%%     <dd><ul>%%       <li>`Function = (syntaxTree()) -> string()'</li>%%     </ul>%%     Specifies a function for prettyprinting Erlang syntax trees.%%     This is used for outputting the resulting module definition, as%%     well as for creating stub files. The function is assumed to%%     return formatted text for the given syntax tree, and should raise%%     an exception if an error occurs. The default formatting function%%     calls `erl_prettypr:format/2'.</dd>%%%%   <dt>`{stub_dir, filename()}'</dt>%%%%     <dd>Specifies the name of the directory to which any generated%%     stub module files are written. The default value is%%     `"stubs"'.</dd>%%%%   <dt>`{stubs, bool()}'</dt>%%%%     <dd>If the value is `true', stub module files will be%%     automatically generated for all exported modules that do not have%%     the same name as the target module. The default value is%%     `true'.</dd>%%%%   <dt>`{suffix, string()}'</dt>%%%%     <dd>Specifies the suffix to be used for the output file names;%%     the default value is `".erl"'.</dd>%% </dl>%%%% See `merge_files/4' for further options.%%%% @see merge/2%% @see merge_files/4%% The defaults for 'merge' are also used for 'create_stubs'.-define(DEFAULT_MERGE_OPTS,	[{backup_suffix, ?DEFAULT_BACKUP_SUFFIX},	 backups, 	 {dir, ?DEFAULT_DIR},	 {printer, fun default_printer/2},	 {stub_dir, ?DEFAULT_STUB_DIR},	 stubs,	 {suffix, ?DEFAULT_SUFFIX},	 {verbose, false}]).merge(Name, Files, Opts) ->    Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,    {Tree, Stubs} = merge_files(Name, Files, Opts1),    Dir = proplists:get_value(dir, Opts1, ""),    Filename = proplists:get_value(outfile, Opts1, Name),    File = write_module(Tree, Filename, Dir, Opts1),    [File | maybe_create_stubs(Stubs, Opts1)].%% =====================================================================%% @spec merge_files(Name::atom(), Files::[filename()],%%                   Options::[term()]) ->%%           {syntaxTree(), [stubDescriptor()]}%% @equiv merge_files(Name, [], Files, Options)merge_files(Name, Files, Options) ->    merge_files(Name, [], Files, Options).%% =====================================================================%% @spec merge_files(Name::atom(), Sources::[Forms],%%                   Files::[filename()], Options::[term()]) ->%%           {syntaxTree(), [stubDescriptor()]}%%     Forms = syntaxTree() | [syntaxTree()]%%%% @doc Merges source code files and syntax trees to a single syntax%% tree. This is a file-reading front end to%% `merge_sources/3'. `Name' specifies the name of%% the resulting module - not the name of the output file.%% `Sources' is a list of syntax trees and/or lists of%% "source code form" syntax trees, each entry representing a module%% definition. `Files' is a list of file names and/or module%% names of source modules to be read and included. All the input%% modules must be distinctly named.%%%% If a name in `Files' is not the name of an existing%% file, Igor assumes it represents a module name, and tries to locate%% and read the corresponding source file. The parsed files are appended%% to `Sources' and passed on to%% `merge_sources/3', i.e., entries in `Sources'%% are listed before entries read from files.%%%% If no exports are listed by an `export' option (see%% `merge_sources/3' for details), then if `Name'%% is also the name of one of the input modules, that module will be%% exported; otherwise, the first listed module will be exported. Cf.%% the examples under `merge/3'.%%%% The result is a pair `{Tree, Stubs}', where

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -