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