2 // driver.cs: The compiler command line driver.
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
5 // Based on mcs by : Miguel de Icaza (miguel@gnu.org)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2002, 2003, 2004 Rafael Teixeira
12 namespace Mono.Languages {
15 using System.Collections;
18 using System.Globalization;
19 using System.Reflection;
20 using System.Reflection.Emit;
23 using Mono.GetOptions;
24 using Mono.GetOptions.Useful;
33 /// The compiler driver.
35 public class CompilerOptions : CommonCompilerOptions {
38 //------------------------------------------------------------------
39 [Option("[IGNORED] Only parses the source file (for debugging the tokenizer)", "parse", SecondLevelHelp = true)]
40 public bool OnlyParse = false;
42 [Option("[IGNORED] Only tokenizes source files", "tokenize", SecondLevelHelp = true)]
43 public bool Tokenize = false;
45 [Option("Shows stack trace at Error location", "stacktrace", SecondLevelHelp = true)]
46 public bool Stacktrace = false;
48 [Option("Makes errors fatal", "fatal", SecondLevelHelp = true)]
49 public bool MakeErrorsFatal = false;
51 [Option("Displays time stamps of various compiler events", "timestamp", SecondLevelHelp = true)]
52 public virtual bool PrintTimeStamps {
55 printTimeStamps = true;
56 last_time = DateTime.Now;
57 DebugListOfArguments.Add("timestamp");
61 // redefining some inherited options
62 //------------------------------------------------------------------
63 [Option("About the MonoBASIC compiler", "about")]
64 public override WhatToDoNext DoAbout()
66 return base.DoAbout();
70 public override WhatToDoNext DoUsage() { return WhatToDoNext.GoAhead; }
73 //------------------------------------------------------------------
75 [Option("Require explicit declaration of variables", "optionexplicit", VBCStyleBoolean = true)]
76 public bool OptionExplicit = false;
78 [Option("Enforce strict language semantics", "optionstrict", VBCStyleBoolean = true)]
79 public bool OptionStrict = false;
81 [Option("Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
82 public bool OptionCompareBinary = true;
84 [Option("Specifies text-style string comparisons.", "optioncompare:text")]
85 public bool OptionCompareText { set { OptionCompareBinary = false; } }
87 protected override void InitializeOtherDefaults()
89 DefineSymbol = "__MonoBASIC__";
90 ImportNamespaces = "Microsoft.VisualBasic";
93 private bool printTimeStamps = false;
95 // Last time we took the time
98 public void ShowTime (string msg)
100 DateTime now = DateTime.Now;
101 TimeSpan span = now - last_time;
105 "[{0:00}:{1:000}] {2}",
106 (int) span.TotalSeconds, span.Milliseconds, msg);
110 public class Driver : CompilerOptions {
112 private void InitializeRootContextAndOthersFromOptions()
114 Report.Stacktrace = Stacktrace;
115 Report.WarningsAreErrors = WarningsAreErrors;
116 // TODO: change Report to receive the whole array
117 for(int i = 0; i < WarningsToIgnore.Length; i++)
118 Report.SetIgnoreWarning(WarningsToIgnore[i]);
119 Report.Fatal = MakeErrorsFatal;
121 RootContext.WarningLevel = WarningLevel;
122 RootContext.Checked = CheckedContext;
123 RootContext.MainClass = MainClassName;
124 RootContext.StdLib = !NoStandardLibraries;
125 RootContext.Unsafe = AllowUnsafeCode;
126 if (RootNamespace != null)
127 RootContext.RootNamespace = RootNamespace;
129 // TODO: semantics are different and should be adjusted
130 GenericParser.yacc_verbose_flag = Verbose ? 1 : 0;
132 Mono.MonoBASIC.Parser.InitialOptionExplicit = OptionExplicit;
133 Mono.MonoBASIC.Parser.InitialOptionStrict = OptionStrict;
134 Mono.MonoBASIC.Parser.InitialOptionCompareBinary = OptionCompareBinary;
135 Mono.MonoBASIC.Parser.ImportsList = Imports;
138 public ArrayList AssembliesToReferenceSoftly = new ArrayList();
140 public int LoadAssembly (string assembly, bool soft)
143 string total_log = "";
146 char[] path_chars = { '/', '\\' };
148 if (assembly.IndexOfAny (path_chars) != -1)
149 a = Assembly.LoadFrom(assembly);
151 string ass = assembly;
152 if (ass.EndsWith (".dll"))
153 ass = assembly.Substring (0, assembly.Length - 4);
154 a = Assembly.Load (ass);
156 TypeManager.AddAssembly (a);
159 catch (FileNotFoundException) {
160 if (PathsToSearchForLibraries != null) {
161 foreach (string dir in PathsToSearchForLibraries) {
162 string full_path = dir + "/" + assembly + ".dll";
165 a = Assembly.LoadFrom (full_path);
166 TypeManager.AddAssembly (a);
169 catch (FileNotFoundException ff) {
170 total_log += ff.FusionLog;
178 catch (BadImageFormatException f) {
179 Error ("// Bad file format while loading assembly");
180 Error ("Log: " + f.FusionLog);
182 } catch (FileLoadException f){
183 Error ("File Load Exception: " + assembly);
184 Error ("Log: " + f.FusionLog);
186 } catch (ArgumentNullException){
187 Error ("// Argument Null exception ");
191 Report.Error (6, "Can not find assembly `" + assembly + "'" );
192 Console.WriteLine ("Log: \n" + total_log);
197 public void LoadModule (MethodInfo adder_method, string module)
199 System.Reflection.Module m;
200 string total_log = "";
204 m = (System.Reflection.Module)adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { module });
206 catch (TargetInvocationException ex) {
207 throw ex.InnerException;
209 TypeManager.AddModule (m);
212 catch (FileNotFoundException) {
213 foreach (string dir in PathsToSearchForLibraries) {
214 string full_path = Path.Combine (dir, module);
215 if (!module.EndsWith (".netmodule"))
216 full_path += ".netmodule";
220 m = (System.Reflection.Module) adder_method.Invoke (CodeGen.AssemblyBuilder, new object [] { full_path });
222 catch (TargetInvocationException ex) {
223 throw ex.InnerException;
225 TypeManager.AddModule (m);
228 catch (FileNotFoundException ff) {
229 total_log += ff.FusionLog;
233 Report.Error (6, "Cannot find module `" + module + "'" );
234 Console.WriteLine ("Log: \n" + total_log);
236 catch (BadImageFormatException f) {
237 Report.Error(6, "Cannot load module (bad file format)" + f.FusionLog);
239 catch (FileLoadException f) {
240 Report.Error(6, "Cannot load module " + f.FusionLog);
242 catch (ArgumentNullException) {
243 Report.Error(6, "Cannot load module (null argument)");
247 void Error(string message)
249 Console.WriteLine(message);
253 /// Loads all assemblies referenced on the command line
255 public int LoadReferences ()
259 foreach (string r in AssembliesToReference)
260 errors += LoadAssembly (r, false);
262 foreach (string r in AssembliesToReferenceSoftly)
263 errors += LoadAssembly (r, true);
269 // Given a path specification, splits the path from the file/pattern
271 void SplitPathAndPattern (string spec, out string path, out string pattern)
273 int p = spec.LastIndexOf ("/");
276 // Windows does not like /file.cs, switch that to:
281 pattern = spec.Substring (1);
283 path = spec.Substring (0, p);
284 pattern = spec.Substring (p + 1);
289 p = spec.LastIndexOf ("\\");
291 path = spec.Substring (0, p);
292 pattern = spec.Substring (p + 1);
300 bool AddFiles (string spec, bool recurse)
302 string path, pattern;
304 SplitPathAndPattern(spec, out path, out pattern);
305 if (pattern.IndexOf("*") == -1) {
306 DefaultArgumentProcessor(spec);
310 string [] files = null;
312 files = Directory.GetFiles(path, pattern);
313 } catch (System.IO.DirectoryNotFoundException) {
314 Report.Error (2001, "Source file `" + spec + "' could not be found");
316 } catch (System.IO.IOException){
317 Report.Error (2001, "Source file `" + spec + "' could not be found");
320 foreach (string f in files)
321 DefaultArgumentProcessor (f);
326 string [] dirs = null;
329 dirs = Directory.GetDirectories(path);
333 foreach (string d in dirs) {
335 // Don't include path in this string, as each
336 // directory entry already does
337 AddFiles (d + "/" + pattern, true);
343 void DefineDefaultConfig ()
346 // For now the "default config" is harcoded into the compiler
347 // we can move this outside later
349 string [] default_config =
354 "Microsoft.VisualBasic" ,
355 #if EXTRA_DEFAULT_REFS
357 // Is it worth pre-loading all this stuff?
360 "System.Configuration.Install",
362 "System.DirectoryServices",
363 "System.Drawing.Design",
365 "System.EnterpriseServices",
368 "System.Runtime.Remoting",
369 "System.Runtime.Serialization.Formatters.Soap",
371 "System.ServiceProcess",
373 "System.Web.RegularExpressions",
374 "System.Web.Services" ,
375 "System.Windows.Forms"
379 foreach (string def in default_config)
380 if (!(AssembliesToReference.Contains(def) || AssembliesToReference.Contains (def + ".dll")))
381 AssembliesToReferenceSoftly.Add(def);
384 void InitializeDebuggingSupport()
386 string[] debug_args = new string [DebugListOfArguments.Count];
387 DebugListOfArguments.CopyTo(debug_args);
388 CodeGen.Init(OutputFileName, OutputFileName, WantDebuggingSupport, debug_args);
389 TypeManager.AddModule(CodeGen.ModuleBuilder);
392 public bool ResolveAllTypes() // Phase 2
394 // Load Core Library for default compilation
395 if (RootContext.StdLib)
396 AssembliesToReference.Insert(0, "mscorlib");
399 DefineDefaultConfig();
401 ShowTime("Loading referenced assemblies");
403 // Load assemblies required
404 if (LoadReferences() > 0) {
405 Error ("Could not load one or more assemblies");
409 ShowTime("References loaded");
411 InitializeDebuggingSupport();
413 // TargetFileType is Module
414 if (TargetFileType == TargetType.Module) {
415 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
416 if (module_only == null) {
417 Report.Error (0, new Location (-1, -1), "Cannot use /TargetFileType:module on this runtime: try the Mono runtime instead.");
418 Environment.Exit (1);
421 MethodInfo set_method = module_only.GetSetMethod (true);
422 set_method.Invoke (CodeGen.AssemblyBuilder, BindingFlags.Default, null, new object[]{true}, null);
424 TypeManager.AddModule (CodeGen.ModuleBuilder);
427 if (NetModulesToAdd.Count > 0) {
428 MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
429 if (adder_method == null) {
430 Report.Error (0, new Location (-1, -1), "Cannot use /addmodule on this runtime: Try the Mono runtime instead.");
431 Environment.Exit (1);
434 foreach (string module in NetModulesToAdd)
435 LoadModule (adder_method, module);
440 // Before emitting, we need to get the core
441 // types emitted from the user defined types
442 // or from the system ones.
444 ShowTime("Initializing Core Types");
446 if (!RootContext.StdLib)
447 RootContext.ResolveCore ();
448 if (Report.Errors > 0)
451 TypeManager.InitCoreTypes();
452 if (Report.Errors > 0)
455 ShowTime(" Core Types done");
457 ShowTime("Resolving tree");
459 // The second pass of the compiler
460 RootContext.ResolveTree ();
461 if (Report.Errors > 0)
464 ShowTime("Populate tree");
466 if (!RootContext.StdLib)
467 RootContext.BootCorlib_PopulateCoreTypes();
468 if (Report.Errors > 0)
471 RootContext.PopulateTypes();
472 if (Report.Errors > 0)
475 TypeManager.InitCodeHelpers();
476 if (Report.Errors > 0)
484 string mainclass = GetFQMainClass();
486 if (mainclass != null) {
487 foreach (string r in AssembliesToReference) {
488 if (r.IndexOf ("System.Windows.Forms") >= 0) {
489 Type t = TypeManager.LookupType(mainclass);
491 return t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
499 string GetFQMainClass()
501 if (RootContext.RootNamespace != "")
502 return RootContext.RootNamespace + "." + RootContext.MainClass;
504 return RootContext.MainClass;
509 if (TargetFileType == TargetType.Exe || TargetFileType == TargetType.WinExe) {
510 MethodInfo ep = RootContext.EntryPoint;
513 // If we don't have a valid entry point yet
514 // AND if System.Windows.Forms is included
515 // among the dependencies, we have to build
516 // a new entry point on-the-fly. Otherwise we
517 // won't be able to compile SWF code out of the box.
520 Type t = TypeManager.LookupType(GetFQMainClass());
523 TypeBuilder tb = t as TypeBuilder;
524 MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
525 typeof(void), new Type[0]);
527 Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
528 Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
529 Type[] args = new Type[1];
531 MethodInfo mi = SWFA.GetMethod("Run", args);
532 ILGenerator ig = mb.GetILGenerator();
533 ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
535 ig.Emit (OpCodes.Newobj, ci);
536 ig.Emit (OpCodes.Call, mi);
537 ig.Emit (OpCodes.Ret);
539 RootContext.EntryPoint = mb as MethodInfo;
546 bool GenerateAssembly()
549 // The code generator
551 ShowTime("Emitting code");
553 RootContext.EmitCode();
555 if (Report.Errors > 0)
560 ShowTime("Closing types");
562 RootContext.CloseTypes ();
563 if (Report.Errors > 0)
568 PEFileKinds k = PEFileKinds.ConsoleApplication;
570 if (TargetFileType == TargetType.Library || TargetFileType == TargetType.Module)
572 else if (TargetFileType == TargetType.Exe)
573 k = PEFileKinds.ConsoleApplication;
574 else if (TargetFileType == TargetType.WinExe)
575 k = PEFileKinds.WindowApplication;
577 if (TargetFileType == TargetType.Exe || TargetFileType == TargetType.WinExe) {
578 MethodInfo ep = RootContext.EntryPoint;
581 Report.Error (30737, "Program " + OutputFileName +
582 " does not have an entry point defined");
586 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
590 if (EmbeddedResources != null)
591 foreach (string file in EmbeddedResources)
592 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
594 CodeGen.Save(OutputFileName);
596 ShowTime("Saved output");
599 if (WantDebuggingSupport) {
600 CodeGen.SaveSymbols ();
601 ShowTime ("Saved symbols");
607 public void CompileAll()
610 InitializeRootContextAndOthersFromOptions();
612 if (!ParseAll()) // Phase 1
615 if (!ResolveAllTypes()) // Phase 2
618 GenerateAssembly(); // Phase 3
620 } catch (Exception ex) {
621 Error("Exception: " + ex.ToString());
625 private bool quiet { get { return DontShowBanner || SuccintErrorDisplay; } }
627 private void Banner()
631 // TODO: remove next lines when the compiler has matured enough
632 Console.WriteLine ("--------");
633 Console.WriteLine ("THIS IS AN ALPHA SOFTWARE.");
634 Console.WriteLine ("--------");
638 bool ParseAll() // Phase 1
640 foreach(FileToCompile file in SourceFilesToCompile)
641 GenericParser.Parse(file.Filename, file.Encoding);
643 return (Report.Errors == 0);
647 /// Parses the arguments, and calls the compilation process.
649 int MainDriver(string [] args)
653 if (SourceFilesToCompile.Count == 0) {
661 return Report.ProcessResults(quiet);
664 public static int Main (string[] args)
666 Driver Exec = new Driver();
668 return Exec.MainDriver(args);