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