2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / ScriptCompilerInfo.cs
index 52b2e726d95e2504a177bb8dbed7ac88d35c60ae..87438fa2bb0b218fb77e334ca631b7756a45da82 100755 (executable)
@@ -6,6 +6,27 @@
 //
 // (C)2003 Novell inc.
 //
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 using System;
 using System.CodeDom;
 using System.CodeDom.Compiler;
@@ -20,6 +41,8 @@ using System.Xml;
 using System.Xml.Schema;
 using System.Xml.XPath;
 using System.Xml.Xsl;
+using Microsoft.CSharp;
+using Microsoft.VisualBasic;
 
 namespace Mono.Xml.Xsl
 {
@@ -38,6 +61,8 @@ namespace Mono.Xml.Xsl
                        set { defaultCompilerOptions = value; }
                }
 
+               public abstract CodeDomProvider CodeDomProvider { get; }
+
                public abstract string Extension { get; }
 
                public abstract string SourceTemplate { get; }
@@ -47,51 +72,58 @@ namespace Mono.Xml.Xsl
                        return String.Concat (DefaultCompilerOptions, " ", targetFileName);
                }
 
-               [MonoTODO ("Should use Assembly.LoadFile() instead of LoadFrom() after its implementation has finished.")]
+
                public virtual Type GetScriptClass (string code, string classSuffix, XPathNavigator scriptNode, Evidence evidence)
                {
-                       string tmpPath = Path.GetTempPath ();
-                       if (!tmpPath.EndsWith (Path.DirectorySeparatorChar.ToString ()))
-                               tmpPath += Path.DirectorySeparatorChar;
-                       string tmpbase = tmpPath + Guid.NewGuid ();
-                       ProcessStartInfo psi = new ProcessStartInfo ();
-                       psi.UseShellExecute = false;
-                       psi.RedirectStandardError = true;
-                       psi.RedirectStandardOutput = true;
-                       Process proc = new Process ();
-                       proc.StartInfo = psi;
-                       StreamWriter sw = null;
+                       PermissionSet ps = SecurityManager.ResolvePolicy (evidence);
+                       if (ps != null)
+                               ps.Demand ();
+
+                       ICodeCompiler compiler = CodeDomProvider.CreateCompiler ();
+                       CompilerParameters parameters = new CompilerParameters ();
+                       parameters.CompilerOptions = DefaultCompilerOptions;
+
+                       // get source filename
+                       string filename = String.Empty;
                        try {
-                               PermissionSet ps = SecurityManager.ResolvePolicy (evidence);
-                               if (ps != null)
-                                       ps.Demand ();
-                               sw = File.CreateText (tmpbase + Extension);
-                               sw.WriteLine (SourceTemplate.Replace ("{0}", DateTime.Now.ToString ()).Replace ("{1}", classSuffix).Replace ("{2}", code));
-
-                               sw.Close ();
-                               psi.FileName = CompilerCommand;
-                               psi.Arguments = String.Concat (GetCompilerArguments (tmpbase + Extension));
-                               psi.WorkingDirectory = tmpPath;
-                               proc.Start ();
-//                             Console.WriteLine (proc.StandardOutput.ReadToEnd ());
-//                             Console.WriteLine (proc.StandardError.ReadToEnd ());
-                               proc.WaitForExit (); // FIXME: should we configure timeout?
-                               Assembly generated = Assembly.LoadFrom (tmpbase + ".dll");
-
-                               if (generated == null)
-                                       throw new XsltCompileException ("Could not load script assembly", null, scriptNode);
-                               return generated.GetType ("GeneratedAssembly.Script" + classSuffix);
-                       } catch (Exception ex) {
-                               throw new XsltCompileException ("Script compilation error: " + ex.Message, ex, scriptNode);
-                       } finally {
-                               try {
-                                       File.Delete (tmpbase + Extension);
-                                       File.Delete (tmpbase + ".dll");
-                                       if (sw != null)
-                                               sw.Close ();
-                               } catch (Exception) {
-                               }
+                               if (scriptNode.BaseURI != String.Empty)
+                                       filename = new Uri (scriptNode.BaseURI).LocalPath;
+                       } catch (FormatException) {
+                       }
+                       if (filename == String.Empty)
+                               filename = "__baseURI_not_supplied__";
+
+                       // get source location
+                       IXmlLineInfo li = scriptNode as IXmlLineInfo;
+                       string lineInfoLine = 
+                               li != null && li.LineNumber > 0 ?
+                               String.Format (CultureInfo.InvariantCulture, "\n#line {0} \"{1}\"", li.LineNumber, filename) :
+                               String.Empty;
+
+                       string source = SourceTemplate.Replace ("{0}", DateTime.Now.ToString ()).Replace ("{1}", classSuffix).Replace ("{2}", lineInfoLine + code);
+
+                       CompilerResults res = compiler.CompileAssemblyFromSource (parameters, source);
+                       if (res.Errors.Count != 0)
+                               throw new XsltCompileException ("Stylesheet script compile error: \n" + FormatErrorMessage (res) /*+ "Code :\n" + source*/, null, scriptNode);
+                       if (res.CompiledAssembly == null)
+                               throw new XsltCompileException ("Cannot compile stylesheet script", null, scriptNode);
+                       return res.CompiledAssembly.GetType ("GeneratedAssembly.Script" + classSuffix);
+               }
+
+               private string FormatErrorMessage (CompilerResults res)
+               {
+                       string s = String.Empty;
+                       foreach (CompilerError e in res.Errors) {
+                               object [] parameters = new object [] {"\n",
+                                       e.FileName,
+                                       e.Line > 0 ? " line " + e.Line : String.Empty,
+                                       e.IsWarning ? " WARNING: " : " ERROR: ",
+                                       e.ErrorNumber,
+                                       ": ",
+                                       e.ErrorText};
+                               s += String.Concat (parameters);
                        }
+                       return s;
                }
        }
 
@@ -103,9 +135,13 @@ namespace Mono.Xml.Xsl
 #if MS_NET
                        this.CompilerCommand = "csc.exe";
 #endif
-                       this.DefaultCompilerOptions = "/t:library /r:Microsoft.VisualBasic.dll";
+                       this.DefaultCompilerOptions = "/t:library /r:System.dll /r:System.Xml.dll /r:Microsoft.VisualBasic.dll";
                }
 
+               public override CodeDomProvider CodeDomProvider {\r
+                       get { return new CSharpCodeProvider (); }\r
+               }\r
+
                public override string Extension {
                        get { return ".cs"; }
                }
@@ -145,6 +181,10 @@ public class Script{1}
                        this.DefaultCompilerOptions = "/t:library  /r:System.dll /r:System.XML.dll /r:Microsoft.VisualBasic.dll";
                }
 
+               public override CodeDomProvider CodeDomProvider {\r
+                       get { return new VBCodeProvider (); }\r
+               }\r
+
                public override string Extension {
                        get { return ".vb"; }
                }
@@ -174,15 +214,29 @@ end namespace
 
        internal class JScriptCompilerInfo : ScriptCompilerInfo
        {
+               static Type providerType;
+
                public JScriptCompilerInfo ()
                {
-                       this.CompilerCommand = "dummy-jscript-compiler.exe";
+                       this.CompilerCommand = "mjs";
 #if MS_NET
                        this.CompilerCommand = "jsc.exe";
 #endif
                        this.DefaultCompilerOptions = "/t:library /r:Microsoft.VisualBasic.dll";
                }
 
+               public override CodeDomProvider CodeDomProvider {
+                       get {
+                               // no need for locking
+                               if (providerType == null) {
+                                       Assembly jsasm = Assembly.LoadWithPartialName ("Microsoft.JScript", null);
+                                       if (jsasm != null)
+                                               providerType = jsasm.GetType ("Microsoft.JScript.JScriptCodeProvider");
+                               }
+                               return (CodeDomProvider) Activator.CreateInstance (providerType); 
+                       }
+               }
+
                public override string Extension {
                        get { return ".js"; }
                }
@@ -209,26 +263,6 @@ class Script{1} {
 ";
                        }
                }
-
-#if !MS_NET
-               public override Type GetScriptClass (string code, string classSuffix, XPathNavigator scriptNode, Evidence evidence)
-               {
-                       PermissionSet ps = SecurityManager.ResolvePolicy (evidence);
-                       if (ps != null)
-                               ps.Demand ();
-                       Assembly jsasm = Assembly.LoadWithPartialName ("Microsoft.JScript.dll", evidence);
-                       Type providerType = jsasm.GetType ("Microsoft.JScript.JScriptCodeProvider");
-                       CodeDomProvider provider = (CodeDomProvider) Activator.CreateInstance (providerType);
-
-                       ICodeCompiler compiler = provider.CreateCompiler ();
-                       CompilerParameters parameters = new CompilerParameters ();
-                       parameters.CompilerOptions = DefaultCompilerOptions;
-                       CompilerResults res = compiler.CompileAssemblyFromSource (parameters, SourceTemplate.Replace ("{0}", DateTime.Now.ToString ()).Replace ("{1}", classSuffix).Replace ("{2}", code));
-                       if (res.CompiledAssembly == null)
-                               throw new XsltCompileException ("Cannot compile stylesheet script", null, scriptNode);
-                       return res.CompiledAssembly.GetType ("GeneratedAssembly.Script" + classSuffix);
-               }
-#endif
        }
 }