%% %% %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_codegen). -include_lib("ic/src/ic.hrl"). -include_lib("ic/src/icforms.hrl"). %%----------------------------------------------------------------- %% External exports %%----------------------------------------------------------------- -export([emit/2, emit/3]). -export([emit_c_enc_rpt/4, emit_c_dec_rpt/4]). -export([comment/2, comment/3, comment/4, comment_inlined/5, comment_prefixed/4]). -export([mcomment/2, mcomment/3, mcomment_inlined/5, mcomment_prefixed/3]). -export([mcomment_light/2, mcomment_light/3, mcomment_light_inlined/5, mcomment_light_prefixed/3]). -export([nl/1, export/2]). -export([record/5]). -export([emit_stub_head/4, emit_hrl_head/4, emit_hrl_foot/2]). %%----------------------------------------------------------------- %% Internal exports %%----------------------------------------------------------------- %%----------------------------------------------------------------- %% External functions %%----------------------------------------------------------------- %%-------------------------------------------------------------------- %% Emit output as a formatted string, (old emit) %%-------------------------------------------------------------------- emit(nil, _) -> ok; emit(Fd, Str) -> file:write(Fd, Str). emit(nil, _, _) -> ok; emit(Fd, Fmt, Args) -> file:write(Fd, io_lib:format(Fmt, Args)). emit_c_enc_rpt(Fd, Prefix, Fmt, Args) -> emit(Fd, Prefix ++ "OE_RPT_ERR(\"Encode error: " ++ Fmt ++ "\");\n", Args). emit_c_dec_rpt(Fd, Prefix, Fmt, Args) -> emit(Fd, Prefix ++ "OE_RPT_ERR(\"Decode error: " ++ Fmt ++ "\");\n", Args). %%-------------------------------------------------------------------- %% Emit comments %%-------------------------------------------------------------------- comment(Fd, C) -> comment_prefixed(Fd, C, [], "%%"). comment(Fd, C, A) -> comment_prefixed(Fd, C, A, "%%"). comment(Fd, C, A, c) -> comment_inlined(Fd, C, A, "/*", "*/"); comment(Fd, C, A, erl) -> comment_prefixed(Fd, C, A, "%%"); comment(Fd, C, A, java) -> comment_prefixed(Fd, C, A, "//"); %% Should be removed after a check if it's used !!!!! (LTH) comment(Fd, C, A, CommentSequence) when is_list(CommentSequence) -> comment_prefixed(Fd, C, A, CommentSequence). comment_inlined(Fd, C, A, Start, End) -> emit(Fd, Start ++ " " ++ C ++ " " ++ End ++"\n", A). comment_prefixed(Fd, C, A, Prefix) -> emit(Fd, Prefix ++ " " ++ C ++ "\n", A). %%-------------------------------------------------------------------- %% Emit multiline comments with nice delimiters %%-------------------------------------------------------------------- mcomment(Fd, List) -> mcomment_prefixed(Fd, List, "%%"). mcomment(Fd, List, c) -> mcomment_inlined(Fd, List, "/*", "*/", " *"); mcomment(Fd, List, erl) -> mcomment_prefixed(Fd, List, "%%"); mcomment(Fd, List, java) -> mcomment_prefixed(Fd, List, "//"). mcomment_inlined(Fd, List, Start, End, Intermediate) -> emit(Fd, Start ++ "------------------------------------------------------------\n"), emit(Fd, Intermediate ++ "\n"), lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List), emit(Fd, Intermediate ++ "\n"), emit(Fd, Intermediate ++ "------------------------------------------------------------" ++ End ++ "\n"), ok. mcomment_prefixed(Fd, List, Prefix) -> emit(Fd, Prefix ++ "------------------------------------------------------------\n"), emit(Fd, Prefix ++ "\n"), lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List), emit(Fd, Prefix ++ "\n"), emit(Fd, Prefix ++ "------------------------------------------------------------\n"), ok. %%-------------------------------------------------------------------- %% Emit multiline comments with nice delimiters as above but a %% little lighter %%-------------------------------------------------------------------- mcomment_light(Fd, List) -> mcomment_light_prefixed(Fd, List, "%%"). mcomment_light(Fd, List, c) -> mcomment_light_inlined(Fd, List, "/*", " */", " *"); mcomment_light(Fd, List, erl) -> mcomment_light_prefixed(Fd, List, "%%"); mcomment_light(Fd, List, java) -> mcomment_light_prefixed(Fd, List, "//"); %% Should be removed after a check if it's used !!!!! (LTH) mcomment_light(Fd, List, Prefix) when is_list(Prefix) -> mcomment_light_prefixed(Fd, List, Prefix). mcomment_light_inlined(Fd, List, Start, End, Intermediate) -> emit(Fd, "\n" ++ Start ++ "\n"), lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List), emit(Fd, End ++ "\n"), ok. mcomment_light_prefixed(Fd, List, Prefix) -> emit(Fd, Prefix), lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List), emit(Fd, Prefix ++ "\n"), ok. %%-------------------------------------------------------------------- %% New line %%-------------------------------------------------------------------- nl(Fd) -> emit(Fd, "\n"). %%-------------------------------------------------------------------- -define(IFRIDFIELD(G), ic_util:mk_name(G, "ID")). %%-------------------------------------------------------------------- %% Emit record definitions for erlang %%-------------------------------------------------------------------- record(G, X, Name, _IFRID, Recs) when is_record(X, struct) -> F = ic_genobj:hrlfiled(G), emit(F, "-record(~p, {~p", [ic_util:to_atom(Name),hd(Recs)]), lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, tl(Recs)), emit(F, "}).\n"); record(G, X, Name, _IFRID, _Recs) when is_record(X, union) -> F = ic_genobj:hrlfiled(G), emit(F, "-record(~p, {label, value}).\n",[ic_util:to_atom(Name)]); record(G, _X, Name, IFRID, Recs) when length(Recs) > 3 -> F = ic_genobj:hrlfiled(G), emit(F, "-record(~p,~n {~p=~p", [ic_util:to_atom(Name), ic_util:to_atom(?IFRIDFIELD(G)), IFRID]), rec2(F, "", ", ", Recs), emit(F, "}).\n"); record(G, _X, Name, IFRID, Recs) -> F = ic_genobj:hrlfiled(G), emit(F, "-record(~p, {~p=~p", [ic_util:to_atom(Name), ic_util:to_atom(?IFRIDFIELD(G)), IFRID]), lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, Recs), emit(F, "}).\n"). rec2(F, Align, Delim, [M1 , M2, M3 | Ms]) -> emit(F, "~s~s~p, ~p, ~p", [Delim, Align, M1, M2, M3]), rec2(F, " ", ",\n", Ms); rec2(F, Align, Delim, [M1 , M2]) -> emit(F, "~s~s~p, ~p", [Delim, Align, M1, M2]); rec2(F, Align, Delim, [M]) -> emit(F, "~s~s~p", [Delim, Align, M]); rec2(_F, _Align, _Delim, []) -> ok. %%-------------------------------------------------------------------- %% Emit export lists for erlang %%-------------------------------------------------------------------- export(F, [E1, E2, E3 | Exports]) -> emit(F, "-export([~s]).\n", [exp_list([E1, E2, E3])]), export(F, Exports); export(_F, []) -> ok; export(F, Exports) -> emit(F, "-export([~s]).\n", [exp_list(Exports)]). exp_list([E1 | L]) -> exp_to_string(E1) ++ lists:map(fun(E) -> ", " ++ exp_to_string(E) end, L). exp_to_string({F,N}) -> io_lib:format("~p/~p", [ic_util:to_atom(F), N]). %%-------------------------------------------------------------------- %% Emit Stub file header %%-------------------------------------------------------------------- emit_stub_head(_G, ignore, _Name, _) -> ignore; emit_stub_head(G, F1, Name, erlang) -> mcomment(F1, stub_header(G, Name)), nl(F1), emit(F1, "-module(~p).\n", [list_to_atom(Name)]), emit(F1, "-ic_compiled(~p).\n", [compiler_vsn(?COMPILERVSN)]), emit(F1, "\n\n"), F1; emit_stub_head(G, F1, Name, erlang_template) -> ic_erl_template:emit_header(G, F1, Name), F1; emit_stub_head(_G, F1, _Name, erlang_template_no_gen) -> F1; emit_stub_head(G, F1, Name, c) -> mcomment(F1, stub_header(G, Name), c), emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), Name]), emit(F1, "\n\n"), F1; emit_stub_head(G, F1, Name, c_server) -> CSName = [Name, "__s"], mcomment(F1, stub_header(G, CSName), c), emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), CSName]), emit(F1, "\n\n"), F1; emit_stub_head(G, F1, Name, java) -> mcomment(F1, stub_header(G, Name), java), emit(F1, "\n\n"), F1. stub_header(G, Name) -> ["Implementation stub file", "", io_lib:format("Target: ~s", [Name]), io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]), io_lib:format("IC vsn: ~s", [?COMPILERVSN]), "", "This file is automatically generated. DO NOT EDIT IT."]. compiler_vsn(Vsn) -> lists:map(fun($.) -> $_; (C) -> C end, Vsn). %%-------------------------------------------------------------------- %% Emit include file header %%-------------------------------------------------------------------- %% Name is Fully scoped (undescore) name of interface or module emit_hrl_head(_G, ignore, _Name, _) -> ignore; emit_hrl_head(G, Fd, Name, erlang) -> mcomment(Fd, ["Erlang header file" | hrl_header(G, Name)]), nl(Fd), nl(Fd), IfdefName = ic_util:to_uppercase(Name++"_HRL"), emit(Fd, "-ifndef(~s).~n", [IfdefName]), emit(Fd, "-define(~s, true).~n", [IfdefName]), nl(Fd), nl(Fd), Fd; emit_hrl_head(G, Fd, Name, c) -> mcomment(Fd, ["C header file" | hrl_header(G, Name)], c), nl(Fd), nl(Fd), IfdefName = ic_util:to_uppercase(Name++"_H"), emit(Fd, "#ifndef ~s~n", [IfdefName]), emit(Fd, "#define ~s ~n", [IfdefName]), nl(Fd), nl(Fd), Fd; emit_hrl_head(G, Fd, Name, c_server) -> mcomment(Fd, ["C header file" | hrl_header(G, [Name, "__s"])], c), nl(Fd), nl(Fd), IfdefName = ic_util:to_uppercase(Name++"__S_H"), emit(Fd, "#ifndef ~s~n", [IfdefName]), emit(Fd, "#define ~s ~n", [IfdefName]), nl(Fd), nl(Fd), Fd. hrl_header(G, Name) -> ["", io_lib:format("Target: ~s", [Name]), io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]), io_lib:format("IC vsn: ~s", [?COMPILERVSN]), "", "This file is automatically generated. DO NOT EDIT IT."]. %%-------------------------------------------------------------------- %% Emit include file footer %%-------------------------------------------------------------------- emit_hrl_foot(_G, erlang_template) -> ok; emit_hrl_foot(_G, erlang_template_no_gen) -> ok; emit_hrl_foot(G, erlang) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "-endif.\n"), nl(Fd), nl(Fd), Fd; false -> ok end; emit_hrl_foot(G, erlang_no_stub) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "-endif.\n"), nl(Fd), nl(Fd), Fd; false -> ok end; emit_hrl_foot(G, c) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "#ifdef __cplusplus\n"), emit(Fd, "}\n"), emit(Fd, "#endif\n"), nl(Fd), emit(Fd, "#endif\n"), nl(Fd), nl(Fd), Fd; false -> ok end; emit_hrl_foot(G, c_server) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "#ifdef __cplusplus\n"), emit(Fd, "}\n"), emit(Fd, "#endif\n"), nl(Fd), emit(Fd, "#endif\n"), nl(Fd), nl(Fd), Fd; false -> ok end; emit_hrl_foot(G, c_no_stub) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "#ifdef __cplusplus\n"), emit(Fd, "}\n"), emit(Fd, "#endif\n"), nl(Fd), emit(Fd, "#endif\n"), nl(Fd), nl(Fd), Fd; false -> ok end; emit_hrl_foot(G, c_server_no_stub) -> case ic_genobj:is_hrlfile_open(G) of true -> Fd = ic_genobj:hrlfiled(G), nl(Fd), nl(Fd), emit(Fd, "#ifdef __cplusplus\n"), emit(Fd, "}\n"), emit(Fd, "#endif\n"), nl(Fd), emit(Fd, "#endif\n"), nl(Fd), nl(Fd), Fd; false -> ok end. %%----------------------------------------------------------------- %% Internal functions %%-----------------------------------------------------------------