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

📄 igor.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
%% `Tree' represents the source code that is the result of%% merging all the code in `Sources' and `Files',%% and `Stubs' is a list of stub module descriptors (see%% `merge_sources/3' for details).%%%% Options:%% <dl>%%   <dt>`{comments, bool()}'</dt>%%%%     <dd>If the value is `true', source code comments in%%     the original files will be preserved in the output. The default%%     value is `true'.</dd>%%%%   <dt>`{find_src_rules, [{string(), string()}]}'</dt>%%%%     <dd>Specifies a list of rules for associating object files with%%     source files, to be passed to the function%%     `filename:find_src/2'. This can be used to change the%%     way Igor looks for source files. If this option is not specified,%%     the default system rules are used. The first occurrence of this%%     option completely overrides any later in the option list.</dd>%%%%   <dt>`{includes, [filename()]}'</dt>%%%%     <dd>Specifies a list of directory names for the Erlang%%     preprocessor, if used, to search for include files (cf. the%%     `preprocess' option). The default value is the empty%%     list. The directory of the source file and the current directory%%     are automatically appended to the list.</dd>%%%%   <dt>`{macros, [{atom(), term()}]}'</dt>%%%%     <dd>Specifies a list of "pre-defined" macro definitions for the%%     Erlang preprocessor, if used (cf. the `preprocess'%%     option). The default value is the empty list.</dd>%%%%   <dt>`{preprocess, bool()}'</dt>%%%%     <dd>If the value is `false', Igor will read source%%     files without passing them through the Erlang preprocessor%%     (`epp'), in order to avoid expansion of preprocessor%%     directives such as `-include(...).',%%     `-define(...).' and `-ifdef(...)', and%%     macro calls such as `?LINE' and `?MY_MACRO(x,%%     y)'. The default value is `false', i.e.,%%     preprocessing is not done. (See the module%%     `epp_dodger' for details.)%%%%     Notes: If a file contains too exotic definitions or uses of%%     macros, it will not be possible to read it without preprocessing.%%     Furthermore, Igor does not currently try to sort out multiple%%     inclusions of the same file, or redefinitions of the same macro%%     name. Therefore, when preprocessing is turned off, it may become%%     necessary to edit the resulting source code, removing such%%     re-inclusions and redefinitions.</dd>%% </dl>%%%% See `merge_sources/3' for further options.%%%% @see merge/3%% @see merge_files/3%% @see merge_sources/3%% @see //stdlib/filename:find_src/2%% @see epp_dodgermerge_files(_, _Trees, [], _) ->    report_error("no files to merge."),    exit(badarg);merge_files(Name, Trees, Files, Opts) ->    Opts1 = Opts ++ [{includes, ?DEFAULT_INCLUDES},		     {macros, ?DEFAULT_MACROS},		     {preprocess, false},		     comments],    Sources = [read_module(F, Opts1) || F <- Files],    merge_sources(Name, Trees ++ Sources, Opts1).%% =====================================================================%% @spec merge_sources(Name::atom(), Sources::[Forms],%%                     Options::[term()]) ->%%           {syntaxTree(), [stubDescriptor()]}%%%%     Forms = syntaxTree() | [syntaxTree()]%%%% @type stubDescriptor() = [{ModuleName, Functions, [Attribute]}]%%	    ModuleName = atom()%%	    Functions = [{FunctionName, {ModuleName, FunctionName}}]%%	    FunctionName = {atom(), integer()}%%	    Attribute = {atom(), term()}.%%%%      A stub module descriptor contains the module name, a list of%%      exported functions, and a list of module attributes. Each%%      function is described by its name (which includes its arity),%%      and the corresponding module and function that it calls. (The%%      arities should always match.) The attributes are simply%%      described by key-value pairs.%%%% @doc Merges syntax trees to a single syntax tree. This is the main%% code merging "engine". `Name' specifies the name of the%% resulting module. `Sources' is a list of syntax trees of%% type `form_list' and/or lists of "source code form" syntax%% trees, each entry representing a module definition. All the input%% modules must be distinctly named.%%%% Unless otherwise specified by the options, all modules are assumed%% to be at least "static", and all except the target module are assumed%% to be "safe". See the `static' and `safe'%% options for details.%%%% If `Name' is also the name of one of the input modules,%% the code from that module will occur at the top of the resulting%% code, and no extra "header" comments will be added. In other words,%% the look of that module will be preserved.%%%% The result is a pair `{Tree, Stubs}', where%% `Tree' represents the source code that is the result of%% merging all the code in `Sources', and `Stubs'%% is a list of stub module descriptors (see below).%%%% `Stubs' contains one entry for each exported input%% module (cf. the `export' option), each entry describing a%% stub module that redirects calls of functions in the original module%% to the corresponding (possibly renamed) functions in the new module.%% The stub descriptors can be used to automatically generate stub%% modules; see `create_stubs/2'.%%%% Options:%% <dl>%%   <dt>`{export, [atom()]}'</dt>%%%%     <dd>Specifies a list of names of input modules whose interfaces%%     should be exported by the output module. A stub descriptor is%%     generated for each specified module, unless its name is%%     `Name'. If no modules are specified, then if%%     `Name' is also the name of an input module, that%%     module will be exported; otherwise the first listed module in%%     `Sources' will be exported. The default value is the%%     empty list.</dd>%%%%   <dt>`{export_all, bool()}'</dt>%%%%     <dd>If the value is `true', this is equivalent to%%     listing all of the input modules in the `export'%%     option. The default value is `false'.</dd>%%%% <dt>`{file_attributes, Preserve}'</dt>%%     <dd><ul>%%       <li>`Preserve = yes | comment | no'</li>%%     </ul>%%     If the value is `yes', all file attributes%%     `-file(...)' in the input sources will be preserved in%%     the resulting code. If the value is `comment', they%%     will be turned into comments, but remain in their original%%     positions in the code relative to the other source code forms. If%%     the value is `no', all file attributes will be removed%%     from the code, unless they have attached comments, in which case%%     they will be handled as in the `comment' case. The%%     default value is `no'.</dd>%%%% <dt>`{no_banner, bool()}'</dt>%%%%     <dd>If the value is `true', no banner comment will be%%     added at the top of the resulting module, even if the target%%     module does not have the same name as any of the input modules.%%     Instead, Igor will try to preserve the look of the module whose%%     code is at the top of the output. The default value is%%     `false'.</dd>%%%% <dt>`{no_headers, bool()}'</dt>%%%%     <dd>If the value is `true', no header comments will be%%     added to the resulting module at the beginning of each section of%%     code that originates from a particular input module. The default%%     value is `false', which means that section headers are%%     normally added whenever more than two or more modules are%%     merged.</dd>%%%% <dt>`{no_imports, bool()}'</dt>%%%%     <dd>If the value is `true', all%%     `-import(...)' declarations in the original code will%%     be expanded in the result; otherwise, as much as possible of the%%     original import declarations will be preserved. The default value%%     is `false'.</dd>%%%% <dt>`{notes, Notes}'</dt>%%     <dd><ul>%%       <li>`Notes = always | yes | no'</li>%%     </ul>%%     If the value is `yes', comments will be inserted where%%     important changes have been made in the code. If the value is%%     `always', <em>all</em> changes to the code will be%%     commented. If the value is `no', changes will be made%%     without comments. The default value is `yes'.</dd>%%%% <dt>`{redirect, [{atom(), atom()}]}'</dt>%%%%     <dd>Specifies a list of pairs of module names, representing a%%     mapping from old names to new. <em>The set of old names may not%%     include any of the names of the input modules.</em> All calls to%%     the listed old modules will be rewritten to refer to the%%     corresponding new modules. <em>The redirected calls will not be%%     further processed, even if the new destination is in one of the%%     input modules.</em> This option mainly exists to support module%%     renaming; cf. `rename/3'. The default value is the%%     empty list.</dd>%%%% <dt>`{safe, [atom()]}'</dt>%%%%     <dd>Specifies a list of names of input modules such that calls to%%     these "safe" modules may be turned into direct local calls, that%%     do not test for code replacement. Typically, this can be done for%%     e.g. standard library modules. If a module is "safe", it is per%%     definition also "static" (cf. below). The list may be empty. By%%     default, all involved modules <em>except the target module</em>%%     are considered "safe".</dd>%%%% <dt>`{static, [atom()]}'</dt>%%%%     <dd>Specifies a list of names of input modules which will be%%     assumed never to be replaced (reloaded) unless the target module%%     is also first replaced. The list may be empty. The target module%%     itself (which may also be one of the input modules) is always%%     regarded as "static", regardless of the value of this option. By%%     default, all involved modules are assumed to be static.</dd>%%%% <dt>`{tidy, bool()}'</dt>%%%%     <dd>If the value is `true', the resulting code will be%%     processed using the `erl_tidy' module, which removes%%     unused functions and does general code cleanup. (See%%     `erl_tidy:module/2' for additional options.) The%%     default value is `true'.</dd>%%%% <dt>`{verbose, bool()}'</dt>%%%%     <dd>If the value is `true', progress messages will be%%     output while the program is running; the default value is%%     `false'.</dd>%% </dl>%%%% Note: The distinction between "static" and "safe" modules is%% necessary in order not to break the semantics of dynamic code%% replacement. A "static" source module will not be replaced unless the%% target module also is. Now imagine a state machine implemented by%% placing the code for each state in a separate module, and suppose%% that we want to merge this into a single target module, marking all%% source modules as static. At each point in the original code where a%% call is made from one of the modules to another (i.e., the state%% transitions), code replacement is expected to be detected. Then, if%% we in the merged code do not check at these points if the%% <em>target</em> module (the result of the merge) has been replaced,%% we can not be sure in general that we will be able to do code%% replacement of the merged state machine - it could run forever%% without detecting the code change. Therefore, all such calls must%% remain remote-calls (detecting code changes), but may call the target%% module directly.%%%% If we are sure that this kind of situation cannot ensue, we may%% specify the involved modules as "safe", and all calls between them%% will become local. Note that if the target module itself is specified%% as safe, "remote" calls to itself will be turned into local calls.%% This would destroy the code replacement properties of e.g. a typical%% server loop.%%%% @see create_stubs/2%% @see rename/3%% @see erl_tidy:module/2%% Currently, there is no run-time support in Erlang for detecting%% whether some module has been changed since the current module was%% loaded. Therefore, if a source module is specified as non-static, not%% much will be gained from merging: a call to a non-static module will%% remain a remote call using the old module name, even when it is%% performed from within the merged code. If that module is specified as%% exported, the old name could then refer to an auto-generated stub,%% redirecting the call back to the corresponding function in the target%% module. This could possibly be useful in some cases, but efficiency%% is not improved by such a transformation. If support for efficient%% testing for module updates is added to Erlang in future versions,%% code merging will be able to use local calls even for non-static%% source modules, opening the way for compiler optimisations over the%% module boundaries.%% Data structure for merging environment.-record(merge, {target,		% = atom()		sources,	% = ordset(atom())		export,		% = ordset(atom())		static,		% = ordset(atom())		safe,		% = ordset(atom())		preserved,	% = bool()		no_headers,	% = bool()		notes,		% = bool()		redirect,	% = dict(atom(), atom())		no_imports,	% = ordset(atom())		options		% = [term()]	       }).merge_sources(Name, Sources, Opts) ->    %% Prepare the options and the inputs.    Opts1 = Opts ++ [{export_all, false},		     {file_attributes, no},		     {no_imports, false},		     {notes, yes},		     tidy,		     {verbose, false}],    Trees = case Sources of		[] ->		    report_error("no sources to merge."),		    exit(badarg);		_ ->		    [if is_list(M) -> erl_syntax:form_list(M);			true -> M		     end		     || M <- Sources]	    end,    %% There must be at least one module to work with.    Modules = [get_module_info(T) || T <- Trees],    merge_sources_1(Name, Modules, Trees, Opts1).%% Data structure for keeping state during transformation.-record(state, {export}).state__add_export(Name, Arity, S) ->    S#state{export = sets:add_element({Name, Arity},				      S#state.export)}.merge_sources_1(Name, Modules, Trees, Opts) ->    %% Get the (nonempty) list of source module names, in the given    %% order. Multiple occurrences of the same source module name are    %% not accepted.    Ns = [M#module.name || M <- Modules],    case duplicates(Ns) of	[] ->	    ok;	Ns1 ->	    report_error("same module names repeated in input: ~p.",			 [Ns1]),	    exit(error)    end,    Sources = ordsets:from_list(Ns),    All = ordsets:add_element(Name, Sources),    %% Initialise the merging environment from the given options.    %%    %% If the `export' option is the empty list, then if the target    %% module is the same as one of the sources, that module will be    %% exported; otherwise the first listed source module is exported.    %% This simplifies use in most cases, and guarantees that the    %% generated module has a well-defined interface. If `export_all' is    %% `true', we expand it here by including the set of source module    %% names.    Es = case proplists:append_values(export, Opts) of	     [] ->		 case ordsets:is_element(Name, Sources) of		     true ->			 [Name];		     false ->			 [hd(Ns)]		 end;	     Es1 when is_list(Es1) ->		 ordsets:from_list(Es1)	 end,    Export = case proplists:get_bool(export_all, Opts) of		 false ->		     Es;		 true ->		     ordsets:union(Sources, Es)	     end,    check_module_names(Export, Sources, "declared as exported"),    verbose("modules exported from `~w': ~p.", [Name, Export], Opts),    %% The target module is always "static". (Particularly useful when

⌨️ 快捷键说明

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