%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1998-2009. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% -module(ic_noc). -export([do_gen/3]). %%------------------------------------------------------------ %% %% Internal stuff %% %%------------------------------------------------------------ -export([unfold/1, mk_attr_func_names/2]). -import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]). -import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]). -import(ic_codegen, [emit/2, emit/3, nl/1]). -import(ic_options, [get_opt/2]). -import(lists, [foreach/2, foldr/3, map/2]). -include("icforms.hrl"). -include("ic.hrl"). %%------------------------------------------------------------ %% %% Generate the client side Erlang stubs. %% %% Each module is generated to a separate file. %% %% Export declarations for all interface functions must be %% generated. Each function then needs to generate a function head and %% a body. IDL parameters must be converted into Erlang parameters %% (variables, capitalised) and a type signature list must be %% generated (for later encode/decode). %% %%------------------------------------------------------------ do_gen(G, File, Form) -> G2 = ic_file:filename_push(G, [], mk_oe_name(G, ic_file:remove_ext(to_list(File))), erlang), gen_head(G2, [], Form), exportDependency(G2), %% Loop through form and adds inheritence data ic_pragma:preproc(G2, [], Form), gen(G2, [], Form), genDependency(G2), ic_file:filename_pop(G2, erlang), ok. gen(G, N, [X|Xs]) when is_record(X, preproc) -> NewG = ic:handle_preproc(G, N, X#preproc.cat, X), gen(NewG, N, Xs); gen(G, N, [X|Xs]) when is_record(X, module) -> CD = ic_code:codeDirective(G,X), G2 = ic_file:filename_push(G, N, X, CD), N2 = [get_id2(X) | N], gen_head(G2, N2, X), gen(G2, N2, get_body(X)), G3 = ic_file:filename_pop(G2, CD), gen(G3, N, Xs); gen(G, N, [X|Xs]) when is_record(X, interface) -> G2 = ic_file:filename_push(G, N, X, erlang), N2 = [get_id2(X) | N], gen_head(G2, N2, X), gen(G2, N2, get_body(X)), foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end, X#interface.inherit_body), gen_serv(G2, N, X), G3 = ic_file:filename_pop(G2, erlang), gen(G3, N, Xs); gen(G, N, [X|Xs]) when is_record(X, const) -> % N2 = [get_id2(X) | N], emit_constant_func(G, X#const.id, X#const.val), gen(G, N, Xs); %% N2 or N? gen(G, N, [X|Xs]) when is_record(X, op) -> {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), case getNocType(G,X,N) of transparent -> emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs); multiple -> mark_not_transparent(G,N), emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs); _XTuple -> mark_not_transparent(G,N), emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs) end, gen(G, N, Xs); gen(G, N, [X|Xs]) when is_record(X, attr) -> emit_attr(G, N, X, fun emit_stub_func/7), gen(G, N, Xs); gen(G, N, [X|Xs]) when is_record(X, except) -> icstruct:except_gen(G, N, X, erlang), gen(G, N, Xs); gen(G, N, [X|Xs]) -> case may_contain_structs(X) of true -> icstruct:struct_gen(G, N, X, erlang); false -> ok end, gen(G, N, Xs); gen(_G, _N, []) -> ok. may_contain_structs(X) when is_record(X, typedef) -> true; may_contain_structs(X) when is_record(X, struct) -> true; may_contain_structs(X) when is_record(X, union) -> true; may_contain_structs(_X) -> false. %%-------------------------------------------------------------------- %% %% Generate the server side (handle_call and handle_cast) %% gen_serv(G, N, X) -> case ic_genobj:is_stubfile_open(G) of true -> emit_serv_std(G, N, X), N2 = [get_id2(X) | N], gen_calls(G, N2, get_body(X)), lists:foreach(fun({_Name, Body}) -> gen_calls(G, N2, Body) end, X#interface.inherit_body), get_if_gen(G, N2, X), gen_end_of_call(G, N, X), % Note N instead of N2 gen_casts(G, N2, get_body(X)), lists:foreach(fun({_Name, Body}) -> gen_casts(G, N2, Body) end, X#interface.inherit_body), gen_end_of_cast(G, N, X), % Note N instead of N2 emit_skel_footer(G, N, X); % Note N instead of N2 false -> ok end. gen_calls(G, N, [X|Xs]) when is_record(X, op) -> case is_oneway(X) of false -> {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs), gen_calls(G, N, Xs); true -> gen_calls(G, N, Xs) end; gen_calls(G, N, [X|Xs]) when is_record(X, attr) -> emit_attr(G, N, X, fun emit_skel_func/7), gen_calls(G, N, Xs); gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs); gen_calls(_G, _N, []) -> ok. gen_casts(G, N, [X|Xs]) when is_record(X, op) -> case is_oneway(X) of true -> {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs), gen_casts(G, N, Xs); false -> gen_casts(G, N, Xs) end; gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs); gen_casts(_G, _N, []) -> ok. emit_attr(G, N, X, F) -> XX = #id_of{type=X}, {GetType, SetType} = mk_attr_func_types(N, X), lists:foreach(fun(Id) -> X2 = XX#id_of{id=Id}, {Get, Set} = mk_attr_func_names(N, get_id(Id)), F(G, N, X2, Get, [], GetType, []), case X#attr.readonly of {readonly, _} -> ok; _ -> F(G, N, X2, Set, [mk_name(G, "Value")], SetType, []) end end, ic_forms:get_idlist(X)). extract_info(G, _N, X) when is_record(X, op) -> Name = get_id2(X), InArgs = ic:filter_params([in,inout], X#op.params), OutArgs = ic:filter_params([out,inout], X#op.params), ArgNames = mk_erl_vars(G, InArgs), TypeList = {ic_forms:get_tk(X), map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs), map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs) }, {Name, ArgNames, TypeList, OutArgs}. emit_serv_std(G, N, X) -> Fd = ic_genobj:stubfiled(G), case transparent(G) of true -> true; _XTupleORMultiple -> Impl = getImplMod(G,X,[get_id2(X)|N]), TypeID = ictk:get_IR_ID(G, N, X), nl(Fd), nl(Fd), nl(Fd), ic_codegen:mcomment(Fd, ["Server implementation."]), nl(Fd), nl(Fd), ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]), nl(Fd), emit(Fd, "typeID() ->\n"), emit(Fd, " \"~s\".\n", [TypeID]), nl(Fd), nl(Fd), ic_codegen:mcomment(Fd, ["Server creation functions."]), nl(Fd), emit(Fd, "oe_create() ->\n"), emit(Fd, " start([], []).\n", []), nl(Fd), emit(Fd, "oe_create_link() ->\n"), emit(Fd, " start_link([], []).\n", []), nl(Fd), emit(Fd, "oe_create(Env) ->\n"), emit(Fd, " start(Env, []).\n", []), nl(Fd), emit(Fd, "oe_create_link(Env) ->\n"), emit(Fd, " start_link(Env, []).\n", []), nl(Fd), emit(Fd, "oe_create(Env, RegName) ->\n"), emit(Fd, " start(RegName, Env, []).\n", []), nl(Fd), emit(Fd, "oe_create_link(Env, RegName) ->\n"), emit(Fd, " start_link(RegName, Env, []).\n", []), nl(Fd), ic_codegen:mcomment(Fd, ["Start functions."]), nl(Fd), emit(Fd, "start(Env, Opt) ->\n"), emit(Fd, " gen_server:start(?MODULE, Env, Opt).\n"), nl(Fd), emit(Fd, "start_link(Env, Opt) ->\n"), emit(Fd, " gen_server:start_link(?MODULE, Env, Opt).\n"), nl(Fd), emit(Fd, "start(RegName, Env, Opt) ->\n"), emit(Fd, " gen_server:start(RegName, ?MODULE, Env, Opt).\n"), nl(Fd), emit(Fd, "start_link(RegName, Env, Opt) ->\n"), emit(Fd, " gen_server:start_link(RegName, ?MODULE, Env, Opt).\n"), nl(Fd), ic_codegen:comment(Fd, "Call to implementation init"), emit(Fd, "init(Env) ->\n"), emit(Fd, " ~p:~p(Env).\n", [Impl, init]), nl(Fd), emit(Fd, "terminate(Reason, State) ->\n"), emit(Fd, " ~p:~p(Reason, State).\n", [Impl, terminate]), nl(Fd), nl(Fd) end, Fd. gen_end_of_call(G, _N, _X) -> case transparent(G) of true -> true; _XTuple -> Fd = ic_genobj:stubfiled(G), nl(Fd), nl(Fd), ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]), emit(Fd, "handle_call(stop, From, State) ->\n"), emit(Fd, " {stop, normal, ok, State}"), case get_opt(G, serv_last_call) of exception -> emit(Fd, ";\n"), nl(Fd), emit(Fd, "handle_call(Req, From, State) ->\n"), emit(Fd, " {reply, ~p, State}.\n",[getCallErr()]); exit -> emit(Fd, ".\n"), nl(Fd), nl(Fd) end end, ok. gen_end_of_cast(G, _N, _X) -> case transparent(G) of true -> true; _XTuple -> Fd = ic_genobj:stubfiled(G), nl(Fd), nl(Fd), ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]), emit(Fd, "handle_cast(stop, State) ->\n"), emit(Fd, " {stop, normal, State}"), case get_opt(G, serv_last_call) of exception -> emit(Fd, ";\n"), nl(Fd), emit(Fd, "handle_cast(Req, State) ->\n"), emit(Fd, " {reply, ~p, State}.\n",[getCastErr()]); exit -> emit(Fd, ".\n"), nl(Fd), nl(Fd) end end, ok. emit_skel_footer(G, N, X) -> case transparent(G) of true -> true; _XTuple -> Fd = ic_genobj:stubfiled(G), nl(Fd), nl(Fd), ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]), emit(Fd, "handle_info(X, State) ->\n"), case use_impl_handle_info(G, N, X) of true -> emit(Fd, " ~p:handle_info(X, State).\n\n", [list_to_atom(ic_genobj:impl(G))]); false -> emit(Fd, " {reply, ~p, State}.\n\n",[getInfoErr()]) end end, ok. use_impl_handle_info(G, N, X) -> FullName = ic_util:to_colon([get_id2(X) | N]), case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of {_, force_false} -> false; {false, false} -> false; _ -> true end. use_timeout(G, N, _X) -> FullName = ic_util:to_colon(N), case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of {_, force_false} -> false; {false, false} -> false; _ -> true end. get_if_name(G) -> mk_oe_name(G, "get_interface"). %% Generates the get_interface function (for Lars) get_if_gen(G, N, X) -> case transparent(G) of true -> ok; _XTuple -> case ic_genobj:is_stubfile_open(G) of true -> IFC_TKS = tk_interface_data(G,N,X), Fd = ic_genobj:stubfiled(G), Name = to_atom(get_if_name(G)), ic_codegen:mcomment_light(Fd, [io_lib:format("Standard Operation: ~p", [Name])]), emit(Fd, "handle_call({~s, ~p, []}, From, State) ->~n", [mk_name(G, "Ref"), Name]), emit(Fd, " {reply, ~p, State};~n", [IFC_TKS]), nl(Fd), ok; false -> ok end end. get_if(G,N,[X|Rest]) when is_record(X, op) -> R = ic_forms:get_tk(X), IN = lists:map(fun(P) -> ic_forms:get_tk(P) end, ic:filter_params([in, inout], X#op.params)), OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end, ic:filter_params([out, inout], X#op.params)), case print_tk(G,N,X) of true -> [{get_id2(X), {R, IN, OUT}} | get_if(G,N,Rest)]; false -> get_if(G,N,Rest) end; get_if(G,N,[X|Rest]) when is_record(X, attr) -> %% Attributes not handled so far <<<<<<<<<<<<<<<<<<<<<<<< {GetT, SetT} = mk_attr_func_types([], X), AList = lists:map(fun(Id) -> {Get, Set} = mk_attr_func_names([], get_id(Id)), case X#attr.readonly of {readonly, _} -> {Get, GetT}; _ -> [{Set, SetT}, {Get, GetT}] end end, ic_forms:get_idlist(X)), lists:flatten(AList) ++ get_if(G,N,Rest); get_if(G,N,[_X|Rest]) -> get_if(G,N,Rest); get_if(_,_,[]) -> []. %%------------------------------------------------------------ %% %% Export stuff %% %% Gathering of all names that should be exported from a stub %% file. %% gen_head_special(G, N, X) when is_record(X, interface) -> Fd = ic_genobj:stubfiled(G), NocType = getNocType(G,X,N), foreach(fun({Name, Body}) -> ic_codegen:comment(Fd, "Exports from ~p", [ic_util:to_colon(Name)]), ic_codegen:export(Fd, exp_top(G, N, Body, NocType, [])), nl(Fd) end, X#interface.inherit_body), case transparent(G) of true -> nl(Fd), nl(Fd); _XTuple -> ic_codegen:comment(Fd, "Type identification function"), ic_codegen:export(Fd, [{typeID, 0}]), nl(Fd), ic_codegen:comment(Fd, "Used to start server"), ic_codegen:export(Fd, [{start, 2},{start_link, 3}]), ic_codegen:export(Fd, [{oe_create, 0}, {oe_create_link, 0}, {oe_create, 1}, {oe_create_link, 1},{oe_create, 2}, {oe_create_link, 2}]), nl(Fd), ic_codegen:comment(Fd, "gen server export stuff"), emit(Fd, "-behaviour(gen_server).\n"), ic_codegen:export(Fd, [{init, 1}, {terminate, 2}, {handle_call, 3}, {handle_cast, 2}, {handle_info, 2}]), nl(Fd), nl(Fd), ic_codegen:mcomment(Fd, ["Object interface functions."]), nl(Fd), nl(Fd), nl(Fd) end, Fd; gen_head_special(_G, _N, _X) -> ok. %% Shall generate all export declarations gen_head(G, N, X) -> case ic_genobj:is_stubfile_open(G) of true -> F = ic_genobj:stubfiled(G), ic_codegen:comment(F, "Interface functions"), ic_codegen:export(F, exp_top(G, N, X, getNocType(G,X,N), [])), nl(F), gen_head_special(G, N, X); false -> ok end. exp_top(_G, _N, X, _NT, Acc) when element(1, X) == preproc -> Acc; exp_top(G, N, L, NT, Acc) when is_list(L) -> exp_list(G, N, L, NT, Acc); exp_top(G, N, M, NT, Acc) when is_record(M, module) -> exp_list(G, N, get_body(M), NT, Acc); exp_top(G, N, I, NT, Acc) when is_record(I, interface) -> exp_list(G, N, get_body(I), NT, Acc); exp_top(G, N, X, NT, Acc) -> exp3(G, N, X, NT, Acc). exp3(_G, _N, C, _NT, Acc) when is_record(C, const) -> [{get_id(C#const.id), 0} | Acc]; exp3(G, N, Op, NocType, Acc) when is_record(Op, op) -> FuncName = get_id(Op#op.id), TA = case use_timeout(G,N,Op) of true -> 1; false -> 0 end, case NocType of transparent -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc]; multiple -> case getModType(G, Op, N) of dt -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc]; do -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc]; spt -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc]; spo -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc] end; _ -> Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, [{FuncName, Arity} | Acc] end; exp3(_G, _N, A, _NT, Acc) when is_record(A, attr) -> lists:foldr(fun(Id, Acc2) -> {Get, Set} = mk_attr_func_names([], get_id(Id)), case A#attr.readonly of {readonly, _} -> [{Get, 1} | Acc2]; _ -> [{Get, 1}, {Set, 2} | Acc2] end end, Acc, ic_forms:get_idlist(A)); exp3(_G, _N, _X, _NT, Acc) -> Acc. exp_list(G, N, L, NT, OrigAcc) -> lists:foldr(fun(X, Acc) -> exp3(G, N, X, NT, Acc) end, OrigAcc, L). %%------------------------------------------------------------ %% %% Emit stuff %% %% Low level generation primitives %% emit_stub_func(G, N, X, Name, ArgNames, TypeList, _OutArgs) -> case ic_genobj:is_stubfile_open(G) of false -> ok; true -> Fd = ic_genobj:stubfiled(G), StubName = list_to_atom(Name), This = mk_name(G, "Ref"), XTuple = getNocType(G,X,N), CallOrCast = case is_oneway(X) of true -> ?CAST; _ -> ?CALL end, %% Type expand operation on comments ic_code:type_expand_op(G,N,X,Fd), case use_timeout(G,N,X) of true -> Timeout = mk_name(G,"Timeout"), emit(Fd, "~p(~s) ->\n", [StubName, mk_list([This, Timeout| ArgNames])]), emit(Fd, " ~p:~s(~s, ~s, ?MODULE, ~p, ~p, [~s], ~p).\n\n", [getImplMod(G,X,N), CallOrCast, This, Timeout, XTuple, StubName, mk_list(ArgNames), tk_operation_data(G, N, X, TypeList)]); false -> emit(Fd, "~p(~s) ->\n", [StubName, mk_list([This | ArgNames])]), emit(Fd, " ~p:~s(~s, ~p, ?MODULE, ~p, [~s], ~p).\n\n", [getImplMod(G,X,N), CallOrCast, This, XTuple, StubName, mk_list(ArgNames), tk_operation_data(G, N, X, TypeList)]) end end. emit_transparent_func(G, N, X, Name, ArgNames, _TypeList, _OutArgs) -> case ic_genobj:is_stubfile_open(G) of false -> ok; true -> Fd = ic_genobj:stubfiled(G), OpName = list_to_atom(Name), ArgList = case use_timeout(G,N,X) of true -> mk_list([mk_name(G,"Ref"),mk_name(G,"Timeout")|ArgNames]); false -> mk_list([mk_name(G,"Ref")|ArgNames]) end, %% Type expand operation on comments ic_code:type_expand_op(G,N,X,Fd), emit(Fd, "~p(~s) ->\n", [OpName,ArgList]), emit(Fd, " ~p:~s(~s).\n\n", [getImplMod(G,X,N), OpName, ArgList]) end. emit_skel_func(G, N, X, OpName, ArgNames, _TypeList, _OutArgs) -> case getNocType(G,X,N) of transparent -> true; multiple -> true; XTuple -> case ic_genobj:is_stubfile_open(G) of false -> ok; true -> Fd = ic_genobj:stubfiled(G), Name = list_to_atom(OpName), This = mk_name(G, "Ref"), From = mk_name(G, "From"), State = mk_name(G, "State"), %% Type expand handle operation on comments ic_code:type_expand_handle_op(G,N,X,Fd), case is_oneway(X) of true -> emit(Fd, "handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s) ->\n", [This, XTuple, Name, mk_list(ArgNames), State]), emit(Fd, " ~p:handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s);\n\n", [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), State]); false -> emit(Fd, "handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s) ->\n", [This, XTuple, Name, mk_list(ArgNames), From, State]), emit(Fd, " ~p:handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s);\n\n", [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), From, State]) end end end. emit_constant_func(G, Id, Val) -> case ic_genobj:is_stubfile_open(G) of false -> ok; true -> Fd = ic_genobj:stubfiled(G), N = list_to_atom(get_id(Id)), emit_const_comment(G, Fd, Id, N), emit(Fd, "~p() -> ~p.\n\n", [N, Val]) end. emit_const_comment(_G, F, _X, Name) -> ic_codegen:mcomment_light(F, [io_lib:format("Constant: ~p", [Name])]). %%------------------------------------------------------------ %% %% Utilities %% %% Convenient little go-get functions %% %%------------------------------------------------------------ %% The automaticly generated get and set operation names for an %% attribute. mk_attr_func_names(_Scope, Name) -> {"_get_" ++ Name, "_set_" ++ Name}. %% Returns TK of the Get and Set attribute functions. mk_attr_func_types(_N, X) -> TK = ic_forms:get_tk(X), {{TK, [], []}, {tk_void, [TK], []}}. %%------------------------------------------------------------ %% %% Generation utilities and common stuff %% %% Convenient stuff for generation %% %%------------------------------------------------------------ %% Input is a list of parameters (in parse form) and output is a list %% of capitalised variable names. mk_var is in icgen mk_erl_vars(_G, Params) -> map(fun(P) -> mk_var(get_id(P#param.id)) end, Params). %% mk_list produces a nice comma separated string of variable names mk_list([]) -> []; mk_list([Arg | Args]) -> Arg ++ mk_list2(Args). mk_list2([Arg | Args]) -> ", " ++ Arg ++ mk_list2(Args); mk_list2([]) -> []. %%------------------------------------------------------------ %% %% Parser utilities %% %% Called from the yecc parser. Expands the identifier list of an %% attribute so that the attribute generator never has to handle %% lists. %% %%------------------------------------------------------------ %% Unfold identifier lists or nested lists. Note that many records %% contain an entry named id that is a list before unfold and a single %% id afterwards. unfold(L) when is_list(L) -> lists:flatten(map(fun(X) -> unfold2(X) end, L)); unfold(X) -> unfold2(X). unfold2(A) when is_record(A, attr) -> map(fun(Id) -> A#attr{id=Id} end, A#attr.id); unfold2(M) when is_record(M, member) -> map(fun(Id) -> M#member{id=Id} end, M#member.id); unfold2(M) when is_record(M, case_dcl) -> map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label); unfold2(T) when is_record(T, typedef) -> map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id ). %% Export code produce for dependency function exportDependency(G) -> Fd = ic_genobj:stubfiled(G), ic_codegen:export(Fd, [{oe_dependency, 0}]), nl(Fd). %% Code produce for dependency function genDependency(G) -> Fd = ic_genobj:stubfiled(G), nl(Fd),nl(Fd), ic_codegen:comment(Fd, "Idl file dependency list function"), emit(Fd, "oe_dependency() ->\n", []), emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]). %%%%%% getImplMod(G,X,Scope) -> %% to_atom(ic_genobj:impl(G)) | ChoicedModuleName %% Get actual pragma appliance scope SpecScope = getActualScope(G,X,Scope), %% The "broker" option is passed %% only by pragmas, seek for module. case ic_pragma:getBrokerData(G,X,SpecScope) of {Module,_Type} -> Module; _List -> element(1,ic_pragma:defaultBrokerData(G)) end. getNocType(G,X,Scope) when is_record(X, interface) -> %% default | specified OpList = getAllOperationScopes(G,Scope), getNocType2(G,X,OpList); getNocType(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN} getNocType3(G,X,Scope). getNocType2(G,X,List) -> getNocType2(G,X,List,[]). getNocType2(_,_,[],Found) -> selectTypeFromList(Found); getNocType2(G,X,[OpScope|OpScopes],Found) -> getNocType2(G,X,OpScopes,[getNocType3(G,X,OpScope)|Found]). getNocType3(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN} %% Get actual pragma appliance scope SpecScope = getActualScope(G,X,Scope), %% The "broker" option is passed %% only by pragmas, seek for type. case ic_pragma:getBrokerData(G,X,SpecScope) of {_Module,Type} -> Type; List -> selectTypeFromList(List) %%transparent/multiple end. getModType(G,X,Scope) -> %% default | specified %% Get actual pragma appliance scope SpecScope = getActualScope(G,X,Scope), %% The "broker" option is passed %% only by pragmas, seek for brokerdata. case ic_pragma:getBrokerData(G,X,SpecScope) of {Module,Type} -> case Module == ic_genobj:impl(G) of true -> case Type of transparent -> dt; %% default + transparent _ -> do %% default + opaque end; false -> case Type of transparent -> spt; %% specified + transparent _ -> spo %% specified + opaque end end; _List -> dt end. %%%% %% %% Returns a list of ALL operation full %% scoped names local and inherited %% from other interfaces %% getAllOperationScopes(G,Scope) -> getOperationScopes(G,Scope) ++ getInhOperationScopes(G,Scope). getOperationScopes(G,Scope) -> getOpScopes(G, Scope, ets:match(ic_genobj:pragmatab(G),{op,'$0',Scope,'_','_'}), []). getOpScopes(_,_,[],OpScopes) -> OpScopes; getOpScopes(G,Scope,[[Name]|Names],Found) -> getOpScopes(G,Scope,Names,[[Name|Scope]|Found]). getInhOperationScopes(G,Scope) -> getInhOpScopes1(G, Scope, ets:match(ic_genobj:pragmatab(G),{inherits,Scope,'$1'}), []). getInhOpScopes1(G,_Scope,[],OpScopes) -> getInhOpScopes2(G,OpScopes); getInhOpScopes1(G,Scope,[[SC]|SCs],Found) -> getInhOpScopes1(G,Scope,SCs,[SC|Found]). getInhOpScopes2(G,Scopes) -> getInhOpScopes2(G,Scopes,[]). getInhOpScopes2(_G,[],Found) -> Found; getInhOpScopes2(G,[SC|SCs],Found) -> getOperationScopes(G,SC) ++ getInhOpScopes2(G,SCs,Found). %% %% %%%% %%%% %% %% %% Seek the actual operation scope : %% %% * if the operation is inherited, get the real scope for it %% %% * if the operation has a specific pragma, apply the real %% scope, otherwise return the including scope %% getActualScope(G, X, Scope) when is_record(X, op) -> OpScope = getRealOpScope(G,X,Scope), case ets:match(ic_genobj:pragmatab(G),{codeopt_specific,OpScope}) of [[]] -> OpScope; _ -> Scope end; getActualScope(_G, _X, N) -> N. %% %% Just seek and return the scope for the operation %% where it were originaly defined %% getRealOpScope(G,X,N) when is_record(X, op) -> Ptab = ic_genobj:pragmatab(G), Id = get_id2(X), case ets:match(Ptab,{op,Id,N,'_','_'}) of [[]] -> [Id|N]; _ -> getRealOpScope(G, Ptab, X, N, Id, ets:match(Ptab,{inherits,N,'$1'})) end; getRealOpScope(_G,_X,N) -> N. getRealOpScope(_G, _S, _X, N, Id, []) -> [Id|N]; getRealOpScope(G, S, X, N, Id, [[OS]|OSs]) -> case ets:match(S,{op,Id,OS,'_','_'}) of [[]] -> [Id|OS]; _ -> getRealOpScope(G, S, X, N, Id, OSs) end. selectTypeFromList([]) -> transparent; selectTypeFromList([{_,transparent}|Rest]) -> selectTypeFromList(Rest); selectTypeFromList([transparent|Rest]) -> selectTypeFromList(Rest); selectTypeFromList([_|_Rest]) -> multiple. getCallErr() -> {'ERROR' ,"Bad Operation -- handle call"}. getCastErr() -> {'ERROR' ,"Bad Operation -- handle cast"}. getInfoErr() -> {'ERROR' ,"Bad Operation -- handle info"}. %% %% Type code access utilities %% tk_operation_data(G, N, X, TL) -> case print_tk(G,N,X) of true -> TL; false -> no_tk end. tk_interface_data(G, N, X) -> InfoList = foldr(fun({_Name, Body}, Acc) -> get_if(G,N,Body)++Acc end, get_if(G,N,get_body(X)), X#interface.inherit_body), case InfoList of [] -> no_tk; %%%%%%%% Should be changed to [] <<<<<<<<<<<<<<<<<<<<<<<<<<< Warning ! _ -> InfoList end. print_tk(G, N, X) when is_record(X, op)-> %% operation case getNocType(G,X,N) of transparent -> false; multiple -> false; _XTuple -> %%check if there are any USETK pragmas operation_usetk(G,N,X) end; print_tk(_G, _N, _X) -> %% error false. operation_usetk(G,N,X) -> PTab = ic_genobj:pragmatab(G), OTab = ic_genobj:optiontab(G), OpName = get_id2(X), % SID = ic_util:to_colon(N), Res = case use_tk(OTab,[N]) of {ok,N} -> true; false -> %% Look if there is an operation with that name %% which can be found in an included file. case ets:match(PTab,{file_data_included,'_','_',op,'$3',OpName,'_','_','_'}) of [] -> false; ScopeList -> case use_tk(OTab,ScopeList) of %% There is an operation with that name, %% look if it is inherited by interface "N" {ok,FoundScope} -> ic_pragma:is_inherited_by(FoundScope,N,PTab); false -> false end end end, Res. use_tk(_,[]) -> false; use_tk(OTab,[[Scope]|Scopes]) -> SID = ic_util:to_colon(Scope), case ets:match(OTab,{{option,{use_tk,SID}},true}) of [] -> case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of [] -> use_tk(OTab,Scopes); _ -> {ok,Scope} end; _ -> {ok,Scope} end; use_tk(OTab,[Scope|Scopes]) -> SID = ic_util:to_colon(Scope), case ets:match(OTab,{{option,{use_tk,SID}},true}) of [] -> case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of [] -> use_tk(OTab,Scopes); _ -> {ok,Scope} end; _ -> {ok,Scope} end. mark_not_transparent(G,N) -> %% Mark that there are multiple %% functions in interface S = ic_genobj:pragmatab(G), ets:insert(S,{no_transparent,N}). transparent(G) -> S = ic_genobj:pragmatab(G), case ets:match_object(S,{no_transparent,'$0'}) of [] -> true; _ -> false end.