1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(prepare_templates).
22-export([gen_asn1ct_rtt/1,gen_asn1ct_eval/1]).
23
24gen_asn1ct_rtt(Ms) ->
25    {ok,Fd} = file:open("asn1ct_rtt.erl", [write]),
26    io:format(Fd,
27	      "%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
28	      "%%\n"
29	      "%% Input files:\n", [?MODULE]),
30    [io:put_chars(Fd, ["%%  ",M,$\n]) || M <- Ms],
31    io:nl(Fd),
32    io:put_chars(Fd,
33		 "-module(asn1ct_rtt).\n"
34		 "-export([assert_defined/1,dependencies/1,code/0]).\n"
35		 "\n"),
36    Forms = lists:sort(lists:append([abstract(M) || M <- Ms])),
37    Exp = lists:sort(exports(Forms)),
38    defined(Fd, Exp),
39    io:nl(Fd),
40    Calls = calls(Forms),
41    R = sofs:relation(Calls),
42    Fam0 = sofs:relation_to_family(R),
43    Fam = sofs:to_external(Fam0),
44    dependencies(Fd, Fam),
45    io:nl(Fd),
46    Funcs = [begin
47		 Bin = list_to_binary([$\n|erl_pp:function(Func)]),
48		 {{M,F,A},Bin}
49	     end || {M,{function,_,F,A,_}=Func} <- Forms],
50    io:format(Fd, "code() ->\n~p.\n\n", [Funcs]),
51    ok = file:close(Fd),
52    halt(0).
53
54gen_asn1ct_eval([File]) ->
55    Output = filename:rootname(File, ".funcs") ++ ".erl",
56    {ok,Fd} = file:open(Output, [write]),
57    {ok,Funcs} = file:consult(File),
58    asn1ct_func:start_link(),
59    [asn1ct_func:need(MFA) || MFA <- Funcs],
60    io:format(Fd,
61	      "%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
62	      "%%\n"
63	      "%% Input file: ~s\n\n", [?MODULE,File]),
64    io:format(Fd, "-module(~s).\n", [filename:rootname(File)]),
65    gen_asn1ct_eval_exp(Fd, Funcs),
66    asn1ct_func:generate(Fd),
67    ok = file:close(Fd),
68    halt(0).
69
70gen_asn1ct_eval_exp(Fd, Funcs) ->
71    io:put_chars(Fd, "-export(["),
72    gen_asn1ct_eval_exp_1(Fd, Funcs, ""),
73    io:put_chars(Fd, "]).\n").
74
75gen_asn1ct_eval_exp_1(Fd, [{_,F,A}|T], Sep) ->
76    io:put_chars(Fd, Sep),
77    io:format(Fd, "~p/~p", [F,A]),
78    gen_asn1ct_eval_exp_1(Fd, T, ",\n");
79gen_asn1ct_eval_exp_1(_, [], _) -> ok.
80
81defined(Fd, [H|T]) ->
82    io:format(Fd, "assert_defined(~p) -> ok", [H]),
83    case T of
84	[] ->
85	    io:put_chars(Fd, ".\n");
86	[_|_] ->
87	    io:put_chars(Fd, ";\n"),
88	    defined(Fd, T)
89    end.
90
91dependencies(Fd, [{K,V}|T]) ->
92    io:format(Fd, "dependencies(~p) ->\n~p;\n", [K,V]),
93    dependencies(Fd, T);
94dependencies(Fd, []) ->
95    io:put_chars(Fd, "dependencies(_) -> [].\n").
96
97abstract(File) ->
98    {ok,{M0,[{abstract_code,Abstract}]}} =
99	beam_lib:chunks(File, [abstract_code]),
100    {raw_abstract_v1,Forms} = Abstract,
101    M = module(M0),
102    [{M,F} || F <- Forms].
103
104module(M0) ->
105    "asn1rtt_" ++ M = atom_to_list(M0),
106    list_to_atom(M).
107
108exports([{M,{attribute,_,export,L}}|T]) ->
109    [{M,F,A} || {F,A} <- L] ++ exports(T);
110exports([_|T]) ->
111    exports(T);
112exports([]) -> [].
113
114calls([{M,{function,_,F,A,Body}}|T]) ->
115    MFA = {M,F,A},
116    case find_calls(Body, M) -- [MFA] of
117	[] ->
118	    calls(T);
119	[_|_]=Calls ->
120	    [{MFA,Callee} || Callee <- Calls] ++ calls(T)
121    end;
122calls([_|T]) ->
123    calls(T);
124calls([]) -> [].
125
126find_calls([{call,_,{atom,_,F},Args}|T], M) ->
127    Calls = find_calls(Args, M) ++ find_calls(T, M),
128    Arity = length(Args),
129    case is_bif(F, Arity) of
130	false ->
131	    [{M,F,Arity}|Calls];
132	true ->
133	    Calls
134    end;
135find_calls([{'fun',_,{function,F,A}}|T], M) ->
136    [{M,F,A}|find_calls(T, M)];
137find_calls([H|T], M) ->
138    find_calls(H, M) ++ find_calls(T, M);
139find_calls(Tuple, M) when is_tuple(Tuple) ->
140    find_calls(tuple_to_list(Tuple), M);
141find_calls(_, _) -> [].
142
143is_bif(F, Arity) ->
144    erl_internal:bif(F, Arity).
145