* CodeGeneratorFromExpressionTest.cs: Added test for
[mono.git] / mcs / class / System / Microsoft.CSharp / CSharpCodeCompiler.cs
index 7e5627941b751d78e2559f1c4cb16430569a3c37..986e2bd47301df983db04f72403409b01d8fd6ec 100644 (file)
@@ -50,8 +50,6 @@ namespace Mono.CSharp
                static CSharpCodeCompiler ()
                {
                        if (Path.DirectorySeparatorChar == '\\') {
-                               // FIXME: right now we use "fixed" version 1.0
-                               // mcs at any time.
                                PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static|BindingFlags.NonPublic);
                                MethodInfo get_gac = gac.GetGetMethod (true);
                                string p = Path.GetDirectoryName (
@@ -65,8 +63,13 @@ namespace Mono.CSharp
                                                Path.GetDirectoryName (
                                                        Path.GetDirectoryName (p)),
                                                "bin\\mono.exe");
+#if NET_2_0
+                               windowsMcsPath =
+                                       Path.Combine (p, "2.0\\gmcs.exe");
+#else
                                windowsMcsPath =
                                        Path.Combine (p, "1.0\\mcs.exe");
+#endif
                        }
                }
 
@@ -80,48 +83,61 @@ namespace Mono.CSharp
                //
                // Methods
                //
-               [MonoTODO]
-               public CompilerResults CompileAssemblyFromDom (
-                       CompilerParameters options,CodeCompileUnit e)
+               public CompilerResults CompileAssemblyFromDom (CompilerParameters options, CodeCompileUnit e)
                {
-                       return CompileAssemblyFromDomBatch(options,new CodeCompileUnit[]{e});
+                       return CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { e });
                }
-               public CompilerResults CompileAssemblyFromDomBatch (
-                       CompilerParameters options,CodeCompileUnit[] ea)
-               {
-                       string[] fileNames=new string[ea.Length];
-                       int i=0;
-                       if (options == null)
-                               options = new CompilerParameters ();
-                       
-                       StringCollection assemblies = options.ReferencedAssemblies;
 
-                       foreach (CodeCompileUnit e in ea) {
-                               fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, i.ToString () + ".cs");
-                               FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
-                               StreamWriter s=new StreamWriter(f, Encoding.UTF8);
-                               if (e.ReferencedAssemblies != null) {
-                                       foreach (string str in e.ReferencedAssemblies) {
-                                               if (!assemblies.Contains (str))
-                                                       assemblies.Add (str);
-                                       }
-                               }
+               public CompilerResults CompileAssemblyFromDomBatch (CompilerParameters options, CodeCompileUnit[] ea)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
 
-                               ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());
-                               s.Close();
-                               f.Close();
-                               i++;
+                       try {
+                               return CompileFromDomBatch (options, ea);
+                       } finally {
+                               options.TempFiles.Delete ();
                        }
-                       return CompileAssemblyFromFileBatch (options, fileNames);
                }
-               
-               public CompilerResults CompileAssemblyFromFile (
-                       CompilerParameters options,string fileName)
+
+               public CompilerResults CompileAssemblyFromFile (CompilerParameters options, string fileName)
                {
-                       return CompileAssemblyFromFileBatch (options, new string []{fileName});
+                       return CompileAssemblyFromFileBatch (options, new string[] { fileName });
                }
 
                public CompilerResults CompileAssemblyFromFileBatch (CompilerParameters options, string[] fileNames)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       try {
+                               return CompileFromFileBatch (options, fileNames);
+                       } finally {
+                               options.TempFiles.Delete ();
+                       }
+               }
+
+               public CompilerResults CompileAssemblyFromSource (CompilerParameters options, string source)
+               {
+                       return CompileAssemblyFromSourceBatch (options, new string[] { source });
+               }
+
+               public CompilerResults CompileAssemblyFromSourceBatch (CompilerParameters options, string[] sources)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       try {
+                               return CompileFromSourceBatch (options, sources);
+                       } finally {
+                               options.TempFiles.Delete ();
+                       }
+               }
+
+               private CompilerResults CompileFromFileBatch (CompilerParameters options, string[] fileNames)
                {
                        if (null == options)
                                throw new ArgumentNullException("options");
@@ -136,9 +152,8 @@ namespace Mono.CSharp
                        // FIXME: these lines had better be platform independent.
                        if (Path.DirectorySeparatorChar == '\\') {
                                mcs.StartInfo.FileName = windowsMonoPath;
-                               mcs.StartInfo.Arguments = windowsMcsPath + ' ' + BuildArgs (options, fileNames);
-                       }
-                       else {
+                               mcs.StartInfo.Arguments = "\"" + windowsMcsPath + "\" " + BuildArgs (options, fileNames);
+                       } else {
 #if NET_2_0
                                // FIXME: This is a temporary hack to make code genaration work in 2.0
                                mcs.StartInfo.FileName="gmcs";
@@ -150,12 +165,15 @@ namespace Mono.CSharp
                        mcs.StartInfo.CreateNoWindow=true;
                        mcs.StartInfo.UseShellExecute=false;
                        mcs.StartInfo.RedirectStandardOutput=true;
+                       mcs.StartInfo.RedirectStandardError=true;
                        try {
                                mcs.Start();
-                               mcs_output=mcs.StandardOutput.ReadToEnd();
+                               // If there are a few kB in stdout, we might lock
+                               mcs_output=mcs.StandardError.ReadToEnd();
+                               mcs.StandardOutput.ReadToEnd ();
                                mcs.WaitForExit();
-                       } finally {
                                results.NativeCompilerReturnValue = mcs.ExitCode;
+                       } finally {
                                mcs.Close();
                        }
                        mcs_output_lines=mcs_output.Split(
@@ -170,35 +188,24 @@ namespace Mono.CSharp
                                        if (!error.IsWarning) loadIt=false;
                                }
                        }
-                       if (loadIt)
-                               results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);
-                       else
-                               results.CompiledAssembly=null;
+                       if (loadIt) {
+                               if (options.GenerateInMemory) {
+                                       using (FileStream fs = File.OpenRead(options.OutputAssembly)) {
+                                               byte[] buffer = new byte[fs.Length];
+                                               fs.Read(buffer, 0, buffer.Length);
+                                               results.CompiledAssembly = Assembly.Load(buffer, null, options.Evidence);
+                                               fs.Close();
+                                       }
+                               } else {
+                                       results.CompiledAssembly = Assembly.LoadFrom(options.OutputAssembly);
+                                       results.PathToAssembly = options.OutputAssembly;
+                               }
+                       } else {
+                               results.CompiledAssembly = null;
+                       }
 
                        return results;
                }
-               public CompilerResults CompileAssemblyFromSource (
-                       CompilerParameters options,string source)
-               {
-                       return CompileAssemblyFromSourceBatch(options,new string[]{source});
-               }
-               public CompilerResults CompileAssemblyFromSourceBatch (
-                       CompilerParameters options,string[] sources)
-               {
-                       string[] fileNames=new string[sources.Length];
-                       int i=0;
-                       foreach (string source in sources) {
-                               fileNames [i] = GetTempFileNameWithExtension (options.TempFiles, i.ToString () + ".cs");
-                               FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);
-                               StreamWriter s=new StreamWriter(f);
-                               s.Write(source);
-                               s.Close();
-                               f.Close();
-                               i++;
-                       }
-                       return CompileAssemblyFromFileBatch (options, fileNames);
-               }
-
 
                private static string BuildArgs(CompilerParameters options,string[] fileNames)
                {
@@ -208,6 +215,10 @@ namespace Mono.CSharp
                        else
                                args.Append("/target:library ");
 
+                       if (options.Win32Resource != null)
+                               args.AppendFormat("/win32res:\"{0}\" ",
+                                       options.Win32Resource);
+
                        if (options.IncludeDebugInformation)
                                args.Append("/debug+ /optimize- ");
                        else
@@ -220,7 +231,7 @@ namespace Mono.CSharp
                                args.AppendFormat ("/warn:{0} ", options.WarningLevel);
 
                        if (options.OutputAssembly==null)
-                               options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, "dll");
+                               options.OutputAssembly = GetTempFileNameWithExtension (options.TempFiles, "dll", !options.GenerateInMemory);
                        args.AppendFormat("/out:\"{0}\" ",options.OutputAssembly);
 
                        if (null != options.ReferencedAssemblies)
@@ -241,12 +252,15 @@ namespace Mono.CSharp
                }
                private static CompilerError CreateErrorFromString(string error_string)
                {
-                       // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
-                       if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))
+#if NET_2_0
+                       if (error_string.StartsWith ("BETA"))
+                               return null;
+#endif
+                       if (error_string == null || error_string == "")
                                return null;
 
                        CompilerError error=new CompilerError();
-                       Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
+                       Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)(:)?\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
                                RegexOptions.Compiled | RegexOptions.ExplicitCapture);
                        Match match=reg.Match(error_string);
                        if (!match.Success) return null;
@@ -256,16 +270,82 @@ namespace Mono.CSharp
                                error.Line=Int32.Parse(match.Result("${line}"));
                        if (String.Empty != match.Result("${column}"))
                                error.Column=Int32.Parse(match.Result("${column}"));
-                       if (match.Result("${level}")=="warning")
-                               error.IsWarning=true;
+
+                       string level = match.Result ("${level}");
+                       if (level == "warning")
+                               error.IsWarning = true;
+                       else if (level != "error")
+                               return null; // error CS8028 will confuse the regex.
+
                        error.ErrorNumber=match.Result("${number}");
                        error.ErrorText=match.Result("${message}");
                        return error;
                }
 
-               static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)
+               private static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension, bool keepFile)
+               {
+                       return temp_files.AddExtension (extension, keepFile);
+               }
+
+               private static string GetTempFileNameWithExtension (TempFileCollection temp_files, string extension)
                {
                        return temp_files.AddExtension (extension);
                }
+
+               private CompilerResults CompileFromDomBatch (CompilerParameters options, CodeCompileUnit[] ea)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       if (ea == null) {
+                               throw new ArgumentNullException ("ea");
+                       }
+
+                       string[] fileNames = new string[ea.Length];
+                       StringCollection assemblies = options.ReferencedAssemblies;
+
+                       for (int i = 0; i < ea.Length; i++) {
+                               CodeCompileUnit compileUnit = ea[i];
+                               fileNames[i] = GetTempFileNameWithExtension (options.TempFiles, i + ".cs");
+                               FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+                               StreamWriter s = new StreamWriter (f, Encoding.UTF8);
+                               if (compileUnit.ReferencedAssemblies != null) {
+                                       foreach (string str in compileUnit.ReferencedAssemblies) {
+                                               if (!assemblies.Contains (str))
+                                                       assemblies.Add (str);
+                                       }
+                               }
+
+                               ((ICodeGenerator) this).GenerateCodeFromCompileUnit (compileUnit, s, new CodeGeneratorOptions ());
+                               s.Close ();
+                               f.Close ();
+                       }
+                       return CompileAssemblyFromFileBatch (options, fileNames);
+               }
+
+               private CompilerResults CompileFromSourceBatch (CompilerParameters options, string[] sources)
+               {
+                       if (options == null) {
+                               throw new ArgumentNullException ("options");
+                       }
+
+                       if (sources == null) {
+                               throw new ArgumentNullException ("sources");
+                       }
+
+                       string[] fileNames = new string[sources.Length];
+
+                       for (int i = 0; i < sources.Length; i++) {
+                               fileNames[i] = GetTempFileNameWithExtension (options.TempFiles, i + ".cs");
+                               FileStream f = new FileStream (fileNames[i], FileMode.OpenOrCreate);
+                               using (StreamWriter s = new StreamWriter (f, Encoding.UTF8)) {
+                                       s.Write (sources[i]);
+                                       s.Close ();
+                               }
+                               f.Close ();
+                       }
+                       return CompileFromFileBatch (options, fileNames);
+               }
        }
 }