2 // driver.cs: The compiler command line driver.
\r
4 // Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
\r
5 // Based on mcs by : Miguel de Icaza (miguel@gnu.org)
\r
7 // Licensed under the terms of the GNU GPL
\r
9 // (C) 2002 Rafael Teixeira
\r
12 namespace Mono.Languages
\r
15 using System.Reflection;
\r
16 using System.Reflection.Emit;
\r
17 using System.Collections;
\r
19 using System.Globalization;
\r
21 using Mono.GetOptions;
\r
25 Library, Exe, Module, WinExe
\r
34 /// The compiler driver.
\r
36 public class Driver : Options
\r
38 // Temporary options
\r
39 //------------------------------------------------------------------
\r
40 [Option("[Mono] Only parses the source file (for debugging the tokenizer)", "parse")]
\r
41 public bool parse_only = false;
\r
43 [Option("[Mono] Only tokenizes source files")]
\r
44 public bool tokenize = false;
\r
46 [Option("[Mono] Shows stack trace at Error location")]
\r
47 public bool stacktrace { set { Report.Stacktrace = value; } }
\r
49 [Option("[Mono] Displays time stamps of various compiler events")]
\r
50 public bool timestamp
\r
55 last_time = DateTime.Now;
\r
56 debug_arglist.Add("timestamp");
\r
60 // Mono-specific options
\r
61 //------------------------------------------------------------------
\r
62 [Option("About the MonoBASIC compiler", "about")]
\r
63 public override WhatToDoNext DoAbout()
\r
65 return base.DoAbout();
\r
68 [Option("[Mono] Don\'t assume the standard library", "nostdlib")]
\r
69 public bool nostdlib { set { RootContext.StdLib = !value; } }
\r
71 [Option("[Mono] Disables implicit references to assemblies", "noconfig")]
\r
72 public bool NoConfig { set { load_default_config = !value; } }
\r
74 [Option("[Mono] Allows unsafe code", "unsafe")]
\r
75 public bool AllowUnsafeCode { set { RootContext.Unsafe = value; } }
\r
77 [Option("[Mono] Set default context to checked", "checked")]
\r
78 public bool Checked { set { RootContext.Checked = value; } }
\r
80 [Option("[Mono] Debugger arguments", "debug-args")]
\r
81 public WhatToDoNext SetDebugArgs(string args)
\r
83 char[] sep = { ',' };
\r
84 debug_arglist.AddRange (args.Split (sep));
\r
85 return WhatToDoNext.GoAhead;
\r
88 [Option("[Mono] Ignores warning number PARAM", "ignorewarn")]
\r
89 public WhatToDoNext SetIgnoreWarning(int warn)
\r
91 Report.SetIgnoreWarning(warn);
\r
92 return WhatToDoNext.GoAhead;
\r
95 [Option("[Mono] Sets warning level (the highest is 4, the default)", "wlevel")]
\r
96 public int wlevel { set { RootContext.WarningLevel = value; } }
\r
98 [Option("[Mono] Makes errors fatal", "fatal")]
\r
99 public bool Fatal { set { Report.Fatal = value; } }
\r
101 // Output file options
\r
102 //------------------------------------------------------------------
\r
103 [Option("Specifies the output file name", 'o', "out")]
\r
104 public string output_file = null;
\r
106 [Option("Specifies the target type for the output file (exe [default], winexe, library, module)", "target")]
\r
107 public WhatToDoNext SetTarget(string type)
\r
109 switch (type.ToLower())
\r
112 target = Target.Library;
\r
113 target_ext = ".dll";
\r
117 target = Target.Exe;
\r
121 target = Target.WinExe;
\r
125 target = Target.Module;
\r
126 target_ext = ".dll";
\r
129 return WhatToDoNext.GoAhead;
\r
132 // input file options
\r
133 //------------------------------------------------------------------
\r
134 [Option("[NOT IMPLEMENTED YET]Reference metadata from specified module", "addmodule")]
\r
135 public string[] addedModules = null;
\r
137 [Option("[NOT IMPLEMENTED YET]Include all files in the current directory and subdirectories according to the wildcard", "recurse")]
\r
138 public WhatToDoNext recurse(string wildcard)
\r
140 //AddFiles (DirName, true); // TODO wrong semantics
\r
141 return WhatToDoNext.GoAhead;
\r
144 [Option(-1, "References metadata from the specified assembly", 'r', "reference")]
\r
145 public string reference { set { references.Add(value); } }
\r
147 // resource options
\r
148 //------------------------------------------------------------------
\r
149 public ArrayList EmbeddedResources = new ArrayList();
\r
151 // TODO : accept a multi-letter short form: 'res'
\r
152 [Option(-1, "Adds the specified file as an embedded assembly resource", "resource")]
\r
153 public string resource { set { EmbeddedResources.Add(value); } }
\r
155 public ArrayList LinkedResources = new ArrayList();
\r
157 // TODO : accept a multi-letter short form: 'linkres'
\r
158 [Option(-1, "[NOT IMPLEMENTED YET]Adds the specified file as an embedded assembly resource", "linkresource")]
\r
159 public string linkresource { set { LinkedResources.Add(value); } }
\r
161 public ArrayList Win32Resources = new ArrayList();
\r
163 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 resource file (.res)", "win32resource")]
\r
164 public string win32resource { set { Win32Resources.Add(value); } }
\r
166 public ArrayList Win32Icons = new ArrayList();
\r
168 // TODO : accept a multi-letter short form: 'res'
\r
169 [Option(-1, "[NOT IMPLEMENTED YET]Specifies a Win32 icon file (.ico) for the default Win32 resources", "win32icon")]
\r
170 public string win32icon { set { Win32Icons.Add(value); } }
\r
173 // code generation options
\r
174 //------------------------------------------------------------------
\r
175 [Option("[NOT IMPLEMENTED YET]Enable optimizations")]
\r
176 public bool optimize = false;
\r
178 [Option("[NOT IMPLEMENTED YET]Remove integer checks. Default off.")]
\r
179 public bool removeintchecks = false;
\r
181 // TODO: handle VB.NET [+|-] boolean syntax
\r
182 [Option("Emit debugging information", "debug")]
\r
183 public bool want_debugging_support = false;
\r
185 [Option("Emit full debugging information (default)", "debug:full")]
\r
186 public bool fullDebugging = false;
\r
188 [Option("[IGNORED]Emit PDB file only", "debug:pdbonly")]
\r
189 public bool pdbOnly = false;
\r
191 // errors and warnings options
\r
192 //------------------------------------------------------------------
\r
193 [Option("Treat warnings as errors", "warnaserror")]
\r
194 public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
\r
196 [Option("Disable warnings")]
\r
197 public bool nowarn { set { if (value) RootContext.WarningLevel = 0; } }
\r
200 // language options
\r
201 //------------------------------------------------------------------
\r
202 public Hashtable Defines = new Hashtable();
\r
204 // TODO: Symbol-List parsing
\r
205 [Option(-1, "[NOT IMPLEMENTED YET]Declares global conditional compilation symbol(s). symbol list:name=value,...", 'd', "define")]
\r
206 public string define {
\r
208 foreach(string item in value.Split(',')) {
\r
209 string[] dados = item.Split('=');
\r
210 if (dados.Length > 1)
\r
211 Defines.Add(dados[0], dados[1]);
\r
213 Defines.Add(dados[0], string.Empty);
\r
218 private string[] importsList = null;
\r
220 [Option("[NOT IMPLEMENTED YET]Declare global Imports for namespaces in referenced metadata files. import list:namespace,...", "imports")]
\r
221 public WhatToDoNext imports(string importslist)
\r
223 importsList = importslist.Split(';');
\r
224 return WhatToDoNext.GoAhead;
\r
227 // TODO: handle VB.NET [+|-] boolean syntax
\r
228 [Option("[NOT IMPLEMENTED YET]Require explicit declaration of variables")]
\r
229 public bool optionexplicit { set { Mono.MonoBASIC.Parser.InitialOptionExplicit = value; } }
\r
231 // TODO: handle VB.NET [+|-] boolean syntax
\r
232 [Option("[NOT IMPLEMENTED YET]Enforce strict language semantics")]
\r
233 public bool optionstrict { set { Mono.MonoBASIC.Parser.InitialOptionStrict = value; } }
\r
235 [Option("[NOT IMPLEMENTED YET]Specifies binary-style string comparisons. This is the default", "optioncompare:binary")]
\r
236 public bool optioncomparebinary { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = true; } }
\r
238 [Option("[NOT IMPLEMENTED YET]Specifies text-style string comparisons.", "optioncompare:text")]
\r
239 public bool optioncomparetext { set { Mono.MonoBASIC.Parser.InitialOptionCompareBinary = false; } }
\r
241 [Option("Specifies de root namespace for all type declarations")]
\r
242 public string rootnamespace { set { RootContext.RootNamespace = value; } }
\r
244 // Miscellaneous options
\r
245 //------------------------------------------------------------------
\r
247 [Option("[NOT IMPLEMENTED YET]Do not display compiler copyright banner")]
\r
248 public bool nologo = false;
\r
250 [Option("[NOT IMPLEMENTED YET]Quiet output mode")]
\r
251 public bool quiet = false;
\r
253 // TODO: semantics are different and should be adjusted
\r
254 [Option("Display verbose messages", 'v')]
\r
255 public bool verbose { set { GenericParser.yacc_verbose_flag = value; } }
\r
257 // Advanced options
\r
258 //------------------------------------------------------------------
\r
259 // TODO: force option to accept number in hex format
\r
260 [Option("[NOT IMPLEMENTED YET]The base address for a library or module (hex)")]
\r
261 public int baseaddress;
\r
263 [Option("[NOT IMPLEMENTED YET]Create bug report file")]
\r
264 public string bugreport;
\r
266 // TODO: handle VB.NET [+|-] boolean syntax
\r
267 [Option("[NOT IMPLEMENTED YET]Delay-sign the assembly using only the public portion of the strong name key")]
\r
268 public bool delaysign;
\r
270 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key container")]
\r
271 public string keycontainer;
\r
273 [Option("[NOT IMPLEMENTED YET]Specifies a strong name key file")]
\r
274 public string keyfile;
\r
276 public string[] libpath = null;
\r
278 [Option("List of directories to search for metada references (semi-colon delimited)", "libpath")]
\r
279 public WhatToDoNext setlibpath(string pathlist)
\r
281 libpath = pathlist.Split(';');
\r
282 return WhatToDoNext.GoAhead;
\r
285 [Option(@"Specifies the Class or Module that contains Sub Main.
\r
286 It can also be a Class that inherits from System.Windows.Forms.Form.",
\r
288 public string main { set { RootContext.MainClass = value; } }
\r
290 // TODO: handle VB.NET [+|-] boolean syntax
\r
291 [Option("[NOT IMPLEMENTED YET]Emit compiler output in UTF8 character encoding")]
\r
292 public bool utf8output;
\r
294 // TODO : response file support
\r
296 ArrayList defines = new ArrayList();
\r
297 ArrayList references = new ArrayList();
\r
298 ArrayList soft_references = new ArrayList();
\r
299 string first_source = null;
\r
300 Target target = Target.Exe;
\r
301 string target_ext = ".exe";
\r
302 ArrayList debug_arglist = new ArrayList ();
\r
303 bool timestamps = false;
\r
304 Hashtable source_files = new Hashtable ();
\r
305 bool load_default_config = true;
\r
308 // Last time we took the time
\r
310 DateTime last_time;
\r
311 void ShowTime (string msg)
\r
313 DateTime now = DateTime.Now;
\r
314 TimeSpan span = now - last_time;
\r
317 Console.WriteLine (
\r
318 "[{0:00}:{1:000}] {2}",
\r
319 (int) span.TotalSeconds, span.Milliseconds, msg);
\r
322 public static int Main (string[] args)
\r
324 Driver Exec = new Driver();
\r
326 return Exec.MainDriver(args);
\r
329 public int LoadAssembly (string assembly, bool soft)
\r
332 string total_log = "";
\r
336 char[] path_chars = { '/', '\\' };
\r
338 if (assembly.IndexOfAny (path_chars) != -1)
\r
339 a = Assembly.LoadFrom(assembly);
\r
341 a = Assembly.Load(assembly);
\r
342 TypeManager.AddAssembly (a);
\r
345 catch (FileNotFoundException)
\r
347 if (libpath != null)
\r
349 foreach (string dir in libpath)
\r
351 string full_path = dir + "/" + assembly + ".dll";
\r
355 a = Assembly.LoadFrom (full_path);
\r
356 TypeManager.AddAssembly (a);
\r
359 catch (FileNotFoundException ff)
\r
361 total_log += ff.FusionLog;
\r
369 catch (BadImageFormatException f)
\r
371 Error ("// Bad file format while loading assembly");
\r
372 Error ("Log: " + f.FusionLog);
\r
374 } catch (FileLoadException f){
\r
375 Error ("File Load Exception: " + assembly);
\r
376 Error ("Log: " + f.FusionLog);
\r
378 } catch (ArgumentNullException){
\r
379 Error ("// Argument Null exception ");
\r
383 Report.Error (6, "Can not find assembly `" + assembly + "'" );
\r
384 Console.WriteLine ("Log: \n" + total_log);
\r
389 void Error(string message)
\r
391 Console.WriteLine(message);
\r
395 /// Loads all assemblies referenced on the command line
\r
397 public int LoadReferences ()
\r
401 foreach (string r in references)
\r
402 errors += LoadAssembly (r, false);
\r
404 foreach (string r in soft_references)
\r
405 errors += LoadAssembly (r, true);
\r
410 void SetupDefaultDefines ()
\r
412 defines = new ArrayList ();
\r
413 defines.Add ("__MonoBASIC__");
\r
418 // Returns the directory where the system assemblies are installed
\r
420 string GetSystemDir ()
\r
422 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
\r
424 foreach (Assembly a in assemblies){
\r
425 string codebase = a.CodeBase;
\r
426 if (codebase.EndsWith ("corlib.dll")){
\r
427 return codebase.Substring (0, codebase.LastIndexOf ("/"));
\r
431 Report.Error (-15, "Can not compute my system path");
\r
436 // Given a path specification, splits the path from the file/pattern
\r
438 void SplitPathAndPattern (string spec, out string path, out string pattern)
\r
440 int p = spec.LastIndexOf ("/");
\r
443 // Windows does not like /file.cs, switch that to:
\r
448 pattern = spec.Substring (1);
\r
450 path = spec.Substring (0, p);
\r
451 pattern = spec.Substring (p + 1);
\r
456 p = spec.LastIndexOf ("\\");
\r
458 path = spec.Substring (0, p);
\r
459 pattern = spec.Substring (p + 1);
\r
467 bool AddFiles (string spec, bool recurse)
\r
469 string path, pattern;
\r
471 SplitPathAndPattern(spec, out path, out pattern);
\r
472 if (pattern.IndexOf("*") == -1)
\r
478 string [] files = null;
\r
480 files = Directory.GetFiles(path, pattern);
\r
481 } catch (System.IO.DirectoryNotFoundException) {
\r
482 Report.Error (2001, "Source file `" + spec + "' could not be found");
\r
484 } catch (System.IO.IOException){
\r
485 Report.Error (2001, "Source file `" + spec + "' could not be found");
\r
488 foreach (string f in files)
\r
494 string [] dirs = null;
\r
497 dirs = Directory.GetDirectories(path);
\r
501 foreach (string d in dirs) {
\r
503 // Don't include path in this string, as each
\r
504 // directory entry already does
\r
505 AddFiles (d + "/" + pattern, true);
\r
511 void DefineDefaultConfig ()
\r
514 // For now the "default config" is harcoded into the compiler
\r
515 // we can move this outside later
\r
517 string [] default_config =
\r
522 "Microsoft.VisualBasic" ,
\r
523 #if EXTRA_DEFAULT_REFS
\r
525 // Is it worth pre-loading all this stuff?
\r
528 "System.Configuration.Install",
\r
530 "System.DirectoryServices",
\r
531 "System.Drawing.Design",
\r
533 "System.EnterpriseServices",
\r
534 "System.Management",
\r
535 "System.Messaging",
\r
536 "System.Runtime.Remoting",
\r
537 "System.Runtime.Serialization.Formatters.Soap",
\r
539 "System.ServiceProcess",
\r
541 "System.Web.RegularExpressions",
\r
542 "System.Web.Services" ,
\r
543 "System.Windows.Forms"
\r
547 foreach (string def in default_config)
\r
548 soft_references.Add(def);
\r
551 [ArgumentProcessor]
\r
552 public void AddFile(string fileName)
\r
554 string f = fileName;
\r
555 if (first_source == null)
\r
558 if (source_files.Contains(f))
\r
559 Report.Error(1516, "Source file '" + f + "' specified multiple times");
\r
561 source_files.Add(f, f);
\r
564 void ProcessSourceFile(string filename)
\r
567 GenericParser.Tokenize(filename);
\r
569 GenericParser.Parse(filename);
\r
572 string outputFile_Name = null;
\r
574 string outputFileName
\r
578 if (outputFile_Name == null)
\r
580 if (output_file == null)
\r
582 int pos = first_source.LastIndexOf(".");
\r
585 output_file = first_source.Substring(0, pos);
\r
587 output_file = first_source;
\r
589 string bname = CodeGen.Basename(output_file);
\r
590 if (bname.IndexOf(".") == -1)
\r
591 output_file += target_ext;
\r
592 outputFile_Name = output_file;
\r
594 return outputFile_Name;
\r
599 /// Parses the arguments, and calls the compilation process.
\r
601 int MainDriver(string [] args)
\r
604 if (first_source == null)
\r
612 if (Report.Errors == 0)
\r
614 Console.Write("Compilation succeeded");
\r
615 if (Report.Warnings > 0)
\r
617 Console.Write(" - {0} warning(s)", Report.Warnings);
\r
619 Console.WriteLine();
\r
622 Console.WriteLine("Compilation failed: {0} Error(s), {1} warnings",
\r
623 Report.Errors, Report.Warnings);
\r
629 SetupDefaultDefines();
\r
632 bool ParseAll() // Phase 1
\r
634 if (first_source == null)
\r
636 Report.Error(2008, "No files to compile were specified");
\r
640 foreach(string filename in source_files.Values)
\r
641 ProcessSourceFile(filename);
\r
643 if (tokenize || parse_only || (Report.Errors > 0))
\r
646 return true; // everything went well go ahead
\r
649 void InitializeDebuggingSupport()
\r
651 string[] debug_args = new string [debug_arglist.Count];
\r
652 debug_arglist.CopyTo(debug_args);
\r
653 CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
\r
654 TypeManager.AddModule(CodeGen.ModuleBuilder);
\r
657 public bool ResolveAllTypes() // Phase 2
\r
659 // Load Core Library for default compilation
\r
660 if (RootContext.StdLib)
\r
661 references.Insert(0, "mscorlib");
\r
663 if (load_default_config)
\r
664 DefineDefaultConfig();
\r
667 ShowTime("Loading references");
\r
669 // Load assemblies required
\r
670 if (LoadReferences() > 0)
\r
672 Error ("Could not load one or more assemblies");
\r
677 ShowTime("References loaded");
\r
679 InitializeDebuggingSupport();
\r
682 // Before emitting, we need to get the core
\r
683 // types emitted from the user defined types
\r
684 // or from the system ones.
\r
687 ShowTime ("Initializing Core Types");
\r
689 if (!RootContext.StdLib)
\r
690 RootContext.ResolveCore ();
\r
691 if (Report.Errors > 0)
\r
694 TypeManager.InitCoreTypes();
\r
695 if (Report.Errors > 0)
\r
699 ShowTime (" Core Types done");
\r
702 ShowTime ("Resolving tree");
\r
704 // The second pass of the compiler
\r
705 RootContext.ResolveTree ();
\r
706 if (Report.Errors > 0)
\r
710 ShowTime ("Populate tree");
\r
712 if (!RootContext.StdLib)
\r
713 RootContext.BootCorlib_PopulateCoreTypes();
\r
714 if (Report.Errors > 0)
\r
717 RootContext.PopulateTypes();
\r
718 if (Report.Errors > 0)
\r
721 TypeManager.InitCodeHelpers();
\r
722 if (Report.Errors > 0)
\r
730 bool hasSWF = false, isForm = false;
\r
731 string mainclass = GetFQMainClass();
\r
733 foreach (string r in references) {
\r
734 if (r.IndexOf ("System.Windows.Forms") >= 0) {
\r
739 if (mainclass != ".") {
\r
740 Type t = TypeManager.LookupType(mainclass);
\r
742 isForm = t.IsSubclassOf (TypeManager.LookupType("System.Windows.Forms.Form"));
\r
744 return (hasSWF && isForm);
\r
747 string GetFQMainClass()
\r
749 if (RootContext.RootNamespace != "")
\r
750 return RootContext.RootNamespace + "." + RootContext.MainClass;
\r
752 return RootContext.MainClass;
\r
755 void FixEntryPoint()
\r
757 if (target == Target.Exe || target == Target.WinExe)
\r
759 MethodInfo ep = RootContext.EntryPoint;
\r
763 // If we don't have a valid entry point yet
\r
764 // AND if System.Windows.Forms is included
\r
765 // among the dependencies, we have to build
\r
766 // a new entry point on-the-fly. Otherwise we
\r
767 // won't be able to compile SWF code out of the box.
\r
771 Type t = TypeManager.LookupType(GetFQMainClass());
\r
774 TypeBuilder tb = t as TypeBuilder;
\r
775 MethodBuilder mb = tb.DefineMethod ("Main", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
\r
776 typeof(void), new Type[0]);
\r
778 Type SWFA = TypeManager.LookupType("System.Windows.Forms.Application");
\r
779 Type SWFF = TypeManager.LookupType("System.Windows.Forms.Form");
\r
780 Type[] args = new Type[1];
\r
782 MethodInfo mi = SWFA.GetMethod("Run", args);
\r
783 ILGenerator ig = mb.GetILGenerator();
\r
784 ConstructorInfo ci = TypeManager.GetConstructor (TypeManager.LookupType(t.FullName), new Type[0]);
\r
786 ig.Emit (OpCodes.Newobj, ci);
\r
787 ig.Emit (OpCodes.Call, mi);
\r
788 ig.Emit (OpCodes.Ret);
\r
790 RootContext.EntryPoint = mb as MethodInfo;
\r
797 bool GenerateAssembly()
\r
800 // The code generator
\r
803 ShowTime ("Emitting code");
\r
807 RootContext.EmitCode();
\r
809 if (Report.Errors > 0)
\r
813 ShowTime (" done");
\r
817 ShowTime ("Closing types");
\r
819 RootContext.CloseTypes ();
\r
820 if (Report.Errors > 0)
\r
824 ShowTime (" done");
\r
826 PEFileKinds k = PEFileKinds.ConsoleApplication;
\r
828 if (target == Target.Library || target == Target.Module)
\r
829 k = PEFileKinds.Dll;
\r
830 else if (target == Target.Exe)
\r
831 k = PEFileKinds.ConsoleApplication;
\r
832 else if (target == Target.WinExe)
\r
833 k = PEFileKinds.WindowApplication;
\r
835 if (target == Target.Exe || target == Target.WinExe)
\r
837 MethodInfo ep = RootContext.EntryPoint;
\r
841 Report.Error (5001, "Program " + outputFileName +
\r
842 " does not have an entry point defined");
\r
846 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
\r
849 // Add the resources
\r
850 if (EmbeddedResources != null)
\r
851 foreach (string file in EmbeddedResources)
\r
852 CodeGen.AssemblyBuilder.AddResourceFile (file, file);
\r
854 CodeGen.Save(outputFileName);
\r
857 ShowTime ("Saved output");
\r
860 if (want_debugging_support)
\r
862 CodeGen.SaveSymbols ();
\r
864 ShowTime ("Saved symbols");
\r
870 public void CompileAll()
\r
873 VB.NET expects the default namespace to be "" (empty string)
\r
875 if (RootContext.RootNamespace == "")
\r
877 RootContext.RootNamespace = System.IO.Path.GetFileNameWithoutExtension(outputFileName);
\r
880 if (!ParseAll()) // Phase 1
\r
883 if (!ResolveAllTypes()) // Phase 2
\r
886 if (!GenerateAssembly()) // Phase 3
\r
889 if (Report.ExpectedError != 0)
\r
890 Error("Failed to report expected Error " + Report.ExpectedError);
\r