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