aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ic/src/ic_codegen.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ic/src/ic_codegen.erl')
-rw-r--r--lib/ic/src/ic_codegen.erl419
1 files changed, 419 insertions, 0 deletions
diff --git a/lib/ic/src/ic_codegen.erl b/lib/ic/src/ic_codegen.erl
new file mode 100644
index 0000000000..f611c69bea
--- /dev/null
+++ b/lib/ic/src/ic_codegen.erl
@@ -0,0 +1,419 @@
+%%
+%% %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
+%%-----------------------------------------------------------------