1%% ``Licensed under the Apache License, Version 2.0 (the "License");
2%% you may not use this file except in compliance with the License.
3%% You may obtain a copy of the License at
4%%
5%%     http://www.apache.org/licenses/LICENSE-2.0
6%%
7%% Unless required by applicable law or agreed to in writing, software
8%% distributed under the License is distributed on an "AS IS" BASIS,
9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10%% See the License for the specific language governing permissions and
11%% limitations under the License.
12%%
13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
15%% AB. All Rights Reserved.''
16%%
17%%     $Id: compile.erl,v 1.1 2008/12/17 09:53:42 mikpe Exp $
18%% Purpose: Run the Erlang compiler.
19
20-module(compile).
21-include("erl_compile.hrl").
22-include("core_parse.hrl").
23
24%% High-level interface.
25-export([file/1,file/2,format_error/1,iofile/1]).
26-export([forms/1,forms/2]).
27-export([output_generated/1]).
28-export([options/0]).
29
30%% Erlc interface.
31-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]).
32
33
34-import(lists, [member/2,reverse/1,keysearch/3,last/1,
35		map/2,flatmap/2,foreach/2,foldr/3,any/2,filter/2]).
36
37%% file(FileName)
38%% file(FileName, Options)
39%%  Compile the module in file FileName.
40
41-define(DEFAULT_OPTIONS, [verbose,report_errors,report_warnings]).
42
43-define(pass(P), {P,fun P/1}).
44
45file(File) -> file(File, ?DEFAULT_OPTIONS).
46
47file(File, Opts) when list(Opts) ->
48    do_compile({file,File}, Opts++env_default_opts());
49file(File, Opt) ->
50    file(File, [Opt|?DEFAULT_OPTIONS]).
51
52forms(File) -> forms(File, ?DEFAULT_OPTIONS).
53
54forms(Forms, Opts) when list(Opts) ->
55    do_compile({forms,Forms}, [binary|Opts++env_default_opts()]);
56forms(Forms, Opts) when atom(Opts) ->
57    forms(Forms, [Opts|?DEFAULT_OPTIONS]).
58
59env_default_opts() ->
60    Key = "ERL_COMPILER_OPTIONS",
61    case os:getenv(Key) of
62	false -> [];
63	Str when list(Str) ->
64	    case erl_scan:string(Str) of
65		{ok,Tokens,_} ->
66		    case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
67			{ok,List} when list(List) -> List;
68			{ok,Term} -> [Term];
69			{error,_Reason} ->
70			    io:format("Ignoring bad term in ~s\n", [Key]),
71			    []
72		    end;
73		{error, {_,_,_Reason}, _} ->
74		    io:format("Ignoring bad term in ~s\n", [Key]),
75		    []
76	    end
77    end.
78
79do_compile(Input, Opts0) ->
80    Opts = expand_opts(Opts0),
81    Self = self(),
82    Serv = spawn_link(fun() -> internal(Self, Input, Opts) end),
83    receive
84	{Serv,Rep} -> Rep
85    end.
86
87%% Given a list of compilation options, returns true if compile:file/2
88%% would have generated a Beam file, false otherwise (if only a binary or a
89%% listing file would have been generated).
90
91output_generated(Opts) ->
92    any(fun ({save_binary,_F}) -> true;
93	    (_Other) -> false
94	end, passes(file, expand_opts(Opts))).
95
96expand_opts(Opts) ->
97    foldr(fun expand_opt/2, [], Opts).
98
99expand_opt(basic_validation, Os) ->
100    [no_code_generation,to_pp,binary|Os];
101expand_opt(strong_validation, Os) ->
102    [no_code_generation,to_kernel,binary|Os];
103expand_opt(report, Os) ->
104    [report_errors,report_warnings|Os];
105expand_opt(return, Os) ->
106    [return_errors,return_warnings|Os];
107expand_opt(r7, Os) ->
108    [no_float_opt,no_new_funs,no_new_binaries,no_new_apply|Os];
109expand_opt(O, Os) -> [O|Os].
110
111filter_opts(Opts0) ->
112    %% Native code generation is not supported if no_new_funs is given.
113    case member(no_new_funs, Opts0) of
114	false -> Opts0;
115	true -> Opts0 -- [native]
116    end.
117
118%% format_error(ErrorDescriptor) -> string()
119
120format_error(no_native_support) ->
121    "this system is not configured for native-code compilation.";
122format_error({native, E}) ->
123    io_lib:fwrite("native-code compilation failed with reason: ~P.",
124		  [E, 25]);
125format_error({native_crash, E}) ->
126    io_lib:fwrite("native-code compilation crashed with reason: ~P.",
127		  [E, 25]);
128format_error({open,E}) ->
129    io_lib:format("open error '~s'", [file:format_error(E)]);
130format_error({epp,E}) ->
131    epp:format_error(E);
132format_error(write_error) ->
133    "error writing file";
134format_error({rename,S}) ->
135    io_lib:format("error renaming ~s", [S]);
136format_error({parse_transform,M,R}) ->
137    io_lib:format("error in parse transform '~s': ~p", [M, R]);
138format_error({core_transform,M,R}) ->
139    io_lib:format("error in core transform '~s': ~p", [M, R]);
140format_error({crash,Pass,Reason}) ->
141    io_lib:format("internal error in ~p;\ncrash reason: ~p", [Pass,Reason]);
142format_error({bad_return,Pass,Reason}) ->
143    io_lib:format("internal error in ~p;\nbad return value: ~p", [Pass,Reason]).
144
145%% The compile state record.
146-record(compile, {filename="",
147		  dir="",
148		  base="",
149		  ifile="",
150		  ofile="",
151		  module=[],
152		  code=[],
153		  core_code=[],
154		  abstract_code=[],		%Abstract code for debugger.
155		  options=[],
156		  errors=[],
157		  warnings=[]}).
158
159internal(Master, Input, Opts) ->
160    Master ! {self(),
161	      case catch internal(Input, Opts) of
162		  {'EXIT', Reason} ->
163		      {error, Reason};
164		  Other ->
165		      Other
166	      end}.
167
168internal({forms,Forms}, Opts) ->
169    Ps = passes(forms, Opts),
170    internal_comp(Ps, "", "", #compile{code=Forms,options=Opts});
171internal({file,File}, Opts) ->
172    Ps = passes(file, Opts),
173    Compile = #compile{options=Opts},
174    case member(from_core, Opts) of
175	true -> internal_comp(Ps, File, ".core", Compile);
176	false ->
177	    case member(from_beam, Opts) of
178		true ->
179		    internal_comp(Ps, File, ".beam", Compile);
180		false ->
181		    case member(from_asm, Opts) orelse member(asm, Opts) of
182			true ->
183			    internal_comp(Ps, File, ".S", Compile);
184			false ->
185			    internal_comp(Ps, File, ".erl", Compile)
186		    end
187	    end
188    end.
189
190internal_comp(Passes, File, Suffix, St0) ->
191    Dir = filename:dirname(File),
192    Base = filename:basename(File, Suffix),
193    St1 = St0#compile{filename=File, dir=Dir, base=Base,
194		      ifile=erlfile(Dir, Base, Suffix),
195		      ofile=objfile(Base, St0)},
196    Run = case member(time, St1#compile.options) of
197	      true  ->
198		  io:format("Compiling ~p\n", [File]),
199		  fun run_tc/2;
200	      false -> fun({_Name,Fun}, St) -> catch Fun(St) end
201	  end,
202    case fold_comp(Passes, Run, St1) of
203	{ok,St2} -> comp_ret_ok(St2);
204	{error,St2} -> comp_ret_err(St2)
205    end.
206
207fold_comp([{Name,Test,Pass}|Ps], Run, St) ->
208    case Test(St) of
209	false ->				%Pass is not needed.
210	    fold_comp(Ps, Run, St);
211	true ->					%Run pass in the usual way.
212	    fold_comp([{Name,Pass}|Ps], Run, St)
213    end;
214fold_comp([{Name,Pass}|Ps], Run, St0) ->
215    case Run({Name,Pass}, St0) of
216	{ok,St1} -> fold_comp(Ps, Run, St1);
217	{error,St1} -> {error,St1};
218	{'EXIT',Reason} ->
219	    Es = [{St0#compile.ifile,[{none,?MODULE,{crash,Name,Reason}}]}],
220	    {error,St0#compile{errors=St0#compile.errors ++ Es}};
221	Other ->
222	    Es = [{St0#compile.ifile,[{none,?MODULE,{bad_return,Name,Other}}]}],
223	    {error,St0#compile{errors=St0#compile.errors ++ Es}}
224    end;
225fold_comp([], _Run, St) -> {ok,St}.
226
227os_process_size() ->
228    case os:type() of
229	{unix, sunos} ->
230	    Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"),
231	    list_to_integer(nonl(Size));
232	_ ->
233	    0
234    end.
235
236nonl([$\n]) -> [];
237nonl([]) -> [];
238nonl([H|T]) -> [H|nonl(T)].
239
240run_tc({Name,Fun}, St) ->
241    Before0 = statistics(runtime),
242    Val = (catch Fun(St)),
243    After0 = statistics(runtime),
244    {Before_c, _} = Before0,
245    {After_c, _} = After0,
246    io:format(" ~-30s: ~10.3f s (~w k)\n",
247	      [Name, (After_c-Before_c) / 1000, os_process_size()]),
248    Val.
249
250comp_ret_ok(#compile{code=Code,warnings=Warn,module=Mod,options=Opts}=St) ->
251    report_warnings(St),
252    Ret1 = case member(binary, Opts) andalso not member(no_code_generation, Opts) of
253	       true -> [Code];
254	       false -> []
255	   end,
256    Ret2 = case member(return_warnings, Opts) of
257	       true -> Ret1 ++ [Warn];
258	       false -> Ret1
259	   end,
260    list_to_tuple([ok,Mod|Ret2]).
261
262comp_ret_err(St) ->
263    report_errors(St),
264    report_warnings(St),
265    case member(return_errors, St#compile.options) of
266	true -> {error,St#compile.errors,St#compile.warnings};
267	false -> error
268    end.
269
270%% passes(form|file, [Option]) -> [{Name,PassFun}]
271%%  Figure out which passes that need to be run.
272
273passes(forms, Opts) ->
274    select_passes(standard_passes(), Opts);
275passes(file, Opts) ->
276    case member(from_beam, Opts) of
277	true ->
278	    Ps = [?pass(read_beam_file)|binary_passes()],
279	    select_passes(Ps, Opts);
280	false ->
281	    Ps = case member(from_asm, Opts) orelse member(asm, Opts) of
282		     true ->
283			 [?pass(beam_consult_asm)|asm_passes()];
284		     false ->
285			 case member(from_core, Opts) of
286			     true ->
287				 [?pass(parse_core)|core_passes()];
288			     false ->
289				 [?pass(parse_module)|standard_passes()]
290			 end
291		 end,
292	    Fs = select_passes(Ps, Opts),
293
294	    %% If the last pass saves the resulting binary to a file,
295	    %% insert a first pass to remove the file.
296	    case last(Fs)  of
297		{save_binary,_Fun} -> [?pass(remove_file)|Fs];
298		_Other -> Fs
299	    end
300    end.
301
302%% select_passes([Command], Opts) ->  [{Name,Function}]
303%%  Interpret the lists of commands to return a pure list of passes.
304%%
305%%  Command can be one of:
306%%
307%%    {pass,Mod}	Will be expanded to a call to the external
308%%			function Mod:module(Code, Options).  This
309%%			function must transform the code and return
310%%			{ok,NewCode} or {error,Term}.
311%%			Example: {pass,beam_codegen}
312%%
313%%    {Name,Fun}	Name is an atom giving the name of the pass.
314%%    			Fun is an 'fun' taking one argument: a compile record.
315%%			The fun should return {ok,NewCompileRecord} or
316%%			{error,NewCompileRecord}.
317%%			Note: ?pass(Name) is equvivalent to {Name,fun Name/1}.
318%%			Example: ?pass(parse_module)
319%%
320%%    {Name,Test,Fun}	Like {Name,Fun} above, but the pass will be run
321%%			(and listed by the `time' option) only if Test(St)
322%%			returns true.
323%%
324%%    {src_listing,Ext}	Produces an Erlang source listing with the
325%%			the file extension Ext.  (Ext should not contain
326%%			a period.)  No more passes will be run.
327%%
328%%    {listing,Ext}	Produce an listing of the terms in the internal
329%%			representation.  The extension of the listing
330%%			file will be Ext.  (Ext should not contain
331%%			a period.)   No more passes will be run.
332%%
333%%    {done,Ext}        End compilation at this point. Produce a listing
334%%                      as with {listing,Ext}, unless 'binary' is
335%%                      specified, in which case the current
336%%                      representation of the code is returned without
337%%                      creating an output file.
338%%
339%%    {iff,Flag,Cmd}	If the given Flag is given in the option list,
340%%			Cmd will be interpreted as a command.
341%%			Otherwise, Cmd will be ignored.
342%%			Example: {iff,dcg,{listing,"codegen}}
343%%
344%%    {unless,Flag,Cmd}	If the given Flag is NOT given in the option list,
345%%			Cmd will be interpreted as a command.
346%%			Otherwise, Cmd will be ignored.
347%%			Example: {unless,no_kernopt,{pass,sys_kernopt}}
348%%
349
350select_passes([{pass,Mod}|Ps], Opts) ->
351    F = fun(St) ->
352		case catch Mod:module(St#compile.code, St#compile.options) of
353		    {ok,Code} ->
354			{ok,St#compile{code=Code}};
355		    {error,Es} ->
356			{error,St#compile{errors=St#compile.errors ++ Es}}
357		end
358	end,
359    [{Mod,F}|select_passes(Ps, Opts)];
360select_passes([{src_listing,Ext}|_], _Opts) ->
361    [{listing,fun (St) -> src_listing(Ext, St) end}];
362select_passes([{listing,Ext}|_], _Opts) ->
363    [{listing,fun (St) -> listing(Ext, St) end}];
364select_passes([{done,Ext}|_], Opts) ->
365    select_passes([{unless,binary,{listing,Ext}}], Opts);
366select_passes([{iff,Flag,Pass}|Ps], Opts) ->
367    select_cond(Flag, true, Pass, Ps, Opts);
368select_passes([{unless,Flag,Pass}|Ps], Opts) ->
369    select_cond(Flag, false, Pass, Ps, Opts);
370select_passes([{_,Fun}=P|Ps], Opts) when is_function(Fun) ->
371    [P|select_passes(Ps, Opts)];
372select_passes([{_,Test,Fun}=P|Ps], Opts) when is_function(Test),
373					      is_function(Fun) ->
374    [P|select_passes(Ps, Opts)];
375select_passes([], _Opts) ->
376    [];
377select_passes([List|Ps], Opts) when is_list(List) ->
378    case select_passes(List, Opts) of
379	[] -> select_passes(Ps, Opts);
380	Nested ->
381	    case last(Nested) of
382		{listing,_Fun} -> Nested;
383		_Other         -> Nested ++ select_passes(Ps, Opts)
384	    end
385    end.
386
387select_cond(Flag, ShouldBe, Pass, Ps, Opts) ->
388    ShouldNotBe = not ShouldBe,
389    case member(Flag, Opts) of
390	ShouldBe    -> select_passes([Pass|Ps], Opts);
391	ShouldNotBe -> select_passes(Ps, Opts)
392    end.
393
394%% The standard passes (almost) always run.
395
396standard_passes() ->
397    [?pass(transform_module),
398     {iff,'dpp',{listing,"pp"}},
399     ?pass(lint_module),
400     {iff,'P',{src_listing,"P"}},
401     {iff,'to_pp',{done,"P"}},
402
403     {iff,'dabstr',{listing,"abstr"}},
404     {iff,debug_info,?pass(save_abstract_code)},
405
406     ?pass(expand_module),
407     {iff,'dexp',{listing,"expand"}},
408     {iff,'E',{src_listing,"E"}},
409     {iff,'to_exp',{done,"E"}},
410
411     %% Conversion to Core Erlang.
412     ?pass(core_module),
413     {iff,'dcore',{listing,"core"}},
414     {iff,'to_core0',{done,"core"}}
415     | core_passes()].
416
417core_passes() ->
418    %% Optimization and transforms of Core Erlang code.
419    [{unless,no_copt,
420      [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1},
421       ?pass(core_fold_module),
422       {core_inline_module,fun test_core_inliner/1,fun core_inline_module/1},
423       {core_fold_after_inline,fun test_core_inliner/1,fun core_fold_module/1},
424       ?pass(core_transforms)]},
425     {iff,dcopt,{listing,"copt"}},
426     {iff,'to_core',{done,"core"}}
427     | kernel_passes()].
428
429kernel_passes() ->
430    %% Destructive setelement/3 optimization and core lint.
431    [?pass(core_dsetel_module),
432     {iff,clint,?pass(core_lint_module)},
433     {iff,core,?pass(save_core_code)},
434
435     %% Kernel Erlang and code generation.
436     ?pass(kernel_module),
437     {iff,dkern,{listing,"kernel"}},
438     {iff,'to_kernel',{done,"kernel"}},
439     {pass,v3_life},
440     {iff,dlife,{listing,"life"}},
441     {pass,v3_codegen},
442     {iff,dcg,{listing,"codegen"}}
443     | asm_passes()].
444
445asm_passes() ->
446    %% Assembly level optimisations.
447    [{unless,no_postopt,
448      [{pass,beam_block},
449       {iff,dblk,{listing,"block"}},
450       {unless,no_bopt,{pass,beam_bool}},
451       {iff,dbool,{listing,"bool"}},
452       {unless,no_topt,{pass,beam_type}},
453       {iff,dtype,{listing,"type"}},
454       {pass,beam_dead},	      %Must always run since it splits blocks.
455       {iff,ddead,{listing,"dead"}},
456       {unless,no_jopt,{pass,beam_jump}},
457       {iff,djmp,{listing,"jump"}},
458       {pass,beam_clean},
459       {iff,dclean,{listing,"clean"}},
460       {pass,beam_flatten}]},
461
462     %% If post optimizations are turned off, we still coalesce
463     %% adjacent labels and remove unused labels to keep the
464     %% HiPE compiler happy.
465     {iff,no_postopt,
466      [?pass(beam_unused_labels),
467       {pass,beam_clean}]},
468
469     {iff,dopt,{listing,"optimize"}},
470     {iff,'S',{listing,"S"}},
471     {iff,'to_asm',{done,"S"}},
472
473     {pass,beam_validator},
474     ?pass(beam_asm)
475     | binary_passes()].
476
477binary_passes() ->
478    [{native_compile,fun test_native/1,fun native_compile/1},
479     {unless,binary,?pass(save_binary)}].
480
481%%%
482%%% Compiler passes.
483%%%
484
485%% Remove the target file so we don't have an old one if the compilation fail.
486remove_file(St) ->
487    file:delete(St#compile.ofile),
488    {ok,St}.
489
490-record(asm_module, {module,
491		     exports,
492		     labels,
493		     functions=[],
494		     cfun,
495		     code,
496		     attributes=[]}).
497
498preprocess_asm_forms(Forms) ->
499    R = #asm_module{},
500    R1 = collect_asm(Forms, R),
501    {R1#asm_module.module,
502     {R1#asm_module.module,
503      R1#asm_module.exports,
504      R1#asm_module.attributes,
505      R1#asm_module.functions,
506      R1#asm_module.labels}}.
507
508collect_asm([], R) ->
509    case R#asm_module.cfun of
510	undefined ->
511	    R;
512	{A,B,C} ->
513	    R#asm_module{functions=R#asm_module.functions++
514			 [{function,A,B,C,R#asm_module.code}]}
515    end;
516collect_asm([{module,M} | Rest], R) ->
517    collect_asm(Rest, R#asm_module{module=M});
518collect_asm([{exports,M} | Rest], R) ->
519    collect_asm(Rest, R#asm_module{exports=M});
520collect_asm([{labels,M} | Rest], R) ->
521    collect_asm(Rest, R#asm_module{labels=M});
522collect_asm([{function,A,B,C} | Rest], R) ->
523    R1 = case R#asm_module.cfun of
524	     undefined ->
525		 R;
526	     {A0,B0,C0} ->
527		 R#asm_module{functions=R#asm_module.functions++
528			      [{function,A0,B0,C0,R#asm_module.code}]}
529	 end,
530    collect_asm(Rest, R1#asm_module{cfun={A,B,C}, code=[]});
531collect_asm([{attributes, Attr} | Rest], R) ->
532    collect_asm(Rest, R#asm_module{attributes=Attr});
533collect_asm([X | Rest], R) ->
534    collect_asm(Rest, R#asm_module{code=R#asm_module.code++[X]}).
535
536beam_consult_asm(St) ->
537    case file:consult(St#compile.ifile) of
538	{ok, Forms0} ->
539	    {Module, Forms} = preprocess_asm_forms(Forms0),
540	    {ok,St#compile{module=Module, code=Forms}};
541	{error,E} ->
542	    Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
543	    {error,St#compile{errors=St#compile.errors ++ Es}}
544    end.
545
546read_beam_file(St) ->
547    case file:read_file(St#compile.ifile) of
548	{ok,Beam} ->
549	    Infile = St#compile.ifile,
550	    case is_too_old(Infile) of
551		true ->
552		    {ok,St#compile{module=none,code=none}};
553		false ->
554		    Mod0 = filename:rootname(filename:basename(Infile)),
555		    Mod = list_to_atom(Mod0),
556		    {ok,St#compile{module=Mod,code=Beam,ofile=Infile}}
557	    end;
558	{error,E} ->
559	    Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
560	    {error,St#compile{errors=St#compile.errors ++ Es}}
561    end.
562
563is_too_old(BeamFile) ->
564    case beam_lib:chunks(BeamFile, ["CInf"]) of
565	{ok,{_,[{"CInf",Term0}]}} ->
566	    Term = binary_to_term(Term0),
567	    Opts = proplists:get_value(options, Term, []),
568	    lists:member(no_new_funs, Opts);
569	_ -> false
570    end.
571
572parse_module(St) ->
573    Opts = St#compile.options,
574    Cwd = ".",
575    IncludePath = [Cwd, St#compile.dir|inc_paths(Opts)],
576    Tab = ets:new(compiler__tab, [protected,named_table]),
577    ets:insert(Tab, {compiler_options,Opts}),
578    R =  epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)),
579    ets:delete(Tab),
580    case R of
581	{ok,Forms} ->
582	    {ok,St#compile{code=Forms}};
583	{error,E} ->
584	    Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}],
585	    {error,St#compile{errors=St#compile.errors ++ Es}}
586    end.
587
588parse_core(St) ->
589    case file:read_file(St#compile.ifile) of
590	{ok,Bin} ->
591	    case core_scan:string(binary_to_list(Bin)) of
592		{ok,Toks,_} ->
593		    case core_parse:parse(Toks) of
594			{ok,Mod} ->
595			    Name = (Mod#c_module.name)#c_atom.val,
596			    {ok,St#compile{module=Name,code=Mod}};
597			{error,E} ->
598			    Es = [{St#compile.ifile,[E]}],
599			    {error,St#compile{errors=St#compile.errors ++ Es}}
600		    end;
601		{error,E,_} ->
602		    Es = [{St#compile.ifile,[E]}],
603		    {error,St#compile{errors=St#compile.errors ++ Es}}
604	    end;
605	{error,E} ->
606	    Es = [{St#compile.ifile,[{none,compile,{open,E}}]}],
607	    {error,St#compile{errors=St#compile.errors ++ Es}}
608    end.
609
610compile_options([{attribute,_L,compile,C}|Fs]) when is_list(C) ->
611    C ++ compile_options(Fs);
612compile_options([{attribute,_L,compile,C}|Fs]) ->
613    [C|compile_options(Fs)];
614compile_options([_F|Fs]) -> compile_options(Fs);
615compile_options([]) -> [].
616
617transforms(Os) -> [ M || {parse_transform,M} <- Os ].
618
619transform_module(St) ->
620    %% Extract compile options from code into options field.
621    Ts = transforms(St#compile.options ++ compile_options(St#compile.code)),
622    foldl_transform(St, Ts).
623
624foldl_transform(St, [T|Ts]) ->
625    Name = "transform " ++ atom_to_list(T),
626    Fun = fun(S) -> T:parse_transform(S#compile.code, S#compile.options) end,
627    Run = case member(time, St#compile.options) of
628	      true  -> fun run_tc/2;
629	      false -> fun({_Name,F}, S) -> catch F(S) end
630	  end,
631    case Run({Name, Fun}, St) of
632	{error,Es,Ws} ->
633	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
634			      errors=St#compile.errors ++ Es}};
635	{'EXIT',R} ->
636	    Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}],
637	    {error,St#compile{errors=St#compile.errors ++ Es}};
638	Forms ->
639	    foldl_transform(St#compile{code=Forms}, Ts)
640    end;
641foldl_transform(St, []) -> {ok,St}.
642
643get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
644
645core_transforms(St) ->
646    %% The options field holds the complete list of options at this
647
648    Ts = get_core_transforms(St#compile.options),
649    foldl_core_transforms(St, Ts).
650
651foldl_core_transforms(St, [T|Ts]) ->
652    Name = "core transform " ++ atom_to_list(T),
653    Fun = fun(S) -> T:core_transform(S#compile.code, S#compile.options) end,
654    Run = case member(time, St#compile.options) of
655	      true  -> fun run_tc/2;
656	      false -> fun({_Name,F}, S) -> catch F(S) end
657	  end,
658    case Run({Name, Fun}, St) of
659	{'EXIT',R} ->
660	    Es = [{St#compile.ifile,[{none,compile,{core_transform,T,R}}]}],
661	    {error,St#compile{errors=St#compile.errors ++ Es}};
662	Forms ->
663	    foldl_core_transforms(St#compile{code=Forms}, Ts)
664    end;
665foldl_core_transforms(St, []) -> {ok,St}.
666
667%%% Fetches the module name from a list of forms. The module attribute must
668%%% be present.
669get_module([{attribute,_,module,{M,_As}} | _]) -> M;
670get_module([{attribute,_,module,M} | _]) -> M;
671get_module([_ | Rest]) ->
672    get_module(Rest).
673
674%%% A #compile state is returned, where St.base has been filled in
675%%% with the module name from Forms, as a string, in case it wasn't
676%%% set in St (i.e., it was "").
677add_default_base(St, Forms) ->
678    F = St#compile.filename,
679    case F of
680	"" ->
681	    M = get_module(Forms),
682	    St#compile{base = atom_to_list(M)};
683	_ ->
684	    St
685    end.
686
687lint_module(St) ->
688    case erl_lint:module(St#compile.code,
689			 St#compile.ifile, St#compile.options) of
690	{ok,Ws} ->
691	    %% Insert name of module as base name, if needed. This is
692	    %% for compile:forms to work with listing files.
693	    St1 = add_default_base(St, St#compile.code),
694	    {ok,St1#compile{warnings=St1#compile.warnings ++ Ws}};
695	{error,Es,Ws} ->
696	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
697			      errors=St#compile.errors ++ Es}}
698    end.
699
700core_lint_module(St) ->
701    case core_lint:module(St#compile.code, St#compile.options) of
702	{ok,Ws} ->
703	    {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
704	{error,Es,Ws} ->
705	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
706			      errors=St#compile.errors ++ Es}}
707    end.
708
709%% expand_module(State) -> State'
710%%  Do the common preprocessing of the input forms.
711
712expand_module(#compile{code=Code,options=Opts0}=St0) ->
713    {Mod,Exp,Forms,Opts1} = sys_pre_expand:module(Code, Opts0),
714    Opts2 = expand_opts(Opts1),
715    Opts = filter_opts(Opts2),
716    {ok,St0#compile{module=Mod,options=Opts,code={Mod,Exp,Forms}}}.
717
718core_module(#compile{code=Code0,options=Opts,ifile=File}=St) ->
719    {ok,Code,Ws} = v3_core:module(Code0, Opts),
720    {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}.
721
722core_fold_module(#compile{code=Code0,options=Opts,ifile=File}=St) ->
723    {ok,Code,Ws} = sys_core_fold:module(Code0, Opts),
724    {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}.
725
726test_old_inliner(#compile{options=Opts}) ->
727    %% The point of this test is to avoid loading the old inliner
728    %% if we know that it will not be used.
729    case any(fun(no_inline) -> true;
730		(_) -> false
731	     end, Opts) of
732      true -> false;
733      false ->
734	any(fun({inline,_}) -> true;
735	       (_) -> false
736	    end, Opts)
737    end.
738
739test_core_inliner(#compile{options=Opts}) ->
740    case any(fun(no_inline) -> true;
741		(_) -> false
742	     end, Opts) of
743	true -> false;
744	false ->
745	    any(fun(inline) -> true;
746		   (_) -> false
747		end, Opts)
748    end.
749
750core_old_inliner(#compile{code=Code0,options=Opts}=St) ->
751    case catch sys_core_inline:module(Code0, Opts) of
752	{ok,Code} ->
753	    {ok,St#compile{code=Code}};
754	{error,Es} ->
755	    {error,St#compile{errors=St#compile.errors ++ Es}}
756    end.
757
758core_inline_module(#compile{code=Code0,options=Opts}=St) ->
759    Code = cerl_inline:core_transform(Code0, Opts),
760    {ok,St#compile{code=Code}}.
761
762core_dsetel_module(#compile{code=Code0,options=Opts}=St) ->
763    {ok,Code} = sys_core_dsetel:module(Code0, Opts),
764    {ok,St#compile{code=Code}}.
765
766kernel_module(#compile{code=Code0,options=Opts,ifile=File}=St) ->
767    {ok,Code,Ws} = v3_kernel:module(Code0, Opts),
768    {ok,St#compile{code=Code,warnings=St#compile.warnings ++ [{File,Ws}]}}.
769
770save_abstract_code(St) ->
771    {ok,St#compile{abstract_code=abstract_code(St)}}.
772
773abstract_code(#compile{code=Code}) ->
774    Abstr = {raw_abstract_v1,Code},
775    case catch erlang:term_to_binary(Abstr, [compressed]) of
776	{'EXIT',_} -> term_to_binary(Abstr);
777	Other -> Other
778    end.
779
780save_core_code(St) ->
781    {ok,St#compile{core_code=cerl:from_records(St#compile.code)}}.
782
783beam_unused_labels(#compile{code=Code0}=St) ->
784    Code = beam_jump:module_labels(Code0),
785    {ok,St#compile{code=Code}}.
786
787beam_asm(#compile{ifile=File,code=Code0,abstract_code=Abst,options=Opts0}=St) ->
788    Source = filename:absname(File),
789    Opts = filter(fun is_informative_option/1, Opts0),
790    case beam_asm:module(Code0, Abst, Source, Opts) of
791	{ok,Code} -> {ok,St#compile{code=Code,abstract_code=[]}};
792	{error,Es} -> {error,St#compile{errors=St#compile.errors ++ Es}}
793    end.
794
795test_native(#compile{options=Opts}) ->
796    %% This test must be made late, because the r7 or no_new_funs options
797    %% will turn off the native option.
798    member(native, Opts).
799
800native_compile(#compile{code=none}=St) -> {ok,St};
801native_compile(St) ->
802    case erlang:system_info(hipe_architecture) of
803	undefined ->
804	    Ws = [{St#compile.ifile,[{none,compile,no_native_support}]}],
805	    {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
806	_ ->
807	    native_compile_1(St)
808    end.
809
810native_compile_1(St) ->
811    Opts0 = [no_new_binaries|St#compile.options],
812    IgnoreErrors = member(ignore_native_errors, Opts0),
813    Opts = case keysearch(hipe, 1, Opts0) of
814	       {value,{hipe,L}} when list(L) -> L;
815	       {value,{hipe,X}} -> [X];
816	       _ -> []
817	   end,
818    case catch hipe:compile(St#compile.module,
819			    St#compile.core_code,
820			    St#compile.code,
821			    Opts) of
822	{ok, {Type,Bin}} when binary(Bin) ->
823	    {ok, embed_native_code(St, {Type,Bin})};
824	{error, R} ->
825	    case IgnoreErrors of
826		true ->
827		    Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
828		    {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
829		false ->
830		    Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
831		    {error,St#compile{errors=St#compile.errors ++ Es}}
832	    end;
833	{'EXIT',R} ->
834	    case IgnoreErrors of
835		true ->
836		    Ws = [{St#compile.ifile,[{none,?MODULE,{native_crash,R}}]}],
837		    {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
838		false ->
839		    exit(R)
840	    end
841    end.
842
843embed_native_code(St, {Architecture,NativeCode}) ->
844    {ok, _, Chunks0} = beam_lib:all_chunks(St#compile.code),
845    ChunkName = hipe_unified_loader:chunk_name(Architecture),
846    Chunks1 = lists:keydelete(ChunkName, 1, Chunks0),
847    Chunks = Chunks1 ++ [{ChunkName,NativeCode}],
848    {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
849    St#compile{code=BeamPlusNative}.
850
851%% Returns true if the option is informative and therefore should be included
852%% in the option list of the compiled module.
853
854is_informative_option(beam) -> false;
855is_informative_option(report_warnings) -> false;
856is_informative_option(report_errors) -> false;
857is_informative_option(binary) -> false;
858is_informative_option(verbose) -> false;
859is_informative_option(_) -> true.
860
861save_binary(#compile{code=none}=St) -> {ok,St};
862save_binary(St) ->
863    Tfile = tmpfile(St#compile.ofile),		%Temp working file
864    case write_binary(Tfile, St#compile.code, St) of
865	ok ->
866	    case file:rename(Tfile, St#compile.ofile) of
867		ok ->
868		    {ok,St};
869		{error,_Error} ->
870		    file:delete(Tfile),
871		    Es = [{St#compile.ofile,[{none,?MODULE,{rename,Tfile}}]}],
872		    {error,St#compile{errors=St#compile.errors ++ Es}}
873	    end;
874	{error,_Error} ->
875	    Es = [{Tfile,[{compile,write_error}]}],
876	    {error,St#compile{errors=St#compile.errors ++ Es}}
877    end.
878
879write_binary(Name, Bin, St) ->
880    Opts = case member(compressed, St#compile.options) of
881	       true -> [compressed];
882	       false -> []
883	   end,
884    case file:write_file(Name, Bin, Opts) of
885	ok -> ok;
886	{error,_}=Error -> Error
887    end.
888
889%% report_errors(State) -> ok
890%% report_warnings(State) -> ok
891
892report_errors(St) ->
893    case member(report_errors, St#compile.options) of
894	true ->
895	    foreach(fun ({{F,_L},Eds}) -> list_errors(F, Eds);
896			({F,Eds}) -> list_errors(F, Eds) end,
897		    St#compile.errors);
898	false -> ok
899    end.
900
901report_warnings(#compile{options=Opts,warnings=Ws0}) ->
902    case member(report_warnings, Opts) of
903	true ->
904	    Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, Eds);
905			     ({F,Eds}) -> format_message(F, Eds) end,
906		     Ws0),
907	    Ws = ordsets:from_list(Ws1),
908	    foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws);
909	false -> ok
910    end.
911
912format_message(F, [{Line,Mod,E}|Es]) ->
913    M = {Line,io_lib:format("~s:~w: Warning: ~s\n", [F,Line,Mod:format_error(E)])},
914    [M|format_message(F, Es)];
915format_message(F, [{Mod,E}|Es]) ->
916    M = {none,io_lib:format("~s: Warning: ~s\n", [F,Mod:format_error(E)])},
917    [M|format_message(F, Es)];
918format_message(_, []) -> [].
919
920%% list_errors(File, ErrorDescriptors) -> ok
921
922list_errors(F, [{Line,Mod,E}|Es]) ->
923    io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]),
924    list_errors(F, Es);
925list_errors(F, [{Mod,E}|Es]) ->
926    io:fwrite("~s: ~s\n", [F,Mod:format_error(E)]),
927    list_errors(F, Es);
928list_errors(_F, []) -> ok.
929
930%% erlfile(Dir, Base) -> ErlFile
931%% outfile(Base, Extension, Options) -> OutputFile
932%% objfile(Base, Target, Options) -> ObjFile
933%% tmpfile(ObjFile) -> TmpFile
934%%  Work out the correct input and output file names.
935
936iofile(File) when atom(File) ->
937    iofile(atom_to_list(File));
938iofile(File) ->
939    {filename:dirname(File), filename:basename(File, ".erl")}.
940
941erlfile(Dir, Base, Suffix) ->
942    filename:join(Dir, Base++Suffix).
943
944outfile(Base, Ext, Opts) when atom(Ext) ->
945    outfile(Base, atom_to_list(Ext), Opts);
946outfile(Base, Ext, Opts) ->
947    Obase = case keysearch(outdir, 1, Opts) of
948		{value, {outdir, Odir}} -> filename:join(Odir, Base);
949		_Other -> Base			% Not found or bad format
950	    end,
951    Obase++"."++Ext.
952
953objfile(Base, St) ->
954    outfile(Base, "beam", St#compile.options).
955
956tmpfile(Ofile) ->
957    reverse([$#|tl(reverse(Ofile))]).
958
959%% pre_defs(Options)
960%% inc_paths(Options)
961%%  Extract the predefined macros and include paths from the option list.
962
963pre_defs([{d,M,V}|Opts]) ->
964    [{M,V}|pre_defs(Opts)];
965pre_defs([{d,M}|Opts]) ->
966    [M|pre_defs(Opts)];
967pre_defs([_|Opts]) ->
968    pre_defs(Opts);
969pre_defs([]) -> [].
970
971inc_paths(Opts) ->
972    [ P || {i,P} <- Opts, list(P) ].
973
974src_listing(Ext, St) ->
975    listing(fun (Lf, {_Mod,_Exp,Fs}) -> do_src_listing(Lf, Fs);
976		(Lf, Fs) -> do_src_listing(Lf, Fs) end,
977	    Ext, St).
978
979do_src_listing(Lf, Fs) ->
980    foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F),"\n"]) end,
981	    Fs).
982
983listing(Ext, St) ->
984    listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, St).
985
986listing(LFun, Ext, St) ->
987    Lfile = outfile(St#compile.base, Ext, St#compile.options),
988    case file:open(Lfile, [write,delayed_write]) of
989	{ok,Lf} ->
990	    LFun(Lf, St#compile.code),
991	    ok = file:close(Lf),
992	    {ok,St};
993	{error,_Error} ->
994	    Es = [{Lfile,[{none,compile,write_error}]}],
995	    {error,St#compile{errors=St#compile.errors ++ Es}}
996    end.
997
998options() ->
999    help(standard_passes()).
1000
1001help([{iff,Flag,{src_listing,Ext}}|T]) ->
1002    io:fwrite("~p - Generate .~s source listing file\n", [Flag,Ext]),
1003    help(T);
1004help([{iff,Flag,{listing,Ext}}|T]) ->
1005    io:fwrite("~p - Generate .~s file\n", [Flag,Ext]),
1006    help(T);
1007help([{iff,Flag,{Name,Fun}}|T]) when function(Fun) ->
1008    io:fwrite("~p - Run ~s\n", [Flag,Name]),
1009    help(T);
1010help([{iff,_Flag,Action}|T]) ->
1011    help(Action),
1012    help(T);
1013help([{unless,Flag,{pass,Pass}}|T]) ->
1014    io:fwrite("~p - Skip the ~s pass\n", [Flag,Pass]),
1015    help(T);
1016help([{unless,no_postopt=Flag,List}|T]) when list(List) ->
1017    %% Hard-coded knowledgde here.
1018    io:fwrite("~p - Skip all post optimisation\n", [Flag]),
1019    help(List),
1020    help(T);
1021help([{unless,_Flag,Action}|T]) ->
1022    help(Action),
1023    help(T);
1024help([_|T]) ->
1025    help(T);
1026help(_) ->
1027    ok.
1028
1029
1030%% compile(AbsFileName, Outfilename, Options)
1031%%   Compile entry point for erl_compile.
1032
1033compile(File0, _OutFile, Options) ->
1034    File = shorten_filename(File0),
1035    case file(File, make_erl_options(Options)) of
1036	{ok,_Mod} -> ok;
1037	Other -> Other
1038    end.
1039
1040compile_beam(File0, _OutFile, Opts) ->
1041    File = shorten_filename(File0),
1042    case file(File, [from_beam|make_erl_options(Opts)]) of
1043	{ok,_Mod} -> ok;
1044	Other -> Other
1045    end.
1046
1047compile_asm(File0, _OutFile, Opts) ->
1048    File = shorten_filename(File0),
1049    case file(File, [asm|make_erl_options(Opts)]) of
1050	{ok,_Mod} -> ok;
1051	Other -> Other
1052    end.
1053
1054compile_core(File0, _OutFile, Opts) ->
1055    File = shorten_filename(File0),
1056    case file(File, [from_core|make_erl_options(Opts)]) of
1057	{ok,_Mod} -> ok;
1058	Other -> Other
1059    end.
1060
1061shorten_filename(Name0) ->
1062    {ok,Cwd} = file:get_cwd(),
1063    case lists:prefix(Cwd, Name0) of
1064	false -> Name0;
1065	true ->
1066	    Name = case lists:nthtail(length(Cwd), Name0) of
1067		       "/"++N -> N;
1068		       N -> N
1069		   end,
1070	    Name
1071    end.
1072
1073%% Converts generic compiler options to specific options.
1074
1075make_erl_options(Opts) ->
1076
1077    %% This way of extracting will work even if the record passed
1078    %% has more fields than known during compilation.
1079
1080    Includes = Opts#options.includes,
1081    Defines = Opts#options.defines,
1082    Outdir = Opts#options.outdir,
1083    Warning = Opts#options.warning,
1084    Verbose = Opts#options.verbose,
1085    Specific = Opts#options.specific,
1086    OutputType = Opts#options.output_type,
1087    Cwd = Opts#options.cwd,
1088
1089    Options =
1090	case Verbose of
1091	    true ->  [verbose];
1092	    false -> []
1093	end ++
1094	case Warning of
1095	    0 -> [];
1096	    _ -> [report_warnings]
1097	end ++
1098	map(
1099	  fun ({Name, Value}) ->
1100		  {d, Name, Value};
1101	      (Name) ->
1102		  {d, Name}
1103	  end,
1104	  Defines) ++
1105	case OutputType of
1106	    undefined -> [];
1107	    jam -> [jam];
1108	    beam -> [beam];
1109	    native -> [native]
1110	end,
1111
1112    Options++[report_errors, {cwd, Cwd}, {outdir, Outdir}|
1113	      map(fun(Dir) -> {i, Dir} end, Includes)]++Specific.
1114