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