1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1998-2021. 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-module(ic_noc).
22
23
24-export([do_gen/3]).
25%%------------------------------------------------------------
26%%
27%% Internal stuff
28%%
29%%------------------------------------------------------------
30
31-export([unfold/1, mk_attr_func_names/2]).
32
33
34-import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]).
35-import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]).
36-import(ic_codegen, [emit/2, emit/3, nl/1]).
37-import(ic_options, [get_opt/2]).
38
39
40-import(lists, [foreach/2, foldr/3, map/2]).
41
42
43-include("icforms.hrl").
44-include("ic.hrl").
45
46
47
48
49%%------------------------------------------------------------
50%%
51%% Generate the client side Erlang stubs.
52%%
53%% Each module is generated to a separate file.
54%%
55%% Export declarations for all interface functions must be
56%% generated. Each function then needs to generate a function head and
57%% a body. IDL parameters must be converted into Erlang parameters
58%% (variables, capitalised) and a type signature list must be
59%% generated (for later encode/decode).
60%%
61%%------------------------------------------------------------
62
63
64do_gen(G, File, Form) ->
65    G2 = ic_file:filename_push(G, [], mk_oe_name(G,
66					       ic_file:remove_ext(to_list(File))),
67			     erlang),
68    gen_head(G2, [], Form),
69    exportDependency(G2),
70    %% Loop through form and adds inheritence data
71    ic_pragma:preproc(G2, [], Form),
72    gen(G2, [], Form),
73    genDependency(G2),
74    ic_file:filename_pop(G2, erlang),
75    ok.
76
77
78gen(G, N, [X|Xs]) when is_record(X, preproc) ->
79    NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
80    gen(NewG, N, Xs);
81
82gen(G, N, [X|Xs]) when is_record(X, module) ->
83    CD = ic_code:codeDirective(G,X),
84    G2 = ic_file:filename_push(G, N, X, CD),
85    N2 = [get_id2(X) | N],
86    gen_head(G2, N2, X),
87    gen(G2, N2, get_body(X)),
88    G3 = ic_file:filename_pop(G2, CD),
89    gen(G3, N, Xs);
90
91gen(G, N, [X|Xs]) when is_record(X, interface) ->
92    G2 = ic_file:filename_push(G, N, X, erlang),
93    N2 = [get_id2(X) | N],
94    gen_head(G2, N2, X),
95    gen(G2, N2, get_body(X)),
96    foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
97	    X#interface.inherit_body),
98    gen_serv(G2, N, X),
99    G3 = ic_file:filename_pop(G2, erlang),
100    gen(G3, N, Xs);
101
102gen(G, N, [X|Xs]) when is_record(X, const) ->
103%    N2 = [get_id2(X) | N],
104    emit_constant_func(G, X#const.id, X#const.val),
105    gen(G, N, Xs); %% N2 or N?
106
107gen(G, N, [X|Xs]) when is_record(X, op) ->
108    {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
109
110    case getNocType(G,X,N) of
111	transparent ->
112	    emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs);
113	multiple ->
114	    mark_not_transparent(G,N),
115	    emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs);
116	_XTuple ->
117	    mark_not_transparent(G,N),
118	    emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs)
119    end,
120
121    gen(G, N, Xs);
122
123
124gen(G, N, [X|Xs]) when is_record(X, attr) ->
125    emit_attr(G, N, X, fun emit_stub_func/7),
126    gen(G, N, Xs);
127
128gen(G, N, [X|Xs]) when is_record(X, except) ->
129    icstruct:except_gen(G, N, X, erlang),
130    gen(G, N, Xs);
131
132gen(G, N, [X|Xs]) ->
133    case may_contain_structs(X) of
134	true -> icstruct:struct_gen(G, N, X, erlang);
135	false -> ok
136    end,
137    gen(G, N, Xs);
138
139gen(_G, _N, []) -> ok.
140
141
142may_contain_structs(X) when is_record(X, typedef) -> true;
143may_contain_structs(X) when is_record(X, struct) -> true;
144may_contain_structs(X) when is_record(X, union) -> true;
145may_contain_structs(_X) -> false.
146
147
148
149%%--------------------------------------------------------------------
150%%
151%% Generate the server side (handle_call and handle_cast)
152%%
153
154gen_serv(G, N, X) ->
155    case ic_genobj:is_stubfile_open(G) of
156	true ->
157	    emit_serv_std(G, N, X),
158	    N2 = [get_id2(X) | N],
159	    gen_calls(G, N2, get_body(X)),
160	    lists:foreach(fun({_Name, Body}) ->
161				  gen_calls(G, N2, Body) end,
162			  X#interface.inherit_body),
163	    get_if_gen(G, N2, X),
164	    gen_end_of_call(G, N, X),		% Note N instead of N2
165
166	    gen_casts(G, N2, get_body(X)),
167	    lists:foreach(fun({_Name, Body}) ->
168				  gen_casts(G, N2, Body) end,
169			  X#interface.inherit_body),
170	    gen_end_of_cast(G, N, X),		% Note N instead of N2
171	    emit_skel_footer(G, N, X);		% Note N instead of N2
172	false ->
173	    ok
174    end.
175
176gen_calls(G, N, [X|Xs]) when is_record(X, op) ->
177    case is_oneway(X) of
178	false ->
179	    {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
180	    emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs),
181	    gen_calls(G, N, Xs);
182	true ->
183	    gen_calls(G, N, Xs)
184    end;
185
186gen_calls(G, N, [X|Xs]) when is_record(X, attr) ->
187    emit_attr(G, N, X, fun emit_skel_func/7),
188    gen_calls(G, N, Xs);
189
190gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs);
191gen_calls(_G, _N, []) -> ok.
192
193gen_casts(G, N, [X|Xs]) when is_record(X, op) ->
194    case is_oneway(X) of
195	true ->
196	    {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
197	    emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs),
198	    gen_casts(G, N, Xs);
199	false ->
200	    gen_casts(G, N, Xs)
201    end;
202
203gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs);
204gen_casts(_G, _N, []) -> ok.
205
206emit_attr(G, N, X, F) ->
207    XX = #id_of{type=X},
208    {GetType, SetType} = mk_attr_func_types(N, X),
209    lists:foreach(fun(Id) ->
210			  X2 = XX#id_of{id=Id},
211			  {Get, Set} = mk_attr_func_names(N, get_id(Id)),
212			  F(G, N, X2, Get, [], GetType, []),
213			  case X#attr.readonly of
214			      {readonly, _} -> ok;
215			      _ ->
216				  F(G, N, X2, Set, [mk_name(G, "Value")],
217				    SetType, [])
218			  end end, ic_forms:get_idlist(X)).
219
220
221extract_info(G, _N, X) when is_record(X, op) ->
222    Name	= get_id2(X),
223    InArgs	= ic:filter_params([in,inout], X#op.params),
224    OutArgs	= ic:filter_params([out,inout], X#op.params),
225    ArgNames	= mk_erl_vars(G, InArgs),
226    TypeList	= {ic_forms:get_tk(X),
227		   map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs),
228		   map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs)
229		  },
230    {Name, ArgNames, TypeList, OutArgs}.
231
232emit_serv_std(G, _N, _X) ->
233    ic_genobj:stubfiled(G).
234
235gen_end_of_call(_G, _N, _X) ->
236    ok.
237
238gen_end_of_cast(_G, _N, _X) ->
239    ok.
240
241emit_skel_footer(_G, _N, _X) ->
242    ok.
243
244%% Not used after cleanup of dialyzer warnings
245%% use_impl_handle_info(G, N, X) ->
246%%     FullName = ic_util:to_colon([get_id2(X) | N]),
247%%     case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of
248%% 	{_, force_false} -> false;
249%% 	{false, false} -> false;
250%% 	_ -> true
251%%     end.
252
253
254use_timeout(G, N, _X) ->
255    FullName = ic_util:to_colon(N),
256    case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of
257	{_, force_false} -> false;
258	{false, false} -> false;
259	_ -> true
260    end.
261
262
263%% Not used after cleanup of dialyzer warnings
264%get_if_name(G) -> mk_oe_name(G, "get_interface").
265
266
267%% Generates the get_interface function (for Lars)
268get_if_gen(_G, _N, _X) ->
269    ok.
270
271
272%% Not used after cleanup of dialyzer warnings
273%% get_if(G,N,[X|Rest]) when is_record(X, op) ->
274%%     R = ic_forms:get_tk(X),
275%%     IN = lists:map(fun(P) -> ic_forms:get_tk(P) end,
276%% 		   ic:filter_params([in, inout], X#op.params)),
277%%     OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end,
278%% 		    ic:filter_params([out, inout], X#op.params)),
279%%     case print_tk(G,N,X) of
280%% 	true ->
281%% 	    [{get_id2(X), {R, IN, OUT}} | get_if(G,N,Rest)];
282%% 	false ->
283%% 	    get_if(G,N,Rest)
284%%     end;
285%% get_if(G,N,[X|Rest]) when is_record(X, attr) -> %% Attributes not handled so far <<<<<<<<<<<<<<<<<<<<<<<<
286%%     {GetT, SetT} = mk_attr_func_types([], X),
287%%     AList = lists:map(fun(Id) ->
288%% 			      {Get, Set} = mk_attr_func_names([], get_id(Id)),
289%% 			      case X#attr.readonly of
290%% 				  {readonly, _} ->
291%% 				      {Get, GetT};
292%% 				  _ ->
293%% 				      [{Set, SetT}, {Get, GetT}]
294%% 			      end end, ic_forms:get_idlist(X)),
295%%     lists:flatten(AList) ++ get_if(G,N,Rest);
296%% get_if(G,N,[_X|Rest]) -> get_if(G,N,Rest);
297%% get_if(_,_,[]) -> [].
298
299
300
301
302%%------------------------------------------------------------
303%%
304%% Export stuff
305%%
306%%	Gathering of all names that should be exported from a stub
307%%	file.
308%%
309
310
311gen_head_special(G, N, X) when is_record(X, interface) ->
312    Fd = ic_genobj:stubfiled(G),
313    NocType = getNocType(G,X,N),
314
315    foreach(fun({Name, Body}) ->
316		    ic_codegen:comment(Fd, "Exports from ~p",
317				  [ic_util:to_colon(Name)]),
318		    ic_codegen:export(Fd, exp_top(G, N, Body, NocType, [])),
319		    nl(Fd)
320	    end, X#interface.inherit_body),
321
322    nl(Fd), nl(Fd),
323    Fd;
324
325gen_head_special(_G, _N, _X) -> ok.
326
327
328
329%% Shall generate all export declarations
330gen_head(G, N, X) ->
331    case ic_genobj:is_stubfile_open(G) of
332	true ->
333	    F = ic_genobj:stubfiled(G),
334	    ic_codegen:comment(F, "Interface functions"),
335	    ic_codegen:export(F, exp_top(G, N, X, getNocType(G,X,N), [])),
336	    nl(F),
337	    gen_head_special(G, N, X);
338	false -> ok
339    end.
340
341exp_top(_G, _N, X, _NT, Acc)  when element(1, X) == preproc ->
342    Acc;
343exp_top(G, N, L, NT, Acc)  when is_list(L) ->
344    exp_list(G, N, L, NT, Acc);
345exp_top(G, N, M, NT, Acc)  when is_record(M, module) ->
346    exp_list(G, N, get_body(M), NT, Acc);
347exp_top(G, N, I, NT, Acc)  when is_record(I, interface) ->
348    exp_list(G, N, get_body(I), NT, Acc);
349exp_top(G, N, X, NT, Acc) ->
350    exp3(G, N, X, NT, Acc).
351
352exp3(_G, _N, C, _NT, Acc)  when is_record(C, const) ->
353    [{get_id(C#const.id), 0} | Acc];
354
355exp3(G, N, Op, NocType, Acc)  when is_record(Op, op) ->
356    FuncName = get_id(Op#op.id),
357
358    TA = case use_timeout(G,N,Op) of
359	     true ->
360		 1;
361	     false ->
362		 0
363	 end,
364
365    case NocType of
366	transparent ->
367	    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
368	    [{FuncName, Arity} | Acc];
369	multiple ->
370	    case getModType(G, Op, N) of
371		dt ->
372		    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
373		    [{FuncName, Arity} | Acc];
374		do ->
375		    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
376		    [{FuncName, Arity} | Acc];
377		spt ->
378		    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
379		    [{FuncName, Arity} | Acc];
380		spo ->
381		    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
382		    [{FuncName, Arity} | Acc]
383	    end;
384	_ ->
385	    Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
386	    [{FuncName, Arity} | Acc]
387    end;
388exp3(_G, _N, A, _NT, Acc)  when is_record(A, attr) ->
389    lists:foldr(fun(Id, Acc2) ->
390			{Get, Set} = mk_attr_func_names([], get_id(Id)),
391			case A#attr.readonly of
392			    {readonly, _} -> [{Get, 1} | Acc2];
393			    _ ->             [{Get, 1}, {Set, 2} | Acc2]
394			end end, Acc, ic_forms:get_idlist(A));
395
396exp3(_G, _N, _X, _NT, Acc) -> Acc.
397
398exp_list(G, N, L, NT, OrigAcc) ->
399    lists:foldr(fun(X, Acc) -> exp3(G, N, X, NT, Acc) end, OrigAcc, L).
400
401
402
403
404%%------------------------------------------------------------
405%%
406%% Emit stuff
407%%
408%%	Low level generation primitives
409%%
410
411emit_stub_func(G, N, X, Name, ArgNames, TypeList, _OutArgs) ->
412    case ic_genobj:is_stubfile_open(G) of
413	false -> ok;
414	true ->
415	    Fd = ic_genobj:stubfiled(G),
416	    StubName = list_to_atom(Name),
417	    This = mk_name(G, "Ref"),
418	    XTuple = getNocType(G,X,N),
419	    CallOrCast =
420		case is_oneway(X) of
421		    true -> ?CAST;
422		    _ -> ?CALL
423		end,
424
425	    %% Type expand operation on comments
426	    ic_code:type_expand_op(G,N,X,Fd),
427
428	    case use_timeout(G,N,X) of
429		true ->
430		    Timeout = mk_name(G,"Timeout"),
431		    emit(Fd, "~p(~s) ->\n",
432			 [StubName, mk_list([This, Timeout| ArgNames])]),
433		    emit(Fd, "    ~p:~s(~s, ~s, ?MODULE, ~p, ~p, [~s], ~p).\n\n",
434			 [getImplMod(G,X,N),
435			  CallOrCast,
436			  This,
437			  Timeout,
438			  XTuple,
439			  StubName,
440			  mk_list(ArgNames),
441			  tk_operation_data(G, N, X, TypeList)]);
442		false ->
443		    emit(Fd, "~p(~s) ->\n",
444			 [StubName, mk_list([This | ArgNames])]),
445
446		    emit(Fd, "    ~p:~s(~s, ~p, ?MODULE, ~p, [~s], ~p).\n\n",
447			 [getImplMod(G,X,N),
448			  CallOrCast,
449			  This,
450			  XTuple,
451			  StubName,
452			  mk_list(ArgNames),
453			  tk_operation_data(G, N, X, TypeList)])
454	    end
455    end.
456
457
458emit_transparent_func(G, N, X, Name, ArgNames, _TypeList, _OutArgs) ->
459    case ic_genobj:is_stubfile_open(G) of
460	false -> ok;
461	true ->
462	    Fd = ic_genobj:stubfiled(G),
463	    OpName = list_to_atom(Name),
464
465	    ArgList = case use_timeout(G,N,X) of
466			  true ->
467			      mk_list([mk_name(G,"Ref"),mk_name(G,"Timeout")|ArgNames]);
468			  false ->
469			       mk_list([mk_name(G,"Ref")|ArgNames])
470		      end,
471
472	    %% Type expand operation on comments
473	    ic_code:type_expand_op(G,N,X,Fd),
474
475	    emit(Fd, "~p(~s) ->\n", [OpName,ArgList]),
476	    emit(Fd, "    ~p:~s(~s).\n\n", [getImplMod(G,X,N), OpName, ArgList])
477    end.
478
479
480
481
482
483
484emit_skel_func(_G, _N, _X, _OpName, _ArgNames, _TypeList, _OutArgs) ->
485    true.
486
487
488
489emit_constant_func(G, Id, Val) ->
490    case ic_genobj:is_stubfile_open(G) of
491	false -> ok;
492	true ->
493	    Fd = ic_genobj:stubfiled(G),
494	    N = list_to_atom(get_id(Id)),
495	    emit_const_comment(G, Fd, Id, N),
496	    emit(Fd, "~p() -> ~p.\n\n", [N, Val])
497    end.
498
499
500emit_const_comment(_G, F, _X, Name) ->
501    ic_codegen:mcomment_light(F,
502			 [io_lib:format("Constant: ~p", [Name])]).
503
504%%------------------------------------------------------------
505%%
506%% Utilities
507%%
508%% Convenient little go-get functions
509%%
510%%------------------------------------------------------------
511
512%% The automaticly generated get and set operation names for an
513%% attribute.
514mk_attr_func_names(_Scope, Name) ->
515    {"_get_" ++ Name, "_set_" ++ Name}.
516
517%% Returns TK of the Get and Set attribute functions.
518mk_attr_func_types(_N, X) ->
519    TK = ic_forms:get_tk(X),
520    {{TK, [], []}, {tk_void, [TK], []}}.
521
522
523
524%%------------------------------------------------------------
525%%
526%% Generation utilities and common stuff
527%%
528%% Convenient stuff for generation
529%%
530%%------------------------------------------------------------
531
532
533%% Input is a list of parameters (in parse form) and output is a list
534%% of capitalised variable names. mk_var is in icgen
535mk_erl_vars(_G, Params) ->
536    map(fun(P) -> mk_var(get_id(P#param.id)) end, Params).
537
538
539%% mk_list produces a nice comma separated string of variable names
540mk_list([]) -> [];
541mk_list([Arg | Args]) ->
542    Arg ++ mk_list2(Args).
543mk_list2([Arg | Args]) ->
544    ", " ++ Arg ++ mk_list2(Args);
545mk_list2([]) -> [].
546
547
548%%------------------------------------------------------------
549%%
550%% Parser utilities
551%%
552%% Called from the yecc parser. Expands the identifier list of an
553%% attribute so that the attribute generator never has to handle
554%% lists.
555%%
556%%------------------------------------------------------------
557
558
559%% Unfold identifier lists or nested lists. Note that many records
560%% contain an entry named id that is a list before unfold and a single
561%% id afterwards.
562unfold(L) when is_list(L) ->
563    lists:flatten(map(fun(X) -> unfold2(X) end, L));
564unfold(X) -> unfold2(X).
565
566unfold2(A) when is_record(A, attr) ->
567    map(fun(Id) -> A#attr{id=Id} end, A#attr.id);
568unfold2(M) when is_record(M, member) ->
569    map(fun(Id) -> M#member{id=Id} end, M#member.id);
570unfold2(M) when is_record(M, case_dcl) ->
571    map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label);
572unfold2(T) when is_record(T, typedef) ->
573    map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id   ).
574
575
576
577
578
579
580%% Export code produce for dependency function
581exportDependency(G) ->
582    Fd = ic_genobj:stubfiled(G),
583    ic_codegen:export(Fd, [{oe_dependency, 0}]),
584    nl(Fd).
585
586%% Code produce for dependency function
587genDependency(G) ->
588    Fd = ic_genobj:stubfiled(G),
589    nl(Fd),nl(Fd),
590    ic_codegen:comment(Fd, "Idl file dependency list function"),
591    emit(Fd, "oe_dependency() ->\n", []),
592    emit(Fd, "    ~p.\n\n", [ic_pragma:get_dependencies(G)]).
593
594
595
596
597
598%%%%%%
599
600
601getImplMod(G,X,Scope) -> %% to_atom(ic_genobj:impl(G)) | ChoicedModuleName
602
603    %% Get actual pragma appliance scope
604    SpecScope = getActualScope(G,X,Scope),
605
606    %% The "broker" option is passed
607    %% only by pragmas, seek for module.
608    case ic_pragma:getBrokerData(G,X,SpecScope) of
609	{Module,_Type} ->
610	    Module;
611	_List ->
612	    element(1,ic_pragma:defaultBrokerData(G))
613    end.
614
615
616getNocType(G,X,Scope) when is_record(X, interface) -> %% default | specified
617    OpList = getAllOperationScopes(G,Scope),
618    getNocType2(G,X,OpList);
619getNocType(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN}
620    getNocType3(G,X,Scope).
621
622getNocType2(G,X,List) ->
623    getNocType2(G,X,List,[]).
624
625getNocType2(_,_,[],Found) ->
626    selectTypeFromList(Found);
627getNocType2(G,X,[OpScope|OpScopes],Found) ->
628    getNocType2(G,X,OpScopes,[getNocType3(G,X,OpScope)|Found]).
629
630getNocType3(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN}
631
632    %% Get actual pragma appliance scope
633    SpecScope = getActualScope(G,X,Scope),
634
635    %% The "broker" option is passed
636    %% only by pragmas, seek for type.
637    case ic_pragma:getBrokerData(G,X,SpecScope) of
638	{_Module,Type} ->
639	    Type;
640	List ->
641	    selectTypeFromList(List) %%transparent/multiple
642    end.
643
644
645getModType(G,X,Scope) -> %% default | specified
646
647    %% Get actual pragma appliance scope
648    SpecScope = getActualScope(G,X,Scope),
649
650    %% The "broker" option is passed
651    %% only by pragmas, seek for brokerdata.
652    case ic_pragma:getBrokerData(G,X,SpecScope) of
653	{Module,Type} ->
654	    case Module == ic_genobj:impl(G) of
655		true ->
656		    case Type of
657			transparent ->
658			    dt; %% default + transparent
659			_ ->
660			    do  %% default + opaque
661		    end;
662		false ->
663		    case Type of
664			transparent ->
665			    spt; %% specified + transparent
666			_ ->
667			    spo  %% specified + opaque
668		    end
669	    end;
670	_List ->
671	    dt
672    end.
673
674
675
676%%%%
677%%
678%% Returns a list of ALL operation full
679%% scoped names local and inherited
680%% from other interfaces
681%%
682
683getAllOperationScopes(G,Scope) ->
684    getOperationScopes(G,Scope) ++
685	getInhOperationScopes(G,Scope).
686
687
688getOperationScopes(G,Scope) ->
689    getOpScopes(G,
690		Scope,
691		ets:match(ic_genobj:pragmatab(G),{op,'$0',Scope,'_','_'}),
692		[]).
693
694getOpScopes(_,_,[],OpScopes) ->
695    OpScopes;
696getOpScopes(G,Scope,[[Name]|Names],Found) ->
697    getOpScopes(G,Scope,Names,[[Name|Scope]|Found]).
698
699
700getInhOperationScopes(G,Scope) ->
701    getInhOpScopes1(G,
702		   Scope,
703		   ets:match(ic_genobj:pragmatab(G),{inherits,Scope,'$1'}),
704		   []).
705
706getInhOpScopes1(G,_Scope,[],OpScopes) ->
707    getInhOpScopes2(G,OpScopes);
708getInhOpScopes1(G,Scope,[[SC]|SCs],Found) ->
709    getInhOpScopes1(G,Scope,SCs,[SC|Found]).
710
711
712getInhOpScopes2(G,Scopes) ->
713    getInhOpScopes2(G,Scopes,[]).
714
715getInhOpScopes2(_G,[],Found) ->
716    Found;
717getInhOpScopes2(G,[SC|SCs],Found) ->
718   getOperationScopes(G,SC) ++ getInhOpScopes2(G,SCs,Found).
719
720%%
721%%
722%%%%
723
724
725
726%%%%
727%%
728%%
729%% Seek the actual operation scope :
730%%
731%%   * if the operation is inherited, get the real scope for it
732%%
733%%   * if the operation has a specific pragma, apply the real
734%%     scope, otherwise return the including scope
735%%
736getActualScope(G, X, Scope) when is_record(X, op) ->
737    OpScope = getRealOpScope(G,X,Scope),
738    case ets:match(ic_genobj:pragmatab(G),{codeopt_specific,OpScope}) of
739	[[]] ->
740	    OpScope;
741	_ ->
742	    Scope
743    end;
744getActualScope(_G, _X, N) ->
745    N.
746
747%%
748%%  Just seek and return the scope for the operation
749%%  where it were originaly defined
750%%
751getRealOpScope(G,X,N) when is_record(X, op) ->
752    Ptab = ic_genobj:pragmatab(G),
753    Id = get_id2(X),
754
755    case ets:match(Ptab,{op,Id,N,'_','_'}) of
756	[[]] ->
757	    [Id|N];
758	_ ->
759	    getRealOpScope(G, Ptab, X, N, Id,  ets:match(Ptab,{inherits,N,'$1'}))
760    end;
761getRealOpScope(_G,_X,N) ->
762    N.
763
764getRealOpScope(_G, _S, _X, N, Id, []) ->
765    [Id|N];
766getRealOpScope(G, S, X, N, Id, [[OS]|OSs]) ->
767    case ets:match(S,{op,Id,OS,'_','_'}) of
768	[[]] ->
769	    [Id|OS];
770	_ ->
771	    getRealOpScope(G, S, X, N, Id, OSs)
772    end.
773
774selectTypeFromList([]) ->
775    transparent;
776selectTypeFromList([{_,transparent}|Rest]) ->
777    selectTypeFromList(Rest);
778selectTypeFromList([transparent|Rest]) ->
779    selectTypeFromList(Rest);
780selectTypeFromList([_|_Rest]) ->
781    multiple.
782
783
784
785%% Not used after cleanup of dialyzer warnings
786%% getCallErr() ->
787%%     {'ERROR' ,"Bad Operation -- handle call"}.
788
789%% Not used after cleanup of dialyzer warnings
790%% getCastErr() ->
791%%     {'ERROR' ,"Bad Operation -- handle cast"}.
792
793%% Not used after cleanup of dialyzer warnings
794%% getInfoErr() ->
795%%     {'ERROR' ,"Bad Operation -- handle info"}.
796
797
798
799
800
801
802%%
803%% Type code access utilities
804%%
805
806tk_operation_data(G, N, X, TL) ->
807    case print_tk(G,N,X) of
808	true ->
809	    TL;
810	false ->
811	    no_tk
812    end.
813
814%% Not used after cleanup of dialyzer warnings
815%% tk_interface_data(G, N, X) ->
816%%     InfoList =
817%% 	foldr(fun({_Name, Body}, Acc) ->
818%% 		      get_if(G,N,Body)++Acc end,
819%% 	      get_if(G,N,get_body(X)),
820%% 	      X#interface.inherit_body),
821%%     case InfoList of
822%% 	[] ->
823%% 	    no_tk;  %%%%%%%% Should be changed to [] <<<<<<<<<<<<<<<<<<<<<<<<<<< Warning !
824%% 	_ ->
825%% 	    InfoList
826%%     end.
827
828
829print_tk(G, N, X) when is_record(X, op)-> %% operation
830    case getNocType(G,X,N) of
831	transparent ->
832	    false;
833	multiple ->
834	    false;
835	_XTuple -> %%check if there are any USETK pragmas
836	    operation_usetk(G,N,X)
837    end;
838print_tk(_G, _N, _X) -> %% error
839    false.
840
841
842operation_usetk(G,N,X) ->
843    PTab = ic_genobj:pragmatab(G),
844    OTab = ic_genobj:optiontab(G),
845    OpName = get_id2(X),
846%    SID = ic_util:to_colon(N),
847    Res = case use_tk(OTab,[N]) of
848	      {ok,N} ->
849		  true;
850	      false ->
851		  %% Look if there is an operation with that name
852                  %% which can be found in an included file.
853		  case ets:match(PTab,{file_data_included,'_','_',op,'$3',OpName,'_','_','_'}) of
854		      [] ->
855			  false;
856		      ScopeList ->
857			  case use_tk(OTab,ScopeList) of
858			      %% There is an operation with that name,
859			      %% look if it is inherited by interface "N"
860			      {ok,FoundScope} ->
861				  ic_pragma:is_inherited_by(FoundScope,N,PTab);
862			      false ->
863				  false
864			  end
865		  end
866	  end,
867    Res.
868
869
870use_tk(_,[]) ->
871    false;
872use_tk(OTab,[[Scope]|Scopes]) ->
873    SID = ic_util:to_colon(Scope),
874    case ets:match(OTab,{{option,{use_tk,SID}},true}) of
875	[] ->
876	    case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of
877		[] ->
878		    use_tk(OTab,Scopes);
879		_ ->
880		    {ok,Scope}
881	    end;
882	_ ->
883	    {ok,Scope}
884    end;
885use_tk(OTab,[Scope|Scopes]) ->
886    SID = ic_util:to_colon(Scope),
887    case ets:match(OTab,{{option,{use_tk,SID}},true}) of
888	[] ->
889	    case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of
890		[] ->
891		    use_tk(OTab,Scopes);
892		_ ->
893		    {ok,Scope}
894	    end;
895	_ ->
896	    {ok,Scope}
897    end.
898
899mark_not_transparent(G,N) ->
900
901    %% Mark that there are multiple
902    %% functions in interface
903    S = ic_genobj:pragmatab(G),
904    ets:insert(S,{no_transparent,N}).
905
906%% Not used after cleanup of dialyzer warnings
907%% transparent(G) ->
908%%     S = ic_genobj:pragmatab(G),
909%%     case ets:match_object(S,{no_transparent,'$0'}) of
910%% 	[] ->
911%% 	    true;
912%% 	_ ->
913%% 	    false
914%%     end.
915
916