erl_parse.yrl

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

YRL
912
字号
mkop(L, {Op,Pos}, R) -> {op,Pos,Op,L,R}.mkop({Op,Pos}, A) -> {op,Pos,Op,A}.%% keep track of line info in tokensline(Tup) -> element(2, Tup).%% Entry points compatible to old erl_parse.%% These really suck and are only here until Calle gets multiple%% entry points working.parse_form(Tokens) ->    parse(Tokens).parse_exprs(Tokens) ->    case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of	{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} ->	    {ok,Exprs};	{error,E} -> {error,E}    end.parse_term(Tokens) ->    case parse([{atom,0,f},{'(',0},{')',0},{'->',0}|Tokens]) of	{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[Expr]}]}} ->	    case catch normalise(Expr) of		{'EXIT',_R} ->		    {error,{line(Expr),?MODULE,"bad term"}};		Term -> {ok,Term}	    end;	{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],[_E1,E2|_Es]}]}} ->	    {error,{line(E2),?MODULE,"bad term"}};	{error,E} -> {error,E}    end.build_type({atom,_,any}, []) -> {type, any, []};build_type({atom,_,atom}, []) -> {type, atom, []};build_type({atom,_,binary}, []) -> {type, binary, []};build_type({atom,_,bool}, []) -> {type, bool, []};build_type({atom,_,byte}, []) -> {type, byte, []};build_type({atom,_,char}, []) -> {type, char, []};build_type({atom,_,float}, []) -> {type, float, []};build_type({atom,_,function}, []) -> {type, 'fun', []};build_type({atom,_,identifier}, []) -> {type, identifier, []};build_type({atom,_,integer}, []) -> {type, integer, []};build_type({atom,_,list}, []) -> {type, list, []};build_type({atom,_,mfa}, []) -> {type, mfa, []};build_type({atom,_,neg_integer}, []) -> {type, neg_integer, []};build_type({atom,_,non_neg_integer}, []) -> {type, non_neg_integer, []};build_type({atom,_,none}, []) -> {type, none, []};build_type({atom,_,nonempty_list}, [C,T]) -> {type, cons, [C,T]};build_type({atom,_,nonempty_possibly_improper_list}, []) ->     {type, cons, []};build_type({atom,_,nonempty_posssibly_improper_list}, [C,T]) ->     {type, cons, [C, T]};build_type({atom,_,number}, []) -> {type, number, []};build_type({atom,_,pid}, []) -> {type, pid, []};build_type({atom,_,port}, []) -> {type, port, []};build_type({atom,_,pos_integer}, []) -> {type, pos_integer, []};build_type({atom,_,possibly_improper_list}, [C,T]) ->     {type, pos_improper_list, [C,T]};build_type({atom,_,possibly_improper_list}, []) ->     {type, pos_improper_list, []};build_type({atom,_,ref}, []) -> {type, ref, []};build_type({atom,_,string}, []) -> {type, string, []};build_type({atom,_,tuple}, []) -> {type, tuple, []};build_type({atom,_,Other}, []) -> {type, var, [Other]}.build_typed_attribute({atom,La,record}, [{atom,_Ln,RecordName},RecTuple]) ->    {attribute,La,record,{RecordName,record_tuple(RecTuple)}};build_typed_attribute({atom,La,spec}, [{op,_Lo,'/',{atom,_La,FunName},				                   {integer,_Li,FunArity}},				       	TypeSpec])  ->    {attribute,La,type_spec,{{FunName,FunArity},TypeSpec}};build_typed_attribute({atom,La,_},_) ->    error_bad_decl(La,spec).lift_unions(T1, {type, union, List}) ->    {type, union, [T1|List]};lift_unions(T1, T2 = {type, _, _}) ->    {type, union, [T1, T2]}.%% build_attribute(AttrName, AttrValue) ->%%	{attribute,Line,module,Module}%%	{attribute,Line,export,Exports}%%	{attribute,Line,import,Imports}%%	{attribute,Line,record,{Name,Inits}}%%	{attribute,Line,file,{Name,Line}}%%	{attribute,Line,Name,Val}build_attribute({atom,La,module}, Val) ->    case Val of	[{atom,_Lm,Module}] ->	    {attribute,La,module,Module};	[{atom,_Lm,Module},ExpList] ->	    {attribute,La,module,{Module,var_list(ExpList)}};	[Name] ->	    case package_segments(Name) of		error ->		    error_bad_decl(La, module);		Module ->		    {attribute,La,module,Module}	    end;	[Name,ExpList] ->	    case package_segments(Name) of		error ->		    error_bad_decl(La, module);		Module ->		    {attribute,La,module,{Module,var_list(ExpList)}}	    end;	_Other ->	    error_bad_decl(La, module)    end;build_attribute({atom,La,export}, Val) ->    case Val of	[ExpList] ->	    {attribute,La,export,farity_list(ExpList)};	_Other -> error_bad_decl(La, export)    end;build_attribute({atom,La,import}, Val) ->    case Val of	[Name] ->	    case package_segments(Name) of		error ->		    error_bad_decl(La, import);		Module ->		    {attribute,La,import,Module}	    end;	[{atom,_Lm,Mod},ImpList] ->	    {attribute,La,import,{Mod,farity_list(ImpList)}};	[Name, ImpList] ->	    case package_segments(Name) of		error ->		    error_bad_decl(La, import);		Module ->		    {attribute,La,import,{Module,farity_list(ImpList)}}	    end;	_Other -> error_bad_decl(La, import)    end;build_attribute({atom,La,record}, Val) ->    case Val of	[{atom,_Ln,Record},RecTuple] ->	    {attribute,La,record,{Record,record_tuple(RecTuple)}};	_Other -> error_bad_decl(La, record)    end;build_attribute({atom,La,file}, Val) ->    case Val of	[{string,_Ln,Name},{integer,_Ll,Line}] ->	    {attribute,La,file,{Name,Line}};	_Other -> error_bad_decl(La, file)    end;build_attribute({atom,La,Attr}, Val) ->    case Val of	[Expr] ->	    {attribute,La,Attr,term(Expr)};	_Other -> return_error(La, "bad attribute")    end.var_list({cons,_Lc,{var,_,V},Tail}) ->    [V|var_list(Tail)];var_list({nil,_Ln}) -> [];var_list(Other) ->    return_error(line(Other), "bad variable list").error_bad_decl(L, S) ->    return_error(L, io_lib:format("bad ~w declaration", [S])).farity_list({cons,_Lc,{op,_Lo,'/',{atom,_La,A},{integer,_Li,I}},Tail}) ->    [{A,I}|farity_list(Tail)];farity_list({nil,_Ln}) -> [];farity_list(Other) ->    return_error(line(Other), "bad function arity").record_tuple({tuple,_Lt,Fields}) ->    record_fields(Fields);record_tuple(Other) ->    return_error(line(Other), "bad record declaration").%%record_fields([{atom,La,A}|Fields]) ->%%    [{record_field,La,{atom,La,A},{atom,La,undefined},{type, any, []}}%%     |record_fields(Fields)];%%record_fields([{match,_Lm,{atom,La,A},Expr}|Fields]) ->%%    [{record_field,La,{atom,La,A},Expr,{type, any, []}}%%     |record_fields(Fields)];%%record_fields([{typed,Expr,TypeInfo}|Fields]) ->%%    [{record_field,La,FieldName,Init,_BogusTypeInfo}] = record_fields([Expr]),%%    [{record_field,La,FieldName,Init,TypeInfo}|record_fields(Fields)];%%record_fields([Other|_Fields]) ->%%    return_error(line(Other), "bad record field");%%record_fields([]) -> [].record_fields([{atom,La,A}|Fields]) ->    [{record_field,La,{atom,La,A}}|record_fields(Fields)];record_fields([{match,_Lm,{atom,La,A},Expr}|Fields]) ->    [{record_field,La,{atom,La,A},Expr}|record_fields(Fields)];record_fields([{typed,Expr,TypeInfo}|Fields]) ->    [Field] = record_fields([Expr]),    TypeInfo1 = 	case Expr of	    {match, _, _, _} -> TypeInfo; %% If we have an initializer.	    {atom, _, _} -> lift_unions({type, atom, ['undefined']}, TypeInfo)	end,     [{typed_record_field,Field,TypeInfo1}|record_fields(Fields)];record_fields([Other|_Fields]) ->    return_error(line(Other), "bad record field");record_fields([]) -> [].term(Expr) ->    case catch normalise(Expr) of	{'EXIT',_R} -> return_error(line(Expr), "bad attribute");	Term -> Term    end.package_segments(Name) ->    package_segments(Name, [], []).package_segments({record_field, _, F1, F2}, Fs, As) ->    package_segments(F1, [F2 | Fs], As);package_segments({atom, _, A}, [F | Fs], As) ->    package_segments(F, Fs, [A | As]);package_segments({atom, _, A}, [], As) ->    lists:reverse([A | As]);package_segments(_, _, _) ->    error.%% build_function([Clause]) -> {function,Line,Name,Arity,[Clause]}build_function(Cs) ->    Name = element(3, hd(Cs)),    Arity = length(element(4, hd(Cs))),    {function,line(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.%% build_rule([Clause]) -> {rule,Line,Name,Arity,[Clause]'}build_rule(Cs) ->    Name = element(3, hd(Cs)),    Arity = length(element(4, hd(Cs))),    {rule,line(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.%% build_fun(Line, [Clause]) -> {'fun',Line,{clauses,[Clause]}}.build_fun(Line, Cs) ->    Arity = length(element(4, hd(Cs))),    {'fun',Line,{clauses,check_clauses(Cs, 'fun', Arity)}}.check_clauses(Cs, Name, Arity) ->     mapl(fun ({clause,L,N,As,G,B}) when N =:= Name, length(As) =:= Arity ->		 {clause,L,As,G,B};	     ({clause,L,_N,_As,_G,_B}) ->		 return_error(L, "head mismatch") end, Cs).build_try(L,Es,Scs,{Ccs,As}) ->    {'try',L,Es,Scs,Ccs,As}.%% mapl(F,List)%% an alternative map which always maps from left to right%% and makes it possible to interrupt the mapping with throw on%% the first occurence from left as expected.%% can be removed when the jam machine (and all other machines)%% uses the standardized (Erlang 5.0) evaluation order (from left to right)mapl(F, [H|T]) ->	V = F(H),	[V | mapl(F,T)];mapl(_, []) ->	[].%% normalise(AbsTerm)%% abstract(Term)%%  Convert between the abstract form of a term and a 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));%% Atom dot-notation, as in 'foo.bar.baz'normalise({record_field,_,_,_}=A) ->    case package_segments(A) of	error -> erlang:fault({badarg, A});	As -> list_to_atom(packages:concat(As))    end;%% 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(X) -> erlang:fault({badarg, X}).normalise_list([H|T]) ->    [normalise(H)|normalise_list(T)];normalise_list([]) ->    [].abstract(T) when is_integer(T) -> {integer,0,T};abstract(T) when is_float(T) -> {float,0,T};abstract(T) when is_atom(T) -> {atom,0,T};abstract([]) -> {nil,0};abstract(B) when is_binary(B) ->    {bin, 0, lists:map(fun(Byte) ->			       {bin_element, 0,				{integer, 0, Byte}, default, default}		       end,		       binary_to_list(B))};abstract([C|T]) when is_integer(C), 0 =< C, C < 256 ->    abstract_string(T, [C]);abstract([H|T]) ->    {cons,0,abstract(H),abstract(T)};abstract(Tuple) when is_tuple(Tuple) ->    {tuple,0,abstract_list(tuple_to_list(Tuple))}.abstract_string([C|T], String) when is_integer(C), 0 =< C, C < 256 ->    abstract_string(T, [C|String]);abstract_string([], String) ->    {string, 0, lists:reverse(String)};abstract_string(T, String) ->    not_string(String, abstract(T)).not_string([C|T], Result) ->    not_string(T, {cons, 0, {integer, 0, C}, Result});not_string([], Result) ->    Result.abstract_list([H|T]) ->    [abstract(H)|abstract_list(T)];abstract_list([]) ->    [].%%% abstract/2 keeps the line numberabstract(T, Line) when is_integer(T) -> {integer,Line,T};abstract(T, Line) when is_float(T) -> {float,Line,T};abstract(T, Line) when is_atom(T) -> {atom,Line,T};abstract([], Line) -> {nil,Line};abstract(B, Line) when is_binary(B) ->    {bin, Line, lists:map(fun(Byte) ->			       {bin_element, Line,				{integer, Line, Byte}, default, default}		       end,		       binary_to_list(B))};abstract([C|T], Line) when is_integer(C), 0 =< C, C < 256 ->    abstract_string(T, [C], Line);abstract([H|T], Line) ->    {cons,Line,abstract(H, Line),abstract(T, Line)};abstract(Tuple, Line) when is_tuple(Tuple) ->    {tuple,Line,abstract_list(tuple_to_list(Tuple), Line)}.abstract_string([C|T], String, Line) when is_integer(C), 0 =< C, C < 256 ->    abstract_string(T, [C|String], Line);abstract_string([], String, Line) ->    {string, Line, lists:reverse(String)};abstract_string(T, String, Line) ->    not_string(String, abstract(T, Line), Line).not_string([C|T], Result, Line) ->    not_string(T, {cons, Line, {integer, Line, C}, Result}, Line);not_string([], Result, _Line) ->    Result.abstract_list([H|T], Line) ->    [abstract(H, Line)|abstract_list(T, Line)];abstract_list([], _Line) ->    [].%% tokens(AbsTerm) -> [Token]%% tokens(AbsTerm, More) -> [Token]%%  Generate a list of tokens representing the abstract term.tokens(Abs) ->    tokens(Abs, []).tokens({char,L,C}, More) -> [{char,L,C}|More];tokens({integer,L,N}, More) -> [{integer,L,N}|More];tokens({float,L,F}, More) -> [{float,L,F}|More];tokens({atom,L,A}, More) -> [{atom,L,A}|More];tokens({var,L,V}, More) -> [{var,L,V}|More];tokens({string,L,S}, More) -> [{string,L,S}|More];tokens({nil,L}, More) -> [{'[',L},{']',L}|More];tokens({cons,L,Head,Tail}, More) ->    [{'[',L}|tokens(Head, tokens_tail(Tail, More))];tokens({tuple,L,[]}, More) ->    [{'{',L},{'}',L}|More];tokens({tuple,L,[E|Es]}, More) ->    [{'{',L}|tokens(E, tokens_tuple(Es, line(E), More))].tokens_tail({cons,L,Head,Tail}, More) ->    [{',',L}|tokens(Head, tokens_tail(Tail, More))];tokens_tail({nil,L}, More) ->    [{']',L}|More];tokens_tail(Other, More) ->    L = line(Other),    [{'|',L}|tokens(Other, [{']',L}|More])].tokens_tuple([E|Es], Line, More) ->    [{',',Line}|tokens(E, tokens_tuple(Es, line(E), More))];tokens_tuple([], Line, More) ->    [{'}',Line}|More].%% Give the relative precedences of operators.inop_prec('=') -> {150,100,100};inop_prec('!') -> {150,100,100};inop_prec('orelse') -> {160,150,150};inop_prec('andalso') -> {200,160,160};inop_prec('==') -> {300,200,300};inop_prec('/=') -> {300,200,300};inop_prec('=<') -> {300,200,300};inop_prec('<') -> {300,200,300};inop_prec('>=') -> {300,200,300};inop_prec('>') -> {300,200,300};inop_prec('=:=') -> {300,200,300};inop_prec('=/=') -> {300,200,300};inop_prec('++') -> {400,300,300};inop_prec('--') -> {400,300,300};inop_prec('+') -> {400,400,500};inop_prec('-') -> {400,400,500};inop_prec('bor') -> {400,400,500};inop_prec('bxor') -> {400,400,500};inop_prec('bsl') -> {400,400,500};inop_prec('bsr') -> {400,400,500};inop_prec('or') -> {400,400,500};inop_prec('xor') -> {400,400,500};inop_prec('*') -> {500,500,600};inop_prec('/') -> {500,500,600};inop_prec('div') -> {500,500,600};inop_prec('rem') -> {500,500,600};inop_prec('band') -> {500,500,600};inop_prec('and') -> {500,500,600};inop_prec('#') -> {800,700,800};inop_prec(':') -> {900,800,900};inop_prec('.') -> {900,900,1000}.preop_prec('catch') -> {0,100};preop_prec('+') -> {600,700};preop_prec('-') -> {600,700};preop_prec('bnot') -> {600,700};preop_prec('not') -> {600,700};preop_prec('#') -> {700,800}.func_prec() -> {800,700}.max_prec() -> 1000.

⌨️ 快捷键说明

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