2005-05-12 Rafael Teixeira <rafaelteixeirabr@hotmail.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(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, 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                                         ParseAllSourceFiles,
278                                         InitializeDebuggingSupport,
279                                         LoadReferencedAssemblies,
280                                         AdjustCodegenWhenTargetIsNetModule,
281                                         LoadAddedNetModules,
282                                         InitializeCoreTypes,
283                                         ResolveTree,
284                                         PopulateCoreTypes,
285                                         PopulateTypes,
286                                         InitCodeHelpers,
287                                         EmitCode,
288                                         CloseTypes,
289                                         SetEntryPoint,
290                                         SaveOutput,
291                                         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, 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 }