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

📄 igor.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
    Split = fun (M) ->		    ordsets:is_element(M#module.name, Export)	    end,    {M1, M2} = split_list(Split, Modules),    R = dict:new(),    Acc = {sets:new(), R},    {M3, Acc1} = merge_namespaces_1(M1, Acc),    %% Detect and warn about renamed interface functions    {_, Maps0} = Acc1,    case [{M, dict:to_list(Map)}	  || {M, Map} <- dict:to_list(Maps0), dict:size(Map) /= 0] of	[] ->	    ok;	Fs ->	    report_warning("interface functions renamed:\n\t~p.",			   [Fs])    end,    {M4, Acc2} = merge_namespaces_1(M2, Acc1),    Ms = M3 ++ M4,    Acc3 = merge_namespaces_2(Ms, Acc2),    {{Names, Maps}, _} = merge_namespaces_3(Ms, Acc3),    {Names, make_renaming_function(Maps)}.%% Adding exported names. (Note that the list gets a new temporary%% format also containing the exports.) This first step initialises the%% Maps "dict-of-dicts" structure.merge_namespaces_1(Modules, Acc) ->    lists:mapfoldl(      fun (Module, {Names, Maps}) ->	      Exports = sets:from_list(Module#module.exports),	      M = Module#module.name,	      {Names1, Map} = add_function_renamings(M, Exports, Names,						     dict:new()),	      Maps1 = dict:store(M, Map, Maps),	      {{Module, Exports}, {Names1, Maps1}}      end,      Acc, Modules).%% Adding nonexported names.merge_namespaces_2(Modules, Acc) ->    lists:foldl(      fun ({Module, Exports}, {Names, Maps}) ->	      Other = sets:subtract(			sets:from_list(Module#module.functions),			Exports),	      M = Module#module.name,	      Map = dict:fetch(M, Maps),	      {Names1, Map1} = add_function_renamings(M, Other, Names,						      Map),	      Maps1 = dict:store(M, Map1, Maps),	      {Names1, Maps1}      end,      Acc, Modules).%% Adding record names. We need to keep a global%% "record-definition-to-new-record-name" mapping RMap while doing this.merge_namespaces_3(Modules, Acc) ->    lists:foldl(      fun ({Module, _Exports}, {{Names, Maps}, RMap}) ->	      Records = Module#module.records,	      M = Module#module.name,	      Map = dict:fetch(M, Maps),	      {Names1, Map1, RMap1} = add_record_renamings(M, Records,							   Names, Map,							   RMap),	      Maps1 = dict:store(M, Map1, Maps),	      {{Names1, Maps1}, RMap1}      end,      {Acc, dict:new()}, Modules).%% This takes the set of added function names together with the existing%% name set, creates new function names where necessary, and returns the%% final name set together with the list of renamings.add_function_renamings(Module, New, Names, Map) ->    Clashes = sets:to_list(sets:intersection(New, Names)),    lists:foldl(      fun (F = {_, A}, {Names, Map}) when is_integer(A) ->	      F1 = new_function_name(Module, F, Names),	      {sets:add_element(F1, Names), dict:store(F, F1, Map)}      end,      {sets:union(New, Names), Map}, Clashes).%% This is similar to the above, but for record names. Note that we add%% both the record name and the whole definition to the namespace.add_record_renamings(Module, Records, Names, Map, RMap) ->    lists:foldl(      fun (N = {R, Fs}, {Names, Map, RMap}) ->	      case sets:is_element(?record_name(R), Names) of		  true ->		      %% The name is already in use.		      case sets:is_element(?record_name(N), Names) of			  true ->			      %% We have seen this definition before;			      %% make sure we use the same name.			      {R1, _} = remap_record_name(N, RMap),			      Map1 = dict:store(?record_name(R),						?record_name(R1), Map),			      {Names, Map1, RMap};			  false ->			      %% Redefinition of existing name. Create			      %% new name and set up renamings.			      N1 = {R1, _} = new_record_name(Module, R,							     Fs, Names),			      Map1 = dict:store(?record_name(R),						?record_name(R1), Map),			      RMap1 = dict:store(N, N1, RMap),			      Names1 = sets:add_element(?record_name(N1),							Names),			      {Names1, Map1, RMap1}		      end;		  false ->		      %% A previously unused record name.		      Names1 = sets:add_element(?record_name(R), Names),		      Names2 = sets:add_element(?record_name(N), Names1),		      {Names2, Map, RMap}	      end      end,      {Names, Map, RMap}, Records).remap_record_name(N, Map) ->    case dict:find(N, Map) of	{ok, N1} -> N1;	error -> N    end.%% This hides the implementation of the record namespace. Since Map%% yields identity for non-remapped names, the remapped names must be%% stored in wrapped form.map_record_name(R, Map) ->    ?record_name(R1) = Map(?record_name(R)),    R1.%% When we rename a function, we want the new name to be as close as%% possible to the old, and as informative as possible. Therefore, we%% first prefix it with the name of the originating module, followed by%% two underscore characters, and then if there still is a name clash,%% we suffix the name by "_N", where N is the smallest possible positive%% integer that does not cause a clash.new_function_name(M, {F, A}, Names) ->    Base = atom_to_list(M) ++ "__" ++ atom_to_list(F),    Name = {list_to_atom(Base), A},    case sets:is_element(Name, Names) of	false ->	    Name;	true ->	    new_function_name(1, A, Base, Names)    end.new_function_name(N, Arity, Base, Names) ->    Name = {list_to_atom(Base ++ "_" ++ integer_to_list(N)),	    Arity},    case sets:is_element(Name, Names) of	false ->	    Name;	true ->	    %% Increment counter and try again.	    new_function_name(N + 1, Arity, Base, Names)    end.%% This is pretty much the same as new_function_name, for now.new_record_name(M, R, Fs, Names) ->    Base = atom_to_list(M) ++ "__" ++ atom_to_list(R),    Name = {list_to_atom(Base), Fs},    case sets:is_element(?record_name(Name), Names) of	false ->	    Name;	true ->	    new_record_name_1(1, Base, Fs, Names)    end.new_record_name_1(N, Base, Fs, Names) ->    Name = {list_to_atom(Base ++ "_" ++ integer_to_list(N)), Fs},    case sets:is_element(?record_name(Name), Names) of	false ->	    Name;	true ->	    %% Increment counter and try again.	    new_record_name_1(N + 1, Base, Fs, Names)    end.%% This returns a *total* function from the set of module names to the%% set of *total* operators on function names, yielding identity for all%% function names that are not specified in the given partial map%% (ModuleName -> (Name -> Name)).make_renaming_function(Maps) ->    fun (Module) ->	    case dict:find(Module, Maps) of		{ok, Map} ->		    fun (Name) ->			    case dict:find(Name, Map) of				{ok, Name1} ->				    Name1;    % renamed				error ->				    Name    % identity			    end		    end;		error ->		    %% Other module - yield identity map.		    fun (Name) -> Name end	    end    end.%% ---------------------------------------------------------------------%% Merging module info records into a target module record, and finding%% necessary alias expansions. Returns `{Module, Expansions}' where%% `Expansions' has type `dict(ModuleName, dict(Alias, FullName))'merge_info(Modules, Names, Renaming, Env) ->    Forbid = sets:from_list(Env#merge.no_imports),    Expansions = alias_expansions(Modules, Names, Forbid),    Module = merge_info_1(Modules, Renaming, Expansions, Env),    {Module, Expansions}.merge_info_1(Modules, Renaming, Expansions, Env) ->    lists:foldl(      fun (M, A) ->	      Name = M#module.name,	      Map = Renaming(Name),	      Functions = join_functions(Map,					 M#module.functions,					 A#module.functions),	      Exports = join_exports(Env, Name, Map,				     M#module.exports,				     A#module.exports),	      Aliases = join_aliases(Name, Expansions,				     M#module.aliases,				     A#module.aliases),	      Attributes = join_attributes(Env, Name,					   M#module.attributes,					   A#module.attributes),	      Records = join_records(Map,				     M#module.records,				     A#module.records),	      A#module{functions = Functions,		       exports = Exports,		       aliases = Aliases,		       attributes = Attributes,		       records = Records}      end,      #module{name = Env#merge.target,	      functions = ordsets:new(),	      exports = ordsets:new(),	      aliases = ordsets:new(),	      attributes = ordsets:new(),	      records = ordsets:new()},      Modules).%% Functions must be renamed before including.join_functions(Map, Source, Target) ->    ordsets:union(ordsets:from_list([Map(A) || A <- Source]),		  Target).%% Exports also need renaming, and are kept only if their originating%% modules are exported.join_exports(Env, Name, Map, Source, Target) ->    case ordsets:is_element(Name, Env#merge.export) of	true ->	    ordsets:union(ordsets:from_list([Map(F)					     || F <- Source]),			  Target);	false ->	    Target    end.%% Aliases never need renaming; instead we always expand uses which%% could cause name clashes. We must then remove the expanded names from%% the imports of the target.join_aliases(Name, Expansions, Source, Target) ->    As = case dict:find(Name, Expansions) of	     {ok, As1} ->		 ordsets:from_list(dict:to_list(As1));	     error ->		 []	 end,    ordsets:union(ordsets:subtract(Source, As), Target).%% We only propagate attributes if the number of source modules is 1 or%% the source module has the same name as the resulting module.join_attributes(Env, Name, Source, Target) ->    if Env#merge.target == Name ->	    ordsets:union(Source, Target);       true ->	    if length(Env#merge.sources) =:= 1 ->		    ordsets:union(Source, Target);	       true ->		    Target	    end    end.%% The final record info in itself is not used at present, but we%% compute the join anyway. We apply renaming to records much like we do%% to functions, but records have a separate namespace.join_records(Map, Source, Target) ->    Renamed = [{map_record_name(R, Map), Fs} || {R, Fs} <- Source],    ordsets:union(ordsets:from_list(Renamed), Target).%% This finds aliases that are in conflict or are for other reasons%% necessary to expand while transforming the code later. It is assumed%% that each module is in itself correct, and thus does not contain%% conflicting definitions of the same alias.%%%% We could of course simply say that *all* aliases, without exception,%% should be expanded, but such a big change in the style of the code%% should not be done unless the user explicitly specifies it.%%%% The returned `Expansions' is a dictionary (module `dict') mapping%% each module name in `Modules' to a dictionary which maps those%% aliases to be expanded for that module to their corresponding full%% names.%%%% Aliases are filtered according to the following rules:%%%%	1. If a name is defined (in some source module) as an alias of a%%	name `M:...', where `M' is any of the source modules(*), then%%	the definition of that alias should be removed, and all its uses%%	(in the same module as the definition) be expanded.%%%%	2. Then, if a name is defined (in some source module) as an%%	alias, but the name occurs in the name space of the resulting%%	module, then the definition should be removed and all uses (in%%	the same module) expanded.%%%%	3. Finally, if a name has two or more distinct alias definitions%%	in the source modules, then all definitions of that alias should%%	be removed and all uses (in all modules) expanded. (We remove%%	all definitions mainly for symmetry.)%%%%	(*) It is actually possible for an alias to refer to the module%%	in which it is itself defined. However, since we also in this%%	case want to expand all uses, we don't have to do any extra work%%	to handle it.%% The filtering is done in two stages.alias_expansions(Modules, Names, Forbid) ->    Table = alias_expansions_1(Modules, Forbid, Names),    alias_expansions_2(Modules, Table).%% First consider each alias in isolation.alias_expansions_1(Modules, Forbid, Names) ->    lists:foldl(      fun (M, T) ->	      Map = lists:foldl(		      fun ({A, F}, T1) ->			      case keep_alias(A, F, Forbid, Names)				  of				  true ->				      T1;				  false ->				      dict:store(A, F, T1)			      end		      end,		      dict:new(), M#module.aliases),	      dict:store(M#module.name, Map, T)      end,      dict:new(), Modules).keep_alias(A, {M, _}, Forbid, Names) ->

⌨️ 快捷键说明

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