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