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