ms_transform.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 982 行 · 第 1/2 页

ERL
982
字号
				     L) ->					 NV = tg(Value,B),					 [{Key,NV}|L];				    ({record_field,_,{var,_,'_'},Value},				     L) ->					 NV = tg(Value,B),					 [{{default},NV}|L];				    (_,_) ->					 throw({error,Line,						{?ERR_GENBADREC+B#tgd.eb,						 RName}})				 end,				 [],				 RFields),    DefValue = case lists:keysearch({default},1,KeyList0) of		   {value,{{default},OverriddenDefValue}} ->		       {true,OverriddenDefValue};		   _ ->		       false	       end,    KeyList = lists:keydelete({default},1,KeyList0),    case lists:keysearch({default},1,KeyList) of	{value,{{default},_}} ->	    throw({error,Line,{?ERR_GENMULTIFIELD+B#tgd.eb,RName,'_'}});	_ ->	    ok    end,    case lists:keysearch(RName,1,RDefs) of	{value, {RName, FieldList0}} ->	    FieldList1 = lists:foldl(			   fun({FN,_,Def},Acc) ->				   El = case lists:keysearch(FN,1,KeyList) of					    {value, {FN, X0}} ->						X0;					    _ ->						case DefValue of 						    {true,Overridden} ->							Overridden;						    false ->							Def						end					end,				   [El | Acc]			   end,			   [],			   FieldList0),	    check_multi_field(RName,Line,KeyList,				 ?ERR_GENMULTIFIELD+B#tgd.eb),	    check_undef_field(RName,Line,KeyList,FieldList0,			      ?ERR_GENBADFIELD+B#tgd.eb),	    {tuple,Line,[{tuple,Line,[{atom,Line,RName}|FieldList1]}]};	_ ->	    throw({error,Line,{?ERR_GENBADREC+B#tgd.eb,RName}})    end;tg({record_index,Line,RName,{atom,Line2,KeyName}},B) ->    RDefs = get_records(),     case lists:keysearch(RName,1,RDefs) of	{value, {RName, FieldList}} ->	    case lists:keysearch(KeyName,1, FieldList) of		{value, {KeyName,Position,_}} ->		    {integer, Line2, Position};		_ ->		    throw({error,Line2,{?ERR_GENBADFIELD+B#tgd.eb, RName, 				       KeyName}})	    end;	_ ->	    throw({error,Line,{?ERR_GENBADREC+B#tgd.eb,RName}})    end;tg({record,Line,{var,Line2,_VName}=AVName, RName,RFields},B) ->    RDefs = get_records(),    MSVName = tg(AVName,B),    KeyList = lists:foldl(fun({record_field,_,{atom,_,Key},Value},				     L) ->					 NV = tg(Value,B),					 [{Key,NV}|L];				    (_,_) ->					 throw({error,Line,?ERR_HEADBADREC})				 end,				 [],				 RFields),    case lists:keysearch(RName,1,RDefs) of	{value, {RName, FieldList0}} ->	    FieldList1 = lists:foldl(			   fun({FN,Pos,_},Acc) ->				   El = case lists:keysearch(FN,1,KeyList) of					    {value, {FN, X0}} ->						X0;					    _ ->						{tuple, Line2, 						 [{atom, Line2, element},						  {integer, Line2, Pos},						  MSVName]}					end,				   [El | Acc]			   end,			   [],			   FieldList0),	    check_multi_field(RName,Line,KeyList,				 ?ERR_GENMULTIFIELD+B#tgd.eb),	    check_undef_field(RName,Line,KeyList,FieldList0,			      ?ERR_GENBADFIELD+B#tgd.eb),	    {tuple,Line,[{tuple,Line,[{atom,Line,RName}|FieldList1]}]};	_ ->	    throw({error,Line,{?ERR_GENBADREC+B#tgd.eb,RName}})    end;tg({bin_element,_Line0,{var, Line, A},_,_} = Whole,B) ->    case lkup_bind(A, B#tgd.b) of	undefined ->	    Whole; % exists in environment hopefully	_AtomName ->	    throw({error,Line,{?ERR_GENBINCONSTRUCT+B#tgd.eb,A}})    end;    tg(default,_B) ->    default;tg({bin_element,Line,X,Y,Z},B) ->    {bin_element, Line, tg(X,B), tg(Y,B), Z};tg({bin,Line,List},B) ->    {bin,Line,[tg(X,B) || X <- List]};    tg(T,B) when is_tuple(T), size(T) >= 2 ->    Element = element(1,T),    Line = element(2,T),    throw({error,Line,{?ERR_GENELEMENT+B#tgd.eb,		       translate_language_element(Element)}}); tg(Other,B) ->    Element = io_lib:format("unknown element ~w", [Other]),    throw({error,unknown,{?ERR_GENELEMENT+B#tgd.eb,Element}}).transform_head([V]) ->    Bind = cre_bind(),    {NewV,NewBind} = toplevel_head_match(V,Bind),    th(NewV,NewBind).toplevel_head_match({match,_,{var,_,VName},Expr},B) ->    {Expr,new_bind({VName,'$_'},B)};toplevel_head_match({match,_,Expr,{var,_,VName}},B) ->    {Expr,new_bind({VName,'$_'},B)};toplevel_head_match(Other,B) ->    {Other,B}.th({record,Line,RName,RFields},B) ->    % youch...    RDefs = get_records(),    {KeyList0,NewB} = lists:foldl(fun({record_field,_,{atom,_,Key},Value},				     {L,B0}) ->					 {NV,B1} = th(Value,B0),					 {[{Key,NV}|L],B1};				    ({record_field,_,{var,_,'_'},Value},				     {L,B0}) ->					 {NV,B1} = th(Value,B0),					 {[{{default},NV}|L],B1};				    (_,_) ->					 throw({error,Line,{?ERR_HEADBADREC,							    RName}})				 end,				 {[],B},				 RFields),    DefValue = case lists:keysearch({default},1,KeyList0) of		   {value,{{default},OverriddenDefValue}} ->		       OverriddenDefValue;		   _ ->		       {atom,Line,'_'}	       end,    KeyList = lists:keydelete({default},1,KeyList0),    case lists:keysearch({default},1,KeyList) of	{value,{{default},_}} ->	    throw({error,Line,{?ERR_HEADMULTIFIELD,RName,'_'}});	_ ->	    ok    end,    case lists:keysearch(RName,1,RDefs) of	{value, {RName, FieldList0}} ->	    FieldList1 = lists:foldl(			   fun({FN,_,_},Acc) ->				   El = case lists:keysearch(FN,1,KeyList) of					    {value, {FN, X0}} ->						X0;					    _ ->						DefValue					end,				   [El | Acc]			   end,			   [],			   FieldList0),	    check_multi_field(RName,Line,KeyList,				 ?ERR_HEADMULTIFIELD),	    check_undef_field(RName,Line,KeyList,FieldList0,			      ?ERR_HEADBADFIELD),	    {{tuple,Line,[{atom,Line,RName}|FieldList1]},NewB};	_ ->	    throw({error,Line,{?ERR_HEADBADREC,RName}})    end;th({match,Line,_,_},_) ->     throw({error,Line,?ERR_HEADMATCH});th({atom,Line,A},B) ->    case atom_to_list(A) of	[$$|NL] ->	    case (catch list_to_integer(NL)) of		N when is_integer(N) ->		    throw({error,Line,{?ERR_HEADDOLLARATOM,A}});		_ ->		    {{atom,Line,A},B}	    end;	_ ->	    {{atom,Line,A},B}    end;th({bin_element,_Line0,{var, Line, A},_,_},_) ->    throw({error,Line,{?ERR_HEADBINMATCH,A}});th({var,Line,Name},B) ->    case lkup_bind(Name,B) of	undefined ->	    NewB = new_bind(Name,B),	    {{atom,Line,lkup_bind(Name,NewB)},NewB};	Trans ->	    {{atom,Line,Trans},B}    end;th([H|T],B) ->    {NH,NB} = th(H,B),    {NT,NNB} = th(T,NB),    {[NH|NT],NNB};th(T,B) when is_tuple(T) ->    {L,NB} = th(tuple_to_list(T),B),    {list_to_tuple(L),NB};th(Nonstruct,B) ->    {Nonstruct,B}.% Could be more efficient...check_multi_field(_,_,[],_) ->    ok;check_multi_field(RName, Line, [{Key,_}|T], ErrCode) ->    case lists:keysearch(Key,1,T) of	{value,_} ->	    throw({error,Line,{ErrCode,RName,Key}});	_ ->	    check_multi_field(RName, Line, T, ErrCode)    end.check_undef_field(_,_,[],_,_) ->    ok;check_undef_field(RName, Line, [{Key,_}|T], FieldList, ErrCode) ->    case lists:keysearch(Key,1,FieldList) of	{value,_} ->	    check_undef_field(RName, Line, T, FieldList, ErrCode); 	_ ->	    throw({error,Line,{ErrCode,RName,Key}})    end.cre_bind() ->    {1,[{'_','_'}]}.lkup_bind(Name,{_,List}) ->    case lists:keysearch(Name,1,List) of	{value, {Name, Trans}} ->	    Trans;	_ ->	    undefined    end.new_bind({Name,Trans},{Next,L}) ->    {Next,[{Name,Trans}|L]};new_bind(Name,{Next,L}) ->    Trans = list_to_atom([$$|integer_to_list(Next)]),    {Next+1,[{Name,Trans}|L]}.translate_language_element(Atom) ->    Transtab = [		{lc,"list comprehension"},		{bc,"binary comprehension"},		{block, "begin/end block"},		{'if', "if"},		{'case', "case"},		{'receive', "receive"},		{'try', "try"},		{'catch', "catch"},		{'match', "match (=)"},		{remote, "external function call"}	       ],    case lists:keysearch(Atom,1,Transtab) of	{value,{Atom, String}} ->	    String;	_ ->	    atom_to_list(Atom)    end.old_bool_test(atom,1) -> is_atom;old_bool_test(constant,1) -> is_constant;old_bool_test(float,1) -> is_float;old_bool_test(integer,1) -> is_integer;old_bool_test(list,1) -> is_list;old_bool_test(number,1) -> is_number;old_bool_test(pid,1) -> is_pid;old_bool_test(port,1) -> is_port;old_bool_test(reference,1) -> is_reference;old_bool_test(tuple,1) -> is_tuple;old_bool_test(binary,1) -> is_binary;old_bool_test(function,1) -> is_function;old_bool_test(record,2) -> is_record;old_bool_test(_,_) -> undefined.bool_test(is_atom,1) -> true;bool_test(is_constant,1) -> true;bool_test(is_float,1) -> true;bool_test(is_integer,1) -> true;bool_test(is_list,1) -> true;bool_test(is_number,1) -> true;bool_test(is_pid,1) -> true;bool_test(is_port,1) -> true;bool_test(is_reference,1) -> true;bool_test(is_tuple,1) -> true;bool_test(is_binary,1) -> true;bool_test(is_function,1) -> true;bool_test(is_record,2) -> true;bool_test(is_seq_trace,0) -> true;bool_test(_,_) -> false.real_guard_function(abs,1) -> true;real_guard_function(element,2) -> true;real_guard_function(hd,1) -> true;real_guard_function(length,1) -> true;real_guard_function(node,0) -> true;real_guard_function(node,1) -> true;real_guard_function(round,1) -> true;real_guard_function(size,1) -> true;real_guard_function(tl,1) -> true;real_guard_function(trunc,1) -> true;real_guard_function(self,0) -> true;real_guard_function(float,1) -> true;real_guard_function(_,_) -> false.pseudo_guard_function(get_tcw,0) -> true;pseudo_guard_function(_,_) -> false.guard_function(X,A) ->    real_guard_function(X,A) or pseudo_guard_function(X,A).action_function(set_seq_token,2) -> true;action_function(get_seq_token,0) -> true;action_function(message,1) -> true;action_function(return_trace,0) -> true;action_function(process_dump,0) -> true;action_function(enable_trace,1) -> true;action_function(enable_trace,2) -> true;action_function(disable_trace,1) -> true;action_function(disable_trace,2) -> true;action_function(display,1) -> true;action_function(caller,0) -> true;action_function(set_tcw,1) -> true;action_function(silent,1) -> true;action_function(_,_) -> false.bool_operator('and',2) ->    true;bool_operator('or',2) ->    true;bool_operator('xor',2) ->    true;bool_operator('not',1) ->    true;bool_operator('andalso',2) ->    true;bool_operator('orelse',2) ->    true;bool_operator(_,_) ->    false.arith_operator('+',1) ->    true;arith_operator('+',2) ->    true;arith_operator('-',1) ->    true;arith_operator('-',2) ->    true;arith_operator('*',2) ->    true;arith_operator('/',2) ->    true;arith_operator('div',2) ->    true;arith_operator('rem',2) ->    true;arith_operator('band',2) ->    true;arith_operator('bor',2) ->    true;arith_operator('bxor',2) ->    true;arith_operator('bnot',1) ->    true;arith_operator('bsl',2) ->    true;arith_operator('bsr',2) ->    true;arith_operator(_,_) ->    false.cmp_operator('>',2) ->    true;cmp_operator('>=',2) ->    true;cmp_operator('<',2) ->    true;cmp_operator('=<',2) ->    true;cmp_operator('==',2) ->    true;cmp_operator('=:=',2) ->    true;cmp_operator('/=',2) ->     true;cmp_operator('=/=',2) ->    true;cmp_operator(_,_) ->    false.is_operator(X,A,_) ->    bool_operator(X,A) or arith_operator(X,A) or cmp_operator(X,A).is_imported_from_erlang(X,A,_) ->    real_guard_function(X,A) or bool_test(X,A) or bool_operator(X,A) or    arith_operator(X,A) or cmp_operator(X,A).is_ms_function(X,A,body) ->    action_function(X,A) or guard_function(X,A) or bool_test(X,A);is_ms_function(X,A,guard) ->    guard_function(X,A) or bool_test(X,A).fixup_environment(L,B) when is_list(L) ->        lists:map(fun(X) ->		      fixup_environment(X,B) 	      end,	      L);fixup_environment({var,Line,Name},B) ->    case lists:keysearch(Name,1,B) of	{value,{Name,Value}} -> 	    freeze(Line,Value);	_ ->	    throw({error,Line,{?ERR_UNBOUND_VARIABLE,atom_to_list(Name)}})    end;fixup_environment(T,B) when is_tuple(T) ->    list_to_tuple(      lists:map(fun(X) ->			fixup_environment(X,B) 		end,		tuple_to_list(T)));fixup_environment(Other,_B) ->    Other.    freeze(Line,Term) ->    {frozen,Line,Term}.% Most of this is bluntly stolen from erl_parse.normalise({frozen,_,Term}) ->    Term;normalise({char,_,C}) -> C;normalise({integer,_,I}) -> I;normalise({float,_,F}) -> F;normalise({atom,_,A}) -> A;normalise({string,_,S}) -> S;normalise({nil,_}) -> [];normalise({bin,_,Fs}) ->    {value, B, _} =	eval_bits:expr_grp(Fs, [],			   fun(E, _) ->				   {value, normalise(E), []}			   end, [], true),    B;normalise({cons,_,Head,Tail}) ->    [normalise(Head)|normalise(Tail)];normalise({tuple,_,Args}) ->    list_to_tuple(normalise_list(Args));%% Special case for unary +/-.normalise({op,_,'+',{char,_,I}}) -> I;normalise({op,_,'+',{integer,_,I}}) -> I;normalise({op,_,'+',{float,_,F}}) -> F;normalise({op,_,'-',{char,_,I}}) -> -I;		%Weird, but compatible!normalise({op,_,'-',{integer,_,I}}) -> -I;normalise({op,_,'-',{float,_,F}}) -> -F.normalise_list([H|T]) ->    [normalise(H)|normalise_list(T)];normalise_list([]) ->    [].

⌨️ 快捷键说明

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