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