2005-05-13 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / mbas / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
5 // Based on mcs by : Miguel de Icaza (miguel@gnu.org)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2002, 2003, 2004 Rafael Teixeira
10 //
11
12 /*
13
14 */
15
16 namespace Mono.Languages {
17
18         using System;
19         using System.Collections;
20         using System.IO;
21         using System.Text;
22         using System.Globalization;
23         using System.Reflection;
24         using System.Reflection.Emit;
25
26         using Mono.MonoBASIC;
27         using Mono.GetOptions.Useful;
28
29         public class Driver {
30                 CompilerOptions options;
31                 
32                 private void InitializeRootContextAndOthersFromOptions()
33                 {
34                         Report.Stacktrace = options.Stacktrace;
35                         Report.WarningsAreErrors = options.WarningsAreErrors;
36                         // TODO: change Report to receive the whole array
37                         for(int i = 0; i < options.WarningsToIgnore.Length; i++)
38                                 Report.SetIgnoreWarning(options.WarningsToIgnore[i]);
39                         Report.Fatal = options.MakeErrorsFatal;
40
41                         RootContext.WarningLevel = options.WarningLevel;
42                         RootContext.Checked = options.CheckedContext;
43                         RootContext.MainClass = options.MainClassName;
44                         RootContext.StdLib = !options.NoStandardLibraries;
45                         RootContext.Unsafe = options.AllowUnsafeCode;
46                         if (options.RootNamespace != null)
47                                 RootContext.RootNamespace = options.RootNamespace;
48                         
49                         // TODO: semantics are different and should be adjusted
50                         GenericParser.yacc_verbose_flag = options.Verbose ? 1 : 0;
51                         
52                         Mono.MonoBASIC.Parser.InitialOptionExplicit = options.OptionExplicit;
53                         Mono.MonoBASIC.Parser.InitialOptionStrict = options.OptionStrict;
54                     Mono.MonoBASIC.Parser.InitialOptionCompareBinary = options.OptionCompareBinary;
55                     Mono.MonoBASIC.Parser.ImportsList = options.Imports;
56                 }
57                 
58                 bool ParseAllSourceFiles()
59                 {
60                         options.StartTime("Parsing Source Files");
61                         foreach(FileToCompile file in options.SourceFilesToCompile)
62                                 GenericParser.Parse(file.Filename, file.Encoding);
63                         options.ShowTime("   Done");
64                         return (Report.Errors == 0);
65                 }
66                 
67                 private bool InitializeDebuggingSupport()
68                 {
69                         string[] debug_args = new string [options.DebugListOfArguments.Count];
70                         options.DebugListOfArguments.CopyTo(debug_args);
71                         CodeGen.Init(options.OutputFileName, options.OutputFileName, options.WantDebuggingSupport, debug_args);
72                         TypeManager.AddModule(CodeGen.ModuleBuilder);
73                         return true;
74                 }
75                 
76                 private bool LoadReferencedAssemblies()
77                 {
78                         return options.LoadReferencedAssemblies(new AssemblyAdder(TypeManager.AddAssembly));
79                 }
80
81                 private bool AdjustCodegenWhenTargetIsNetModule()
82                 {
83                         options.AdjustCodegenWhenTargetIsNetModule(CodeGen.AssemblyBuilder);
84                         return true;
85                 }
86                 
87                 private bool LoadAddedNetModules()
88                 {
89                         return options.LoadAddedNetModules(CodeGen.AssemblyBuilder, new ModuleAdder(TypeManager.AddModule));
90                 }
91                 
92                 private bool InitializeCoreTypes()
93                 {
94                         //
95                         // Before emitting, we need to get the core
96                         // types emitted from the user defined types
97                         // or from the system ones.
98                         //
99                         options.StartTime("Initializing Core Types");
100
101                         if (!RootContext.StdLib)
102                                 RootContext.ResolveCore ();
103                         if (Report.Errors > 0)
104                                 return false;
105                         
106                         TypeManager.InitCoreTypes();
107                                 
108                         options.ShowTime("Core Types Done");
109                         return Report.Errors == 0;
110                 }
111
112                 private bool ResolveTree()
113                 {
114                         options.StartTime("Resolving tree");
115                         RootContext.ResolveTree (); // The second pass of the compiler
116                         options.ShowTime("Tree resolved");
117                         return Report.Errors == 0;
118                 }
119                 
120                 private bool PopulateCoreTypes()
121                 {
122                         if (!RootContext.StdLib) {
123                                 options.StartTime("Populate core types");
124                                 RootContext.BootCorlib_PopulateCoreTypes();
125                                 options.ShowTime("   Done");
126                         }
127                         return Report.Errors == 0;
128                 }
129                                                 
130                 private bool PopulateTypes()
131                 {
132                         options.StartTime("Populate types");
133                         RootContext.PopulateTypes();
134                         options.ShowTime("   Done");
135                         return Report.Errors == 0;
136                 }
137                                                 
138                 private bool InitCodeHelpers()
139                 {
140                         options.StartTime("Initialize code helpers");
141                         TypeManager.InitCodeHelpers();
142                         options.ShowTime("   Done");
143                         return Report.Errors == 0;
144                 }
145                                                 
146                 string GetFQMainClass()
147                 {       
148                         if (RootContext.RootNamespace != "")
149                                 return RootContext.RootNamespace + "." + RootContext.MainClass;
150                         else
151                                 return RootContext.MainClass;                   
152                 }
153                 
154                 bool IsSWFApp()
155                 {
156                         string mainclass = GetFQMainClass();
157                         
158                         if (mainclass != null) {
159                                 foreach (string r in options.AssembliesToReference) {
160                                         if (r.IndexOf ("System.Windows.Forms") >= 0) {
161                                                 Type t = TypeManager.LookupType(mainclass);
162                                                 if (t != null) 
163                                                         return t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
164                                                 break;  
165                                         }       
166                                 }
167                         }
168                         return false;
169                 }
170                 
171                 void FixEntryPoint()
172                 {
173                         if (options.TargetFileType == TargetType.Exe || options.TargetFileType == TargetType.WinExe) {
174                                 MethodInfo ep = RootContext.EntryPoint;
175                         
176                                 if (ep == null) {
177                                         // If we don't have a valid entry point yet
178                                         // AND if System.Windows.Forms is included
179                                         // among the dependencies, we have to build
180                                         // a new entry point on-the-fly. Otherwise we
181                                         // won't be able to compile SWF code out of the box.
182
183                                         if (IsSWFApp())  {
184                                                 Type t = TypeManager.LookupType(GetFQMainClass());
185                                                 if (t != null) 
186                                                 {                                                       
187                                                         TypeBuilder tb = t as TypeBuilder;
188                                                         MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, 
189                                                                 typeof(void), new Type[0]);
190
191                                                         Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
192                                                         Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
193                                                         Type[] args = new Type[1];
194                                                         args[0] = SWFF;
195                                                         MethodInfo mi = SWFA.GetMethod("Run", args);
196                                                         ILGenerator ig = mb.GetILGenerator();
197                                                         ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
198                                                         
199                                                         ig.Emit (OpCodes.Newobj, ci);
200                                                         ig.Emit (OpCodes.Call, mi);
201                                                         ig.Emit (OpCodes.Ret);
202
203                                                         RootContext.EntryPoint = mb as MethodInfo;
204                                                 }
205                                         }
206                                 }
207                         }
208                 }
209                 
210                 private bool EmitCode()
211                 {
212                         options.StartTime("Emitting code");                     
213                         RootContext.EmitCode();
214                         FixEntryPoint();
215                         options.ShowTime("   Done");
216                         return Report.Errors == 0;
217                 }
218
219                 private bool CloseTypes()
220                 {
221                         options.StartTime("Closing types");                     
222                         RootContext.CloseTypes ();
223                         options.ShowTime("   Done");
224                         return Report.Errors == 0;
225                 }
226
227                 private bool SetEntryPoint()
228                 {
229                         if (options.TargetFileType == TargetType.Exe || options.TargetFileType == TargetType.WinExe) {
230                                 options.StartTime("Setting entry point");                       
231                                 MethodInfo ep = RootContext.EntryPoint;
232                         
233                                 if (ep == null) {
234                                         Report.Error (30737, "Program " + options.OutputFileName + " does not have an entry point defined");
235                                         return false;
236                                 }
237                                                         
238                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, 
239                                         (options.TargetFileType == TargetType.Exe)?PEFileKinds.ConsoleApplication:PEFileKinds.WindowApplication);
240                                 options.ShowTime("   Done");
241                         }
242                         return Report.Errors == 0;
243                 }
244
245                 private bool EmbedResources()
246                 {
247                         options.StartTime("Embedding resources");                       
248                         options.EmbedResources(CodeGen.AssemblyBuilder);
249                         options.ShowTime("   Done");
250                         return Report.Errors == 0;
251                 }
252
253                 private bool SaveOutput()
254                 {
255                         options.StartTime("Saving Output");                     
256                         CodeGen.Save(options.OutputFileName);
257                         options.ShowTime("   Done");
258                         return Report.Errors == 0;
259                 }
260
261
262                 private bool SaveDebugSymbols()
263                 {
264                         if (options.WantDebuggingSupport)  {
265                                 options.StartTime("Saving Debug Symbols");                      
266                                 CodeGen.SaveSymbols ();
267                                 options.ShowTime ("   Done");
268                         }
269                         return true;
270                 }
271
272                 delegate bool CompilerStep();
273                 
274                 private CompilerStep[] Steps {
275                         get {
276                                 return new CompilerStep[] {
277                                         new CompilerStep(ParseAllSourceFiles),
278                                         new CompilerStep(InitializeDebuggingSupport),
279                                         new CompilerStep(LoadReferencedAssemblies),
280                                         new CompilerStep(AdjustCodegenWhenTargetIsNetModule),
281                                         new CompilerStep(LoadAddedNetModules),
282                                         new CompilerStep(InitializeCoreTypes),
283                                         new CompilerStep(ResolveTree),
284                                         new CompilerStep(PopulateCoreTypes),
285                                         new CompilerStep(PopulateTypes),
286                                         new CompilerStep(InitCodeHelpers),
287                                         new CompilerStep(EmitCode),
288                                         new CompilerStep(CloseTypes),
289                                         new CompilerStep(SetEntryPoint),
290                                         new CompilerStep(SaveOutput),
291                                         new CompilerStep(SaveDebugSymbols) } ;
292                         }
293                 }
294
295                 /// <summary>
296                 ///    Parses the arguments, and calls the compilation process.
297                 /// </summary>
298                 int MainDriver(string [] args)
299                 {
300                         options = new CompilerOptions(args, new ErrorReporter(Report.Error));           
301                         if (options.NothingToCompile)
302                                 return 2;               
303                         try {
304                                 InitializeRootContextAndOthersFromOptions();
305                                 
306                                 foreach(CompilerStep step in Steps)
307                                         if (!step())
308                                                 break;
309                                                 
310                         } catch (Exception ex) {
311                                 Report.Error(0, "Exception: " + ex.ToString());
312                         }
313                         return Report.ProcessResults(options.BeQuiet);
314                 }
315
316                 public static int Main (string[] args)
317                 {
318                         Driver Exec = new Driver();
319                         
320                         return Exec.MainDriver(args);
321                 }
322
323
324         }
325 }