%%
%% %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_code).


-include_lib("ic/src/ic.hrl").
-include_lib("ic/src/icforms.hrl").

%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([get_basetype/2, insert_typedef/3, codeDirective/2]).
-export([gen_includes/3, gen_includes/4, mk_list/1]).

-export([type_expand_op/4, type_expand_handle_op/4]).
-export([ type_expand_op_exec/4, type_expand_all/6, type_expand/7]).

-export([type_expand_null/3, type_expand_void/3, type_expand_float/3, type_expand_double/3]).
-export([type_expand_short/3, type_expand_ushort/3, type_expand_long/3, type_expand_ulong/3]).
-export([type_expand_longlong/3, type_expand_ulonglong/3]).
-export([type_expand_char/3, type_expand_wchar/3, type_expand_boolean/3]).
-export([type_expand_octet/3, type_expand_any/3,  type_expand_wstring/3]).
-export([type_expand_object/3, type_expand_string/3, type_expand_struct/7, type_expand_union/7]).
-export([type_expand_enum/4, type_expand_sequence/7, type_expand_array/7, type_expand_error/3]).

-export([type_expand_struct_rule/3, type_expand_union_rule/2, type_expand_enum_rule/4]).
-export([type_expand_enum_elements/3, type_expand_longdouble/3, type_expand_typecode/3]).
-export([type_expand_principal/3, type_expand_exception/7]).

%%-----------------------------------------------------------------
%% External functions
%%-----------------------------------------------------------------

%%-------------------------------------------------------------------------------------
%%
%% Trackrecording of generated sequence type structs, thist is just used for C today.
%%
%%-------------------------------------------------------------------------------------

get_basetype(G, MyId) ->
    case ?lookup(ic_genobj:typedeftab(G), MyId) of
	[] ->
	     MyId;
	X ->
	    get_basetype(G, X)
    end.

insert_typedef(_G, "erlang_term", _) ->
    ok;
insert_typedef(G, MyId, DefinedAsId) ->
    ?insert(ic_genobj:typedeftab(G), MyId, DefinedAsId).

codeDirective(G,X) ->
    case produceCode(X) of
        true ->
            case ic_options:get_opt(G, be) of
                c_genserv ->
                    c;
		c_client ->
		    c;
		c_server ->
		    c_server;
                _ ->
                    erlang
            end;
        false ->
            case ic_options:get_opt(G, be) of              
                c_genserv ->
                    c_no_stub;
		c_client ->
		    c_no_stub;
		c_server ->
		    c_server_no_stub;
                _ ->
                    erlang_no_stub
            end
    end.

%% Checks if X should produce code
produceCode(X) when is_record(X, module) ->
    case ic_forms:get_body(X) of
        [] ->
            true;
        List ->
            produceModuleCode(List)
    end;
produceCode(_X) ->    
    false.
    
produceModuleCode([]) ->
    false;
produceModuleCode([X|_Xs]) when is_record(X, const) ->
    true;
produceModuleCode([_X|Xs]) ->
    produceModuleCode(Xs).
 
%% Includes needed c file headers for included idl files
gen_includes(Fd,G,Type) ->
    case Type of
	c_client ->
	    IncludeList = 
		ic_pragma:get_included_c_headers(G),
	    gen_includes_loop(Fd,IncludeList,Type);
	c_server ->
	    IncludeList = 
		ic_pragma:get_included_c_headers(G),
	    gen_includes_loop(Fd,IncludeList,Type);
	_ ->
	    ok
    end,
    ic_codegen:nl(Fd),
    ic_codegen:emit(Fd, "#ifdef __cplusplus\n"),
    ic_codegen:emit(Fd, "extern \"C\" {\n"),
    ic_codegen:emit(Fd, "#endif\n\n").


%% Includes needed c file headers for local interfaces
gen_includes(Fd,G,X,Type) ->
    case Type of
	c_client ->
	    IncludeList = 
		ic_pragma:get_local_c_headers(G,X),
	    gen_includes_loop(Fd,IncludeList,Type);
	c_server ->
	    IncludeList = 
		ic_pragma:get_local_c_headers(G,X),
	    gen_includes_loop(Fd,IncludeList,Type);
	_ ->
	    ok
    end,
    ic_codegen:nl(Fd),
    ic_codegen:emit(Fd, "#ifdef __cplusplus\n"),
    ic_codegen:emit(Fd, "extern \"C\" {\n"),
    ic_codegen:emit(Fd, "#endif\n\n").


gen_includes_loop(_,[],_) ->
    ok;
gen_includes_loop(Fd,[I|Is],Type) ->
    L = string:tokens(I,"/"),
    File = lists:last(L),
    case File of
	"erlang" -> % Erlang is NOT generated that way !
	    gen_includes_loop(Fd,Is,Type);
	"oe_erlang" -> % Erlang is NOT generated that way !
	    gen_includes_loop(Fd,Is,Type);
	_ ->
	    case Type of
		c_client ->
		    ic_codegen:emit(Fd, "#include \"~s.h\"\n", [File]);
		c_server ->
		    ic_codegen:emit(Fd, "#include \"~s__s.h\"\n", [File])
	    end,
	    gen_includes_loop(Fd,Is,Type)
    end.




%%
%% Used in NOC only
%%


%%
%% Type expand on function head comments
%%
type_expand_op(G,N,X,Fd) ->
    case catch type_expand_op_exec(G,N,X,Fd) of
	{'EXIT',_Reason} ->
	    ic_codegen:nl(Fd),
	    ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]),
	    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]);
	_ ->
	    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[])
    end.


type_expand_op_exec(G,N,X,Fd) ->
    InArgs = ic:filter_params([in,inout], X#op.params),
    OutArgs = ic:filter_params([out,inout], X#op.params),
    ParamNr = length(InArgs)+1,
    Tabs = "",
    
    ic_codegen:nl(Fd),
    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]),

     case ic_forms:is_oneway(X) of
	false ->
	    ic_codegen:emit(Fd,"%% Operation: ~s/~p~n",[ic_forms:get_id2(X),ParamNr]);
	true ->
	    ic_codegen:emit(Fd,"%% Operation: ~s/~p  (oneway)~n",[ic_forms:get_id2(X),ParamNr])
    end,

    if  X#op.raises == [] -> [];
	true ->
	    ic_codegen:emit(Fd,"%%~n",[]),
	    RaisesList=["%% Raises: " ++ 
			mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end, 
					  X#op.raises))],
	    ic_codegen:emit(Fd,RaisesList,[]),
	    ic_codegen:nl(Fd)
    end,

    %% Print argument names
    ic_codegen:emit(Fd,"%%\n",[]),
    InArgNames = ["OE_Ref"]++[ic_util:mk_var(ic_forms:get_id(InArg#param.id)) || InArg <- InArgs ],
    OutArgNames = ["Ret"]++[ic_util:mk_var(ic_forms:get_id(OutArg#param.id)) || OutArg <- OutArgs ],
    case length(InArgNames) > 1 of
	true ->
	    ic_codegen:emit(Fd,"%% Input value(s)  : ~s~n",[mk_list(InArgNames)]);
	false ->
	    ic_codegen:emit(Fd,"%% Input value     : ~s~n",[mk_list(InArgNames)])
    end,
    case length(OutArgNames) > 1 of
	true ->
	    ic_codegen:emit(Fd,"%% Return value(s) : ~s~n",[mk_list(OutArgNames)]);
	false ->
	    ic_codegen:emit(Fd,"%% Return value    : ~s~n",[mk_list(OutArgNames)])
    end,
    ic_codegen:emit(Fd,"%%\n",[]),

    InArgsTypeList = 
	[{ic_util:mk_var(ic_forms:get_id(InArg#param.id)),ic_forms:get_tk(InArg)} || InArg <- InArgs ],
    case InArgsTypeList of
	[] -> %% no input parameters
	    ok;
	_ ->
	    ic_codegen:emit(Fd,"%%                                             --input-params-~n",[]),
	    type_expand_all(G,N,X,Fd,Tabs,InArgsTypeList)
    end,

    ReturnTypeList =[{"Ret",X#op.tk}],
    ic_codegen:emit(Fd,"%%                                             --return-value-~n",[]),
    type_expand_all(G,N,X,Fd,Tabs,ReturnTypeList),

    OutArgsTypeList = 
	[{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)),ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ], 
    case OutArgsTypeList of
	[] -> %% no input parameters
	    ok;
	_ ->
	    ic_codegen:emit(Fd,"%%                                             -output-values-~n",[]),
	    type_expand_all(G,N,X,Fd,Tabs,OutArgsTypeList)
    end.




type_expand_handle_op(G,N,X,Fd) ->
    case catch type_expand_handle_op_exec(G,N,X,Fd) of
	{'EXIT',_Reason} ->
	    ic_codegen:nl(Fd),
	    ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]),
	    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]);
	_ ->
	    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[])
    end.


type_expand_handle_op_exec(_G,_N,X,Fd) ->
    InArgs = ic:filter_params([in,inout], X#op.params),
    ParamNr = length(InArgs)+1,
    
    ic_codegen:nl(Fd),
    ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]),

    case ic_forms:is_oneway(X) of
	false ->
	    ic_codegen:emit(Fd,"%% Handle operation: handle_call/3~n",[]);
	true ->
	    ic_codegen:emit(Fd,"%% Handle operation: handle_cast/3~n",[])
    end,
    ic_codegen:emit(Fd,"%%~n",[]),
    ic_codegen:emit(Fd,"%% Used for operation ~s/~p implementation~n",[ic_forms:get_id2(X),ParamNr]).



type_expand_all(_G,_N,_X,_Fd,_Tabs,[]) -> 
    ok;
type_expand_all(G,N,X,Fd,Tabs,[{ArgName,Type}|Rest]) ->
    type_expand(G,N,X,Fd,Tabs,ArgName,Type),
    type_expand_all(G,N,X,Fd,Tabs,Rest);
type_expand_all(G,N,X,Fd,Tabs,[{default,_ArgName,Type}|Rest]) ->
    type_expand(G,N,X,Fd,Tabs,"Def",Type),
    type_expand_all(G,N,X,Fd,Tabs,Rest);
type_expand_all(G,N,X,Fd,Tabs,[{LabelNr,_ArgName,Type}|Rest]) when is_integer(LabelNr) ->
    type_expand(G,N,X,Fd,Tabs,"V" ++ integer_to_list(LabelNr),Type),
    type_expand_all(G,N,X,Fd,Tabs,Rest);
type_expand_all(G,N,X,Fd,Tabs,[{Label,_ArgName,Type}|Rest]) ->
    type_expand(G,N,X,Fd,Tabs,Label,Type),
    type_expand_all(G,N,X,Fd,Tabs,Rest).



type_expand(_G,_N,_X,Fd,Tabs,Name,tk_null) ->
    type_expand_null(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_void) ->
    type_expand_void(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_float) ->
    type_expand_float(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_double) ->
    type_expand_double(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longdouble) ->
    type_expand_longdouble(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_short) ->
    type_expand_short(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ushort) ->
    type_expand_ushort(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_long) ->
    type_expand_long(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longlong) ->
    type_expand_longlong(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulong) ->
    type_expand_ulong(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulonglong) ->
    type_expand_ulonglong(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_char) ->
    type_expand_char(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_wchar) ->
    type_expand_wchar(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_boolean) ->
    type_expand_boolean(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_octet) ->
    type_expand_octet(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_any) ->
    type_expand_any(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_TypeCode) ->
    type_expand_typecode(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,tk_Principal) ->
    type_expand_principal(Fd,Tabs,Name);
type_expand(G, N, X,Fd,Tabs,Name, {tk_except, Id, ExcName, ElementList}) ->
    type_expand_exception(G, N, X, Fd,Tabs,Name, 
			  {tk_except, Id, ExcName, ElementList});
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_fixed, _Digits, _Scale}) ->
    type_expand_fixed(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjTabs, _ObjName}) ->
    type_expand_object(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjName}) ->
    type_expand_object(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_string, _Length}) ->
    type_expand_string(Fd,Tabs,Name);
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_wstring, _Length}) ->
    type_expand_wstring(Fd,Tabs,Name);
type_expand(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList}) ->
    type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList});
type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList}) ->
    type_expand_enum(Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList});
type_expand(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length}) ->
    type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length});
type_expand(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length}) ->
    type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length});
type_expand(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) ->
    type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList});
type_expand(_G,_N,_X,Fd,Tabs,Name,_) ->
    type_expand_error(Fd,Tabs,Name).


%% Basic OMG IDL types

type_expand_null(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = null()~n",[Tabs,Name]).

type_expand_void(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = void()~n",[Tabs,Name]).

type_expand_float(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = float()~n",[Tabs,Name]).

type_expand_double(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = double()~n",[Tabs,Name]).

type_expand_longdouble(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = long_double()~n",[Tabs,Name]).

type_expand_short(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = short()~n",[Tabs,Name]).

type_expand_ushort(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = unsigned_Short()~n",[Tabs,Name]).

type_expand_long(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = long()~n",[Tabs,Name]).

type_expand_longlong(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = long_Long()~n",[Tabs,Name]).

type_expand_ulong(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long()~n",[Tabs,Name]).

type_expand_ulonglong(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long_Long()~n",[Tabs,Name]).

type_expand_char(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = char()~n",[Tabs,Name]).

type_expand_wchar(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = wchar()~n",[Tabs,Name]).

type_expand_boolean(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = boolean()~n",[Tabs,Name]).

type_expand_octet(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = octet()~n",[Tabs,Name]).

type_expand_any(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = any()~n",[Tabs,Name]).

type_expand_typecode(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = TypeCode()~n",[Tabs,Name]).

type_expand_principal(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = principal()~n",[Tabs,Name]).


type_expand_fixed(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = fixed()~n",[Tabs,Name]).

type_expand_object(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = Object_Ref()~n",[Tabs,Name]).


%% Constructed OMG IDL types

type_expand_string(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = String()~n",[Tabs,Name]).

type_expand_wstring(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = WString()~n",[Tabs,Name]).

type_expand_exception(G, N, X, Fd, Tabs, Name, {tk_except, Id, ExcName, ElementList}) ->
    ScopedStructName = getScopedName(G, N, ExcName, Id),
    ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs, Name]),
    type_expand_exception_rule(Fd, ScopedStructName, ElementList),
    type_expand_all(G, N, X, Fd, Tabs, ElementList).

type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) ->
    ScopedStructName = getScopedName(G,N,StructName,IFRId),
    ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]),
    type_expand_struct_rule(Fd,ScopedStructName,TcList),
    type_expand_all(G,N,X,Fd,Tabs,TcList).

type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, _DNr, LblList}) ->
    ScopedUnionName = getScopedName(G,N,UnionName,IFRId),
    ic_codegen:emit(Fd,"%%~s ~s = #'~s'{label, value}\n",[Tabs,Name,ScopedUnionName]),
    type_expand(G,N,X,Fd,Tabs,"label",DTC),
    ic_codegen:emit(Fd,"%%~s value = ",[Tabs]),
    type_expand_union_rule(Fd,LblList),
    type_expand_all(G,N,X,Fd,Tabs,LblList).

type_expand_enum(Fd,Tabs,Name,{tk_enum, _IFRId, EnumName, ElemNameList}) ->
    ic_codegen:emit(Fd,"%%~s ~s = ~s~n",[Tabs,Name,EnumName]),
    type_expand_enum_rule(Fd,Tabs,EnumName,ElemNameList).

type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, _Length}) ->
    ic_codegen:emit(Fd,"%%~s ~s = [ ~sElem ]~n",[Tabs,Name,Name]),
    type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC).

type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, _Length}) ->
    ic_codegen:emit(Fd,"%%~s ~s = { ~sElem[,..~sElem] }~n",[Tabs,Name,Name,Name]),
    type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC).

type_expand_error(Fd,Tabs,Name) ->
    ic_codegen:emit(Fd,"%%~s ~s = ????~n",[Tabs,Name]).


type_expand_exception_rule(Fd,_Name,[]) ->
    ic_codegen:emit(Fd," ???? ");
type_expand_exception_rule(Fd,Name,TcList) ->
    ic_codegen:emit(Fd,"#'~s'{",[Name]), 
    type_expand_exception_rule(Fd,TcList).

type_expand_exception_rule(Fd,[{Name,_TC}]) ->
    ic_codegen:emit(Fd,"~s}~n",[Name]);
type_expand_exception_rule(Fd,[{Name,_TC}|Rest]) ->
    ic_codegen:emit(Fd,"~s,",[Name]),
    type_expand_exception_rule(Fd,Rest).

type_expand_struct_rule(Fd,_Name,[]) ->
    ic_codegen:emit(Fd," ???? ");
type_expand_struct_rule(Fd,Name,TcList) ->
    ic_codegen:emit(Fd,"#'~s'{",[Name]), 
    type_expand_struct_rule(Fd,TcList).

type_expand_struct_rule(Fd,[{Name,_TC}]) ->
    ic_codegen:emit(Fd,"~s}~n",[Name]);
type_expand_struct_rule(Fd,[{Name,_TC}|Rest]) ->
    ic_codegen:emit(Fd,"~s,",[Name]),
    type_expand_struct_rule(Fd,Rest).


type_expand_union_rule(Fd,[]) ->
    ic_codegen:emit(Fd," ????");
type_expand_union_rule(Fd,[{default,_Name,_TC}]) ->
    ic_codegen:emit(Fd,"Def~n",[]);
type_expand_union_rule(Fd,[{LNr,_Name,_TC}]) when is_integer(LNr)->
    ic_codegen:emit(Fd,"V~p~n",[LNr]);
type_expand_union_rule(Fd,[{Label,_Name,_TC}]) ->
    ic_codegen:emit(Fd,"~s~n",[Label]);
type_expand_union_rule(Fd,[{default,_Name,_TC}|Rest]) ->
    ic_codegen:emit(Fd,"Default | "),
    type_expand_union_rule(Fd,Rest);
type_expand_union_rule(Fd,[{LNr,_Name,_TC}|Rest]) when is_integer(LNr) ->
    ic_codegen:emit(Fd,"V~p | ",[LNr]),
    type_expand_union_rule(Fd,Rest);
type_expand_union_rule(Fd,[{Label,_Name,_TC}|Rest]) ->
    ic_codegen:emit(Fd,"~s | ",[Label]),
    type_expand_union_rule(Fd,Rest).


type_expand_enum_rule(Fd,Tabs,Name,[]) ->
    ic_codegen:emit(Fd,"%%~s ~s = ????",[Tabs,Name]);
type_expand_enum_rule(Fd,Tabs,Name,ElList) ->
    ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]),
    type_expand_enum_rule(Fd,ElList).

type_expand_enum_rule(Fd,[ElName]) ->
    ic_codegen:emit(Fd,"'~s' ~n",[ElName]);
type_expand_enum_rule(Fd,[First|Rest]) ->
    ic_codegen:emit(Fd,"'~s' | ",[First]),
    type_expand_enum_rule(Fd,Rest).

type_expand_enum_elements(_Fd,_Tabs,[]) ->
    ok;
type_expand_enum_elements(Fd,Tabs,[Elem|Elems]) ->
    ic_codegen:emit(Fd,"%%~s ~s = Atom()~n",[Tabs,Elem]),
    type_expand_enum_elements(Fd,Tabs,Elems).



%% Returns the right scoped name to be used
%% along with the expansion comments 
getScopedName(G,N,Name,IfrId) ->
    PTab = ic_genobj:pragmatab(G),
    case ets:match(PTab,{alias,'$0',IfrId}) of
	[] -> %% No Alias - should never happen
	    ic_util:to_undersc(ic_pragma:mk_scope(IfrId));
	[[[_S|N]]] -> %% An alias
	    ic_util:to_undersc([Name|N]);
	[[[S|FoundScope]]] -> %% Maybe inherited
	    case ic_pragma:is_inherited_by(FoundScope,N,PTab) of
		false -> %% Not inherited
		    ic_util:to_undersc([S|FoundScope]);
		true -> %% inherited
		    ic_util:to_undersc([Name|N])
	    end
    end.


%% 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([]) -> [].



%%-----------------------------------------------------------------
%% Internal functions
%%-----------------------------------------------------------------



