%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(prepare_templates).
-export([gen_asn1ct_rtt/1,gen_asn1ct_eval/1]).
gen_asn1ct_rtt(Ms) ->
{ok,Fd} = file:open("asn1ct_rtt.erl", [write]),
io:format(Fd,
"%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
"%%\n"
"%% Input files:\n", [?MODULE]),
[io:put_chars(Fd, ["%% ",M,$\n]) || M <- Ms],
io:nl(Fd),
io:put_chars(Fd,
"-module(asn1ct_rtt).\n"
"-export([assert_defined/1,dependencies/1,code/0]).\n"
"\n"),
Forms = lists:sort(lists:append([abstract(M) || M <- Ms])),
Exp = lists:sort(exports(Forms)),
defined(Fd, Exp),
io:nl(Fd),
Calls = calls(Forms),
R = sofs:relation(Calls),
Fam0 = sofs:relation_to_family(R),
Fam = sofs:to_external(Fam0),
dependencies(Fd, Fam),
io:nl(Fd),
Funcs = [begin
Bin = list_to_binary([$\n|erl_pp:function(Func)]),
{{M,F,A},Bin}
end || {M,{function,_,F,A,_}=Func} <- Forms],
io:format(Fd, "code() ->\n~p.\n\n", [Funcs]),
ok = file:close(Fd),
halt(0).
gen_asn1ct_eval([File]) ->
Output = filename:rootname(File, ".funcs") ++ ".erl",
{ok,Fd} = file:open(Output, [write]),
{ok,Funcs} = file:consult(File),
asn1ct_func:start_link(),
[asn1ct_func:need(MFA) || MFA <- Funcs],
io:format(Fd,
"%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
"%%\n"
"%% Input file: ~s\n\n", [?MODULE,File]),
io:format(Fd, "-module(~s).\n", [filename:rootname(File)]),
gen_asn1ct_eval_exp(Fd, Funcs),
asn1ct_func:generate(Fd),
ok = file:close(Fd),
halt(0).
gen_asn1ct_eval_exp(Fd, Funcs) ->
io:put_chars(Fd, "-export(["),
gen_asn1ct_eval_exp_1(Fd, Funcs, ""),
io:put_chars(Fd, "]).\n").
gen_asn1ct_eval_exp_1(Fd, [{_,F,A}|T], Sep) ->
io:put_chars(Fd, Sep),
io:format(Fd, "~p/~p", [F,A]),
gen_asn1ct_eval_exp_1(Fd, T, ",\n");
gen_asn1ct_eval_exp_1(_, [], _) -> ok.
defined(Fd, [H|T]) ->
io:format(Fd, "assert_defined(~p) -> ok", [H]),
case T of
[] ->
io:put_chars(Fd, ".\n");
[_|_] ->
io:put_chars(Fd, ";\n"),
defined(Fd, T)
end.
dependencies(Fd, [{K,V}|T]) ->
io:format(Fd, "dependencies(~p) ->\n~p;\n", [K,V]),
dependencies(Fd, T);
dependencies(Fd, []) ->
io:put_chars(Fd, "dependencies(_) -> [].\n").
abstract(File) ->
{ok,{M0,[{abstract_code,Abstract}]}} =
beam_lib:chunks(File, [abstract_code]),
{raw_abstract_v1,Forms} = Abstract,
M = module(M0),
[{M,F} || F <- Forms].
module(M0) ->
"asn1rtt_" ++ M = atom_to_list(M0),
list_to_atom(M).
exports([{M,{attribute,_,export,L}}|T]) ->
[{M,F,A} || {F,A} <- L] ++ exports(T);
exports([_|T]) ->
exports(T);
exports([]) -> [].
calls([{M,{function,_,F,A,Body}}|T]) ->
MFA = {M,F,A},
case find_calls(Body, M) -- [MFA] of
[] ->
calls(T);
[_|_]=Calls ->
[{MFA,Callee} || Callee <- Calls] ++ calls(T)
end;
calls([_|T]) ->
calls(T);
calls([]) -> [].
find_calls([{call,_,{atom,_,F},Args}|T], M) ->
Calls = find_calls(Args, M) ++ find_calls(T, M),
Arity = length(Args),
case is_bif(F, Arity) of
false ->
[{M,F,Arity}|Calls];
true ->
Calls
end;
find_calls([{'fun',_,{function,F,A}}|T], M) ->
[{M,F,A}|find_calls(T, M)];
find_calls([H|T], M) ->
find_calls(H, M) ++ find_calls(T, M);
find_calls(Tuple, M) when is_tuple(Tuple) ->
find_calls(tuple_to_list(Tuple), M);
find_calls(_, _) -> [].
is_bif(F, Arity) ->
erl_internal:bif(F, Arity).