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