2007-04-01 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                         //
462                         // Load Core Library for default compilation
463                         //
464                         if (RootContext.StdLib)
465                                 LoadAssembly ("mscorlib", false);
466
467                         foreach (string r in soft_references)
468                                 LoadAssembly (r, true);
469
470                         foreach (string r in references)
471                                 LoadAssembly (r, false);
472
473                         foreach (DictionaryEntry entry in external_aliases)
474                                 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
475                         
476                         return;
477                 }
478
479                 static void SetupDefaultDefines ()
480                 {
481                         defines = new ArrayList ();
482                         defines.Add ("__MonoCS__");
483                 }
484
485                 static string [] LoadArgs (string file)
486                 {
487                         StreamReader f;
488                         ArrayList args = new ArrayList ();
489                         string line;
490                         try {
491                                 f = new StreamReader (file);
492                         } catch {
493                                 return null;
494                         }
495
496                         StringBuilder sb = new StringBuilder ();
497                         
498                         while ((line = f.ReadLine ()) != null){
499                                 int t = line.Length;
500
501                                 for (int i = 0; i < t; i++){
502                                         char c = line [i];
503                                         
504                                         if (c == '"' || c == '\''){
505                                                 char end = c;
506                                                 
507                                                 for (i++; i < t; i++){
508                                                         c = line [i];
509
510                                                         if (c == end)
511                                                                 break;
512                                                         sb.Append (c);
513                                                 }
514                                         } else if (c == ' '){
515                                                 if (sb.Length > 0){
516                                                         args.Add (sb.ToString ());
517                                                         sb.Length = 0;
518                                                 }
519                                         } else
520                                                 sb.Append (c);
521                                 }
522                                 if (sb.Length > 0){
523                                         args.Add (sb.ToString ());
524                                         sb.Length = 0;
525                                 }
526                         }
527
528                         string [] ret_value = new string [args.Count];
529                         args.CopyTo (ret_value, 0);
530
531                         return ret_value;
532                 }
533
534                 //
535                 // Returns the directory where the system assemblies are installed
536                 //
537                 static string GetSystemDir ()
538                 {
539                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
540                 }
541
542                 //
543                 // Given a path specification, splits the path from the file/pattern
544                 //
545                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
546                 {
547                         int p = spec.LastIndexOf ('/');
548                         if (p != -1){
549                                 //
550                                 // Windows does not like /file.cs, switch that to:
551                                 // "\", "file.cs"
552                                 //
553                                 if (p == 0){
554                                         path = "\\";
555                                         pattern = spec.Substring (1);
556                                 } else {
557                                         path = spec.Substring (0, p);
558                                         pattern = spec.Substring (p + 1);
559                                 }
560                                 return;
561                         }
562
563                         p = spec.LastIndexOf ('\\');
564                         if (p != -1){
565                                 path = spec.Substring (0, p);
566                                 pattern = spec.Substring (p + 1);
567                                 return;
568                         }
569
570                         path = ".";
571                         pattern = spec;
572                 }
573
574                 static void ProcessFile (string f)
575                 {
576                         if (first_source == null)
577                                 first_source = f;
578
579                         Location.AddFile (f);
580                 }
581
582                 static void ProcessFiles ()
583                 {
584                         Location.Initialize ();
585
586                         foreach (SourceFile file in Location.SourceFiles) {
587                                 if (tokenize) {
588                                         tokenize_file (file);
589                                 } else {
590                                         parse (file);
591                                 }
592                         }
593                 }
594
595                 static void CompileFiles (string spec, bool recurse)
596                 {
597                         string path, pattern;
598
599                         SplitPathAndPattern (spec, out path, out pattern);
600                         if (pattern.IndexOf ('*') == -1){
601                                 ProcessFile (spec);
602                                 return;
603                         }
604
605                         string [] files = null;
606                         try {
607                                 files = Directory.GetFiles (path, pattern);
608                         } catch (System.IO.DirectoryNotFoundException) {
609                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
610                                 return;
611                         } catch (System.IO.IOException){
612                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
613                                 return;
614                         }
615                         foreach (string f in files) {
616                                 ProcessFile (f);
617                         }
618
619                         if (!recurse)
620                                 return;
621                         
622                         string [] dirs = null;
623
624                         try {
625                                 dirs = Directory.GetDirectories (path);
626                         } catch {
627                         }
628                         
629                         foreach (string d in dirs) {
630                                         
631                                 // Don't include path in this string, as each
632                                 // directory entry already does
633                                 CompileFiles (d + "/" + pattern, true);
634                         }
635                 }
636
637                 static void DefineDefaultConfig ()
638                 {
639                         //
640                         // For now the "default config" is harcoded into the compiler
641                         // we can move this outside later
642                         //
643                         string [] default_config = {
644                                 "System",
645                                 "System.Xml"
646 #if false
647                                 //
648                                 // Is it worth pre-loading all this stuff?
649                                 //
650                                 "Accessibility",
651                                 "System.Configuration.Install",
652                                 "System.Data",
653                                 "System.Design",
654                                 "System.DirectoryServices",
655                                 "System.Drawing.Design",
656                                 "System.Drawing",
657                                 "System.EnterpriseServices",
658                                 "System.Management",
659                                 "System.Messaging",
660                                 "System.Runtime.Remoting",
661                                 "System.Runtime.Serialization.Formatters.Soap",
662                                 "System.Security",
663                                 "System.ServiceProcess",
664                                 "System.Web",
665                                 "System.Web.RegularExpressions",
666                                 "System.Web.Services",
667                                 "System.Windows.Forms"
668 #endif
669                         };
670                         
671                         if (RootContext.Version == LanguageVersion.LINQ)
672                                 soft_references.Add ("System.Core");
673
674                         soft_references.AddRange (default_config);
675                 }
676
677                 public static string OutputFile
678                 {
679                         set {
680                                 output_file = value;
681                         }
682                         get {
683                                 return Path.GetFileName (output_file);
684                         }
685                 }
686
687                 static void SetWarningLevel (string s)
688                 {
689                         int level = -1;
690
691                         try {
692                                 level = Int32.Parse (s);
693                         } catch {
694                         }
695                         if (level < 0 || level > 4){
696                                 Report.Error (1900, "Warning level must be in the range 0-4");
697                                 return;
698                         }
699                         RootContext.WarningLevel = level;
700                 }
701
702                 static void SetupV2 ()
703                 {
704                         RootContext.Version = LanguageVersion.Default;
705                         defines.Add ("__V2__");
706                 }
707                 
708                 static void Version ()
709                 {
710                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
711                         Console.WriteLine ("Mono C# compiler version {0}", version);
712                         Environment.Exit (0);
713                 }
714
715                 //
716                 // This is to test the tokenizer internal parser that is used to deambiguate
717                 // '(' type identifier from '(' type others so that we are able to parse
718                 // without introducing reduce/reduce conflicts in the grammar.
719                 // 
720                 static void LambdaTypeParseTest (string fname)
721                 {
722                         bool fail = false;
723
724                         using (FileStream fs = File.OpenRead (fname)){
725                                 StreamReader r = new StreamReader (fs, encoding);
726                                 string line;
727                                 
728                                 while ((line = r.ReadLine ())!= null){
729                                         if (line [0] == '!')
730                                                 continue;
731                                         bool must_pass = line [0] == '+';
732                                         StringReader test = new StringReader (line.Substring (1));
733                                         SeekableStreamReader reader = new SeekableStreamReader (test);
734                                         SourceFile file = new SourceFile (fname, fname, 0);
735                                         
736                                         Tokenizer lexer = new Tokenizer (reader, file, defines);
737                                         bool res = lexer.parse_lambda_parameters ();
738                                         
739                                         Console.WriteLine ("{3} ({1}=={2}): {0}", line.Substring (1), res, must_pass, res == must_pass);
740                                         if (res != must_pass)
741                                                 fail = true;
742                                 }
743                         }
744                         Console.WriteLine ("fail={0}", fail);
745                         Environment.Exit (fail ? 1 : 0);
746                 }
747                 
748                 //
749                 // Currently handles the Unix-like command line options, but will be
750                 // deprecated in favor of the CSCParseOption, which will also handle the
751                 // options that start with a dash in the future.
752                 //
753                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
754                 {
755                         switch (arg){
756                         case "-v":
757                                 CSharpParser.yacc_verbose_flag++;
758                                 return true;
759
760                         case "--version":
761                                 Version ();
762                                 return true;
763                                 
764                         case "--parse":
765                                 parse_only = true;
766                                 return true;
767                                 
768                         case "--main": case "-m":
769                                 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
770                                 if ((i + 1) >= args.Length){
771                                         Usage ();
772                                         Environment.Exit (1);
773                                 }
774                                 RootContext.MainClass = args [++i];
775                                 return true;
776                                 
777                         case "--unsafe":
778                                 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
779                                 RootContext.Unsafe = true;
780                                 return true;
781                                 
782                         case "/?": case "/h": case "/help":
783                         case "--help":
784                                 Usage ();
785                                 Environment.Exit (0);
786                                 return true;
787
788                         case "--define":
789                                 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
790                                 if ((i + 1) >= args.Length){
791                                         Usage ();
792                                         Environment.Exit (1);
793                                 }
794                                 defines.Add (args [++i]);
795                                 return true;
796
797                         case "--show-counters":
798                                 show_counters = true;
799                                 return true;
800                                 
801                         case "--expect-error": {
802                                 int code = 0;
803                                 
804                                 try {
805                                         code = Int32.Parse (
806                                                 args [++i], NumberStyles.AllowLeadingSign);
807                                         Report.ExpectedError = code;
808                                 } catch {
809                                         Report.Error (-14, "Invalid number specified");
810                                 } 
811                                 return true;
812                         }
813                                 
814                         case "--tokenize": 
815                                 tokenize = true;
816                                 return true;
817                                 
818                         case "-o": 
819                         case "--output":
820                                 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
821                                 if ((i + 1) >= args.Length){
822                                         Usage ();
823                                         Environment.Exit (1);
824                                 }
825                                 OutputFile = args [++i];
826                                 return true;
827
828                         case "--checked":
829                                 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
830                                 RootContext.Checked = true;
831                                 return true;
832                                 
833                         case "--stacktrace":
834                                 Report.Stacktrace = true;
835                                 return true;
836                                 
837                         case "--linkresource":
838                         case "--linkres":
839                                 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
840                                 if ((i + 1) >= args.Length){
841                                         Usage ();
842                                         Report.Error (5, "Missing argument to --linkres"); 
843                                         Environment.Exit (1);
844                                 }
845                                 if (embedded_resources == null)
846                                         embedded_resources = new Resources ();
847                                 
848                                 embedded_resources.Add (false, args [++i], args [i]);
849                                 return true;
850                                 
851                         case "--resource":
852                         case "--res":
853                                 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
854                                 if ((i + 1) >= args.Length){
855                                         Usage ();
856                                         Report.Error (5, "Missing argument to --resource"); 
857                                         Environment.Exit (1);
858                                 }
859                                 if (embedded_resources == null)
860                                         embedded_resources = new Resources ();
861                                 
862                                 embedded_resources.Add (true, args [++i], args [i]);
863                                 return true;
864                                 
865                         case "--target":
866                                 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
867                                 if ((i + 1) >= args.Length){
868                                         Environment.Exit (1);
869                                         return true;
870                                 }
871                                 
872                                 string type = args [++i];
873                                 switch (type){
874                                 case "library":
875                                         RootContext.Target = Target.Library;
876                                         RootContext.TargetExt = ".dll";
877                                         break;
878                                         
879                                 case "exe":
880                                         RootContext.Target = Target.Exe;
881                                         break;
882                                         
883                                 case "winexe":
884                                         RootContext.Target = Target.WinExe;
885                                         break;
886                                         
887                                 case "module":
888                                         RootContext.Target = Target.Module;
889                                         RootContext.TargetExt = ".dll";
890                                         break;
891                                 default:
892                                         TargetUsage ();
893                                         break;
894                                 }
895                                 return true;
896                                 
897                         case "-r":
898                                 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
899                                 if ((i + 1) >= args.Length){
900                                         Usage ();
901                                         Environment.Exit (1);
902                                 }
903                                 
904                                 string val = args [++i];
905                                 int idx = val.IndexOf ('=');
906                                 if (idx > -1) {
907                                         string alias = val.Substring (0, idx);
908                                         string assembly = val.Substring (idx + 1);
909                                         AddExternAlias (alias, assembly);
910                                         return true;
911                                 }
912
913                                 references.Add (val);
914                                 return true;
915                                 
916                         case "-L":
917                                 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
918                                 if ((i + 1) >= args.Length){
919                                         Usage ();       
920                                         Environment.Exit (1);
921                                 }
922                                 link_paths.Add (args [++i]);
923                                 return true;
924                                 
925                         case "--nostdlib":
926                                 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
927                                 RootContext.StdLib = false;
928                                 return true;
929                                 
930                         case "--fatal":
931                                 Report.Fatal = true;
932                                 return true;
933                                 
934                         case "--werror":
935                                 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
936                                 Report.WarningsAreErrors = true;
937                                 return true;
938
939                         case "--nowarn":
940                                 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
941                                 if ((i + 1) >= args.Length){
942                                         Usage ();
943                                         Environment.Exit (1);
944                                 }
945                                 int warn = 0;
946                                 
947                                 try {
948                                         warn = Int32.Parse (args [++i]);
949                                 } catch {
950                                         Usage ();
951                                         Environment.Exit (1);
952                                 }
953                                 Report.SetIgnoreWarning (warn);
954                                 return true;
955                                 
956                         case "--wlevel":
957                                 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
958                                 if ((i + 1) >= args.Length){
959                                         Report.Error (
960                                                 1900,
961                                                 "--wlevel requires a value from 0 to 4");
962                                         Environment.Exit (1);
963                                 }
964
965                                 SetWarningLevel (args [++i]);
966                                 return true;
967
968                         case "--mcs-debug":
969                                 if ((i + 1) >= args.Length){
970                                         Report.Error (5, "--mcs-debug requires an argument");
971                                         Environment.Exit (1);
972                                 }
973
974                                 try {
975                                         Report.DebugFlags = Int32.Parse (args [++i]);
976                                 } catch {
977                                         Report.Error (5, "Invalid argument to --mcs-debug");
978                                         Environment.Exit (1);
979                                 }
980                                 return true;
981                                 
982                         case "--about":
983                                 About ();
984                                 return true;
985                                 
986                         case "--recurse":
987                                 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
988                                 if ((i + 1) >= args.Length){
989                                         Report.Error (5, "--recurse requires an argument");
990                                         Environment.Exit (1);
991                                 }
992                                 CompileFiles (args [++i], true); 
993                                 return true;
994                                 
995                         case "--timestamp":
996                                 timestamps = true;
997                                 last_time = first_time = DateTime.Now;
998                                 return true;
999
1000                         case "--pause":
1001                                 pause = true;
1002                                 return true;
1003                                 
1004                         case "--debug": case "-g":
1005                                 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1006                                 want_debugging_support = true;
1007                                 return true;
1008                                 
1009                         case "--noconfig":
1010                                 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1011                                 load_default_config = false;
1012                                 return true;
1013
1014                         case "--typetest":
1015                                 if ((i + 1) >= args.Length){
1016                                         Report.Error (5, "--typetest requires a filename argument");
1017                                         Environment.Exit (1);
1018                                 }
1019                                 LambdaTypeParseTest (args [++i]);
1020                                 return true;
1021                         }
1022
1023                         return false;
1024                 }
1025
1026                 //
1027                 // This parses the -arg and /arg options to the compiler, even if the strings
1028                 // in the following text use "/arg" on the strings.
1029                 //
1030                 static bool CSCParseOption (string option, ref string [] args, ref int i)
1031                 {
1032                         int idx = option.IndexOf (':');
1033                         string arg, value;
1034
1035                         if (idx == -1){
1036                                 arg = option;
1037                                 value = "";
1038                         } else {
1039                                 arg = option.Substring (0, idx);
1040
1041                                 value = option.Substring (idx + 1);
1042                         }
1043
1044                         switch (arg){
1045                         case "/nologo":
1046                                 return true;
1047
1048                         case "/t":
1049                         case "/target":
1050                                 switch (value){
1051                                 case "exe":
1052                                         RootContext.Target = Target.Exe;
1053                                         break;
1054
1055                                 case "winexe":
1056                                         RootContext.Target = Target.WinExe;
1057                                         break;
1058
1059                                 case "library":
1060                                         RootContext.Target = Target.Library;
1061                                         RootContext.TargetExt = ".dll";
1062                                         break;
1063
1064                                 case "module":
1065                                         RootContext.Target = Target.Module;
1066                                         RootContext.TargetExt = ".netmodule";
1067                                         break;
1068
1069                                 default:
1070                                         TargetUsage ();
1071                                         break;
1072                                 }
1073                                 return true;
1074
1075                         case "/out":
1076                                 if (value.Length == 0){
1077                                         Usage ();
1078                                         Environment.Exit (1);
1079                                 }
1080                                 OutputFile = value;
1081                                 return true;
1082
1083                         case "/o":
1084                         case "/o+":
1085                         case "/optimize":
1086                         case "/optimize+":
1087                                 RootContext.Optimize = true;
1088                                 return true;
1089
1090                         case "/o-":
1091                         case "/optimize-":
1092                                 RootContext.Optimize = false;
1093                                 return true;
1094
1095                         case "/incremental":
1096                         case "/incremental+":
1097                         case "/incremental-":
1098                                 // nothing.
1099                                 return true;
1100
1101                         case "/d":
1102                         case "/define": {
1103                                 if (value.Length == 0){
1104                                         Usage ();
1105                                         Environment.Exit (1);
1106                                 }
1107
1108                                 foreach (string d in value.Split (';', ',')){
1109                                         if (!Tokenizer.IsValidIdentifier (d)) {
1110                                                 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1111                                                 continue;
1112                                         }
1113                                         defines.Add (d);
1114                                 }
1115                                 return true;
1116                         }
1117
1118                         case "/bugreport":
1119                                 //
1120                                 // We should collect data, runtime, etc and store in the file specified
1121                                 //
1122                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1123                                 return true;
1124
1125                         case "/pkg": {
1126                                 string packages;
1127
1128                                 if (value.Length == 0){
1129                                         Usage ();
1130                                         Environment.Exit (1);
1131                                 }
1132                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1133                                 
1134                                 ProcessStartInfo pi = new ProcessStartInfo ();
1135                                 pi.FileName = "pkg-config";
1136                                 pi.RedirectStandardOutput = true;
1137                                 pi.UseShellExecute = false;
1138                                 pi.Arguments = "--libs " + packages;
1139                                 Process p = null;
1140                                 try {
1141                                         p = Process.Start (pi);
1142                                 } catch (Exception e) {
1143                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1144                                         Environment.Exit (1);
1145                                 }
1146
1147                                 if (p.StandardOutput == null){
1148                                         Report.Warning (-27, 1, "Specified package did not return any information");
1149                                         return true;
1150                                 }
1151                                 string pkgout = p.StandardOutput.ReadToEnd ();
1152                                 p.WaitForExit ();
1153                                 if (p.ExitCode != 0) {
1154                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1155                                         Environment.Exit (1);
1156                                 }
1157
1158                                 if (pkgout != null){
1159                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1160                                                 Split (new Char [] { ' ', '\t'});
1161                                         args = AddArgs (args, xargs);
1162                                 }
1163                                 
1164                                 p.Close ();
1165                                 return true;
1166                         }
1167                                 
1168                         case "/linkres":
1169                         case "/linkresource":
1170                         case "/res":
1171                         case "/resource":
1172                                 if (embedded_resources == null)
1173                                         embedded_resources = new Resources ();
1174
1175                                 bool embeded = arg.StartsWith ("/r");
1176                                 string[] s = value.Split (',');
1177                                 switch (s.Length) {
1178                                         case 1:
1179                                                 if (s[0].Length == 0)
1180                                                         goto default;
1181                                                 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1182                                                 break;
1183                                         case 2:
1184                                                 embedded_resources.Add (embeded, s [0], s [1]);
1185                                                 break;
1186                                         case 3:
1187                                                 if (s [2] != "public" && s [2] != "private") {
1188                                                         Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1189                                                         return true;
1190                                                 }
1191                                                 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1192                                                 break;
1193                                         default:
1194                                                 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1195                                                 break;
1196                                 }
1197
1198                                 return true;
1199                                 
1200                         case "/recurse":
1201                                 if (value.Length == 0){
1202                                         Report.Error (5, "-recurse requires an argument");
1203                                         Environment.Exit (1);
1204                                 }
1205                                 CompileFiles (value, true); 
1206                                 return true;
1207
1208                         case "/r":
1209                         case "/reference": {
1210                                 if (value.Length == 0){
1211                                         Report.Error (5, "-reference requires an argument");
1212                                         Environment.Exit (1);
1213                                 }
1214
1215                                 string [] refs = value.Split (new char [] { ';', ',' });
1216                                 foreach (string r in refs){
1217                                         string val = r;
1218                                         int index = val.IndexOf ('=');
1219                                         if (index > -1) {
1220                                                 string alias = r.Substring (0, index);
1221                                                 string assembly = r.Substring (index + 1);
1222                                                 AddExternAlias (alias, assembly);
1223                                                 return true;
1224                                         }
1225                                         
1226                                         references.Add (val);
1227                                 }
1228                                 return true;
1229                         }
1230                         case "/addmodule": {
1231                                 if (value.Length == 0){
1232                                         Report.Error (5, arg + " requires an argument");
1233                                         Environment.Exit (1);
1234                                 }
1235
1236                                 string [] refs = value.Split (new char [] { ';', ',' });
1237                                 foreach (string r in refs){
1238                                         modules.Add (r);
1239                                 }
1240                                 return true;
1241                         }
1242                         case "/win32res": {
1243                                 if (value.Length == 0) {
1244                                         Report.Error (5, arg + " requires an argument");
1245                                         Environment.Exit (1);
1246                                 }
1247
1248                                 win32ResourceFile = value;
1249                                 return true;
1250                         }
1251                         case "/win32icon": {
1252                                 if (value.Length == 0) {
1253                                         Report.Error (5, arg + " requires an argument");
1254                                         Environment.Exit (1);
1255                                 }
1256
1257                                 win32IconFile = value;
1258                                 return true;
1259                         }
1260                         case "/doc": {
1261                                 if (value.Length == 0){
1262                                         Report.Error (2006, arg + " requires an argument");
1263                                         Environment.Exit (1);
1264                                 }
1265                                 RootContext.Documentation = new Documentation (value);
1266                                 return true;
1267                         }
1268                         case "/lib": {
1269                                 string [] libdirs;
1270                                 
1271                                 if (value.Length == 0){
1272                                         Report.Error (5, "/lib requires an argument");
1273                                         Environment.Exit (1);
1274                                 }
1275
1276                                 libdirs = value.Split (new Char [] { ',' });
1277                                 foreach (string dir in libdirs)
1278                                         link_paths.Add (dir);
1279                                 return true;
1280                         }
1281
1282                         case "/debug-":
1283                                 want_debugging_support = false;
1284                                 return true;
1285                                 
1286                         case "/debug":
1287                         case "/debug+":
1288                                 want_debugging_support = true;
1289                                 return true;
1290
1291                         case "/checked":
1292                         case "/checked+":
1293                                 RootContext.Checked = true;
1294                                 return true;
1295
1296                         case "/checked-":
1297                                 RootContext.Checked = false;
1298                                 return true;
1299
1300                         case "/clscheck":
1301                         case "/clscheck+":
1302                                 return true;
1303
1304                         case "/clscheck-":
1305                                 RootContext.VerifyClsCompliance = false;
1306                                 return true;
1307
1308                         case "/unsafe":
1309                         case "/unsafe+":
1310                                 RootContext.Unsafe = true;
1311                                 return true;
1312
1313                         case "/unsafe-":
1314                                 RootContext.Unsafe = false;
1315                                 return true;
1316
1317                         case "/warnaserror":
1318                         case "/warnaserror+":
1319                                 Report.WarningsAreErrors = true;
1320                                 return true;
1321
1322                         case "/warnaserror-":
1323                                 Report.WarningsAreErrors = false;
1324                                 return true;
1325
1326                         case "/warn":
1327                                 SetWarningLevel (value);
1328                                 return true;
1329
1330                         case "/nowarn": {
1331                                 string [] warns;
1332
1333                                 if (value.Length == 0){
1334                                         Report.Error (5, "/nowarn requires an argument");
1335                                         Environment.Exit (1);
1336                                 }
1337                                 
1338                                 warns = value.Split (new Char [] {','});
1339                                 foreach (string wc in warns){
1340                                         try {
1341                                                 int warn = Int32.Parse (wc);
1342                                                 if (warn < 1) {
1343                                                         throw new ArgumentOutOfRangeException("warn");
1344                                                 }
1345                                                 Report.SetIgnoreWarning (warn);
1346                                         } catch {
1347                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1348                                         }
1349                                 }
1350                                 return true;
1351                         }
1352
1353                         case "/noconfig-":
1354                                 load_default_config = true;
1355                                 return true;
1356                                 
1357                         case "/noconfig":
1358                         case "/noconfig+":
1359                                 load_default_config = false;
1360                                 return true;
1361
1362                         case "/help2":
1363                                 OtherFlags ();
1364                                 Environment.Exit(0);
1365                                 return true;
1366                                 
1367                         case "/help":
1368                         case "/?":
1369                                 Usage ();
1370                                 Environment.Exit (0);
1371                                 return true;
1372
1373                         case "/main":
1374                         case "/m":
1375                                 if (value.Length == 0){
1376                                         Report.Error (5, arg + " requires an argument");                                        
1377                                         Environment.Exit (1);
1378                                 }
1379                                 RootContext.MainClass = value;
1380                                 return true;
1381
1382                         case "/nostdlib":
1383                         case "/nostdlib+":
1384                                 RootContext.StdLib = false;
1385                                 return true;
1386
1387                         case "/nostdlib-":
1388                                 RootContext.StdLib = true;
1389                                 return true;
1390
1391                         case "/fullpaths":
1392                                 return true;
1393
1394                         case "/keyfile":
1395                                 if (value == String.Empty) {
1396                                         Report.Error (5, arg + " requires an argument");
1397                                         Environment.Exit (1);
1398                                 }
1399                                 RootContext.StrongNameKeyFile = value;
1400                                 return true;
1401                         case "/keycontainer":
1402                                 if (value == String.Empty) {
1403                                         Report.Error (5, arg + " requires an argument");
1404                                         Environment.Exit (1);
1405                                 }
1406                                 RootContext.StrongNameKeyContainer = value;
1407                                 return true;
1408                         case "/delaysign+":
1409                                 RootContext.StrongNameDelaySign = true;
1410                                 return true;
1411                         case "/delaysign-":
1412                                 RootContext.StrongNameDelaySign = false;
1413                                 return true;
1414
1415                         case "/v2":
1416                         case "/2":
1417                                 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1418                                 SetupV2 ();
1419                                 return true;
1420                                 
1421                         case "/langversion":
1422                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1423                                 case "iso-1":
1424                                         RootContext.Version = LanguageVersion.ISO_1;
1425                                         return true;
1426                                         
1427                                 case "default":
1428                                         SetupV2 ();
1429                                         return true;
1430                                         
1431                                 case "linq":
1432                                         RootContext.Version = LanguageVersion.LINQ;
1433                                         Tokenizer.LinqEnabled = true;
1434                                         return true;
1435                                 }
1436                                 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
1437                                 return true;
1438
1439                         case "/codepage":
1440                                 switch (value) {
1441                                 case "utf8":
1442                                         encoding = new UTF8Encoding();
1443                                         break;
1444                                 case "reset":
1445                                         encoding = Encoding.Default;
1446                                         break;
1447                                 default:
1448                                         try {
1449                                                 encoding = Encoding.GetEncoding (
1450                                                 Int32.Parse (value));
1451                                         } catch {
1452                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1453                                         }
1454                                         break;
1455                                 }
1456                                 return true;
1457                         }
1458
1459                         return false;
1460                 }
1461
1462                 static void Error_WrongOption (string option)
1463                 {
1464                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1465                 }
1466
1467                 static string [] AddArgs (string [] args, string [] extra_args)
1468                 {
1469                         string [] new_args;
1470                         new_args = new string [extra_args.Length + args.Length];
1471
1472                         // if args contains '--' we have to take that into account
1473                         // split args into first half and second half based on '--'
1474                         // and add the extra_args before --
1475                         int split_position = Array.IndexOf (args, "--");
1476                         if (split_position != -1)
1477                         {
1478                                 Array.Copy (args, new_args, split_position);
1479                                 extra_args.CopyTo (new_args, split_position);
1480                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1481                         }
1482                         else
1483                         {
1484                                 args.CopyTo (new_args, 0);
1485                                 extra_args.CopyTo (new_args, args.Length);
1486                         }
1487
1488                         return new_args;
1489                 }
1490
1491                 static void AddExternAlias (string identifier, string assembly)
1492                 {
1493                         if (assembly.Length == 0) {
1494                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1495                                 return;
1496                         }
1497
1498                         if (!IsExternAliasValid (identifier)) {
1499                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1500                                 return;
1501                         }
1502                         
1503                         // Could here hashtable throw an exception?
1504                         external_aliases [identifier] = assembly;
1505                 }
1506                 
1507                 static bool IsExternAliasValid (string identifier)
1508                 {
1509                         if (identifier.Length == 0)
1510                                 return false;
1511                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1512                                 return false;
1513
1514                         for (int i = 1; i < identifier.Length; i++) {
1515                                 char c = identifier [i];
1516                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1517                                         continue;
1518
1519                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1520                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1521                                                 category != UnicodeCategory.SpacingCombiningMark ||
1522                                                 category != UnicodeCategory.ConnectorPunctuation)
1523                                         return false;
1524                         }
1525                         
1526                         return true;
1527                 }
1528                 
1529                 /// <summary>
1530                 ///    Parses the arguments, and drives the compilation
1531                 ///    process.
1532                 /// </summary>
1533                 ///
1534                 /// <remarks>
1535                 ///    TODO: Mostly structured to debug the compiler
1536                 ///    now, needs to be turned into a real driver soon.
1537                 /// </remarks>
1538                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1539                 internal static bool MainDriver (string [] args)
1540                 {
1541                         int i;
1542                         bool parsing_options = true;
1543
1544                         encoding = Encoding.Default;
1545
1546                         references = new ArrayList ();
1547                         external_aliases = new Hashtable ();
1548                         soft_references = new ArrayList ();
1549                         modules = new ArrayList ();
1550                         link_paths = new ArrayList ();
1551
1552                         SetupDefaultDefines ();
1553                         
1554                         //
1555                         // Setup defaults
1556                         //
1557                         // This is not required because Assembly.Load knows about this
1558                         // path.
1559                         //
1560
1561                         Hashtable response_file_list = null;
1562
1563                         for (i = 0; i < args.Length; i++){
1564                                 string arg = args [i];
1565                                 if (arg.Length == 0)
1566                                         continue;
1567
1568                                 if (arg.StartsWith ("@")){
1569                                         string [] extra_args;
1570                                         string response_file = arg.Substring (1);
1571
1572                                         if (response_file_list == null)
1573                                                 response_file_list = new Hashtable ();
1574                                         
1575                                         if (response_file_list.Contains (response_file)){
1576                                                 Report.Error (
1577                                                         1515, "Response file `" + response_file +
1578                                                         "' specified multiple times");
1579                                                 Environment.Exit (1);
1580                                         }
1581                                         
1582                                         response_file_list.Add (response_file, response_file);
1583                                                     
1584                                         extra_args = LoadArgs (response_file);
1585                                         if (extra_args == null){
1586                                                 Report.Error (2011, "Unable to open response file: " +
1587                                                               response_file);
1588                                                 return false;
1589                                         }
1590
1591                                         args = AddArgs (args, extra_args);
1592                                         continue;
1593                                 }
1594
1595                                 if (parsing_options){
1596                                         if (arg == "--"){
1597                                                 parsing_options = false;
1598                                                 continue;
1599                                         }
1600                                         
1601                                         if (arg.StartsWith ("-")){
1602                                                 if (UnixParseOption (arg, ref args, ref i))
1603                                                         continue;
1604
1605                                                 // Try a -CSCOPTION
1606                                                 string csc_opt = "/" + arg.Substring (1);
1607                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1608                                                         continue;
1609
1610                                                 Error_WrongOption (arg);
1611                                                 return false;
1612                                         } else {
1613                                                 if (arg [0] == '/'){
1614                                                         if (CSCParseOption (arg, ref args, ref i))
1615                                                                 continue;
1616
1617                                                         // Need to skip `/home/test.cs' however /test.cs is considered as error
1618                                                         if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
1619                                                                 Error_WrongOption (arg);
1620                                                                 return false;
1621                                                         }
1622                                                 }
1623                                         }
1624                                 }
1625
1626                                 CompileFiles (arg, false); 
1627                         }
1628
1629                         ProcessFiles ();
1630
1631                         if (tokenize)
1632                                 return true;
1633
1634                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1635                                 throw new InternalErrorException ("who set it?");
1636
1637                         //
1638                         // If we are an exe, require a source file for the entry point
1639                         //
1640                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
1641                                 if (first_source == null){
1642                                         Report.Error (2008, "No files to compile were specified");
1643                                         return false;
1644                                 }
1645
1646                         }
1647
1648                         //
1649                         // If there is nothing to put in the assembly, and we are not a library
1650                         //
1651                         if (first_source == null && embedded_resources == null){
1652                                 Report.Error (2008, "No files to compile were specified");
1653                                 return false;
1654                         }
1655
1656                         if (Report.Errors > 0)
1657                                 return false;
1658                         
1659                         if (parse_only)
1660                                 return true;
1661
1662                         if (load_default_config)
1663                                 DefineDefaultConfig ();
1664
1665                         if (Report.Errors > 0){
1666                                 return false;
1667                         }
1668
1669                         //
1670                         // Load assemblies required
1671                         //
1672                         if (timestamps)
1673                                 ShowTime ("Loading references");
1674                         link_paths.Add (GetSystemDir ());
1675                         link_paths.Add (Directory.GetCurrentDirectory ());
1676                         LoadReferences ();
1677                         
1678                         if (timestamps)
1679                                 ShowTime ("   References loaded");
1680                         
1681                         if (Report.Errors > 0){
1682                                 return false;
1683                         }
1684
1685                         //
1686                         // Quick hack
1687                         //
1688                         if (output_file == null){
1689                                 if (first_source == null){
1690                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1691                                         return false;
1692                                 }
1693                                         
1694                                 int pos = first_source.LastIndexOf ('.');
1695
1696                                 if (pos > 0)
1697                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1698                                 else
1699                                         output_file = first_source + RootContext.TargetExt;
1700                         }
1701
1702                         if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1703                                 return false;
1704
1705                         if (RootContext.Target == Target.Module) {
1706                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1707                                 if (module_only == null) {
1708                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1709                                         Environment.Exit (1);
1710                                 }
1711
1712                                 MethodInfo set_method = module_only.GetSetMethod (true);
1713                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1714                         }
1715
1716                         RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1717
1718                         if (modules.Count > 0) {
1719                                 foreach (string module in modules)
1720                                         LoadModule (module);
1721                         }
1722                         
1723                         //
1724                         // Before emitting, we need to get the core
1725                         // types emitted from the user defined types
1726                         // or from the system ones.
1727                         //
1728                         if (timestamps)
1729                                 ShowTime ("Initializing Core Types");
1730                         if (!RootContext.StdLib){
1731                                 RootContext.ResolveCore ();
1732                                 if (Report.Errors > 0)
1733                                         return false;
1734                         }
1735                         
1736                         TypeManager.InitCoreTypes ();
1737                         if (timestamps)
1738                                 ShowTime ("   Core Types done");
1739
1740                         CodeGen.Module.Resolve ();
1741
1742                         //
1743                         // The second pass of the compiler
1744                         //
1745                         if (timestamps)
1746                                 ShowTime ("Resolving tree");
1747                         RootContext.ResolveTree ();
1748
1749                         if (Report.Errors > 0)
1750                                 return false;
1751                         if (timestamps)
1752                                 ShowTime ("Populate tree");
1753                         if (!RootContext.StdLib)
1754                                 RootContext.BootCorlib_PopulateCoreTypes ();
1755                         RootContext.PopulateTypes ();
1756
1757                         TypeManager.InitCodeHelpers ();
1758
1759                         RootContext.DefineTypes ();
1760                         
1761                         if (Report.Errors == 0 &&
1762                                 RootContext.Documentation != null &&
1763                                 !RootContext.Documentation.OutputDocComment (
1764                                         output_file))
1765                                 return false;
1766
1767                         //
1768                         // Verify using aliases now
1769                         //
1770                         NamespaceEntry.VerifyAllUsing ();
1771                         
1772                         if (Report.Errors > 0){
1773                                 return false;
1774                         }
1775
1776                         CodeGen.Assembly.Resolve ();
1777                         
1778                         if (RootContext.VerifyClsCompliance) {
1779                                 if (CodeGen.Assembly.IsClsCompliant) {
1780                                         AttributeTester.VerifyModulesClsCompliance ();
1781                                         TypeManager.LoadAllImportedTypes ();
1782                                 }
1783                         }
1784                         if (Report.Errors > 0)
1785                                 return false;
1786                         
1787                         //
1788                         // The code generator
1789                         //
1790                         if (timestamps)
1791                                 ShowTime ("Emitting code");
1792                         ShowTotalTime ("Total so far");
1793                         RootContext.EmitCode ();
1794                         if (timestamps)
1795                                 ShowTime ("   done");
1796
1797                         if (Report.Errors > 0){
1798                                 return false;
1799                         }
1800
1801                         if (timestamps)
1802                                 ShowTime ("Closing types");
1803
1804                         RootContext.CloseTypes ();
1805
1806                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1807
1808                         switch (RootContext.Target) {
1809                         case Target.Library:
1810                         case Target.Module:
1811                                 k = PEFileKinds.Dll; break;
1812                         case Target.Exe:
1813                                 k = PEFileKinds.ConsoleApplication; break;
1814                         case Target.WinExe:
1815                                 k = PEFileKinds.WindowApplication; break;
1816                         }
1817
1818                         if (RootContext.NeedsEntryPoint) {
1819                                 MethodInfo ep = RootContext.EntryPoint;
1820
1821                                 if (ep == null) {
1822                                         if (RootContext.MainClass != null) {
1823                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1824                                                 if (main_cont == null) {
1825                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1826                                                         return false;
1827                                                 }
1828
1829                                                 if (!(main_cont is ClassOrStruct)) {
1830                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1831                                                         return false;
1832                                                 }
1833
1834                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1835                                                 return false;
1836                                         }
1837
1838                                         if (Report.Errors == 0)
1839                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1840                                                         output_file);
1841                                         return false;
1842                                 }
1843
1844                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1845                         } else if (RootContext.MainClass != null) {
1846                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1847                         }
1848
1849                         if (embedded_resources != null){
1850                                 if (RootContext.Target == Target.Module) {
1851                                         Report.Error (1507, "Cannot link resource file when building a module");
1852                                         return false;
1853                                 }
1854
1855                                 embedded_resources.Emit ();
1856                         }
1857
1858                         //
1859                         // Add Win32 resources
1860                         //
1861
1862                         CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1863
1864                         if (win32ResourceFile != null) {
1865                                 try {
1866                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1867                                 }
1868                                 catch (ArgumentException) {
1869                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1870                                 }
1871                         }
1872
1873                         if (win32IconFile != null) {
1874                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1875                                 if (define_icon == null) {
1876                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1877                                 }
1878                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1879                         }
1880
1881                         if (Report.Errors > 0)
1882                                 return false;
1883                         
1884                         CodeGen.Save (output_file);
1885                         if (timestamps) {
1886                                 ShowTime ("Saved output");
1887                                 ShowTotalTime ("Total");
1888                         }
1889
1890                         Timer.ShowTimers ();
1891                         
1892                         if (Report.ExpectedError != 0) {
1893                                 if (Report.Errors == 0) {
1894                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1895                                                 "No other errors reported.");
1896                                         
1897                                         Environment.Exit (2);
1898                                 } else {
1899                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1900                                                 "However, other errors were reported.");
1901                                         
1902                                         Environment.Exit (1);
1903                                 }
1904                                 
1905                                 
1906                                 return false;
1907                         }
1908
1909 #if DEBUGME
1910                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1911                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1912 #endif
1913                         return (Report.Errors == 0);
1914                 }
1915         }
1916
1917         class Resources
1918         {
1919                 interface IResource
1920                 {
1921                         void Emit ();
1922                         string FileName { get; }
1923                 }
1924
1925                 class EmbededResource : IResource
1926                 {
1927                         static MethodInfo embed_res;
1928
1929                         static EmbededResource () {
1930                                 Type[] argst = new Type [] { 
1931                                                                                            typeof (string), typeof (string), typeof (ResourceAttributes)
1932                                                                                    };
1933
1934                                 embed_res = typeof (AssemblyBuilder).GetMethod (
1935                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1936                                         null, CallingConventions.Any, argst, null);
1937                                 
1938                                 if (embed_res == null) {
1939                                         Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1940                                 }
1941                         }
1942
1943                         readonly object[] args;
1944
1945                         public EmbededResource (string name, string file, bool isPrivate)
1946                         {
1947                                 args = new object [3];
1948                                 args [0] = name;
1949                                 args [1] = file;
1950                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1951                         }
1952
1953                         public void Emit()
1954                         {
1955                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1956                         }
1957
1958                         public string FileName {
1959                                 get {
1960                                         return (string)args [1];
1961                                 }
1962                         }
1963                 }
1964
1965                 class LinkedResource : IResource
1966                 {
1967                         readonly string file;
1968                         readonly string name;
1969                         readonly ResourceAttributes attribute;
1970
1971                         public LinkedResource (string name, string file, bool isPrivate)
1972                         {
1973                                 this.name = name;
1974                                 this.file = file;
1975                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1976                         }
1977
1978                         public void Emit ()
1979                         {
1980                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1981                         }
1982
1983                         public string FileName {
1984                                 get {
1985                                         return file;
1986                                 }
1987                         }
1988                 }
1989
1990
1991                 IDictionary embedded_resources = new HybridDictionary ();
1992
1993                 public void Add (bool embeded, string file, string name)
1994                 {
1995                         Add (embeded, file, name, false);
1996                 }
1997
1998                 public void Add (bool embeded, string file, string name, bool isPrivate)
1999                 {
2000                         if (embedded_resources.Contains (name)) {
2001                                 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
2002                                 return;
2003                         }
2004                         IResource r = embeded ? 
2005                                 (IResource) new EmbededResource (name, file, isPrivate) : 
2006                                 new LinkedResource (name, file, isPrivate);
2007
2008                         embedded_resources.Add (name, r);
2009                 }
2010
2011                 public void Emit ()
2012                 {
2013                         foreach (IResource r in embedded_resources.Values) {
2014                                 if (!File.Exists (r.FileName)) {
2015                                         Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
2016                                         continue;
2017                                 }
2018                                 
2019                                 r.Emit ();
2020                         }
2021                 }
2022         }
2023
2024         //
2025         // This is the only public entry point
2026         //
2027         public class CompilerCallableEntryPoint : MarshalByRefObject {
2028                 public static bool InvokeCompiler (string [] args, TextWriter error)
2029                 {
2030                         Report.Stderr = error;
2031                         try {
2032                                 return Driver.MainDriver (args) && Report.Errors == 0;
2033                         }
2034                         finally {
2035                                 Report.Stderr = Console.Error;
2036                                 Reset ();
2037                         }
2038                 }
2039
2040                 public static int[] AllWarningNumbers {
2041                         get {
2042                                 return Report.AllWarnings;
2043                         }
2044                 }
2045                 
2046                 static void Reset ()
2047                 {
2048                         Driver.Reset ();
2049                         Tokenizer.Reset ();
2050                         Location.Reset ();
2051                         RootContext.Reset ();
2052                         Report.Reset ();
2053                         TypeManager.Reset ();
2054                         TypeHandle.Reset ();
2055                         RootNamespace.Reset ();
2056                         NamespaceEntry.Reset ();
2057                         CodeGen.Reset ();
2058                         Attribute.Reset ();
2059                         AttributeTester.Reset ();
2060                 }
2061         }
2062 }