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 + -
显示快捷键?