2010-01-20 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@gnu.org)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
12 //
13
14 namespace Mono.CSharp
15 {
16         using System;
17         using System.Reflection;
18         using System.Reflection.Emit;
19         using System.Collections.Generic;
20         using System.IO;
21         using System.Text;
22         using System.Globalization;
23         using System.Diagnostics;
24
25         public enum Target {
26                 Library, Exe, Module, WinExe
27         };
28
29         public enum Platform {
30                 AnyCPU, X86, X64, IA64
31         }
32         
33         /// <summary>
34         ///    The compiler driver.
35         /// </summary>
36         class Driver
37         {
38                 //
39                 // Assemblies references to be linked.   Initialized with
40                 // mscorlib.dll here.
41                 List<string> references;
42
43                 //
44                 // If any of these fail, we ignore the problem.  This is so
45                 // that we can list all the assemblies in Windows and not fail
46                 // if they are missing on Linux.
47                 //
48                 List<string> soft_references;
49
50                 // 
51                 // External aliases for assemblies.
52                 //
53                 Dictionary<string, string> external_aliases;
54
55                 //
56                 // Modules to be linked
57                 //
58                 List<string> modules;
59
60                 // Lookup paths
61                 List<string> link_paths;
62
63                 // Whether we want to only run the tokenizer
64                 bool tokenize;
65                 
66                 string first_source;
67
68                 bool want_debugging_support;
69                 bool parse_only;
70                 bool timestamps;
71                 bool fatal_errors;
72                 
73                 //
74                 // Whether to load the initial config file (what CSC.RSP has by default)
75                 // 
76                 bool load_default_config = true;
77
78                 //
79                 // A list of resource files
80                 //
81                 Resources embedded_resources;
82                 string win32ResourceFile;
83                 string win32IconFile;
84
85                 //
86                 // Output file
87                 //
88                 static string output_file;
89
90                 //
91                 // Last time we took the time
92                 //
93                 DateTime last_time, first_time;
94
95                 //
96                 // Encoding.
97                 //
98                 Encoding encoding;
99
100                 readonly CompilerContext ctx;
101
102                 static readonly char[] argument_value_separator = new char [] { ';', ',' };
103
104                 static public void Reset ()
105                 {
106                         output_file = null;
107                 }
108
109                 private Driver (CompilerContext ctx)
110                 {
111                         this.ctx = ctx;
112                         encoding = Encoding.Default;
113                 }
114
115                 public static Driver Create (string[] args, bool require_files, ReportPrinter printer)
116                 {
117                         Driver d = new Driver (new CompilerContext (new Report (printer)));
118
119                         if (!d.ParseArguments (args, require_files))
120                                 return null;
121
122                         return d;
123                 }
124
125                 Report Report {
126                         get { return ctx.Report; }
127                 }
128
129                 void ShowTime (string msg)
130                 {
131                         if (!timestamps)
132                                 return;
133
134                         DateTime now = DateTime.Now;
135                         TimeSpan span = now - last_time;
136                         last_time = now;
137
138                         Console.WriteLine (
139                                 "[{0:00}:{1:000}] {2}",
140                                 (int) span.TotalSeconds, span.Milliseconds, msg);
141                 }
142
143                 void ShowTotalTime (string msg)
144                 {
145                         if (!timestamps)
146                                 return;
147
148                         DateTime now = DateTime.Now;
149                         TimeSpan span = now - first_time;
150                         last_time = now;
151
152                         Console.WriteLine (
153                                 "[{0:00}:{1:000}] {2}",
154                                 (int) span.TotalSeconds, span.Milliseconds, msg);
155                 }              
156                
157                 void tokenize_file (CompilationUnit file, CompilerContext ctx)
158                 {
159                         Stream input;
160
161                         try {
162                                 input = File.OpenRead (file.Name);
163                         } catch {
164                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
165                                 return;
166                         }
167
168                         using (input){
169                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
170                                 Tokenizer lexer = new Tokenizer (reader, file, ctx);
171                                 int token, tokens = 0, errors = 0;
172
173                                 while ((token = lexer.token ()) != Token.EOF){
174                                         tokens++;
175                                         if (token == Token.ERROR)
176                                                 errors++;
177                                 }
178                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
179                         }
180                         
181                         return;
182                 }
183
184                 void Parse (CompilationUnit file)
185                 {
186                         Stream input;
187
188                         try {
189                                 input = File.OpenRead (file.Name);
190                         } catch {
191                                 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
192                                 return;
193                         }
194
195                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
196
197                         // Check 'MZ' header
198                         if (reader.Read () == 77 && reader.Read () == 90) {
199                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
200                                 input.Close ();
201                                 return;
202                         }
203
204                         reader.Position = 0;
205                         Parse (reader, file);
206                         reader.Dispose ();
207                         input.Close ();
208                 }       
209                 
210                 void Parse (SeekableStreamReader reader, CompilationUnit file)
211                 {
212                         CSharpParser parser = new CSharpParser (reader, file, ctx);
213                         parser.parse ();
214                 }
215
216                 static void OtherFlags ()
217                 {
218                         Console.WriteLine (
219                                 "Other flags in the compiler\n" +
220                                 "   --fatal            Makes errors fatal\n" +
221                                 "   --parse            Only parses the source file\n" +
222                                 "   --typetest         Tests the tokenizer's built-in type parser\n" +
223                                 "   --stacktrace       Shows stack trace at error location\n" +
224                                 "   --timestamp        Displays time stamps of various compiler events\n" +
225                                 "   --expect-error X   Expect that error X will be encountered\n" +
226                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
227                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
228                 }
229                 
230                 static void Usage ()
231                 {
232                         Console.WriteLine (
233                                 "Mono C# compiler, Copyright 2001 - 2008 Novell, Inc.\n" +
234                                 "mcs [options] source-files\n" +
235                                 "   --about              About the Mono C# compiler\n" +
236                                 "   -addmodule:M1[,Mn]   Adds the module to the generated assembly\n" + 
237                                 "   -checked[+|-]        Sets default aritmetic overflow context\n" +
238                                 "   -codepage:ID         Sets code page to the one in ID (number, utf8, reset)\n" +
239                                 "   -clscheck[+|-]       Disables CLS Compliance verifications\n" +
240                                 "   -define:S1[;S2]      Defines one or more conditional symbols (short: -d)\n" +
241                                 "   -debug[+|-], -g      Generate debugging information\n" + 
242                                 "   -delaysign[+|-]      Only insert the public key into the assembly (no signing)\n" +
243                                 "   -doc:FILE            Process documentation comments to XML file\n" + 
244                                 "   -help                Lists all compiler options (short: -?)\n" + 
245                                 "   -keycontainer:NAME   The key pair container used to sign the output assembly\n" +
246                                 "   -keyfile:FILE        The key file used to strongname the ouput assembly\n" +
247                                 "   -langversion:TEXT    Specifies language version: ISO-1, ISO-2, Default, or Future\n" + 
248                                 "   -lib:PATH1[,PATHn]   Specifies the location of referenced assemblies\n" +
249                                 "   -main:CLASS          Specifies the class with the Main method (short: -m)\n" +
250                                 "   -noconfig            Disables implicitly referenced assemblies\n" +
251                                 "   -nostdlib[+|-]       Does not reference mscorlib.dll library\n" +
252                                 "   -nowarn:W1[,Wn]      Suppress one or more compiler warnings\n" + 
253                                 "   -optimize[+|-]       Enables advanced compiler optimizations (short: -o)\n" + 
254                                 "   -out:FILE            Specifies output assembly name\n" +
255 #if !SMCS_SOURCE
256                                 "   -pkg:P1[,Pn]         References packages P1..Pn\n" + 
257 #endif
258                                 "   -platform:ARCH       Specifies the target platform of the output assembly\n" +
259                                 "                        ARCH can be one of: anycpu, x86, x64 or itanium\n" +
260                                 "   -recurse:SPEC        Recursively compiles files according to SPEC pattern\n" + 
261                                 "   -reference:A1[,An]   Imports metadata from the specified assembly (short: -r)\n" +
262                                 "   -reference:ALIAS=A   Imports metadata using specified extern alias (short: -r)\n" +                         
263                                 "   -target:KIND         Specifies the format of the output assembly (short: -t)\n" +
264                                 "                        KIND can be one of: exe, winexe, library, module\n" +
265                                 "   -unsafe[+|-]         Allows to compile code which uses unsafe keyword\n" +
266                                 "   -warnaserror[+|-]    Treats all warnings as errors\n" +
267                                 "   -warnaserror[+|-]:W1[,Wn] Treats one or more compiler warnings as errors\n" +
268                                 "   -warn:0-4            Sets warning level, the default is 4 (short -w:)\n" +
269                                 "   -help2               Shows internal compiler options\n" + 
270                                 "\n" +
271                                 "Resources:\n" +
272                                 "   -linkresource:FILE[,ID] Links FILE as a resource (short: -linkres)\n" +
273                                 "   -resource:FILE[,ID]     Embed FILE as a resource (short: -res)\n" +
274                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
275                                 "   -win32icon:FILE         Use this icon for the output\n" +
276                                 "   @file                   Read response file for more options\n\n" +
277                                 "Options can be of the form -option or /option");
278                 }
279
280                 void TargetUsage ()
281                 {
282                         Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
283                 }
284                 
285                 static void About ()
286                 {
287                         Console.WriteLine (
288                                 "The Mono C# compiler is Copyright 2001-2008, Novell, Inc.\n\n" +
289                                 "The compiler source code is released under the terms of the \n"+
290                                 "MIT X11 or GNU GPL licenses\n\n" +
291
292                                 "For more information on Mono, visit the project Web site\n" +
293                                 "   http://www.mono-project.com\n\n" +
294
295                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
296                         Environment.Exit (0);
297                 }
298
299                 public static int Main (string[] args)
300                 {
301                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
302                         var crp = new ConsoleReportPrinter ();
303                         Driver d = Driver.Create (args, true, crp);
304                         if (d == null)
305                                 return 1;
306
307                         crp.Fatal = d.fatal_errors;
308
309                         if (d.Compile () && d.Report.Errors == 0) {
310                                 if (d.Report.Warnings > 0) {
311                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
312                                 }
313                                 Environment.Exit (0);
314                                 return 0;
315                         }
316                         
317                         
318                         Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
319                                 d.Report.Errors, d.Report.Warnings);
320                         Environment.Exit (1);
321                         return 1;
322                 }
323
324                 public void LoadAssembly (string assembly, bool soft)
325                 {
326                         LoadAssembly (assembly, null, soft);
327                 }
328
329                 void Error6 (string name, string log)
330                 {
331                         if (log != null && log.Length > 0)
332                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
333                         Report.Error (6, "cannot find metadata file `{0}'", name);
334                 }
335
336                 void Error9 (string type, string filename, string log)
337                 {
338                         if (log != null && log.Length > 0)
339                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
340                         Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
341                 }
342
343                 void BadAssembly (string filename, string log)
344                 {
345                         MethodInfo adder_method = AssemblyClass.AddModule_Method;
346
347                         if (adder_method != null) {
348                                 AssemblyName an = new AssemblyName ();
349                                 an.Name = ".temp";
350                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
351                                 try {
352                                         object m = null;
353                                         try {
354                                                 m = adder_method.Invoke (ab, new object [] { filename });
355                                         } catch (TargetInvocationException ex) {
356                                                 throw ex.InnerException;
357                                         }
358
359                                         if (m != null) {
360                                                 Report.Error (1509, "Referenced file `{0}' is not an assembly. Consider using `-addmodule' option instead",
361                                                               Path.GetFileName (filename));
362                                                 return;
363                                         }
364                                 } catch (FileNotFoundException) {
365                                         // did the file get deleted during compilation? who cares? swallow the exception
366                                 } catch (BadImageFormatException) {
367                                         // swallow exception
368                                 } catch (FileLoadException) {
369                                         // swallow exception
370                                 }
371                         }
372                         Error9 ("assembly", filename, log);
373                 }
374
375                 public void LoadAssembly (string assembly, string alias, bool soft)
376                 {
377                         Assembly a = null;
378                         string total_log = "";
379
380                         try {
381                                 try {
382                                         char[] path_chars = { '/', '\\' };
383
384                                         if (assembly.IndexOfAny (path_chars) != -1) {
385                                                 a = Assembly.LoadFrom (assembly);
386                                         } else {
387                                                 string ass = assembly;
388                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
389                                                         ass = assembly.Substring (0, assembly.Length - 4);
390                                                 a = Assembly.Load (ass);
391                                         }
392                                 } catch (FileNotFoundException) {
393                                         bool err = !soft;
394                                         foreach (string dir in link_paths) {
395                                                 string full_path = Path.Combine (dir, assembly);
396                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
397                                                         full_path += ".dll";
398
399                                                 try {
400                                                         a = Assembly.LoadFrom (full_path);
401                                                         err = false;
402                                                         break;
403                                                 } catch (FileNotFoundException ff) {
404                                                         if (soft)
405                                                                 return;
406                                                         total_log += ff.FusionLog;
407                                                 }
408                                         }
409                                         if (err) {
410                                                 Error6 (assembly, total_log);
411                                                 return;
412                                         }
413                                 }
414
415                                 // Extern aliased refs require special handling
416                                 if (alias == null)
417                                         GlobalRootNamespace.Instance.AddAssemblyReference (a);
418                                 else
419                                         GlobalRootNamespace.Instance.DefineRootNamespace (alias, a, ctx);
420
421                         } catch (BadImageFormatException f) {
422                                 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
423                                 BadAssembly (f.FileName, f.FusionLog);
424                         } catch (FileLoadException f) {
425                                 // ... while .NET 1.1 throws this
426                                 BadAssembly (f.FileName, f.FusionLog);
427                         }
428                 }
429
430                 public void LoadModule (string module)
431                 {
432                         Module m = null;
433                         string total_log = "";
434
435                         try {
436                                 try {
437                                         m = CodeGen.Assembly.AddModule (module);
438                                 } catch (FileNotFoundException) {
439                                         bool err = true;
440                                         foreach (string dir in link_paths) {
441                                                 string full_path = Path.Combine (dir, module);
442                                                 if (!module.EndsWith (".netmodule"))
443                                                         full_path += ".netmodule";
444
445                                                 try {
446                                                         m = CodeGen.Assembly.AddModule (full_path);
447                                                         err = false;
448                                                         break;
449                                                 } catch (FileNotFoundException ff) {
450                                                         total_log += ff.FusionLog;
451                                                 }
452                                         }
453                                         if (err) {
454                                                 Error6 (module, total_log);
455                                                 return;
456                                         }
457                                 }
458
459                                 GlobalRootNamespace.Instance.AddModuleReference (m);
460
461                         } catch (BadImageFormatException f) {
462                                 Error9 ("module", f.FileName, f.FusionLog);
463                         } catch (FileLoadException f) {
464                                 Error9 ("module", f.FileName, f.FusionLog);
465                         }
466                 }
467
468                 /// <summary>
469                 ///   Loads all assemblies referenced on the command line
470                 /// </summary>
471                 public void LoadReferences ()
472                 {
473                         link_paths.Add (GetSystemDir ());
474                         link_paths.Add (Directory.GetCurrentDirectory ());
475
476                         //
477                         // Load Core Library for default compilation
478                         //
479                         if (RootContext.StdLib)
480                                 LoadAssembly ("mscorlib", false);
481
482                         foreach (string r in soft_references)
483                                 LoadAssembly (r, true);
484
485                         foreach (string r in references)
486                                 LoadAssembly (r, false);
487
488                         foreach (var entry in external_aliases)
489                                 LoadAssembly (entry.Value, entry.Key, false);
490                                 
491                         GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
492                 }
493
494                 static string [] LoadArgs (string file)
495                 {
496                         StreamReader f;
497                         var args = new List<string> ();
498                         string line;
499                         try {
500                                 f = new StreamReader (file);
501                         } catch {
502                                 return null;
503                         }
504
505                         StringBuilder sb = new StringBuilder ();
506                         
507                         while ((line = f.ReadLine ()) != null){
508                                 int t = line.Length;
509
510                                 for (int i = 0; i < t; i++){
511                                         char c = line [i];
512                                         
513                                         if (c == '"' || c == '\''){
514                                                 char end = c;
515                                                 
516                                                 for (i++; i < t; i++){
517                                                         c = line [i];
518
519                                                         if (c == end)
520                                                                 break;
521                                                         sb.Append (c);
522                                                 }
523                                         } else if (c == ' '){
524                                                 if (sb.Length > 0){
525                                                         args.Add (sb.ToString ());
526                                                         sb.Length = 0;
527                                                 }
528                                         } else
529                                                 sb.Append (c);
530                                 }
531                                 if (sb.Length > 0){
532                                         args.Add (sb.ToString ());
533                                         sb.Length = 0;
534                                 }
535                         }
536
537                         return args.ToArray ();
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 (Report, f);
586                 }
587
588                 bool ParseArguments (string[] args, bool require_files)
589                 {
590                         references = new List<string> ();
591                         external_aliases = new Dictionary<string, string> ();
592                         soft_references = new List<string> ();
593                         modules = new List<string> (2);
594                         link_paths = new List<string> ();
595
596                         List<string> 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 List<string> ();
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                         var cu = Location.SourceFiles;
694                         for (int i = 0; i < cu.Count; ++i) {
695                                 if (tokenize) {
696                                         tokenize_file (cu [i], ctx);
697                                 } else {
698                                         Parse (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                 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.Printer.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 (ctx);
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 (ctx);
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                                 fatal_errors = 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, Report report)
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                                         string conditional = d.Trim ();
1194                                         if (!Tokenizer.IsValidIdentifier (conditional)) {
1195                                                 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", conditional);
1196                                                 continue;
1197                                         }
1198                                         RootContext.AddConditional (conditional);
1199                                 }
1200                                 return true;
1201                         }
1202
1203                         case "/bugreport":
1204                                 //
1205                                 // We should collect data, runtime, etc and store in the file specified
1206                                 //
1207                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1208                                 return true;
1209 #if !SMCS_SOURCE
1210                         case "/pkg": {
1211                                 string packages;
1212
1213                                 if (value.Length == 0){
1214                                         Usage ();
1215                                         Environment.Exit (1);
1216                                 }
1217                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1218                                 string pkgout = GetPackageFlags (packages, true, Report);
1219                                 
1220                                 if (pkgout != null){
1221                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1222                                                 Split (new Char [] { ' ', '\t'});
1223                                         args = AddArgs (args, xargs);
1224                                 }
1225                                 
1226                                 return true;
1227                         }
1228 #endif
1229                         case "/linkres":
1230                         case "/linkresource":
1231                         case "/res":
1232                         case "/resource":
1233                                 if (embedded_resources == null)
1234                                         embedded_resources = new Resources (ctx);
1235
1236                                 bool embeded = arg [1] == 'r' || arg [1] == 'R';
1237                                 string[] s = value.Split (argument_value_separator);
1238                                 switch (s.Length) {
1239                                 case 1:
1240                                         if (s[0].Length == 0)
1241                                                 goto default;
1242                                         embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1243                                         break;
1244                                 case 2:
1245                                         embedded_resources.Add (embeded, s [0], s [1]);
1246                                         break;
1247                                 case 3:
1248                                         if (s [2] != "public" && s [2] != "private") {
1249                                                 Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1250                                                 return true;
1251                                         }
1252                                         embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1253                                         break;
1254                                 default:
1255                                         Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1256                                         break;
1257                                 }
1258
1259                                 return true;
1260                                 
1261                         case "/recurse":
1262                                 if (value.Length == 0){
1263                                         Report.Error (5, "-recurse requires an argument");
1264                                         Environment.Exit (1);
1265                                 }
1266                                 ProcessSourceFiles (value, true); 
1267                                 return true;
1268
1269                         case "/r":
1270                         case "/reference": {
1271                                 if (value.Length == 0){
1272                                         Report.Error (5, "-reference requires an argument");
1273                                         Environment.Exit (1);
1274                                 }
1275
1276                                 string[] refs = value.Split (argument_value_separator);
1277                                 foreach (string r in refs){
1278                                         string val = r;
1279                                         int index = val.IndexOf ('=');
1280                                         if (index > -1) {
1281                                                 string alias = r.Substring (0, index);
1282                                                 string assembly = r.Substring (index + 1);
1283                                                 AddExternAlias (alias, assembly);
1284                                                 return true;
1285                                         }
1286
1287                                         if (val.Length != 0)
1288                                                 references.Add (val);
1289                                 }
1290                                 return true;
1291                         }
1292                         case "/addmodule": {
1293                                 if (value.Length == 0){
1294                                         Report.Error (5, arg + " requires an argument");
1295                                         Environment.Exit (1);
1296                                 }
1297
1298                                 string[] refs = value.Split (argument_value_separator);
1299                                 foreach (string r in refs){
1300                                         modules.Add (r);
1301                                 }
1302                                 return true;
1303                         }
1304                         case "/win32res": {
1305                                 if (value.Length == 0) {
1306                                         Report.Error (5, arg + " requires an argument");
1307                                         Environment.Exit (1);
1308                                 }
1309                                 
1310                                 if (win32IconFile != null)
1311                                         Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1312
1313                                 win32ResourceFile = value;
1314                                 return true;
1315                         }
1316                         case "/win32icon": {
1317                                 if (value.Length == 0) {
1318                                         Report.Error (5, arg + " requires an argument");
1319                                         Environment.Exit (1);
1320                                 }
1321
1322                                 if (win32ResourceFile != null)
1323                                         Report.Error (1565, "Cannot specify the `win32res' and the `win32ico' compiler option at the same time");
1324
1325                                 win32IconFile = value;
1326                                 return true;
1327                         }
1328                         case "/doc": {
1329                                 if (value.Length == 0){
1330                                         Report.Error (2006, arg + " requires an argument");
1331                                         Environment.Exit (1);
1332                                 }
1333                                 RootContext.Documentation = new Documentation (value);
1334                                 return true;
1335                         }
1336                         case "/lib": {
1337                                 string [] libdirs;
1338                                 
1339                                 if (value.Length == 0){
1340                                         Report.Error (5, "/lib requires an argument");
1341                                         Environment.Exit (1);
1342                                 }
1343
1344                                 libdirs = value.Split (argument_value_separator);
1345                                 foreach (string dir in libdirs)
1346                                         link_paths.Add (dir);
1347                                 return true;
1348                         }
1349
1350                         case "/debug-":
1351                                 want_debugging_support = false;
1352                                 return true;
1353                                 
1354                         case "/debug":
1355                                 if (value == "full" || value == "")
1356                                         want_debugging_support = true;
1357
1358                                 return true;
1359                                 
1360                         case "/debug+":
1361                                 want_debugging_support = true;
1362                                 return true;
1363
1364                         case "/checked":
1365                         case "/checked+":
1366                                 RootContext.Checked = true;
1367                                 return true;
1368
1369                         case "/checked-":
1370                                 RootContext.Checked = false;
1371                                 return true;
1372
1373                         case "/clscheck":
1374                         case "/clscheck+":
1375                                 return true;
1376
1377                         case "/clscheck-":
1378                                 RootContext.VerifyClsCompliance = false;
1379                                 return true;
1380
1381                         case "/unsafe":
1382                         case "/unsafe+":
1383                                 RootContext.Unsafe = true;
1384                                 return true;
1385
1386                         case "/unsafe-":
1387                                 RootContext.Unsafe = false;
1388                                 return true;
1389
1390                         case "/warnaserror":
1391                         case "/warnaserror+":
1392                                 if (value.Length == 0) {
1393                                         Report.WarningsAreErrors = true;
1394                                 } else {
1395                                         foreach (string wid in value.Split (argument_value_separator))
1396                                                 Report.AddWarningAsError (wid);
1397                                 }
1398                                 return true;
1399
1400                         case "/warnaserror-":
1401                                 if (value.Length == 0) {
1402                                         Report.WarningsAreErrors = false;
1403                                 } else {
1404                                         foreach (string wid in value.Split (argument_value_separator))
1405                                                 Report.RemoveWarningAsError (wid);
1406                                 }
1407                                 return true;
1408
1409                         case "/warn":
1410                                 SetWarningLevel (value);
1411                                 return true;
1412
1413                         case "/nowarn": {
1414                                 string [] warns;
1415
1416                                 if (value.Length == 0){
1417                                         Report.Error (5, "/nowarn requires an argument");
1418                                         Environment.Exit (1);
1419                                 }
1420
1421                                 warns = value.Split (argument_value_separator);
1422                                 foreach (string wc in warns){
1423                                         try {
1424                                                 if (wc.Trim ().Length == 0)
1425                                                         continue;
1426
1427                                                 int warn = Int32.Parse (wc);
1428                                                 if (warn < 1) {
1429                                                         throw new ArgumentOutOfRangeException("warn");
1430                                                 }
1431                                                 Report.SetIgnoreWarning (warn);
1432                                         } catch {
1433                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1434                                         }
1435                                 }
1436                                 return true;
1437                         }
1438
1439                         case "/noconfig":
1440                                 load_default_config = false;
1441                                 return true;
1442
1443                         case "/platform":
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
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                                 case "default":
1528                                         RootContext.Version = LanguageVersion.Default;
1529                                         RootContext.AddConditional ("__V2__");
1530                                         return true;
1531                                 case "iso-2":
1532                                         RootContext.Version = LanguageVersion.ISO_2;
1533                                         return true;
1534                                 case "3":
1535                                         RootContext.Version = LanguageVersion.V_3;
1536                                         return true;
1537                                 case "future":
1538                                         RootContext.Version = LanguageVersion.Future;
1539                                         return true;
1540                                 }
1541
1542                                 Report.Error (1617, "Invalid -langversion option `{0}'. It must be `ISO-1', `ISO-2', `3' or `Default'", value);
1543                                 return true;
1544
1545                         case "/codepage":
1546                                 switch (value) {
1547                                 case "utf8":
1548                                         encoding = new UTF8Encoding();
1549                                         break;
1550                                 case "reset":
1551                                         encoding = Encoding.Default;
1552                                         break;
1553                                 default:
1554                                         try {
1555                                                 encoding = Encoding.GetEncoding (
1556                                                 Int32.Parse (value));
1557                                         } catch {
1558                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1559                                         }
1560                                         break;
1561                                 }
1562                                 return true;
1563                         }
1564
1565                         return false;
1566                 }
1567
1568                 void Error_WrongOption (string option)
1569                 {
1570                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1571                 }
1572
1573                 static string [] AddArgs (string [] args, string [] extra_args)
1574                 {
1575                         string [] new_args;
1576                         new_args = new string [extra_args.Length + args.Length];
1577
1578                         // if args contains '--' we have to take that into account
1579                         // split args into first half and second half based on '--'
1580                         // and add the extra_args before --
1581                         int split_position = Array.IndexOf (args, "--");
1582                         if (split_position != -1)
1583                         {
1584                                 Array.Copy (args, new_args, split_position);
1585                                 extra_args.CopyTo (new_args, split_position);
1586                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1587                         }
1588                         else
1589                         {
1590                                 args.CopyTo (new_args, 0);
1591                                 extra_args.CopyTo (new_args, args.Length);
1592                         }
1593
1594                         return new_args;
1595                 }
1596
1597                 void AddExternAlias (string identifier, string assembly)
1598                 {
1599                         if (assembly.Length == 0) {
1600                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1601                                 return;
1602                         }
1603
1604                         if (!IsExternAliasValid (identifier)) {
1605                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1606                                 return;
1607                         }
1608                         
1609                         // Could here hashtable throw an exception?
1610                         external_aliases [identifier] = assembly;
1611                 }
1612                 
1613                 static bool IsExternAliasValid (string identifier)
1614                 {
1615                         if (identifier.Length == 0)
1616                                 return false;
1617                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1618                                 return false;
1619
1620                         for (int i = 1; i < identifier.Length; i++) {
1621                                 char c = identifier [i];
1622                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1623                                         continue;
1624
1625                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1626                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1627                                                 category != UnicodeCategory.SpacingCombiningMark ||
1628                                                 category != UnicodeCategory.ConnectorPunctuation)
1629                                         return false;
1630                         }
1631                         
1632                         return true;
1633                 }
1634
1635                 //
1636                 // Main compilation method
1637                 //
1638                 public bool Compile ()
1639                 {
1640                         // TODO: Should be passed to parser as an argument
1641                         RootContext.ToplevelTypes = new ModuleCompiled (ctx, RootContext.Unsafe);
1642
1643                         Parse ();
1644                         if (Report.Errors > 0)
1645                                 return false;
1646
1647                         if (tokenize || parse_only)
1648                                 return true;
1649
1650                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1651                                 throw new InternalErrorException ("who set it?");
1652
1653                         ProcessDefaultConfig ();
1654
1655                         //
1656                         // Quick hack
1657                         //
1658                         if (output_file == null){
1659                                 if (first_source == null){
1660                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1661                                         return false;
1662                                 }
1663                                         
1664                                 int pos = first_source.LastIndexOf ('.');
1665
1666                                 if (pos > 0)
1667                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1668                                 else
1669                                         output_file = first_source + RootContext.TargetExt;
1670                         }
1671
1672                         if (!CodeGen.Init (output_file, output_file, want_debugging_support, ctx))
1673                                 return false;
1674
1675                         if (RootContext.Target == Target.Module) {
1676                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1677                                 if (module_only == null) {
1678                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1679                                         Environment.Exit (1);
1680                                 }
1681
1682                                 MethodInfo set_method = module_only.GetSetMethod (true);
1683                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1684                         }
1685
1686                         GlobalRootNamespace.Instance.AddModuleReference (RootContext.ToplevelTypes.Builder);
1687
1688                         //
1689                         // Load assemblies required
1690                         //
1691                         if (timestamps)
1692                                 ShowTime ("Loading references");
1693
1694                         LoadReferences ();
1695                         
1696                         if (modules.Count > 0) {
1697                                 foreach (string module in modules)
1698                                         LoadModule (module);
1699                         }
1700                         
1701                         if (timestamps)
1702                                 ShowTime ("References loaded");
1703                         
1704                         if (!TypeManager.InitCoreTypes (ctx) || Report.Errors > 0)
1705                                 return false;
1706
1707                         TypeManager.InitOptionalCoreTypes (ctx);
1708
1709                         if (timestamps)
1710                                 ShowTime ("   Core Types done");
1711
1712                         //
1713                         // The second pass of the compiler
1714                         //
1715                         if (timestamps)
1716                                 ShowTime ("Resolving tree");
1717                         RootContext.ResolveTree ();
1718
1719                         if (Report.Errors > 0)
1720                                 return false;
1721                         if (timestamps)
1722                                 ShowTime ("Populate tree");
1723                         if (!RootContext.StdLib)
1724                                 RootContext.BootCorlib_PopulateCoreTypes ();
1725                         RootContext.PopulateTypes ();
1726
1727                         if (Report.Errors == 0 &&
1728                                 RootContext.Documentation != null &&
1729                                 !RootContext.Documentation.OutputDocComment (
1730                                         output_file, Report))
1731                                 return false;
1732
1733                         //
1734                         // Verify using aliases now
1735                         //
1736                         NamespaceEntry.VerifyAllUsing ();
1737                         
1738                         if (Report.Errors > 0){
1739                                 return false;
1740                         }
1741
1742                         CodeGen.Assembly.Resolve ();
1743                         
1744                         if (RootContext.VerifyClsCompliance) {
1745                                 if (CodeGen.Assembly.IsClsCompliant) {
1746                                         AttributeTester.VerifyModulesClsCompliance (ctx);
1747                                         TypeManager.LoadAllImportedTypes ();
1748                                 }
1749                         }
1750                         if (Report.Errors > 0)
1751                                 return false;
1752                         
1753                         //
1754                         // The code generator
1755                         //
1756                         if (timestamps)
1757                                 ShowTime ("Emitting code");
1758                         ShowTotalTime ("Total so far");
1759                         RootContext.EmitCode ();
1760                         if (timestamps)
1761                                 ShowTime ("   done");
1762
1763                         if (Report.Errors > 0){
1764                                 return false;
1765                         }
1766
1767                         if (timestamps)
1768                                 ShowTime ("Closing types");
1769
1770                         RootContext.CloseTypes ();
1771
1772                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1773
1774                         switch (RootContext.Target) {
1775                         case Target.Library:
1776                         case Target.Module:
1777                                 k = PEFileKinds.Dll; break;
1778                         case Target.Exe:
1779                                 k = PEFileKinds.ConsoleApplication; break;
1780                         case Target.WinExe:
1781                                 k = PEFileKinds.WindowApplication; break;
1782                         }
1783
1784                         if (RootContext.NeedsEntryPoint) {
1785                                 Method ep = RootContext.EntryPoint;
1786
1787                                 if (ep == null) {
1788                                         if (RootContext.MainClass != null) {
1789                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1790                                                 if (main_cont == null) {
1791                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1792                                                         return false;
1793                                                 }
1794
1795                                                 if (!(main_cont is ClassOrStruct)) {
1796                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1797                                                         return false;
1798                                                 }
1799
1800                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1801                                                 return false;
1802                                         }
1803
1804                                         if (Report.Errors == 0)
1805                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1806                                                         output_file);
1807                                         return false;
1808                                 }
1809
1810                                 CodeGen.Assembly.Builder.SetEntryPoint (ep.MethodBuilder, k);
1811                         } else if (RootContext.MainClass != null) {
1812                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1813                         }
1814
1815                         if (embedded_resources != null){
1816                                 if (RootContext.Target == Target.Module) {
1817                                         Report.Error (1507, "Cannot link resource file when building a module");
1818                                         return false;
1819                                 }
1820
1821                                 embedded_resources.Emit ();
1822                         }
1823
1824                         //
1825                         // Add Win32 resources
1826                         //
1827
1828                         if (win32ResourceFile != null) {
1829                                 try {
1830                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1831                                 } catch (ArgumentException) {
1832                                         Report.RuntimeMissingSupport (Location.Null, "resource embedding ");
1833                                 }
1834                         } else {
1835                                 CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1836                         }
1837
1838                         if (win32IconFile != null) {
1839                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1840                                 if (define_icon == null) {
1841                                         Report.RuntimeMissingSupport (Location.Null, "resource embedding");
1842                                 } else {
1843                                         define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1844                                 }
1845                         }
1846
1847                         if (Report.Errors > 0)
1848                                 return false;
1849                         
1850                         CodeGen.Save (output_file, want_debugging_support, Report);
1851                         if (timestamps) {
1852                                 ShowTime ("Saved output");
1853                                 ShowTotalTime ("Total");
1854                         }
1855
1856                         Timer.ShowTimers ();
1857
1858 #if DEBUGME
1859                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1860                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1861 #endif
1862                         return (Report.Errors == 0);
1863                 }
1864         }
1865
1866         class Resources
1867         {
1868                 interface IResource
1869                 {
1870                         void Emit (CompilerContext cc);
1871                         string FileName { get; }
1872                 }
1873
1874                 class EmbededResource : IResource
1875                 {
1876                         static MethodInfo embed_res;
1877                         readonly object[] args;
1878
1879                         public EmbededResource (string name, string file, bool isPrivate)
1880                         {
1881                                 args = new object [3];
1882                                 args [0] = name;
1883                                 args [1] = file;
1884                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1885                         }
1886
1887                         public void Emit (CompilerContext cc)
1888                         {
1889                                 if (embed_res == null) {
1890                                         var argst = new [] {
1891                                                 typeof (string), typeof (string), typeof (ResourceAttributes)
1892                                         };
1893
1894                                         embed_res = typeof (AssemblyBuilder).GetMethod (
1895                                                 "EmbedResourceFile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1896                                                 null, CallingConventions.Any, argst, null);
1897
1898                                         if (embed_res == null) {
1899                                                 cc.Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1900                                         }
1901                                 }
1902
1903                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1904                         }
1905
1906                         public string FileName {
1907                                 get {
1908                                         return (string)args [1];
1909                                 }
1910                         }
1911                 }
1912
1913                 class LinkedResource : IResource
1914                 {
1915                         readonly string file;
1916                         readonly string name;
1917                         readonly ResourceAttributes attribute;
1918
1919                         public LinkedResource (string name, string file, bool isPrivate)
1920                         {
1921                                 this.name = name;
1922                                 this.file = file;
1923                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1924                         }
1925
1926                         public void Emit (CompilerContext cc)
1927                         {
1928                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1929                         }
1930
1931                         public string FileName {
1932                                 get {
1933                                         return file;
1934                                 }
1935                         }
1936                 }
1937
1938
1939                 Dictionary<string, IResource> embedded_resources = new Dictionary<string, IResource> ();
1940                 readonly CompilerContext ctx;
1941
1942                 public Resources (CompilerContext ctx)
1943                 {
1944                         this.ctx = ctx;
1945                 }
1946
1947                 public void Add (bool embeded, string file, string name)
1948                 {
1949                         Add (embeded, file, name, false);
1950                 }
1951
1952                 public void Add (bool embeded, string file, string name, bool isPrivate)
1953                 {
1954                         if (embedded_resources.ContainsKey (name)) {
1955                                 ctx.Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1956                                 return;
1957                         }
1958                         IResource r = embeded ? 
1959                                 (IResource) new EmbededResource (name, file, isPrivate) : 
1960                                 new LinkedResource (name, file, isPrivate);
1961
1962                         embedded_resources.Add (name, r);
1963                 }
1964
1965                 public void Emit ()
1966                 {
1967                         foreach (IResource r in embedded_resources.Values) {
1968                                 if (!File.Exists (r.FileName)) {
1969                                         ctx.Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
1970                                         continue;
1971                                 }
1972                                 
1973                                 r.Emit (ctx);
1974                         }
1975                 }
1976         }
1977
1978         //
1979         // This is the only public entry point
1980         //
1981         public class CompilerCallableEntryPoint : MarshalByRefObject {
1982                 public static bool InvokeCompiler (string [] args, TextWriter error)
1983                 {
1984                         try {
1985                                 StreamReportPrinter srp = new StreamReportPrinter (error);
1986                                 Driver d = Driver.Create (args, true, srp);
1987                                 if (d == null)
1988                                         return false;
1989
1990                                 return d.Compile () && srp.ErrorsCount == 0;
1991                         } finally {
1992                                 Reset ();
1993                         }
1994                 }
1995
1996                 public static int[] AllWarningNumbers {
1997                         get {
1998                                 return Report.AllWarnings;
1999                         }
2000                 }
2001
2002                 public static void Reset ()
2003                 {
2004                         Reset (true);
2005                 }
2006
2007                 public static void PartialReset ()
2008                 {
2009                         Reset (false);
2010                 }
2011                 
2012                 public static void Reset (bool full_flag)
2013                 {
2014                         Driver.Reset ();
2015                         CSharpParser.yacc_verbose_flag = 0;
2016                         RootContext.Reset (full_flag);
2017                         Location.Reset ();
2018                         TypeManager.Reset ();
2019                         PredefinedAttributes.Reset ();
2020                         TypeHandle.Reset ();
2021
2022                         if (full_flag)
2023                                 GlobalRootNamespace.Reset ();
2024                         
2025                         NamespaceEntry.Reset ();
2026                         CodeGen.Reset ();
2027                         Attribute.Reset ();
2028                         AttributeTester.Reset ();
2029                         AnonymousTypeClass.Reset ();
2030                         AnonymousMethodBody.Reset ();
2031                         AnonymousMethodStorey.Reset ();
2032                         SymbolWriter.Reset ();
2033                         Switch.Reset ();
2034                         Linq.QueryBlock.TransparentParameter.Reset ();
2035                         Convert.Reset ();
2036                         TypeInfo.Reset ();
2037                         DynamicExpressionStatement.Reset ();
2038                 }
2039         }
2040 }