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