2008-06-11 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@gnu.org)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
12 //
13
14 namespace Mono.CSharp
15 {
16         using System;
17         using System.Reflection;
18         using System.Reflection.Emit;
19         using System.Collections;
20         using System.Collections.Specialized;
21         using System.IO;
22         using System.Text;
23         using System.Globalization;
24         using System.Diagnostics;
25
26         public enum Target {
27                 Library, Exe, Module, WinExe
28         };
29         
30         /// <summary>
31         ///    The compiler driver.
32         /// </summary>
33         class Driver
34         {
35                 //
36                 // Assemblies references to be linked.   Initialized with
37                 // mscorlib.dll here.
38                 static ArrayList references;
39
40                 //
41                 // If any of these fail, we ignore the problem.  This is so
42                 // that we can list all the assemblies in Windows and not fail
43                 // if they are missing on Linux.
44                 //
45                 static ArrayList soft_references;
46
47                 // 
48                 // External aliases for assemblies.
49                 //
50                 static Hashtable external_aliases;
51
52                 //
53                 // Modules to be linked
54                 //
55                 static ArrayList modules;
56
57                 // Lookup paths
58                 static ArrayList link_paths;
59
60                 // Whether we want to only run the tokenizer
61                 bool tokenize;
62                 
63                 string first_source;
64
65                 bool want_debugging_support;
66                 bool parse_only;
67                 bool timestamps;
68                 
69                 //
70                 // Whether to load the initial config file (what CSC.RSP has by default)
71                 // 
72                 bool load_default_config = true;
73
74                 //
75                 // A list of resource files
76                 //
77                 static Resources embedded_resources;
78                 static string win32ResourceFile;
79                 static string win32IconFile;
80
81                 //
82                 // An array of the defines from the command line
83                 //
84                 ArrayList defines;
85
86                 //
87                 // Output file
88                 //
89                 static string output_file;
90
91                 //
92                 // Last time we took the time
93                 //
94                 DateTime last_time, first_time;
95
96                 //
97                 // Encoding.
98                 //
99                 Encoding encoding;
100
101                 static public void Reset ()
102                 {
103                         embedded_resources = null;
104                         win32ResourceFile = win32IconFile = null;
105                         output_file = null;
106                 }
107
108                 public Driver ()
109                 {
110                         encoding = Encoding.Default;
111
112                         //
113                         // Setup default defines
114                         //
115                         defines = new ArrayList ();
116                         defines.Add ("__MonoCS__");
117                 }
118
119                 public static Driver Create (string [] args)
120                 {
121                         Driver d = new Driver ();
122                         if (!d.ParseArguments (args))
123                                 return null;
124
125                         return d;
126                 }
127
128                 void ShowTime (string msg)
129                 {
130                         if (!timestamps)
131                                 return;
132
133                         DateTime now = DateTime.Now;
134                         TimeSpan span = now - last_time;
135                         last_time = now;
136
137                         Console.WriteLine (
138                                 "[{0:00}:{1:000}] {2}",
139                                 (int) span.TotalSeconds, span.Milliseconds, msg);
140                 }
141
142                 void ShowTotalTime (string msg)
143                 {
144                         if (!timestamps)
145                                 return;
146
147                         DateTime now = DateTime.Now;
148                         TimeSpan span = now - first_time;
149                         last_time = now;
150
151                         Console.WriteLine (
152                                 "[{0:00}:{1:000}] {2}",
153                                 (int) span.TotalSeconds, span.Milliseconds, msg);
154                 }              
155                
156                 void tokenize_file (CompilationUnit file)
157                 {
158                         Stream input;
159
160                         try {
161                                 input = File.OpenRead (file.Name);
162                         } catch {
163                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
164                                 return;
165                         }
166
167                         using (input){
168                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
169                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
170                                 int token, tokens = 0, errors = 0;
171
172                                 while ((token = lexer.token ()) != Token.EOF){
173                                         tokens++;
174                                         if (token == Token.ERROR)
175                                                 errors++;
176                                 }
177                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
178                         }
179                         
180                         return;
181                 }
182
183                 void Parse (CompilationUnit file)
184                 {
185                         Stream input;
186
187                         try {
188                                 input = File.OpenRead (file.Name);
189                         } catch {
190                                 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
191                                 return;
192                         }
193
194                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
195
196                         // Check 'MZ' header
197                         if (reader.Read () == 77 && reader.Read () == 90) {
198                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
199                                 input.Close ();
200                                 return;
201                         }
202
203                         reader.Position = 0;
204                         Parse (reader, file);
205                         input.Close ();
206                 }       
207                 
208                 void Parse (SeekableStreamReader reader, CompilationUnit file)
209                 {
210                         CSharpParser parser = new CSharpParser (reader, file, defines);
211                         parser.ErrorOutput = Report.Stderr;
212                         try {
213                                 parser.parse ();
214                         } catch (Exception ex) {
215                                 Report.Error(589, parser.Lexer.Location,
216                                         "Compilation aborted in file `{0}', {1}", file.Name, ex);
217                         }
218                 }
219
220                 static void OtherFlags ()
221                 {
222                         Console.WriteLine (
223                                 "Other flags in the compiler\n" +
224                                 "   --fatal            Makes errors fatal\n" +
225                                 "   --parse            Only parses the source file\n" +
226                                 "   --typetest         Tests the tokenizer's built-in type parser\n" +
227                                 "   --stacktrace       Shows stack trace at error location\n" +
228                                 "   --timestamp        Displays time stamps of various compiler events\n" +
229                                 "   --expect-error X   Expect that error X will be encountered\n" +
230                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
231                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
232                 }
233                 
234                 static void Usage ()
235                 {
236                         Console.WriteLine (
237                                 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
238                                 "mcs [options] source-files\n" +
239                                 "   --about            About the Mono C# compiler\n" +
240                                 "   -addmodule:M1[,Mn] Adds the module to the generated assembly\n" + 
241                                 "   -checked[+|-]      Sets default aritmetic overflow context\n" +
242                                 "   -codepage:ID       Sets code page to the one in ID (number, utf8, reset)\n" +
243                                 "   -clscheck[+|-]     Disables CLS Compliance verifications\n" +
244                                 "   -define:S1[;S2]    Defines one or more conditional symbols (short: -d)\n" +
245                                 "   -debug[+|-], -g    Generate debugging information\n" + 
246                                 "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
247                                 "   -doc:FILE          Process documentation comments to XML file\n" + 
248                                 "   -help              Lists all compiler options (short: -?)\n" + 
249                                 "   -keycontainer:NAME The key pair container used to sign the output assembly\n" +
250                                 "   -keyfile:FILE      The key file used to strongname the ouput assembly\n" +
251                                 "   -langversion:TEXT  Specifies language version modes: ISO-1, ISO-2, or Default\n" + 
252                                 "   -lib:PATH1[,PATHn] Specifies the location of referenced assemblies\n" +
253                                 "   -main:CLASS        Specifies the class with the Main method (short: -m)\n" +
254                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
255                                 "   -nostdlib[+|-]     Does not reference mscorlib.dll library\n" +
256                                 "   -nowarn:W1[,Wn]    Suppress one or more compiler warnings\n" + 
257                                 "   -optimize[+|-]     Enables advanced compiler optimizations (short: -o)\n" + 
258                                 "   -out:FILE          Specifies output assembly name\n" +
259                                 "   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
260                                 "   -recurse:SPEC      Recursively compiles files according to SPEC pattern\n" + 
261                                 "   -reference:A1[,An] Imports metadata from the specified assembly (short: -r)\n" +
262                                 "   -reference:ALIAS=A Imports metadata using specified extern alias (short: -r)\n" +                           
263                                 "   -target:KIND       Specifies the format of the output assembly (short: -t)\n" +
264                                 "                      KIND can be one of: exe, winexe, library, module\n" +
265                                 "   -unsafe[+|-]       Allows to compile code which uses unsafe keyword\n" +
266                                 "   -warnaserror[+|-]  Treats all warnings as errors\n" +
267                                 "   -warn:0-4          Sets warning level, the default is 3 (short -w:)\n" +
268                                 "   -help2             Shows internal compiler options\n" + 
269                                 "\n" +
270                                 "Resources:\n" +
271                                 "   -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
272                                 "   -resource:FILE[,ID]     Embed FILE as a resource (short: -res)\n" +
273                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
274                                 "   -win32icon:FILE         Use this icon for the output\n" +
275                                 "   @file                   Read response file for more options\n\n" +
276                                 "Options can be of the form -option or /option");
277                 }
278
279                 static void TargetUsage ()
280                 {
281                         Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
282                 }
283                 
284                 static void About ()
285                 {
286                         Console.WriteLine (
287                                 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
288                                 "The compiler source code is released under the terms of the \n"+
289                                 "MIT X11 or GNU GPL licenses\n\n" +
290
291                                 "For more information on Mono, visit the project Web site\n" +
292                                 "   http://www.mono-project.com\n\n" +
293
294                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
295                         Environment.Exit (0);
296                 }
297
298                 public static int Main (string[] args)
299                 {
300                         RootContext.Version = LanguageVersion.Default;
301
302                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
303
304                         Driver d = Driver.Create (args);
305                         if (d == null)
306                                 return 1;
307
308                         if (d.Compile () && Report.Errors == 0) {
309                                 if (Report.Warnings > 0) {
310                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
311                                 }
312                                 return 0;
313                         } else {
314                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
315                                         Report.Errors, Report.Warnings);
316                                 return 1;
317                         }
318                 }
319
320                 static public void LoadAssembly (string assembly, bool soft)
321                 {
322                         LoadAssembly (assembly, null, soft);
323                 }
324
325                 static void Error6 (string name, string log)
326                 {
327                         if (log != null && log.Length > 0)
328                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
329                         Report.Error (6, "cannot find metadata file `{0}'", name);
330                 }
331
332                 static void Error9 (string type, string filename, string log)
333                 {
334                         if (log != null && log.Length > 0)
335                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
336                         Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
337                 }
338
339                 static void BadAssembly (string filename, string log)
340                 {
341                         MethodInfo adder_method = AssemblyClass.AddModule_Method;
342
343                         if (adder_method != null) {
344                                 AssemblyName an = new AssemblyName ();
345                                 an.Name = ".temp";
346                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
347                                 try {
348                                         object m = null;
349                                         try {
350                                                 m = adder_method.Invoke (ab, new object [] { filename });
351                                         } catch (TargetInvocationException ex) {
352                                                 throw ex.InnerException;
353                                         }
354
355                                         if (m != null) {
356                                                 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
357                                                               Path.GetFileName (filename));
358                                                 return;
359                                         }
360                                 } catch (FileNotFoundException) {
361                                         // did the file get deleted during compilation? who cares? swallow the exception
362                                 } catch (BadImageFormatException) {
363                                         // swallow exception
364                                 } catch (FileLoadException) {
365                                         // swallow exception
366                                 }
367                         }
368                         Error9 ("assembly", filename, log);
369                 }
370
371                 static public void LoadAssembly (string assembly, string alias, bool soft)
372                 {
373                         Assembly a = null;
374                         string total_log = "";
375
376                         try {
377                                 try {
378                                         char[] path_chars = { '/', '\\' };
379
380                                         if (assembly.IndexOfAny (path_chars) != -1) {
381                                                 a = Assembly.LoadFrom (assembly);
382                                         } else {
383                                                 string ass = assembly;
384                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
385                                                         ass = assembly.Substring (0, assembly.Length - 4);
386                                                 a = Assembly.Load (ass);
387                                         }
388                                 } catch (FileNotFoundException) {
389                                         bool err = !soft;
390                                         foreach (string dir in link_paths) {
391                                                 string full_path = Path.Combine (dir, assembly);
392                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
393                                                         full_path += ".dll";
394
395                                                 try {
396                                                         a = Assembly.LoadFrom (full_path);
397                                                         err = false;
398                                                         break;
399                                                 } catch (FileNotFoundException ff) {
400                                                         if (soft)
401                                                                 return;
402                                                         total_log += ff.FusionLog;
403                                                 }
404                                         }
405                                         if (err) {
406                                                 Error6 (assembly, total_log);
407                                                 return;
408                                         }
409                                 }
410
411                                 // Extern aliased refs require special handling
412                                 if (alias == null)
413                                         RootNamespace.Global.AddAssemblyReference (a);
414                                 else
415                                         RootNamespace.DefineRootNamespace (alias, a);
416
417                         } catch (BadImageFormatException f) {
418                                 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
419                                 BadAssembly (f.FileName, f.FusionLog);
420                         } catch (FileLoadException f) {
421                                 // ... while .NET 1.1 throws this
422                                 BadAssembly (f.FileName, f.FusionLog);
423                         }
424                 }
425
426                 static public void LoadModule (string module)
427                 {
428                         Module m = null;
429                         string total_log = "";
430
431                         try {
432                                 try {
433                                         m = CodeGen.Assembly.AddModule (module);
434                                 } catch (FileNotFoundException) {
435                                         bool err = true;
436                                         foreach (string dir in link_paths) {
437                                                 string full_path = Path.Combine (dir, module);
438                                                 if (!module.EndsWith (".netmodule"))
439                                                         full_path += ".netmodule";
440
441                                                 try {
442                                                         m = CodeGen.Assembly.AddModule (full_path);
443                                                         err = false;
444                                                         break;
445                                                 } catch (FileNotFoundException ff) {
446                                                         total_log += ff.FusionLog;
447                                                 }
448                                         }
449                                         if (err) {
450                                                 Error6 (module, total_log);
451                                                 return;
452                                         }
453                                 }
454
455                                 RootNamespace.Global.AddModuleReference (m);
456
457                         } catch (BadImageFormatException f) {
458                                 Error9 ("module", f.FileName, f.FusionLog);
459                         } catch (FileLoadException f) {
460                                 Error9 ("module", f.FileName, f.FusionLog);
461                         }
462                 }
463
464                 /// <summary>
465                 ///   Loads all assemblies referenced on the command line
466                 /// </summary>
467                 static public void LoadReferences ()
468                 {
469                         //
470                         // Load Core Library for default compilation
471                         //
472                         if (RootContext.StdLib)
473                                 LoadAssembly ("mscorlib", false);
474
475                         foreach (string r in soft_references)
476                                 LoadAssembly (r, true);
477
478                         foreach (string r in references)
479                                 LoadAssembly (r, false);
480
481                         foreach (DictionaryEntry entry in external_aliases)
482                                 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
483                         
484                         return;
485                 }
486
487                 static string [] LoadArgs (string file)
488                 {
489                         StreamReader f;
490                         ArrayList args = new ArrayList ();
491                         string line;
492                         try {
493                                 f = new StreamReader (file);
494                         } catch {
495                                 return null;
496                         }
497
498                         StringBuilder sb = new StringBuilder ();
499                         
500                         while ((line = f.ReadLine ()) != null){
501                                 int t = line.Length;
502
503                                 for (int i = 0; i < t; i++){
504                                         char c = line [i];
505                                         
506                                         if (c == '"' || c == '\''){
507                                                 char end = c;
508                                                 
509                                                 for (i++; i < t; i++){
510                                                         c = line [i];
511
512                                                         if (c == end)
513                                                                 break;
514                                                         sb.Append (c);
515                                                 }
516                                         } else if (c == ' '){
517                                                 if (sb.Length > 0){
518                                                         args.Add (sb.ToString ());
519                                                         sb.Length = 0;
520                                                 }
521                                         } else
522                                                 sb.Append (c);
523                                 }
524                                 if (sb.Length > 0){
525                                         args.Add (sb.ToString ());
526                                         sb.Length = 0;
527                                 }
528                         }
529
530                         string [] ret_value = new string [args.Count];
531                         args.CopyTo (ret_value, 0);
532
533                         return ret_value;
534                 }
535
536                 //
537                 // Returns the directory where the system assemblies are installed
538                 //
539                 static string GetSystemDir ()
540                 {
541                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
542                 }
543
544                 //
545                 // Given a path specification, splits the path from the file/pattern
546                 //
547                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
548                 {
549                         int p = spec.LastIndexOf ('/');
550                         if (p != -1){
551                                 //
552                                 // Windows does not like /file.cs, switch that to:
553                                 // "\", "file.cs"
554                                 //
555                                 if (p == 0){
556                                         path = "\\";
557                                         pattern = spec.Substring (1);
558                                 } else {
559                                         path = spec.Substring (0, p);
560                                         pattern = spec.Substring (p + 1);
561                                 }
562                                 return;
563                         }
564
565                         p = spec.LastIndexOf ('\\');
566                         if (p != -1){
567                                 path = spec.Substring (0, p);
568                                 pattern = spec.Substring (p + 1);
569                                 return;
570                         }
571
572                         path = ".";
573                         pattern = spec;
574                 }
575
576                 void AddSourceFile (string f)
577                 {
578                         if (first_source == null)
579                                 first_source = f;
580
581                         Location.AddFile (f);
582                 }
583
584                 bool ParseArguments (string[] args)
585                 {
586                         references = new ArrayList ();
587                         external_aliases = new Hashtable ();
588                         soft_references = new ArrayList ();
589                         modules = new ArrayList (2);
590                         link_paths = new ArrayList ();
591
592                         ArrayList response_file_list = null;
593                         bool parsing_options = true;
594
595                         for (int i = 0; i < args.Length; i++) {
596                                 string arg = args [i];
597                                 if (arg.Length == 0)
598                                         continue;
599
600                                 if (arg.StartsWith ("@")) {
601                                         string [] extra_args;
602                                         string response_file = arg.Substring (1);
603
604                                         if (response_file_list == null)
605                                                 response_file_list = new ArrayList ();
606
607                                         if (response_file_list.Contains (response_file)) {
608                                                 Report.Error (
609                                                         1515, "Response file `" + response_file +
610                                                         "' specified multiple times");
611                                                 return false;
612                                         }
613
614                                         response_file_list.Add (response_file);
615
616                                         extra_args = LoadArgs (response_file);
617                                         if (extra_args == null) {
618                                                 Report.Error (2011, "Unable to open response file: " +
619                                                                   response_file);
620                                                 return false;
621                                         }
622
623                                         args = AddArgs (args, extra_args);
624                                         continue;
625                                 }
626
627                                 if (parsing_options) {
628                                         if (arg == "--") {
629                                                 parsing_options = false;
630                                                 continue;
631                                         }
632
633                                         if (arg.StartsWith ("-")) {
634                                                 if (UnixParseOption (arg, ref args, ref i))
635                                                         continue;
636
637                                                 // Try a -CSCOPTION
638                                                 string csc_opt = "/" + arg.Substring (1);
639                                                 if (CSCParseOption (csc_opt, ref args, ref i))
640                                                         continue;
641
642                                                 Error_WrongOption (arg);
643                                                 return false;
644                                         }
645                                         if (arg [0] == '/') {
646                                                 if (CSCParseOption (arg, ref args, ref i))
647                                                         continue;
648
649                                                 // Need to skip `/home/test.cs' however /test.cs is considered as error
650                                                 if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
651                                                         Error_WrongOption (arg);
652                                                         return false;
653                                                 }
654                                         }
655                                 }
656
657                                 ProcessSourceFiles (arg, false);
658                         }
659
660                         //
661                         // If we are an exe, require a source file for the entry point
662                         //
663                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module) {
664                                 if (first_source == null) {
665                                         Report.Error (2008, "No files to compile were specified");
666                                         return false;
667                                 }
668
669                         }
670
671                         //
672                         // If there is nothing to put in the assembly, and we are not a library
673                         //
674                         if (first_source == null && embedded_resources == null) {
675                                 Report.Error (2008, "No files to compile were specified");
676                                 return false;
677                         }
678
679                         return true;
680                 }
681
682                 public void Parse ()
683                 {
684                         Location.Initialize ();
685
686                         int files_count = Location.SourceFiles.Length;
687                         for (int i = 0; i < files_count; ++i) {
688                                 if (tokenize) {
689                                         tokenize_file (Location.SourceFiles [i]);
690                                 } else {
691                                         Parse (Location.SourceFiles [i]);
692                                 }
693                         }
694                 }
695
696                 void ProcessSourceFiles (string spec, bool recurse)
697                 {
698                         string path, pattern;
699
700                         SplitPathAndPattern (spec, out path, out pattern);
701                         if (pattern.IndexOf ('*') == -1){
702                                 AddSourceFile (spec);
703                                 return;
704                         }
705
706                         string [] files = null;
707                         try {
708                                 files = Directory.GetFiles (path, pattern);
709                         } catch (System.IO.DirectoryNotFoundException) {
710                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
711                                 return;
712                         } catch (System.IO.IOException){
713                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
714                                 return;
715                         }
716                         foreach (string f in files) {
717                                 AddSourceFile (f);
718                         }
719
720                         if (!recurse)
721                                 return;
722                         
723                         string [] dirs = null;
724
725                         try {
726                                 dirs = Directory.GetDirectories (path);
727                         } catch {
728                         }
729                         
730                         foreach (string d in dirs) {
731                                         
732                                 // Don't include path in this string, as each
733                                 // directory entry already does
734                                 ProcessSourceFiles (d + "/" + pattern, true);
735                         }
736                 }
737
738                 static void DefineDefaultConfig ()
739                 {
740                         //
741                         // For now the "default config" is harcoded into the compiler
742                         // we can move this outside later
743                         //
744                         string [] default_config = {
745                                 "System",
746                                 "System.Xml",
747 #if NET_2_1
748                                 "System.Core",
749                                 "System.Net",
750                                 "System.Windows",
751                                 "System.Windows.Browser",
752 #endif
753 #if false
754                                 //
755                                 // Is it worth pre-loading all this stuff?
756                                 //
757                                 "Accessibility",
758                                 "System.Configuration.Install",
759                                 "System.Data",
760                                 "System.Design",
761                                 "System.DirectoryServices",
762                                 "System.Drawing.Design",
763                                 "System.Drawing",
764                                 "System.EnterpriseServices",
765                                 "System.Management",
766                                 "System.Messaging",
767                                 "System.Runtime.Remoting",
768                                 "System.Runtime.Serialization.Formatters.Soap",
769                                 "System.Security",
770                                 "System.ServiceProcess",
771                                 "System.Web",
772                                 "System.Web.RegularExpressions",
773                                 "System.Web.Services",
774                                 "System.Windows.Forms"
775 #endif
776                         };
777                         
778                         if (RootContext.Version == LanguageVersion.LINQ)
779                                 soft_references.Add ("System.Core");
780
781                         soft_references.AddRange (default_config);
782                 }
783
784                 public static string OutputFile
785                 {
786                         set {
787                                 output_file = value;
788                         }
789                         get {
790                                 return Path.GetFileName (output_file);
791                         }
792                 }
793
794                 static void SetWarningLevel (string s)
795                 {
796                         int level = -1;
797
798                         try {
799                                 level = Int32.Parse (s);
800                         } catch {
801                         }
802                         if (level < 0 || level > 4){
803                                 Report.Error (1900, "Warning level must be in the range 0-4");
804                                 return;
805                         }
806                         Report.WarningLevel = level;
807                 }
808
809                 static void Version ()
810                 {
811                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
812                         Console.WriteLine ("Mono C# compiler version {0}", version);
813                         Environment.Exit (0);
814                 }
815                 
816                 //
817                 // Currently handles the Unix-like command line options, but will be
818                 // deprecated in favor of the CSCParseOption, which will also handle the
819                 // options that start with a dash in the future.
820                 //
821                 bool UnixParseOption (string arg, ref string [] args, ref int i)
822                 {
823                         switch (arg){
824                         case "-v":
825                                 CSharpParser.yacc_verbose_flag++;
826                                 return true;
827
828                         case "--version":
829                                 Version ();
830                                 return true;
831                                 
832                         case "--parse":
833                                 parse_only = true;
834                                 return true;
835                                 
836                         case "--main": case "-m":
837                                 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
838                                 if ((i + 1) >= args.Length){
839                                         Usage ();
840                                         Environment.Exit (1);
841                                 }
842                                 RootContext.MainClass = args [++i];
843                                 return true;
844                                 
845                         case "--unsafe":
846                                 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
847                                 RootContext.Unsafe = true;
848                                 return true;
849                                 
850                         case "/?": case "/h": case "/help":
851                         case "--help":
852                                 Usage ();
853                                 Environment.Exit (0);
854                                 return true;
855
856                         case "--define":
857                                 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
858                                 if ((i + 1) >= args.Length){
859                                         Usage ();
860                                         Environment.Exit (1);
861                                 }
862                                 defines.Add (args [++i]);
863                                 return true;
864
865                         case "--tokenize": 
866                                 tokenize = true;
867                                 return true;
868                                 
869                         case "-o": 
870                         case "--output":
871                                 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
872                                 if ((i + 1) >= args.Length){
873                                         Usage ();
874                                         Environment.Exit (1);
875                                 }
876                                 OutputFile = args [++i];
877                                 return true;
878
879                         case "--checked":
880                                 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
881                                 RootContext.Checked = true;
882                                 return true;
883                                 
884                         case "--stacktrace":
885                                 Report.Stacktrace = true;
886                                 return true;
887                                 
888                         case "--linkresource":
889                         case "--linkres":
890                                 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
891                                 if ((i + 1) >= args.Length){
892                                         Usage ();
893                                         Report.Error (5, "Missing argument to --linkres"); 
894                                         Environment.Exit (1);
895                                 }
896                                 if (embedded_resources == null)
897                                         embedded_resources = new Resources ();
898                                 
899                                 embedded_resources.Add (false, args [++i], args [i]);
900                                 return true;
901                                 
902                         case "--resource":
903                         case "--res":
904                                 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
905                                 if ((i + 1) >= args.Length){
906                                         Usage ();
907                                         Report.Error (5, "Missing argument to --resource"); 
908                                         Environment.Exit (1);
909                                 }
910                                 if (embedded_resources == null)
911                                         embedded_resources = new Resources ();
912                                 
913                                 embedded_resources.Add (true, args [++i], args [i]);
914                                 return true;
915                                 
916                         case "--target":
917                                 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
918                                 if ((i + 1) >= args.Length){
919                                         Environment.Exit (1);
920                                         return true;
921                                 }
922                                 
923                                 string type = args [++i];
924                                 switch (type){
925                                 case "library":
926                                         RootContext.Target = Target.Library;
927                                         RootContext.TargetExt = ".dll";
928                                         break;
929                                         
930                                 case "exe":
931                                         RootContext.Target = Target.Exe;
932                                         break;
933                                         
934                                 case "winexe":
935                                         RootContext.Target = Target.WinExe;
936                                         break;
937                                         
938                                 case "module":
939                                         RootContext.Target = Target.Module;
940                                         RootContext.TargetExt = ".dll";
941                                         break;
942                                 default:
943                                         TargetUsage ();
944                                         break;
945                                 }
946                                 return true;
947                                 
948                         case "-r":
949                                 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
950                                 if ((i + 1) >= args.Length){
951                                         Usage ();
952                                         Environment.Exit (1);
953                                 }
954                                 
955                                 string val = args [++i];
956                                 int idx = val.IndexOf ('=');
957                                 if (idx > -1) {
958                                         string alias = val.Substring (0, idx);
959                                         string assembly = val.Substring (idx + 1);
960                                         AddExternAlias (alias, assembly);
961                                         return true;
962                                 }
963
964                                 references.Add (val);
965                                 return true;
966                                 
967                         case "-L":
968                                 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
969                                 if ((i + 1) >= args.Length){
970                                         Usage ();       
971                                         Environment.Exit (1);
972                                 }
973                                 link_paths.Add (args [++i]);
974                                 return true;
975                                 
976                         case "--nostdlib":
977                                 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
978                                 RootContext.StdLib = false;
979                                 return true;
980                                 
981                         case "--fatal":
982                                 Report.Fatal = true;
983                                 return true;
984                                 
985                         case "--werror":
986                                 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
987                                 Report.WarningsAreErrors = true;
988                                 return true;
989
990                         case "--nowarn":
991                                 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
992                                 if ((i + 1) >= args.Length){
993                                         Usage ();
994                                         Environment.Exit (1);
995                                 }
996                                 int warn = 0;
997                                 
998                                 try {
999                                         warn = Int32.Parse (args [++i]);
1000                                 } catch {
1001                                         Usage ();
1002                                         Environment.Exit (1);
1003                                 }
1004                                 Report.SetIgnoreWarning (warn);
1005                                 return true;
1006                                 
1007                         case "--wlevel":
1008                                 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
1009                                 if ((i + 1) >= args.Length){
1010                                         Report.Error (
1011                                                 1900,
1012                                                 "--wlevel requires a value from 0 to 4");
1013                                         Environment.Exit (1);
1014                                 }
1015
1016                                 SetWarningLevel (args [++i]);
1017                                 return true;
1018
1019                         case "--mcs-debug":
1020                                 if ((i + 1) >= args.Length){
1021                                         Report.Error (5, "--mcs-debug requires an argument");
1022                                         Environment.Exit (1);
1023                                 }
1024
1025                                 try {
1026                                         Report.DebugFlags = Int32.Parse (args [++i]);
1027                                 } catch {
1028                                         Report.Error (5, "Invalid argument to --mcs-debug");
1029                                         Environment.Exit (1);
1030                                 }
1031                                 return true;
1032                                 
1033                         case "--about":
1034                                 About ();
1035                                 return true;
1036                                 
1037                         case "--recurse":
1038                                 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
1039                                 if ((i + 1) >= args.Length){
1040                                         Report.Error (5, "--recurse requires an argument");
1041                                         Environment.Exit (1);
1042                                 }
1043                                 ProcessSourceFiles (args [++i], true); 
1044                                 return true;
1045                                 
1046                         case "--timestamp":
1047                                 timestamps = true;
1048                                 last_time = first_time = DateTime.Now;
1049                                 return true;
1050
1051                         case "--debug": case "-g":
1052                                 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1053                                 want_debugging_support = true;
1054                                 return true;
1055                                 
1056                         case "--noconfig":
1057                                 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1058                                 load_default_config = false;
1059                                 return true;
1060                         }
1061
1062                         return false;
1063                 }
1064
1065                 //
1066                 // This parses the -arg and /arg options to the compiler, even if the strings
1067                 // in the following text use "/arg" on the strings.
1068                 //
1069                 bool CSCParseOption (string option, ref string [] args, ref int i)
1070                 {
1071                         int idx = option.IndexOf (':');
1072                         string arg, value;
1073
1074                         if (idx == -1){
1075                                 arg = option;
1076                                 value = "";
1077                         } else {
1078                                 arg = option.Substring (0, idx);
1079
1080                                 value = option.Substring (idx + 1);
1081                         }
1082
1083                         switch (arg){
1084                         case "/nologo":
1085                                 return true;
1086
1087                         case "/t":
1088                         case "/target":
1089                                 switch (value){
1090                                 case "exe":
1091                                         RootContext.Target = Target.Exe;
1092                                         break;
1093
1094                                 case "winexe":
1095                                         RootContext.Target = Target.WinExe;
1096                                         break;
1097
1098                                 case "library":
1099                                         RootContext.Target = Target.Library;
1100                                         RootContext.TargetExt = ".dll";
1101                                         break;
1102
1103                                 case "module":
1104                                         RootContext.Target = Target.Module;
1105                                         RootContext.TargetExt = ".netmodule";
1106                                         break;
1107
1108                                 default:
1109                                         TargetUsage ();
1110                                         break;
1111                                 }
1112                                 return true;
1113
1114                         case "/out":
1115                                 if (value.Length == 0){
1116                                         Usage ();
1117                                         Environment.Exit (1);
1118                                 }
1119                                 OutputFile = value;
1120                                 return true;
1121
1122                         case "/o":
1123                         case "/o+":
1124                         case "/optimize":
1125                         case "/optimize+":
1126                                 RootContext.Optimize = true;
1127                                 return true;
1128
1129                         case "/o-":
1130                         case "/optimize-":
1131                                 RootContext.Optimize = false;
1132                                 return true;
1133
1134                         case "/incremental":
1135                         case "/incremental+":
1136                         case "/incremental-":
1137                                 // nothing.
1138                                 return true;
1139
1140                         case "/d":
1141                         case "/define": {
1142                                 if (value.Length == 0){
1143                                         Usage ();
1144                                         Environment.Exit (1);
1145                                 }
1146
1147                                 foreach (string d in value.Split (';', ',')){
1148                                         if (!Tokenizer.IsValidIdentifier (d)) {
1149                                                 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1150                                                 continue;
1151                                         }
1152                                         defines.Add (d);
1153                                 }
1154                                 return true;
1155                         }
1156
1157                         case "/bugreport":
1158                                 //
1159                                 // We should collect data, runtime, etc and store in the file specified
1160                                 //
1161                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1162                                 return true;
1163
1164                         case "/pkg": {
1165                                 string packages;
1166
1167                                 if (value.Length == 0){
1168                                         Usage ();
1169                                         Environment.Exit (1);
1170                                 }
1171                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1172                                 
1173                                 ProcessStartInfo pi = new ProcessStartInfo ();
1174                                 pi.FileName = "pkg-config";
1175                                 pi.RedirectStandardOutput = true;
1176                                 pi.UseShellExecute = false;
1177                                 pi.Arguments = "--libs " + packages;
1178                                 Process p = null;
1179                                 try {
1180                                         p = Process.Start (pi);
1181                                 } catch (Exception e) {
1182                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1183                                         Environment.Exit (1);
1184                                 }
1185
1186                                 if (p.StandardOutput == null){
1187                                         Report.Warning (-27, 1, "Specified package did not return any information");
1188                                         return true;
1189                                 }
1190                                 string pkgout = p.StandardOutput.ReadToEnd ();
1191                                 p.WaitForExit ();
1192                                 if (p.ExitCode != 0) {
1193                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1194                                         Environment.Exit (1);
1195                                 }
1196
1197                                 if (pkgout != null){
1198                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1199                                                 Split (new Char [] { ' ', '\t'});
1200                                         args = AddArgs (args, xargs);
1201                                 }
1202                                 
1203                                 p.Close ();
1204                                 return true;
1205                         }
1206                                 
1207                         case "/linkres":
1208                         case "/linkresource":
1209                         case "/res":
1210                         case "/resource":
1211                                 if (embedded_resources == null)
1212                                         embedded_resources = new Resources ();
1213
1214                                 bool embeded = arg.StartsWith ("/r");
1215                                 string[] s = value.Split (',');
1216                                 switch (s.Length) {
1217                                         case 1:
1218                                                 if (s[0].Length == 0)
1219                                                         goto default;
1220                                                 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1221                                                 break;
1222                                         case 2:
1223                                                 embedded_resources.Add (embeded, s [0], s [1]);
1224                                                 break;
1225                                         case 3:
1226                                                 if (s [2] != "public" && s [2] != "private") {
1227                                                         Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1228                                                         return true;
1229                                                 }
1230                                                 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1231                                                 break;
1232                                         default:
1233                                                 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1234                                                 break;
1235                                 }
1236
1237                                 return true;
1238                                 
1239                         case "/recurse":
1240                                 if (value.Length == 0){
1241                                         Report.Error (5, "-recurse requires an argument");
1242                                         Environment.Exit (1);
1243                                 }
1244                                 ProcessSourceFiles (value, true); 
1245                                 return true;
1246
1247                         case "/r":
1248                         case "/reference": {
1249                                 if (value.Length == 0){
1250                                         Report.Error (5, "-reference requires an argument");
1251                                         Environment.Exit (1);
1252                                 }
1253
1254                                 string [] refs = value.Split (new char [] { ';', ',' });
1255                                 foreach (string r in refs){
1256                                         string val = r;
1257                                         int index = val.IndexOf ('=');
1258                                         if (index > -1) {
1259                                                 string alias = r.Substring (0, index);
1260                                                 string assembly = r.Substring (index + 1);
1261                                                 AddExternAlias (alias, assembly);
1262                                                 return true;
1263                                         }
1264                                         
1265                                         references.Add (val);
1266                                 }
1267                                 return true;
1268                         }
1269                         case "/addmodule": {
1270                                 if (value.Length == 0){
1271                                         Report.Error (5, arg + " requires an argument");
1272                                         Environment.Exit (1);
1273                                 }
1274
1275                                 string [] refs = value.Split (new char [] { ';', ',' });
1276                                 foreach (string r in refs){
1277                                         modules.Add (r);
1278                                 }
1279                                 return true;
1280                         }
1281                         case "/win32res": {
1282                                 if (value.Length == 0) {
1283                                         Report.Error (5, arg + " requires an argument");
1284                                         Environment.Exit (1);
1285                                 }
1286
1287                                 win32ResourceFile = value;
1288                                 return true;
1289                         }
1290                         case "/win32icon": {
1291                                 if (value.Length == 0) {
1292                                         Report.Error (5, arg + " requires an argument");
1293                                         Environment.Exit (1);
1294                                 }
1295
1296                                 win32IconFile = value;
1297                                 return true;
1298                         }
1299                         case "/doc": {
1300                                 if (value.Length == 0){
1301                                         Report.Error (2006, arg + " requires an argument");
1302                                         Environment.Exit (1);
1303                                 }
1304                                 RootContext.Documentation = new Documentation (value);
1305                                 return true;
1306                         }
1307                         case "/lib": {
1308                                 string [] libdirs;
1309                                 
1310                                 if (value.Length == 0){
1311                                         Report.Error (5, "/lib requires an argument");
1312                                         Environment.Exit (1);
1313                                 }
1314
1315                                 libdirs = value.Split (new Char [] { ',' });
1316                                 foreach (string dir in libdirs)
1317                                         link_paths.Add (dir);
1318                                 return true;
1319                         }
1320
1321                         case "/debug-":
1322                                 want_debugging_support = false;
1323                                 return true;
1324                                 
1325                         case "/debug":
1326                         case "/debug+":
1327                                 want_debugging_support = true;
1328                                 return true;
1329
1330                         case "/checked":
1331                         case "/checked+":
1332                                 RootContext.Checked = true;
1333                                 return true;
1334
1335                         case "/checked-":
1336                                 RootContext.Checked = false;
1337                                 return true;
1338
1339                         case "/clscheck":
1340                         case "/clscheck+":
1341                                 return true;
1342
1343                         case "/clscheck-":
1344                                 RootContext.VerifyClsCompliance = false;
1345                                 return true;
1346
1347                         case "/unsafe":
1348                         case "/unsafe+":
1349                                 RootContext.Unsafe = true;
1350                                 return true;
1351
1352                         case "/unsafe-":
1353                                 RootContext.Unsafe = false;
1354                                 return true;
1355
1356                         case "/warnaserror":
1357                         case "/warnaserror+":
1358                                 Report.WarningsAreErrors = true;
1359                                 return true;
1360
1361                         case "/warnaserror-":
1362                                 Report.WarningsAreErrors = false;
1363                                 return true;
1364
1365                         case "/warn":
1366                                 SetWarningLevel (value);
1367                                 return true;
1368
1369                         case "/nowarn": {
1370                                 string [] warns;
1371
1372                                 if (value.Length == 0){
1373                                         Report.Error (5, "/nowarn requires an argument");
1374                                         Environment.Exit (1);
1375                                 }
1376                                 
1377                                 warns = value.Split (new Char [] {','});
1378                                 foreach (string wc in warns){
1379                                         try {
1380                                                 int warn = Int32.Parse (wc);
1381                                                 if (warn < 1) {
1382                                                         throw new ArgumentOutOfRangeException("warn");
1383                                                 }
1384                                                 Report.SetIgnoreWarning (warn);
1385                                         } catch {
1386                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1387                                         }
1388                                 }
1389                                 return true;
1390                         }
1391
1392                         case "/noconfig-":
1393                                 load_default_config = true;
1394                                 return true;
1395                                 
1396                         case "/noconfig":
1397                         case "/noconfig+":
1398                                 load_default_config = false;
1399                                 return true;
1400
1401                         case "/help2":
1402                                 OtherFlags ();
1403                                 Environment.Exit(0);
1404                                 return true;
1405                                 
1406                         case "/help":
1407                         case "/?":
1408                                 Usage ();
1409                                 Environment.Exit (0);
1410                                 return true;
1411
1412                         case "/main":
1413                         case "/m":
1414                                 if (value.Length == 0){
1415                                         Report.Error (5, arg + " requires an argument");                                        
1416                                         Environment.Exit (1);
1417                                 }
1418                                 RootContext.MainClass = value;
1419                                 return true;
1420
1421                         case "/nostdlib":
1422                         case "/nostdlib+":
1423                                 RootContext.StdLib = false;
1424                                 return true;
1425
1426                         case "/nostdlib-":
1427                                 RootContext.StdLib = true;
1428                                 return true;
1429
1430                         case "/fullpaths":
1431                                 return true;
1432
1433                         case "/keyfile":
1434                                 if (value == String.Empty) {
1435                                         Report.Error (5, arg + " requires an argument");
1436                                         Environment.Exit (1);
1437                                 }
1438                                 RootContext.StrongNameKeyFile = value;
1439                                 return true;
1440                         case "/keycontainer":
1441                                 if (value == String.Empty) {
1442                                         Report.Error (5, arg + " requires an argument");
1443                                         Environment.Exit (1);
1444                                 }
1445                                 RootContext.StrongNameKeyContainer = value;
1446                                 return true;
1447                         case "/delaysign+":
1448                                 RootContext.StrongNameDelaySign = true;
1449                                 return true;
1450                         case "/delaysign-":
1451                                 RootContext.StrongNameDelaySign = false;
1452                                 return true;
1453
1454                         case "/langversion":
1455                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1456                                 case "iso-1":
1457                                         RootContext.Version = LanguageVersion.ISO_1;
1458                                         return true;
1459                                         
1460                                 case "default":
1461                                         RootContext.Version = LanguageVersion.Default;
1462 #if GMCS_SOURCE                                 
1463                                         defines.Add ("__V2__");
1464 #endif
1465                                         return true;
1466 #if GMCS_SOURCE
1467                                 case "iso-2":
1468                                         RootContext.Version = LanguageVersion.ISO_2;
1469                                         return true;
1470                                         
1471                                 case "linq":
1472                                         Report.Warning (-30, 1, "Deprecated: The `linq' option is no longer required and should not be used");
1473                                         return true;
1474 #endif
1475                                 }
1476                                 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
1477                                 return true;
1478
1479                         case "/codepage":
1480                                 switch (value) {
1481                                 case "utf8":
1482                                         encoding = new UTF8Encoding();
1483                                         break;
1484                                 case "reset":
1485                                         encoding = Encoding.Default;
1486                                         break;
1487                                 default:
1488                                         try {
1489                                                 encoding = Encoding.GetEncoding (
1490                                                 Int32.Parse (value));
1491                                         } catch {
1492                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1493                                         }
1494                                         break;
1495                                 }
1496                                 return true;
1497                         }
1498
1499                         return false;
1500                 }
1501
1502                 static void Error_WrongOption (string option)
1503                 {
1504                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1505                 }
1506
1507                 static string [] AddArgs (string [] args, string [] extra_args)
1508                 {
1509                         string [] new_args;
1510                         new_args = new string [extra_args.Length + args.Length];
1511
1512                         // if args contains '--' we have to take that into account
1513                         // split args into first half and second half based on '--'
1514                         // and add the extra_args before --
1515                         int split_position = Array.IndexOf (args, "--");
1516                         if (split_position != -1)
1517                         {
1518                                 Array.Copy (args, new_args, split_position);
1519                                 extra_args.CopyTo (new_args, split_position);
1520                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1521                         }
1522                         else
1523                         {
1524                                 args.CopyTo (new_args, 0);
1525                                 extra_args.CopyTo (new_args, args.Length);
1526                         }
1527
1528                         return new_args;
1529                 }
1530
1531                 static void AddExternAlias (string identifier, string assembly)
1532                 {
1533                         if (assembly.Length == 0) {
1534                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1535                                 return;
1536                         }
1537
1538                         if (!IsExternAliasValid (identifier)) {
1539                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1540                                 return;
1541                         }
1542                         
1543                         // Could here hashtable throw an exception?
1544                         external_aliases [identifier] = assembly;
1545                 }
1546                 
1547                 static bool IsExternAliasValid (string identifier)
1548                 {
1549                         if (identifier.Length == 0)
1550                                 return false;
1551                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1552                                 return false;
1553
1554                         for (int i = 1; i < identifier.Length; i++) {
1555                                 char c = identifier [i];
1556                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1557                                         continue;
1558
1559                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1560                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1561                                                 category != UnicodeCategory.SpacingCombiningMark ||
1562                                                 category != UnicodeCategory.ConnectorPunctuation)
1563                                         return false;
1564                         }
1565                         
1566                         return true;
1567                 }
1568                 
1569                 //
1570                 // Main compilation method
1571                 //
1572                 public bool Compile ()
1573                 {
1574                         Parse ();
1575                         if (Report.Errors > 0)
1576                                 return false;
1577
1578                         if (tokenize || parse_only)
1579                                 return true;
1580
1581                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1582                                 throw new InternalErrorException ("who set it?");
1583
1584                         if (load_default_config)
1585                                 DefineDefaultConfig ();
1586
1587                         if (Report.Errors > 0){
1588                                 return false;
1589                         }
1590
1591                         //
1592                         // Load assemblies required
1593                         //
1594                         if (timestamps)
1595                                 ShowTime ("Loading references");
1596                         link_paths.Add (GetSystemDir ());
1597                         link_paths.Add (Directory.GetCurrentDirectory ());
1598                         LoadReferences ();
1599                         
1600                         if (timestamps)
1601                                 ShowTime ("   References loaded");
1602                         
1603                         if (Report.Errors > 0){
1604                                 return false;
1605                         }
1606
1607                         //
1608                         // Quick hack
1609                         //
1610                         if (output_file == null){
1611                                 if (first_source == null){
1612                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1613                                         return false;
1614                                 }
1615                                         
1616                                 int pos = first_source.LastIndexOf ('.');
1617
1618                                 if (pos > 0)
1619                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1620                                 else
1621                                         output_file = first_source + RootContext.TargetExt;
1622                         }
1623
1624                         if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1625                                 return false;
1626
1627                         if (RootContext.Target == Target.Module) {
1628                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1629                                 if (module_only == null) {
1630                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1631                                         Environment.Exit (1);
1632                                 }
1633
1634                                 MethodInfo set_method = module_only.GetSetMethod (true);
1635                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1636                         }
1637
1638                         RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1639
1640                         if (modules.Count > 0) {
1641                                 foreach (string module in modules)
1642                                         LoadModule (module);
1643                         }
1644                         
1645                         if (!TypeManager.InitCoreTypes ())
1646                                 return false;
1647
1648                         TypeManager.InitOptionalCoreTypes ();
1649
1650                         if (timestamps)
1651                                 ShowTime ("   Core Types done");
1652
1653                         CodeGen.Module.Resolve ();
1654
1655                         //
1656                         // The second pass of the compiler
1657                         //
1658                         if (timestamps)
1659                                 ShowTime ("Resolving tree");
1660                         RootContext.ResolveTree ();
1661
1662                         if (Report.Errors > 0)
1663                                 return false;
1664                         if (timestamps)
1665                                 ShowTime ("Populate tree");
1666                         if (!RootContext.StdLib)
1667                                 RootContext.BootCorlib_PopulateCoreTypes ();
1668                         RootContext.PopulateTypes ();
1669
1670                         RootContext.DefineTypes ();
1671                         
1672                         if (Report.Errors == 0 &&
1673                                 RootContext.Documentation != null &&
1674                                 !RootContext.Documentation.OutputDocComment (
1675                                         output_file))
1676                                 return false;
1677
1678                         //
1679                         // Verify using aliases now
1680                         //
1681                         NamespaceEntry.VerifyAllUsing ();
1682                         
1683                         if (Report.Errors > 0){
1684                                 return false;
1685                         }
1686
1687                         CodeGen.Assembly.Resolve ();
1688                         
1689                         if (RootContext.VerifyClsCompliance) {
1690                                 if (CodeGen.Assembly.IsClsCompliant) {
1691                                         AttributeTester.VerifyModulesClsCompliance ();
1692                                         TypeManager.LoadAllImportedTypes ();
1693                                 }
1694                         }
1695                         if (Report.Errors > 0)
1696                                 return false;
1697                         
1698                         //
1699                         // The code generator
1700                         //
1701                         if (timestamps)
1702                                 ShowTime ("Emitting code");
1703                         ShowTotalTime ("Total so far");
1704                         RootContext.EmitCode ();
1705                         if (timestamps)
1706                                 ShowTime ("   done");
1707
1708                         if (Report.Errors > 0){
1709                                 return false;
1710                         }
1711
1712                         if (timestamps)
1713                                 ShowTime ("Closing types");
1714
1715                         RootContext.CloseTypes ();
1716
1717                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1718
1719                         switch (RootContext.Target) {
1720                         case Target.Library:
1721                         case Target.Module:
1722                                 k = PEFileKinds.Dll; break;
1723                         case Target.Exe:
1724                                 k = PEFileKinds.ConsoleApplication; break;
1725                         case Target.WinExe:
1726                                 k = PEFileKinds.WindowApplication; break;
1727                         }
1728
1729                         if (RootContext.NeedsEntryPoint) {
1730                                 MethodInfo ep = RootContext.EntryPoint;
1731
1732                                 if (ep == null) {
1733                                         if (RootContext.MainClass != null) {
1734                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1735                                                 if (main_cont == null) {
1736                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1737                                                         return false;
1738                                                 }
1739
1740                                                 if (!(main_cont is ClassOrStruct)) {
1741                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1742                                                         return false;
1743                                                 }
1744
1745                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1746                                                 return false;
1747                                         }
1748
1749                                         if (Report.Errors == 0)
1750                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1751                                                         output_file);
1752                                         return false;
1753                                 }
1754
1755                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1756                         } else if (RootContext.MainClass != null) {
1757                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1758                         }
1759
1760                         if (embedded_resources != null){
1761                                 if (RootContext.Target == Target.Module) {
1762                                         Report.Error (1507, "Cannot link resource file when building a module");
1763                                         return false;
1764                                 }
1765
1766                                 embedded_resources.Emit ();
1767                         }
1768
1769                         //
1770                         // Add Win32 resources
1771                         //
1772
1773                         if (win32ResourceFile != null) {
1774                                 try {
1775                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1776                                 } catch (ArgumentException) {
1777                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1778                                 }
1779                         } else {
1780                                 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1781                         }
1782
1783                         if (win32IconFile != null) {
1784                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1785                                 if (define_icon == null) {
1786                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1787                                 }
1788                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1789                         }
1790
1791                         if (Report.Errors > 0)
1792                                 return false;
1793                         
1794                         CodeGen.Save (output_file, want_debugging_support);
1795                         if (timestamps) {
1796                                 ShowTime ("Saved output");
1797                                 ShowTotalTime ("Total");
1798                         }
1799
1800                         Timer.ShowTimers ();
1801                         
1802                         if (Report.ExpectedError != 0) {
1803                                 if (Report.Errors == 0) {
1804                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1805                                                 "No other errors reported.");
1806                                         
1807                                         Environment.Exit (2);
1808                                 } else {
1809                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1810                                                 "However, other errors were reported.");
1811                                         
1812                                         Environment.Exit (1);
1813                                 }
1814                                 
1815                                 
1816                                 return false;
1817                         }
1818
1819 #if DEBUGME
1820                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1821                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1822 #endif
1823                         return (Report.Errors == 0);
1824                 }
1825         }
1826
1827         class Resources
1828         {
1829                 interface IResource
1830                 {
1831                         void Emit ();
1832                         string FileName { get; }
1833                 }
1834
1835                 class EmbededResource : IResource
1836                 {
1837                         static MethodInfo embed_res;
1838
1839                         static EmbededResource () {
1840                                 Type[] argst = new Type [] { 
1841                                                                                            typeof (string), typeof (string), typeof (ResourceAttributes)
1842                                                                                    };
1843
1844                                 embed_res = typeof (AssemblyBuilder).GetMethod (
1845                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1846                                         null, CallingConventions.Any, argst, null);
1847                                 
1848                                 if (embed_res == null) {
1849                                         Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1850                                 }
1851                         }
1852
1853                         readonly object[] args;
1854
1855                         public EmbededResource (string name, string file, bool isPrivate)
1856                         {
1857                                 args = new object [3];
1858                                 args [0] = name;
1859                                 args [1] = file;
1860                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1861                         }
1862
1863                         public void Emit()
1864                         {
1865                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1866                         }
1867
1868                         public string FileName {
1869                                 get {
1870                                         return (string)args [1];
1871                                 }
1872                         }
1873                 }
1874
1875                 class LinkedResource : IResource
1876                 {
1877                         readonly string file;
1878                         readonly string name;
1879                         readonly ResourceAttributes attribute;
1880
1881                         public LinkedResource (string name, string file, bool isPrivate)
1882                         {
1883                                 this.name = name;
1884                                 this.file = file;
1885                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1886                         }
1887
1888                         public void Emit ()
1889                         {
1890                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1891                         }
1892
1893                         public string FileName {
1894                                 get {
1895                                         return file;
1896                                 }
1897                         }
1898                 }
1899
1900
1901                 IDictionary embedded_resources = new HybridDictionary ();
1902
1903                 public void Add (bool embeded, string file, string name)
1904                 {
1905                         Add (embeded, file, name, false);
1906                 }
1907
1908                 public void Add (bool embeded, string file, string name, bool isPrivate)
1909                 {
1910                         if (embedded_resources.Contains (name)) {
1911                                 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1912                                 return;
1913                         }
1914                         IResource r = embeded ? 
1915                                 (IResource) new EmbededResource (name, file, isPrivate) : 
1916                                 new LinkedResource (name, file, isPrivate);
1917
1918                         embedded_resources.Add (name, r);
1919                 }
1920
1921                 public void Emit ()
1922                 {
1923                         foreach (IResource r in embedded_resources.Values) {
1924                                 if (!File.Exists (r.FileName)) {
1925                                         Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1926                                         continue;
1927                                 }
1928                                 
1929                                 r.Emit ();
1930                         }
1931                 }
1932         }
1933
1934         //
1935         // This is the only public entry point
1936         //
1937         public class CompilerCallableEntryPoint : MarshalByRefObject {
1938                 public static bool InvokeCompiler (string [] args, TextWriter error)
1939                 {
1940                         Report.Stderr = error;
1941                         try {
1942                                 Driver d = Driver.Create (args);
1943                                 if (d == null)
1944                                         return false;
1945
1946                                 return d.Compile () && Report.Errors == 0;
1947                         }
1948                         finally {
1949                                 Report.Stderr = Console.Error;
1950                                 Reset ();
1951                         }
1952                 }
1953
1954                 public static int[] AllWarningNumbers {
1955                         get {
1956                                 return Report.AllWarnings;
1957                         }
1958                 }
1959                 
1960                 static void Reset ()
1961                 {
1962                         Driver.Reset ();
1963                         RootContext.Reset ();
1964                         Tokenizer.Reset ();
1965                         Location.Reset ();
1966                         Report.Reset ();
1967                         TypeManager.Reset ();
1968                         TypeHandle.Reset ();
1969                         RootNamespace.Reset ();
1970                         NamespaceEntry.Reset ();
1971                         CodeGen.Reset ();
1972                         Attribute.Reset ();
1973                         AttributeTester.Reset ();
1974                         CompilerGeneratedClass.Reset ();
1975                         AnonymousTypeClass.Reset ();
1976                 }
1977         }
1978 }