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