9dbbdf69a3d8aeba247d2f9f55937993054df43a
[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 Rafael Teixeira
10 //
11
12 namespace Mono.Languages
13 {
14         using System;
15         using System.Collections;
16         using System.Diagnostics;
17         using System.IO;
18         using System.Globalization;
19         using System.Reflection;
20         using System.Reflection.Emit;
21
22         using Mono.MonoBASIC;
23         using Mono.GetOptions;
24
25         enum Target 
26         {
27                 Library, Exe, Module, WinExe
28         };
29         
30         enum OptionCompare
31         {
32                 Binary, Text
33         };
34         
35         /// <summary>
36         ///    The compiler driver.
37         /// </summary>
38         public class Driver : Options
39         {
40                 // Temporary options
41                 //------------------------------------------------------------------
42                 [Option("[Mono] Only parses the source file (for debugging the tokenizer)", "parse")]
43                 public bool parse_only = false;
44
45                 [Option("[Mono] Only tokenizes source files")]
46                 public bool tokenize = false;
47
48                 [Option("[Mono] Shows stack trace at Error location")]
49                 public bool stacktrace { set { Report.Stacktrace = value; } }
50
51                 [Option("[Mono] Displays time stamps of various compiler events")]
52                 public bool timestamp
53                 {
54                         set
55                         {
56                                 timestamps = true;
57                                 last_time = DateTime.Now;
58                                 debug_arglist.Add("timestamp");
59                         }
60                 }
61
62                 // Mono-specific options
63                 //------------------------------------------------------------------
64                 [Option("About the MonoBASIC compiler", "about")]
65                 public override WhatToDoNext DoAbout()
66                 {
67                         return base.DoAbout();
68                 }
69
70                 [Option(-1, "[Mono] References packages listed. {packagelist}=package,...", "pkg")]
71                 public WhatToDoNext ReferenceSomePackage(string packageName)
72                 {
73                         return ReferencePackage(packageName)?WhatToDoNext.GoAhead:WhatToDoNext.AbandonProgram;
74                 }
75
76                 [Option("[Mono] Don\'t assume the standard library", "nostdlib")]
77                 public bool NoStandardLibraries { set { RootContext.StdLib = !value; } }
78
79                 [Option("[Mono] Disables implicit references to assemblies", "noconfig")]
80                 public bool NoConfig { set { load_default_config = !value; } }
81
82                 [Option("[Mono] Allows unsafe code", "unsafe")]
83                 public bool AllowUnsafeCode { set { RootContext.Unsafe = value; } }
84
85                 [Option("[Mono] Debugger {arguments}", "debug-args")]
86                 public WhatToDoNext SetDebugArgs(string args)
87                 {
88                         debug_arglist.AddRange (args.Split(','));
89                         return WhatToDoNext.GoAhead;
90                 }
91
92                 [Option("[Mono] Ignores warning number {XXXX}", "ignorewarn")]
93                 public WhatToDoNext SetIgnoreWarning(int warn)
94                 {
95                         Report.SetIgnoreWarning(warn);
96                         return WhatToDoNext.GoAhead;
97                 }       
98
99                 [Option("[Mono] Sets warning {level} (the highest is 4, the default)", "wlevel")]
100                 public int WarningLevel { set { RootContext.WarningLevel = value; } }
101
102                 [Option("[Mono] Makes errors fatal", "fatal")]
103                 public bool Fatal { set { Report.Fatal = value; } }
104
105                 // Output file options
106                 //------------------------------------------------------------------
107                 [Option("Specifies the output {file} name", 'o', "out")]
108                 public string OutputFileName = null;
109
110                 [Option("Specifies the target {type} for the output file (exe [default], winexe, library, module)", 't', "target")]
111                 public WhatToDoNext SetTarget(string type)
112                 {
113                         switch (type.ToLower())
114                         {
115                                 case "library":
116                                         target = Target.Library;
117                                         target_ext = ".dll";
118                                         break;
119                                                         
120                                 case "exe":
121                                         target = Target.Exe;
122                                         break;
123                                                         
124                                 case "winexe":
125                                         target = Target.WinExe;
126                                         break;
127                                                         
128                                 case "module":
129                                         target = Target.Module;
130                                         target_ext = ".netmodule";
131                                         break;
132                         }
133                         return WhatToDoNext.GoAhead;
134                 }
135
136                 // input file options
137                 //------------------------------------------------------------------
138                 public ArrayList AddedModules = new ArrayList();
139
140                 [Option(-1, "References metadata from specified {module}", "addmodule")]
141                 public string AddedModule { set { AddedModules.Add(value); } }
142
143 //              [Option("[NOT IMPLEMENTED YET]Include all files in the current directory and subdirectories according to the {wildcard}", "recurse")]
144                 public WhatToDoNext Recurse(string wildcard)
145                 {
146                         //AddFiles (DirName, true); // TODO wrong semantics
147                         return WhatToDoNext.GoAhead;
148                 }
149
150                 [Option(-1, "References metadata from the specified {assembly}", 'r', "reference")]
151                 public string AddedReference { set { references.Add(value); } }
152                 
153                 // support for the Compact Framework
154                 //------------------------------------------------------------------
155 //              [Option("[NOT IMPLEMENTED YET]Sets the compiler to target the Compact Framework","netcf")]
156                 public bool CompileForCompactFramework = false;
157                 
158 //              [Option("[NOT IMPLEMENTED YET]Specifies the {path} to the location of mscorlib.dll and microsoft.visualbasic.dll", "sdkpath")]
159                 public string SDKPath = null;
160
161                 // resource options
162                 //------------------------------------------------------------------
163                 public ArrayList EmbeddedResources = new ArrayList();
164                 
165                 [Option(-1, "Adds the specified {file} as an embedded assembly resource", "resource", "res")]
166                 public string AddedResource { set { EmbeddedResources.Add(value); } }
167
168                 public ArrayList LinkedResources = new ArrayList();
169                 
170 //              [Option(-1, "[NOT IMPLEMENTED YET]Adds the specified {file} as a linked assembly resource", "linkresource", "linkres")]
171                 public string AddedLinkresource { set { LinkedResources.Add(value); } }
172
173                 public ArrayList Win32Resources = new ArrayList();
174                 
175 //              [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 resource {file} (.res)", "win32resource")]
176                 public string AddedWin32resource { set { Win32Resources.Add(value); } }
177
178                 public ArrayList Win32Icons = new ArrayList();
179                 
180 //              [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 icon {file} (.ico) for the default Win32 resources", "win32icon")]
181                 public string AddedWin32icon { set { Win32Icons.Add(value); } }
182
183                 // code generation options
184                 //------------------------------------------------------------------
185 //              [Option("[NOT IMPLEMENTED YET]Enable optimizations", "optimize")]
186                 public bool optimize = false;
187
188                 // TODO: handle VB.NET [+|-] boolean syntax
189                 [Option("Remove integer checks. Default off.")]
190                 public bool removeintchecks { set { RootContext.Checked = !value; } }
191
192                 // TODO: handle VB.NET [+|-] boolean syntax
193                 [Option("Emit debugging information", 'g', "debug")]
194                 public bool want_debugging_support = false;
195
196                 [Option("Emit full debugging information (default)", "debug:full")]
197                 public bool fullDebugging = false;
198
199                 [Option("[IGNORED]Emit PDB file only", "debug:pdbonly")]
200                 public bool pdbOnly = false;
201
202                 // errors and warnings options
203                 //------------------------------------------------------------------
204                 [Option("Treat warnings as errors", "warnaserror")]
205                 public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
206
207                 [Option("Disable warnings", "nowarn")]
208                 public bool NoWarnings { set { if (value) RootContext.WarningLevel = 0; } }
209
210
211                 // language options
212                 //------------------------------------------------------------------
213                 public Hashtable Defines = new Hashtable();
214                 
215                 [Option(-1, "Declares global conditional compilation symbol(s). {symbol-list}:name=value,...", 'd', "define")]
216                 public string define { 
217                         set 
218                         {
219                                 foreach(string item in value.Split(',')) 
220                                 {       
221                                         string[] dados = item.Split('=');
222                                         try
223                                         {
224                                                 if (dados.Length > 1)
225                                                         Defines.Add(dados[0], dados[1]); 
226                                                 else
227                                                         Defines.Add(dados[0], string.Empty);
228                                         }
229                                         catch 
230                                         {
231                                                 Error ("Could not define symbol" + dados[0]);
232                                         }
233                                 }
234                         } 
235                 }
236                 
237                 [Option("Declare global Imports for namespaces in referenced metadata files. {import-list}:namespace,...", "imports")]
238                 public WhatToDoNext imports(string importslist)
239                 {
240                         Mono.MonoBASIC.Parser.ImportsList.AddRange(importslist.Split(','));
241                         return WhatToDoNext.GoAhead;
242                 }
243
244                 // TODO: handle VB.NET [+|-] boolean syntax
245 //              [Option("[NOT IMPLEMENTED YET]Require explicit declaration of variables")]
246                 public bool optionexplicit { set { Mono.MonoBASIC.Parser.InitialOptionExplicit = value; } }
247
248                 // TODO: handle VB.NET [+|-] boolean syntax
249 //              [Option("[NOT IMPLEMENTED YET]Enforce strict language semantics")]
250                 public bool optionstrict { set { Mono.MonoBASIC.Parser.InitialOptionStrict = value; } }
251                 
252 //              [Option("[NOT IMPLEMENTED YET]Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
253                 public bool optioncomparebinary { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = true; } }
254
255 //              [Option("[NOT IMPLEMENTED YET]Specifies text-style string comparisons.", "optioncompare:text")]
256                 public bool optioncomparetext { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = false; } }
257
258                 [Option("Specifies de root {namespace} for all type declarations")]
259                 public string rootnamespace { set { RootContext.RootNamespace = value; } }
260                 
261                 // Miscellaneous options        
262                 //------------------------------------------------------------------
263                 
264                 [Option("[IGNORED]Do not display compiler copyright banner")]
265                 public bool nologo = false;
266                 
267 //              [Option("[NOT IMPLEMENTED YET]Quiet output mode")]
268                 public bool quiet = false;
269                 
270                 // TODO: semantics are different and should be adjusted
271                 [Option("Display verbose messages", 'v')] 
272                 public bool verbose     { set { GenericParser.yacc_verbose_flag = value; } }
273
274                 // Advanced options     
275                 //------------------------------------------------------------------
276                 // TODO: force option to accept number in hex format
277 //              [Option("[NOT IMPLEMENTED YET]The base {address} for a library or module (hex)")]
278                 public int baseaddress;
279                 
280 //              [Option("[NOT IMPLEMENTED YET]Create bug report {file}")]
281                 public string bugreport;
282                 
283                 // TODO: handle VB.NET [+|-] boolean syntax
284 //              [Option("[NOT IMPLEMENTED YET]Delay-sign the assembly using only the public portion of the strong name key")]
285                 public bool delaysign;
286                 
287 //              [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {container}")]
288                 public string keycontainer;
289                 
290 //              [Option("[NOT IMPLEMENTED YET]Specifies a strong name key {file}")]
291                 public string keyfile;
292
293                 public string[] libpath = null;
294                 
295                 [Option("List of directories to search for metadata references {path-list}:path;...", "libpath")]
296                 public WhatToDoNext setlibpath(string pathlist)
297                 {
298                         libpath = pathlist.Split(';');
299                         return WhatToDoNext.GoAhead;
300                 }
301
302                 [Option(@"Specifies the Class or Module that contains Sub Main.
303                         It can also be a {class} that inherits from System.Windows.Forms.Form.",
304                         'm', "main")]
305                 public string main { set { RootContext.MainClass = value; } }
306
307                 // TODO: handle VB.NET [+|-] boolean syntax
308                 [Option("[IGNORED]Emit compiler output in UTF8 character encoding")]
309                 public bool utf8output;
310
311                 ArrayList defines = new ArrayList();
312                 ArrayList references = new ArrayList();
313                 ArrayList soft_references = new ArrayList();
314                 
315                 string first_source = null;
316                 Target target = Target.Exe;
317                 string target_ext = ".exe";
318                 ArrayList debug_arglist = new ArrayList ();
319                 bool timestamps = false;
320                 Hashtable source_files = new Hashtable ();
321                 bool load_default_config = true;
322
323                 //
324                 // Last time we took the time
325                 //
326                 DateTime last_time;
327                 void ShowTime (string msg)
328                 {
329                         DateTime now = DateTime.Now;
330                         TimeSpan span = now - last_time;
331                         last_time = now;
332
333                         Console.WriteLine (
334                                 "[{0:00}:{1:000}] {2}",
335                                 (int) span.TotalSeconds, span.Milliseconds, msg);
336                 }
337                         
338                 public int LoadAssembly (string assembly, bool soft)
339                 {
340                         Assembly a;
341                         string total_log = "";
342
343                         try 
344                         {
345                                 char[] path_chars = { '/', '\\' };
346
347                                 if (assembly.IndexOfAny (path_chars) != -1)
348                                         a = Assembly.LoadFrom(assembly);
349                                 else {
350                                         string ass = assembly;
351                                         if (ass.EndsWith (".dll"))
352                                                 ass = assembly.Substring (0, assembly.Length - 4);
353                                         a = Assembly.Load (ass);
354                                 }
355                                 TypeManager.AddAssembly (a);
356                                 return 0;
357                         }
358                         catch (FileNotFoundException)
359                         {
360                                 if (libpath != null)
361                                 {
362                                         foreach (string dir in libpath)
363                                         {
364                                                 string full_path = dir + "/" + assembly + ".dll";
365
366                                                 try 
367                                                 {
368                                                         a = Assembly.LoadFrom (full_path);
369                                                         TypeManager.AddAssembly (a);
370                                                         return 0;
371                                                 } 
372                                                 catch (FileNotFoundException ff) 
373                                                 {
374                                                         total_log += ff.FusionLog;
375                                                         continue;
376                                                 }
377                                         }
378                                 }
379                                 if (soft)
380                                         return 0;
381                         }
382                         catch (BadImageFormatException f) 
383                         {
384                                 Error ("// Bad file format while loading assembly");
385                                 Error ("Log: " + f.FusionLog);
386                                 return 1;
387                         } catch (FileLoadException f){
388                                 Error ("File Load Exception: " + assembly);
389                                 Error ("Log: " + f.FusionLog);
390                                 return 1;
391                         } catch (ArgumentNullException){
392                                 Error ("// Argument Null exception ");
393                                 return 1;
394                         }
395                         
396                         Report.Error (6, "Can not find assembly `" + assembly + "'" );
397                         Console.WriteLine ("Log: \n" + total_log);
398
399                         return 0;
400                 }
401
402                 public bool ReferencePackage(string packageName)
403                 {
404                         if (packageName == ""){
405                                 DoAbout ();
406                                 return false;
407                         }
408                                 
409                         ProcessStartInfo pi = new ProcessStartInfo ();
410                         pi.FileName = "pkg-config";
411                         pi.RedirectStandardOutput = true;
412                         pi.UseShellExecute = false;
413                         pi.Arguments = "--libs " + packageName;
414                         Process p = null;
415                         try {
416                                 p = Process.Start (pi);
417                         } catch (Exception e) {
418                                 Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
419                                 return false;
420                         }
421
422                         if (p.StandardOutput == null){
423                                 Report.Warning (-27, "Specified package did not return any information");
424                         }
425                         string pkgout = p.StandardOutput.ReadToEnd ();
426                         p.WaitForExit ();
427                         if (p.ExitCode != 0) {
428                                 Report.Error (-27, "Error running pkg-config. Check the above output.");
429                                 return false;
430                         }
431                         p.Close ();
432                         
433                         if (pkgout != null) {
434                                 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
435                                         Split (new Char [] { ' ', '\t'});
436                                 foreach(string arg in xargs) {
437                                         string[] zargs = arg.Split(':', '=');
438                                         try {
439                                                 if (zargs.Length > 1)
440                                                         AddedReference = zargs[1];
441                                                 else
442                                                         AddedReference = arg;
443                                         } catch (Exception e) {
444                                                 Report.Error (-27, "Something wrong with argument (" + arg + ") in 'pkg-config --libs' output: " + e.Message);
445                                                 return false;
446                                         }
447                                 }
448                         }
449
450                         return true;
451                 }
452
453                 public void LoadModule (MethodInfo adder_method, string module)
454                 {
455                         System.Reflection.Module m;
456                         string total_log = "";
457
458                         try {
459                                 try {
460                                         m = (System.Reflection.Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { module });
461                                 }
462                                 catch (TargetInvocationException ex) {
463                                         throw ex.InnerException;
464                                 }
465                                 TypeManager.AddModule (m);
466
467                         } 
468                         catch (FileNotFoundException) {
469                                 foreach (string dir in libpath) {
470                                         string full_path = Path.Combine (dir, module);
471                                         if (!module.EndsWith (".netmodule"))
472                                                 full_path += ".netmodule";
473
474                                         try {
475                                                 try {
476                                                         m = (System.Reflection.Module) adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { full_path });
477                                                 }
478                                                 catch (TargetInvocationException ex) {
479                                                         throw ex.InnerException;
480                                                 }
481                                                 TypeManager.AddModule (m);
482                                                 return;
483                                         }
484                                         catch (FileNotFoundException ff) {
485                                                 total_log += ff.FusionLog;
486                                                 continue;
487                                         }
488                                 }
489                                 Report.Error (6, "Cannot find module `" + module + "'" );
490                                 Console.WriteLine ("Log: \n" + total_log);
491                         }
492                         catch (BadImageFormatException f) {
493                                 Report.Error(6, "Cannot load module (bad file format)" + f.FusionLog);
494                         }
495                         catch (FileLoadException f)     {
496                                 Report.Error(6, "Cannot load module " + f.FusionLog);
497                         }
498                         catch (ArgumentNullException) {
499                                 Report.Error(6, "Cannot load module (null argument)");
500                         }
501                 }
502
503                 void Error(string message)
504                 {
505                         Console.WriteLine(message);
506                 }
507
508                 /// <summary>
509                 ///   Loads all assemblies referenced on the command line
510                 /// </summary>
511                 public int LoadReferences ()
512                 {
513                         int errors = 0;
514
515                         foreach (string r in references)
516                                 errors += LoadAssembly (r, false);
517
518                         foreach (string r in soft_references)
519                                 errors += LoadAssembly (r, true);
520                         
521                         return errors;
522                 }
523
524                 void SetupDefaultDefines ()
525                 {
526                         defines = new ArrayList ();
527                         defines.Add ("__MonoBASIC__");
528                 }
529                 
530                 void SetupDefaultImports()
531                 {
532                         Mono.MonoBASIC.Parser.ImportsList = new ArrayList();
533                         Mono.MonoBASIC.Parser.ImportsList.Add("Microsoft.VisualBasic");
534                 }
535
536                 //
537                 // Given a path specification, splits the path from the file/pattern
538                 //
539                 void SplitPathAndPattern (string spec, out string path, out string pattern)
540                 {
541                         int p = spec.LastIndexOf ("/");
542                         if (p != -1){
543                                 //
544                                 // Windows does not like /file.cs, switch that to:
545                                 // "\", "file.cs"
546                                 //
547                                 if (p == 0){
548                                         path = "\\";
549                                         pattern = spec.Substring (1);
550                                 } else {
551                                         path = spec.Substring (0, p);
552                                         pattern = spec.Substring (p + 1);
553                                 }
554                                 return;
555                         }
556
557                         p = spec.LastIndexOf ("\\");
558                         if (p != -1){
559                                 path = spec.Substring (0, p);
560                                 pattern = spec.Substring (p + 1);
561                                 return;
562                         }
563
564                         path = ".";
565                         pattern = spec;
566                 }
567
568                 bool AddFiles (string spec, bool recurse)
569                 {
570                         string path, pattern;
571
572                         SplitPathAndPattern(spec, out path, out pattern);
573                         if (pattern.IndexOf("*") == -1)
574                         {
575                                 AddFile(spec);
576                                 return true;
577                         }
578
579                         string [] files = null;
580                         try {
581                                 files = Directory.GetFiles(path, pattern);
582                         } catch (System.IO.DirectoryNotFoundException) {
583                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
584                                 return false;
585                         } catch (System.IO.IOException){
586                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
587                                 return false;
588                         }
589                         foreach (string f in files)
590                                 AddFile (f);
591
592                         if (!recurse)
593                                 return true;
594                         
595                         string [] dirs = null;
596
597                         try {
598                                 dirs = Directory.GetDirectories(path);
599                         } catch {
600                         }
601                         
602                         foreach (string d in dirs) {
603                                         
604                                 // Don't include path in this string, as each
605                                 // directory entry already does
606                                 AddFiles (d + "/" + pattern, true);
607                         }
608
609                         return true;
610                 }
611
612                 void DefineDefaultConfig ()
613                 {
614                         //
615                         // For now the "default config" is harcoded into the compiler
616                         // we can move this outside later
617                         //
618                         string [] default_config = 
619                         {
620                                 "System",
621                                 "System.Data",
622                                 "System.Xml",
623                                 "Microsoft.VisualBasic" , 
624 #if EXTRA_DEFAULT_REFS
625                                 //
626                                 // Is it worth pre-loading all this stuff?
627                                 //
628                                 "Accessibility",
629                                 "System.Configuration.Install",
630                                 "System.Design",
631                                 "System.DirectoryServices",
632                                 "System.Drawing.Design",
633                                 "System.Drawing",
634                                 "System.EnterpriseServices",
635                                 "System.Management",
636                                 "System.Messaging",
637                                 "System.Runtime.Remoting",
638                                 "System.Runtime.Serialization.Formatters.Soap",
639                                 "System.Security",
640                                 "System.ServiceProcess",
641                                 "System.Web",
642                                 "System.Web.RegularExpressions",
643                                 "System.Web.Services" ,
644                                 "System.Windows.Forms"
645 #endif
646                         };
647                         
648                         foreach (string def in default_config)
649                                 if (!(references.Contains(def) || references.Contains (def + ".dll")))
650                                         soft_references.Add(def);
651                 }
652
653                 [ArgumentProcessor]
654                 public void AddFile(string fileName)
655                 {
656                         string f = fileName;
657                         if (first_source == null)
658                                 first_source = f;
659
660                         if (source_files.Contains(f))
661                                 Report.Error(1516, "Source file '" + f + "' specified multiple times");
662                         else
663                                 source_files.Add(f, f);
664                 }
665
666                 void ProcessSourceFile(string filename)
667                 {
668                         if (tokenize)
669                                 GenericParser.Tokenize(filename);
670                         else
671                                 GenericParser.Parse(filename);
672                 }
673
674                 string outputFile_Name = null;
675
676                 string outputFileName
677                 {
678                         get 
679                         {
680                                 if (outputFile_Name == null)
681                                 {
682                                         if (OutputFileName == null)
683                                         {
684                                                 int pos = first_source.LastIndexOf(".");
685
686                                                 if (pos > 0)
687                                                         OutputFileName = first_source.Substring(0, pos);
688                                                 else
689                                                         OutputFileName = first_source;
690                                         }
691                                         string bname = CodeGen.Basename(OutputFileName);
692                                         if (bname.IndexOf(".") == -1)
693                                                 OutputFileName +=  target_ext;
694                                         outputFile_Name = OutputFileName;
695                                 }
696                                 return outputFile_Name;
697                         }
698                 }
699
700                 bool ParseAll() // Phase 1
701                 {
702                         if (first_source == null) {
703                                 Report.Error(2008, "No files to compile were specified");
704                                 return false;
705                         }
706
707                         foreach(string filename in source_files.Values)
708                                 ProcessSourceFile(filename);
709
710                         if (tokenize || parse_only || (Report.Errors > 0))
711                                 return false;           
712
713                         return true; // everything went well go ahead
714                 }
715
716                 void InitializeDebuggingSupport()
717                 {
718                         string[] debug_args = new string [debug_arglist.Count];
719                         debug_arglist.CopyTo(debug_args);
720                         CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
721                         TypeManager.AddModule(CodeGen.ModuleBuilder);
722                 }
723
724                 public bool ResolveAllTypes() // Phase 2
725                 {
726                         // Load Core Library for default compilation
727                         if (RootContext.StdLib)
728                                 references.Insert(0, "mscorlib");
729
730                         if (load_default_config)
731                                 DefineDefaultConfig();
732
733                         if (timestamps)
734                                 ShowTime("Loading references");
735
736                         // Load assemblies required
737                         if (LoadReferences() > 0)
738                         {
739                                 Error ("Could not load one or more assemblies");
740                                 return false;
741                         }
742
743                         if (timestamps)
744                                 ShowTime("References loaded");
745
746                         InitializeDebuggingSupport();
747
748                         // target is Module 
749                         if (target == Target.Module) {
750                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
751                                 if (module_only == null) {
752                                         Report.Error (0, new Location (-1, -1), "Cannot use /target:module on this runtime: try the Mono runtime instead.");
753                                         Environment.Exit (1);
754                                 }
755
756                                 MethodInfo set_method = module_only.GetSetMethod (true);
757                                 set_method.Invoke (CodeGen.AssemblyBuilder, BindingFlags.Default, null, new object[]{true}, null);
758
759                                 TypeManager.AddModule (CodeGen.ModuleBuilder);
760                         }
761
762                         if (AddedModules.Count > 0) {
763                                 MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
764                                 if (adder_method == null) {
765                                         Report.Error (0, new Location (-1, -1), "Cannot use /addmodule on this runtime: Try the Mono runtime instead.");
766                                         Environment.Exit (1);
767                                 }
768
769                                 foreach (string module in AddedModules)
770                                         LoadModule (adder_method, module);
771                         }
772
773
774                         //
775                         // Before emitting, we need to get the core
776                         // types emitted from the user defined types
777                         // or from the system ones.
778                         //
779                         if (timestamps)
780                                 ShowTime ("Initializing Core Types");
781
782                         if (!RootContext.StdLib)
783                                 RootContext.ResolveCore ();
784                         if (Report.Errors > 0)
785                                 return false;
786                         
787                         TypeManager.InitCoreTypes();
788                         if (Report.Errors > 0)
789                                 return false;
790
791                         if (timestamps)
792                                 ShowTime ("   Core Types done");
793
794                         if (timestamps)
795                                 ShowTime ("Resolving tree");
796
797                         // The second pass of the compiler
798                         RootContext.ResolveTree ();
799                         if (Report.Errors > 0)
800                                 return false;
801                         
802                         if (timestamps)
803                                 ShowTime ("Populate tree");
804
805                         if (!RootContext.StdLib)
806                                 RootContext.BootCorlib_PopulateCoreTypes();
807                         if (Report.Errors > 0)
808                                 return false;
809
810                         RootContext.PopulateTypes();
811                         if (Report.Errors > 0)
812                                 return false;
813                         
814                         TypeManager.InitCodeHelpers();
815                         if (Report.Errors > 0)
816                                 return false;
817
818                         return true;
819                 }
820                 
821                 bool IsSWFApp()
822                 {
823                         string mainclass = GetFQMainClass();
824                         
825                         if (mainclass != null) {
826                                 foreach (string r in references) {
827                                         if (r.IndexOf ("System.Windows.Forms") >= 0) {
828                                                 Type t = TypeManager.LookupType(mainclass);
829                                                 if (t != null) 
830                                                         return t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
831                                                 break;  
832                                         }       
833                                 }
834                         }
835                         return false;
836                 }
837                 
838                 string GetFQMainClass()
839                 {       
840                         if (RootContext.RootNamespace != "")
841                                 return RootContext.RootNamespace + "." + RootContext.MainClass;
842                         else
843                                 return RootContext.MainClass;                   
844                 }
845                 
846                 void FixEntryPoint()
847                 {
848                         if (target == Target.Exe || target == Target.WinExe)
849                         {
850                                 MethodInfo ep = RootContext.EntryPoint;
851                         
852                                 if (ep == null)
853                                 {
854                                         // If we don't have a valid entry point yet
855                                         // AND if System.Windows.Forms is included
856                                         // among the dependencies, we have to build
857                                         // a new entry point on-the-fly. Otherwise we
858                                         // won't be able to compile SWF code out of the box.
859
860                                         if (IsSWFApp()) 
861                                         {                                                                                               
862                                                 Type t = TypeManager.LookupType(GetFQMainClass());
863                                                 if (t != null) 
864                                                 {                                                       
865                                                         TypeBuilder tb = t as TypeBuilder;
866                                                         MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, 
867                                                                 typeof(void), new Type[0]);
868
869                                                         Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
870                                                         Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
871                                                         Type[] args = new Type[1];
872                                                         args[0] = SWFF;
873                                                         MethodInfo mi = SWFA.GetMethod("Run", args);
874                                                         ILGenerator ig = mb.GetILGenerator();
875                                                         ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
876                                                         
877                                                         ig.Emit (OpCodes.Newobj, ci);
878                                                         ig.Emit (OpCodes.Call, mi);
879                                                         ig.Emit (OpCodes.Ret);
880
881                                                         RootContext.EntryPoint = mb as MethodInfo;
882                                                 }
883                                         }
884                                 }
885                         }
886                 }
887
888                 bool GenerateAssembly()
889                 {
890                         //
891                         // The code generator
892                         //
893                         if (timestamps)
894                                 ShowTime ("Emitting code");
895                         
896                         
897
898                         RootContext.EmitCode();
899                         FixEntryPoint();
900                         if (Report.Errors > 0)
901                                 return false;
902
903                         if (timestamps)
904                                 ShowTime ("   done");
905
906
907                         if (timestamps)
908                                 ShowTime ("Closing types");
909
910                         RootContext.CloseTypes ();
911                         if (Report.Errors > 0)
912                                 return false;
913
914                         if (timestamps)
915                                 ShowTime ("   done");
916
917                         PEFileKinds k = PEFileKinds.ConsoleApplication;
918                                                         
919                         if (target == Target.Library || target == Target.Module)
920                                 k = PEFileKinds.Dll;
921                         else if (target == Target.Exe)
922                                 k = PEFileKinds.ConsoleApplication;
923                         else if (target == Target.WinExe)
924                                 k = PEFileKinds.WindowApplication;
925                         
926                         if (target == Target.Exe || target == Target.WinExe)
927                         {
928                                 MethodInfo ep = RootContext.EntryPoint;
929                         
930                                 if (ep == null)
931                                 {
932                                         Report.Error (30737, "Program " + outputFileName +
933                                                 " does not have an entry point defined");
934                                         return false;
935                                 }
936                                                         
937                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
938                         }
939
940                         // Add the resources
941                         if (EmbeddedResources != null)
942                                 foreach (string file in EmbeddedResources)
943                                         CodeGen.AssemblyBuilder.AddResourceFile (file, file);
944                         
945                         CodeGen.Save(outputFileName);
946
947                         if (timestamps)
948                                 ShowTime ("Saved output");
949
950                         
951                         if (want_debugging_support) 
952                         {
953                                 CodeGen.SaveSymbols ();
954                                 if (timestamps)
955                                         ShowTime ("Saved symbols");
956                         }
957
958                         return true;
959                 }
960
961                 public void CompileAll()
962                 {
963 /* 
964                     VB.NET expects the default namespace to be "" (empty string)                
965                     
966                     if (RootContext.RootNamespace == "")
967                     {
968                       RootContext.RootNamespace = System.IO.Path.GetFileNameWithoutExtension(outputFileName);
969                     }
970 */
971                         if (!ParseAll()) // Phase 1
972                                 return;
973
974                         if (!ResolveAllTypes()) // Phase 2
975                                 return;
976
977                         GenerateAssembly(); // Phase 3 
978                 }
979
980                 /// <summary>
981                 ///    Parses the arguments, and calls the compilation process.
982                 /// </summary>
983                 int MainDriver(string [] args)
984                 {
985                         Console.WriteLine ("--------");
986                         Console.WriteLine ("MonoBASIC: THIS IS AN ALPHA SOFTWARE.");
987                         Console.WriteLine ("--------");
988                         SetupDefaultDefines();  
989                         
990                         SetupDefaultImports();
991
992                         // Some defaults
993                         RootContext.Checked = true;
994
995                         ProcessArgs(args);
996                         
997                         if (first_source == null)
998                         {
999                                 if (!quiet) 
1000                                         DoHelp();
1001                                 return 2;
1002                         }
1003
1004                         CompileAll();
1005
1006                         return Report.ProcessResults(quiet);
1007                 }
1008
1009                 public static int Main (string[] args)
1010                 {
1011                         Driver Exec = new Driver();
1012                         
1013                         Report.Stacktrace = false;
1014
1015                         return Exec.MainDriver(args);
1016                 }
1017
1018         }
1019 }