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