%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2016. 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(ic_fetch).
-include("icforms.hrl").
-export([member2type/3]).
-export([fetchTk/3, isArray/3, isBasicType/1, isBasicType/2,
isBasicType/3, isBasicTypeOrEterm/3, isEterm/3, isString/3,
isStruct/3, isUnion/3, name2type/2, searchIncludedTk/2,
searchInsideTks/2, searchTk/2, searchTk/3]).
name2type(G, Name) ->
S = ic_genobj:tktab(G),
ScopedName = lists:reverse(string:tokens(Name,"_")),
InfoList = ets:lookup( S, ScopedName ),
filter( InfoList ).
%% This is en overloaded function,
%% differs in input on unions
member2type(_G, X, I) when is_record(X, union)->
Name = ic_forms:get_id2(I),
case lists:keysearch(Name,2,element(6,X#union.tk)) of
false ->
error;
{value,Rec} ->
fetchType(element(3,Rec))
end;
member2type( G, SName, MName ) ->
S = ic_genobj:tktab( G ),
SNList = lists:reverse(string:tokens(SName,"_")),
ScopedName = [MName | SNList],
InfoList = ets:lookup( S, ScopedName ),
case filter( InfoList ) of
error ->
%% Try a little harder, seeking inside tktab
case lookup_member_type_in_tktab(S, ScopedName, MName) of
error ->
%% Check if this is the "return to return1" case
case MName of
"return1" ->
%% Do it all over again !
ScopedName2 = ["return" | SNList],
InfoList2 = ets:lookup( S, ScopedName2 ),
case filter( InfoList2 ) of
error ->
%% Last resort: seek in pragma table
lookup_type_in_pragmatab(G, SName);
Other ->
Other
end;
_ ->
%% Last resort: seek in pragma table
lookup_type_in_pragmatab(G, SName)
end;
Other ->
Other
end;
Other ->
Other
end.
lookup_member_type_in_tktab(S, ScopedName, MName) ->
case ets:match_object(S, {'_',member,{MName,'_'},nil}) of
[] ->
error;
[{_FullScopedName,member,{MName,TKInfo},nil}]->
fetchType( TKInfo );
List ->
lookup_member_type_in_tktab(List,ScopedName)
end.
lookup_member_type_in_tktab([],_ScopedName) ->
error;
lookup_member_type_in_tktab([{FullScopedName,_,{_,TKInfo},_}|Rest],ScopedName) ->
case lists:reverse(string:tokens(ic_util:to_undersc(FullScopedName),"_")) of
ScopedName ->
fetchType(TKInfo);
_ ->
lookup_member_type_in_tktab(Rest,ScopedName)
end.
lookup_type_in_pragmatab(G, SName) ->
S = ic_genobj:pragmatab(G),
%% Look locally first
case ets:match(S,{file_data_local,'_','_','$2','_','_',SName,'_','_'}) of
[] ->
%% No match, seek included
case ets:match(S,{file_data_included,'_','_','$2','_','_',SName,'_','_'}) of
[] ->
error;
[[Type]] ->
io:format("1 Found(~p) : ~p~n",[SName,Type]),
Type
end;
[[Type]] ->
io:format("2 Found(~p) : ~p~n",[SName,Type]),
Type
end.
filter( [] ) ->
error;
filter( [I | Is ] ) ->
case I of
{ _, member, { _, TKINFO }, _ } ->
fetchType( TKINFO );
{ _, struct, _, _ } ->
struct;
{ _, typedef, TKINFO, _ } ->
fetchType( TKINFO );
{ _, module, _, _ } ->
module;
{ _, interface, _, _ } ->
interface;
{ _, op, _, _ } ->
op;
{ _,enum, _, _ } ->
enum;
{ _, spellcheck } ->
filter( Is );
_ ->
error
end.
fetchType( { tk_sequence, _, _ } ) ->
sequence;
fetchType( { tk_array, _, _ } ) ->
array;
fetchType( { tk_struct, _, _, _} ) ->
struct;
fetchType( { tk_string, _} ) ->
string;
fetchType( tk_short ) ->
short;
fetchType( tk_long ) ->
long;
fetchType( tk_ushort ) ->
ushort;
fetchType( tk_ulong ) ->
ulong;
fetchType( tk_float ) ->
float;
fetchType( tk_double ) ->
double;
fetchType( tk_boolean ) ->
boolean;
fetchType( tk_char ) ->
char;
fetchType( tk_octet ) ->
octet;
fetchType( { tk_enum, _, _, _ } ) ->
enum;
fetchType( { tk_union, _, _, _, _, _ } ) ->
union;
fetchType( tk_any ) ->
any;
fetchType( _ ) ->
error.
isBasicTypeOrEterm(G, N, S) ->
case isBasicType(G, N, S) of
true ->
true;
false ->
isEterm(G, N, S)
end.
isEterm(G, N, S) when element(1, S) == scoped_id ->
{FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of
"erlang_term" ->
true;
"ETERM*" ->
true;
_X ->
false
end;
isEterm(_G, _Ni, _X) ->
false.
isBasicType(G, N, S) when element(1, S) == scoped_id ->
{_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
isBasicType(fetchType(TK));
isBasicType(_G, _N, {string, _} ) ->
false;
isBasicType(_G, _N, {Type, _} ) ->
isBasicType(Type).
isBasicType(G, Name) ->
isBasicType(name2type(G, Name )).
isBasicType(Type) ->
lists:member(Type,
[tk_short,short,
tk_long,long,
tk_ushort,ushort,
tk_ulong,ulong,
tk_float,float,
tk_double,double,
tk_boolean,boolean,
tk_char,char,
tk_octet,octet]).
isString(G, N, T) when element(1, T) == scoped_id ->
case ic_symtab:get_full_scoped_name(G, N, T) of
{_FullScopedName, _, {'tk_string',_}, _} ->
true;
_ ->
false
end;
isString(_G, _N, T) when is_record(T, string) ->
true;
isString(_G, _N, _Other) ->
false.
isArray(G, N, T) when element(1, T) == scoped_id ->
case ic_symtab:get_full_scoped_name(G, N, T) of
{_FullScopedName, _, {'tk_array', _, _}, _} ->
true;
_ ->
false
end;
isArray(_G, _N, T) when is_record(T, array) ->
true;
isArray(_G, _N, _Other) ->
false.
isStruct(G, N, T) when element(1, T) == scoped_id ->
case ic_symtab:get_full_scoped_name(G, N, T) of
{_FullScopedName, _, {'tk_struct', _, _, _}, _} ->
true;
_ ->
false
end;
isStruct(_G, _N, T) when is_record(T, struct) ->
true;
isStruct(_G, _N, _Other) ->
false.
isUnion(G, N, T) when element(1, T) == scoped_id ->
case ic_symtab:get_full_scoped_name(G, N, T) of
{_FullScopedName, _, {'tk_union', _, _, _,_,_}, _} ->
true;
_Other ->
false
end;
isUnion(_G, _N, T) when is_record(T, union) ->
true;
isUnion(_G, _N, _Other) ->
false.
%%------------------------------------------------------------
%%
%% Always fetchs TK of a record.
%%
%%------------------------------------------------------------
fetchTk(G,N,X) ->
case ic_forms:get_tk(X) of
undefined ->
searchTk(G,ictk:get_IR_ID(G, N, X));
TK ->
TK
end.
%%------------------------------------------------------------
%%
%% seek type code when not accessible by get_tk/1
%%
%%------------------------------------------------------------
searchTk(G,IR_ID) ->
S = ic_genobj:tktab(G),
case catch searchTk(S,IR_ID,typedef) of
{value,TK} ->
TK;
_ -> %% false / exit
case catch searchTk(S,IR_ID,struct) of
{value,TK} ->
TK;
_ -> %% false / exit
case catch searchTk(S,IR_ID,union) of
{value,TK} ->
TK;
_ ->
undefined
end
end
end.
searchTk(S,IR_ID,Type) ->
L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})),
case lists:keysearch(IR_ID,2,L) of
{value,TK} ->
{value,TK};
false ->
searchInsideTks(L,IR_ID)
end.
searchInsideTks([],_IR_ID) ->
false;
searchInsideTks([{tk_array,TK,_}|Xs],IR_ID) ->
case searchIncludedTk(TK,IR_ID) of
{value,TK} ->
{value,TK};
false ->
searchInsideTks(Xs,IR_ID)
end.
searchIncludedTk({tk_array,TK,_},IR_ID) ->
searchIncludedTk(TK,IR_ID);
searchIncludedTk({tk_sequence,TK,_},IR_ID) ->
searchIncludedTk(TK,IR_ID);
searchIncludedTk(TK,_IR_ID) when is_atom(TK) ->
false;
searchIncludedTk(TK,IR_ID) ->
case element(2,TK) == IR_ID of
true ->
{value,TK};
false ->
false
end.