diff options
Diffstat (limited to 'lib/ic/src/ic_codegen.erl')
-rw-r--r-- | lib/ic/src/ic_codegen.erl | 419 |
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 +%%----------------------------------------------------------------- |