erl_id_trans.erl

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

ERL
519
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(erl_id_trans).%% A identity transformer of Erlang abstract syntax.%% This module only traverses legal Erlang code. This is most noticeable%% in guards where only a limited number of expressions are allowed.%% N.B. if this module is to be used as a basis for tranforms then%% all the error cases must be handled otherwise this module just crashes!-export([parse_transform/2]).parse_transform(Forms, _Options) ->    forms(Forms).%% forms(Fs) -> lists:map(fun (F) -> form(F) end, Fs).forms([F0|Fs0]) ->    F1 = form(F0),    Fs1 = forms(Fs0),    [F1|Fs1];forms([]) -> [].%% -type form(Form) -> Form.%%  Here we show every known form and valid internal structure. We do not%%  that the ordering is correct!%% First the various attributes.form({attribute,Line,module,Mod}) ->    {attribute,Line,module,Mod};form({attribute,Line,file,{File,Line}}) ->	%This is valid anywhere.    {attribute,Line,file,{File,Line}};form({attribute,Line,export,Es0}) ->    Es1 = farity_list(Es0),    {attribute,Line,export,Es1};form({attribute,Line,import,{Mod,Is0}}) ->    Is1 = farity_list(Is0),    {attribute,Line,import,{Mod,Is1}};form({attribute,Line,compile,C}) ->    {attribute,Line,compile,C};form({attribute,Line,record,{Name,Defs0}}) ->    Defs1 = record_defs(Defs0),    {attribute,Line,record,{Name,Defs1}};form({attribute,Line,asm,{function,N,A,Code}}) ->    {attribute,Line,asm,{function,N,A,Code}};form({attribute,Line,Attr,Val}) ->		%The general attribute.    {attribute,Line,Attr,Val};form({function,Line,Name0,Arity0,Clauses0}) ->    {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0),    {function,Line,Name,Arity,Clauses};% Mnemosyne, ignore...form({rule,Line,Name,Arity,Body}) ->    {rule,Line,Name,Arity,Body}; % Dont dig into this%% Extra forms from the parser.form({error,E}) -> {error,E};form({warning,W}) -> {warning,W};form({eof,Line}) -> {eof,Line}.%% -type farity_list([Farity]) -> [Farity] when Farity <= {atom(),integer()}.farity_list([{Name,Arity}|Fas]) ->    [{Name,Arity}|farity_list(Fas)];farity_list([]) -> [].%% -type record_defs([RecDef]) -> [RecDef].%%  N.B. Field names are full expressions here but only atoms are allowed%%  by the *parser*!record_defs([{record_field,Line,{atom,La,A},Val0}|Is]) ->    Val1 = expr(Val0),    [{record_field,Line,{atom,La,A},Val1}|record_defs(Is)];record_defs([{record_field,Line,{atom,La,A}}|Is]) ->    [{record_field,Line,{atom,La,A}}|record_defs(Is)];record_defs([]) -> [].%% -type function(atom(), integer(), [Clause]) -> {atom(),integer(),[Clause]}.function(Name, Arity, Clauses0) ->    Clauses1 = clauses(Clauses0),    {Name,Arity,Clauses1}.%% -type clauses([Clause]) -> [Clause].clauses([C0|Cs]) ->    C1 = clause(C0),    [C1|clauses(Cs)];clauses([]) -> [].%% -type clause(Clause) -> Clause.clause({clause,Line,H0,G0,B0}) ->    H1 = head(H0),    G1 = guard(G0),    B1 = exprs(B0),    {clause,Line,H1,G1,B1}.%% -type head([Pattern]) -> [Pattern].head(Ps) -> patterns(Ps).%% -type patterns([Pattern]) -> [Pattern].%%  These patterns are processed "sequentially" for purposes of variable%%  definition etc.patterns([P0|Ps]) ->    P1 = pattern(P0),    [P1|patterns(Ps)];patterns([]) -> [].%% -type pattern(Pattern) -> Pattern.%%  N.B. Only valid patterns are included here.pattern({var,Line,V}) -> {var,Line,V};pattern({match,Line,L0,R0}) ->    L1 = pattern(L0),    R1 = pattern(R0),    {match,Line,L1,R1};pattern({integer,Line,I}) -> {integer,Line,I};pattern({char,Line,C}) -> {char,Line,C};pattern({float,Line,F}) -> {float,Line,F};pattern({atom,Line,A}) -> {atom,Line,A};pattern({string,Line,S}) -> {string,Line,S};pattern({nil,Line}) -> {nil,Line};pattern({cons,Line,H0,T0}) ->    H1 = pattern(H0),    T1 = pattern(T0),    {cons,Line,H1,T1};pattern({tuple,Line,Ps0}) ->    Ps1 = pattern_list(Ps0),    {tuple,Line,Ps1};%%pattern({struct,Line,Tag,Ps0}) ->%%    Ps1 = pattern_list(Ps0),%%    {struct,Line,Tag,Ps1};pattern({record,Line,Name,Pfs0}) ->    Pfs1 = pattern_fields(Pfs0),    {record,Line,Name,Pfs1};pattern({record_index,Line,Name,Field0}) ->    Field1 = pattern(Field0),    {record_index,Line,Name,Field1};%% record_field occurs in query expressionspattern({record_field,Line,Rec0,Name,Field0}) ->    Rec1 = expr(Rec0),    Field1 = expr(Field0),    {record_field,Line,Rec1,Name,Field1};pattern({record_field,Line,Rec0,Field0}) ->    Rec1 = expr(Rec0),    Field1 = expr(Field0),    {record_field,Line,Rec1,Field1};pattern({bin,Line,Fs}) ->    Fs2 = pattern_grp(Fs),    {bin,Line,Fs2};pattern({op,Line,Op,A}) ->    {op,Line,Op,A};pattern({op,Line,Op,L,R}) ->    {op,Line,Op,L,R}.pattern_grp([{bin_element,L1,E1,S1,T1} | Fs]) ->    S2 = case S1 of	     default ->		 default;	     _ ->		 expr(S1)	 end,    T2 = case T1 of	     default ->		 default;	     _ ->		 bit_types(T1)	 end,    [{bin_element,L1,expr(E1),S2,T2} | pattern_grp(Fs)];pattern_grp([]) ->    [].bit_types([]) ->    [];bit_types([Atom | Rest]) when atom(Atom) ->    [Atom | bit_types(Rest)];bit_types([{Atom, Integer} | Rest]) when atom(Atom), integer(Integer) ->    [{Atom, Integer} | bit_types(Rest)].%% -type pattern_list([Pattern]) -> [Pattern].%%  These patterns are processed "in parallel" for purposes of variable%%  definition etc.pattern_list([P0|Ps]) ->    P1 = pattern(P0),    [P1|pattern_list(Ps)];pattern_list([]) -> [].%% -type pattern_fields([Field]) -> [Field].%%  N.B. Field names are full expressions here but only atoms are allowed%%  by the *linter*!.pattern_fields([{record_field,Lf,{atom,La,F},P0}|Pfs]) ->    P1 = pattern(P0),    [{record_field,Lf,{atom,La,F},P1}|pattern_fields(Pfs)];pattern_fields([{record_field,Lf,{var,La,'_'},P0}|Pfs]) ->    P1 = pattern(P0),    [{record_field,Lf,{var,La,'_'},P1}|pattern_fields(Pfs)];pattern_fields([]) -> [].%% -type guard([GuardTest]) -> [GuardTest].guard([G0|Gs]) when list(G0) ->    [guard0(G0) | guard(Gs)];guard(L) ->    guard0(L).guard0([G0|Gs]) ->    G1 =  guard_test(G0),    [G1|guard0(Gs)];guard0([]) -> [].guard_test(Expr={call,Line,{atom,La,F},As0}) ->    case erl_internal:type_test(F, length(As0)) of	true -> 	    As1 = gexpr_list(As0),	    {call,Line,{atom,La,F},As1};	_ ->	    gexpr(Expr)    end;guard_test(Any) ->    gexpr(Any).%% Before R9, there were special rules regarding the expressions on%% top level in guards. Those limitations are now lifted - therefore%% there is no need for a special clause for the toplevel expressions.%% -type gexpr(GuardExpr) -> GuardExpr.gexpr({var,Line,V}) -> {var,Line,V};gexpr({integer,Line,I}) -> {integer,Line,I};gexpr({char,Line,C}) -> {char,Line,C};gexpr({float,Line,F}) -> {float,Line,F};gexpr({atom,Line,A}) -> {atom,Line,A};gexpr({string,Line,S}) -> {string,Line,S};gexpr({nil,Line}) -> {nil,Line};gexpr({cons,Line,H0,T0}) ->    H1 = gexpr(H0),    T1 = gexpr(T0),				%They see the same variables    {cons,Line,H1,T1};gexpr({tuple,Line,Es0}) ->    Es1 = gexpr_list(Es0),

⌨️ 快捷键说明

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