1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21
22-module(ic_symtab).
23
24
25-include_lib("ic/src/ic.hrl").
26-include_lib("ic/src/icforms.hrl").
27
28%%-----------------------------------------------------------------
29%% External exports
30%%-----------------------------------------------------------------
31-export([new/0, store/3, retrieve/2, soft_retrieve/2, intf_resolv/3]).
32-export([get_full_scoped_name/3, scoped_id_new_global/1, scoped_id_new/1]).
33-export([scoped_id_strip/1,symtab_add_faked_included_types/1]).
34-export([scoped_id_is_global/1, scoped_id_add/2]).
35
36%%-----------------------------------------------------------------
37%% Internal exports
38%%-----------------------------------------------------------------
39-export([]).
40
41%%-----------------------------------------------------------------
42%% External functions
43%%-----------------------------------------------------------------
44
45
46%%--------------------------------------------------------------------
47%%
48%% Symbol table routines
49%%
50%%	Symbol tables handles mappings Id -> Value, where Id is an
51%%	ordinary Id from the parser (or a string) and value is an
52%%	arbitrary term.
53%%
54%%--------------------------------------------------------------------
55
56%%-----------------------------------------------------------------
57%% Func: new/0 (used to be symtab_new)
58%%-----------------------------------------------------------------
59new() ->
60    ets:new(symtab, [set, public]).
61
62%%-----------------------------------------------------------------
63%% Func: store/3 (used to be symtab_store)
64%%-----------------------------------------------------------------
65store(G, N, X) ->
66    Name = [ic_forms:get_id2(X) | N],
67    %%io:format("Adding id: ~p~n", [N]),
68    case soft_retrieve(G, Name) of
69	{error, _} ->
70	    ets:insert(G#genobj.symtab, {Name, X});
71	{ok, Y} when is_record(Y, forward) ->
72	    ets:insert(G#genobj.symtab, {Name, X});
73	{ok, Y} when is_record(Y, constr_forward) ->
74	    ets:insert(G#genobj.symtab, {Name, X});
75	{ok, _Y} ->
76	    ic_error:error(G, {multiply_defined, X})
77    end.
78
79
80%%-----------------------------------------------------------------
81%% Func: retrieve/2 (used to be symtab_retrieve)
82%%
83%%	Makes a lookup in the symbol table for Id. Will throw
84%%	not_found if it fails.
85%%-----------------------------------------------------------------
86retrieve(G, Id) ->
87    case ets:lookup(G#genobj.symtab, Id) of
88	[{_, Val}] -> Val;
89	[] -> ic_error:error(G, {symtab_not_found, Id})
90    end.
91
92
93%%-----------------------------------------------------------------
94%% Func: soft_retrieve/2 (used to be symtab_soft_retrieve)
95%%
96%%	Same as retrieve but will use tagged return values.
97%%
98%%-----------------------------------------------------------------
99soft_retrieve(G, Id) ->
100    case ets:lookup(G#genobj.symtab, Id) of
101	[{_, Val}] -> {ok, Val};
102	[] -> {error, {symtab_not_found, Id}}
103    end.
104
105
106%%-----------------------------------------------------------------
107%% Func: intf_resolv/3 and  resolv2/3
108%%       (used to be symtab_intf_resolv  and symtab_intf_resolv2)
109%%
110%%	Tries to resolv the interface identifier reference. The id can
111%%	be either a scoped name or an standard identifier. The
112%%	function returns a global reference to the id.
113%%
114%%	Will throw not_found if the id really cannot be found. Will
115%%	throw illegal_forward if any forward references are founf in
116%%	the inheritance list.
117%%
118%%-----------------------------------------------------------------
119intf_resolv(G, Scope, Id) ->
120    case scoped_id_is_global(Id) of
121	true ->
122	    retrieve(G, Id),
123	    Id;
124	false ->
125	    intf_resolv2(G, Scope, Id)
126    end.
127
128intf_resolv2(G, Scope, Id) ->
129    N = scoped_id_add(Scope, Id),
130    case soft_retrieve(G, scoped_id_strip(N)) of
131	{ok, F} when is_record(F, forward) ->
132	    ic_error:error(G, {illegal_forward, Id}), [];
133	{ok, _Val} ->
134	    scoped_id_mk_global(N);
135	_ ->
136	    case scoped_id_is_top(Scope) of
137		false ->
138		    intf_resolv2(G, scoped_id_up_one(Scope), Id);
139		true ->
140		    ic_error:error(G, {symtab_not_found, Id}), []
141	    end
142    end.
143
144
145
146%%--------------------------------------------------------------------
147%%
148%% Scoped id routines
149%%
150%%	A scoped id is an id written as M::Id in IDL. Scoped ids are
151%%	implemented as lists of id in reverse order, so M1::F1 becomes
152%%	[F1, M1].
153%%
154%%--------------------------------------------------------------------
155
156get_full_scoped_name(G, N, S)  when element(1, S) == scoped_id ->
157    ictype:scoped_lookup(G, ic_genobj:tktab(G), N, S).
158
159scoped_id_new_global(Id) ->
160    X=scoped_id_new(Id), X#scoped_id{type=global}.
161
162scoped_id_new(Id) ->
163    #scoped_id{line=ic_forms:get_line(Id), id=[ic_forms:get_id(Id)]}.
164
165%% Adds one more id to the list of ids
166scoped_id_add(S1, S2) when is_record(S2, scoped_id) ->
167    S1#scoped_id{id=S2#scoped_id.id ++  S1#scoped_id.id,
168		 line=S2#scoped_id.line};
169scoped_id_add(S, Id) ->
170    S#scoped_id{id=[ic_forms:get_id(Id) | S#scoped_id.id], line=ic_forms:get_line(Id)}.
171
172
173scoped_id_mk_global(S) -> S#scoped_id{type=global}.
174
175scoped_id_is_global(S) when is_record(S, scoped_id), S#scoped_id.type==global ->
176    true;
177scoped_id_is_global(_) -> false.
178
179%% Top level scope (i.e no more cd ..)
180scoped_id_is_top(S) when S#scoped_id.id==[] -> true;
181scoped_id_is_top(_) -> false.
182
183
184scoped_id_up_one(S) -> S#scoped_id{id=tl(S#scoped_id.id)}. % cd .. in scope
185%%scoped_id_get_def(S) -> hd(S#scoped_id.id).	% Last added id
186scoped_id_strip(S) -> S#scoped_id.id.		% Strips all junk
187
188
189
190
191% Add CORBA::<Types> that as if they
192% were defined in an included file.
193% This is only supported in the case
194% of Corba backend
195symtab_add_faked_included_types(G) ->
196    case ic_options:get_opt(G, be) of
197	false ->
198	    %% Add TypeCode as if it were defiend in included file
199	    ets:insert(G#genobj.symtab, {["CORBA"],
200					 {interface,{'<identifier>',0,"TypeCode"},
201					  [],
202					  [],
203					  [],
204					  {tk_objref,
205					   "IDL:omg.org/CORBA/TypeCode:1.0",
206					   "TypeCode"}}});
207	erl_corba ->
208	    %% Add TypeCode as if it were defiend in included file
209	    ets:insert(G#genobj.symtab, {["CORBA"],
210					 {interface,{'<identifier>',0,"TypeCode"},
211					  [],
212					  [],
213					  [],
214					  {tk_objref,
215					   "IDL:omg.org/CORBA/TypeCode:1.0",
216					   "TypeCode"}}});
217	erl_template ->
218	    %% Add TypeCode as if it were defiend in included file
219	    ets:insert(G#genobj.symtab, {["CORBA"],
220					 {interface,{'<identifier>',0,"TypeCode"},
221					  [],
222					  [],
223					  [],
224					  {tk_objref,
225					   "IDL:omg.org/CORBA/TypeCode:1.0",
226					   "TypeCode"}}});
227	_ ->
228	    ok
229    end.
230
231
232
233%%-----------------------------------------------------------------
234%% Internal functions
235%%-----------------------------------------------------------------
236