%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(xref_scanner). -include("xref.hrl"). -export([scan/1]). scan(Chars) -> case erl_scan:string(Chars) of {ok, Tokens, _Line} -> {ok, lex(a1(Tokens))}; {error, {Line,Module,Info}, _EndLine} -> {error, Module:format_error(Info), Line} end. a1([{'-',N},{integer,N,1} | L]) -> [{integer,N,-1} | a1(L)]; a1([T | L]) -> [T | a1(L)]; a1([]) -> []. -define(MFA(M,F,A,N), {atom,N,M}, {':',_}, {atom,_,F}, {'/',_}, {integer,_,A}). -define(MFA2(M,F,A,N), {'{',N},{atom,_,M},{',',_},{atom,_,F},{',',_},{integer,_,A},{'}',_}). -define(DECL(N1,N2,T), {':',N1},{var,N2,T}). lex([{atom,N,V1},{'->',_},{atom,_,V2} | L]) -> Constant = {constant, unknown, edge, {V1,V2}}, [{edge,N,Constant} | lex(L)]; lex([{'{',N},{atom,_,V1},{',',_},{atom,_,V2},{'}',_} | L]) -> Constant = {constant, unknown, edge, {V1,V2}}, [{edge,N,Constant} | lex(L)]; lex([?MFA(M,F,A,N),{'->',_},?MFA(M2,F2,A2,_) | L]) -> Constant = {constant, 'Fun', edge, {{M,F,A},{M2,F2,A2}}}, [{edge,N,Constant} | lex(L)]; lex([?MFA(M,F,A,N) | L]) -> Constant = {constant, 'Fun', vertex, {M,F,A}}, [{vertex,N,Constant} | lex(L)]; lex([{'{',N},?MFA2(M,F,A,_),{',',_},?MFA2(M2,F2,A2,_),{'}',_} | L]) -> Constant = {constant, 'Fun', edge, {{M,F,A},{M2,F2,A2}}}, [{edge,N,Constant} | lex(L)]; lex([?MFA2(M,F,A,N) | L]) -> Constant = {constant, 'Fun', vertex, {M,F,A}}, [{vertex,N,Constant} | lex(L)]; lex([?DECL(N1,N2,Decl) | L]) -> case is_type(Decl) of false -> [?DECL(N1, N2, Decl) | lex(L)]; true -> [{decl,N1,Decl} | lex(L)] end; lex([{':',N},{'=',_} | L]) -> [{':=',N} | lex(L)]; lex([{'||',N},{'|',_} | L]) -> [{'|||',N} | lex(L)]; lex([V={var,N,Var} | L]) -> T = case is_type(Var) of false -> V; true -> {cast,N,Var} end, [T | lex(L)]; lex([T | Ts]) -> [T | lex(Ts)]; lex([]) -> [{'$end', erl_anno:new(?XREF_END_LINE)}]. is_type('Rel') -> true; is_type('App') -> true; is_type('Mod') -> true; is_type('Fun') -> true; is_type('Lin') -> true; is_type('LLin') -> true; is_type('XLin') -> true; is_type('ELin') -> true; is_type('XXL') -> true; is_type(_) -> false.