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