BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / ScriptCompilerInfo.cs
1 //
2 // MSXslScriptManager.cs
3 //
4 // Author:
5 //      Atsushi Enomoto (atsushi@ximian.com)
6 //
7 // (C)2003 Novell inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.CodeDom;
32 using System.CodeDom.Compiler;
33 using System.Diagnostics;
34 using System.Collections;
35 using System.Globalization;
36 using System.IO;
37 using System.Reflection;
38 using System.Security;
39 using System.Security.Policy;
40 using System.Xml;
41 using System.Xml.Schema;
42 using System.Xml.XPath;
43 using System.Xml.Xsl;
44 using Microsoft.CSharp;
45 using Microsoft.VisualBasic;
46
47 namespace Mono.Xml.Xsl
48 {
49         internal abstract class ScriptCompilerInfo
50         {
51                 string compilerCommand;
52                 string defaultCompilerOptions;
53
54                 public virtual string CompilerCommand {
55                         get { return compilerCommand; }
56                         set { compilerCommand = value; }
57                 }
58
59                 public virtual string DefaultCompilerOptions {
60                         get { return defaultCompilerOptions; }
61                         set { defaultCompilerOptions = value; }
62                 }
63
64                 public abstract CodeDomProvider CodeDomProvider { get; }
65
66                 public abstract string Extension { get; }
67
68                 public abstract string SourceTemplate { get; }
69
70                 public abstract string FormatSource (IXmlLineInfo li, string file, string code);
71
72                 public virtual string GetCompilerArguments (string targetFileName)
73                 {
74                         return String.Concat (DefaultCompilerOptions, " ", targetFileName);
75                 }
76
77
78                 public virtual Type GetScriptClass (string code, string classSuffix, XPathNavigator scriptNode, Evidence evidence)
79                 {
80                         PermissionSet ps = SecurityManager.ResolvePolicy (evidence);
81                         if (ps != null)
82                                 ps.Demand ();
83
84                         // The attempt to use an already pre-compiled
85                         // class assumes the caller has computed the
86                         // classSuffix as a hash of the code
87                         // string. MSXslScriptManager.cs does that.
88                         // The mechanism how exactly such pre-compiled
89                         // classes should be produced are not
90                         // specified here.
91                         string scriptname = "Script" + classSuffix;
92                         string typename = "GeneratedAssembly." + scriptname;
93                         try {
94                                 Type retval = Type.GetType (typename);
95                                 if (retval != null)
96                                         return retval;
97                         } catch {
98                         }
99
100                         try {
101                                 Type retval =  Assembly.LoadFrom (scriptname + ".dll").GetType (typename);
102                                 if (retval != null)
103                                         return retval;
104                         } catch {
105                         }
106
107                         // OK, we have to actually compile the script.
108                         ICodeCompiler compiler = CodeDomProvider.CreateCompiler ();
109                         CompilerParameters parameters = new CompilerParameters ();
110                         parameters.CompilerOptions = DefaultCompilerOptions;
111
112                         // get source filename
113                         string filename = String.Empty;
114                         try {
115                                 if (scriptNode.BaseURI != String.Empty)
116                                         filename = new Uri (scriptNode.BaseURI).LocalPath;
117                         } catch (FormatException) {
118                         }
119                         if (filename == String.Empty)
120                                 filename = "__baseURI_not_supplied__";
121
122                         // get source location
123                         IXmlLineInfo li = scriptNode as IXmlLineInfo;
124
125                         string source = SourceTemplate.Replace ("{0}",
126                                 DateTime.Now.ToString (CultureInfo.InvariantCulture))
127                                 .Replace ("{1}", classSuffix)
128                                 .Replace ("{2}", code);
129                         source = FormatSource (li, filename, source);
130
131                         CompilerResults res = compiler.CompileAssemblyFromSource (parameters, source);
132                         foreach (CompilerError err in res.Errors)
133                                 if (!err.IsWarning)
134                                         // Actually it should be
135                                         // XsltCompileException, but to match 
136                                         // with silly MS implementation...
137 //                                      throw new XsltCompileException ("Stylesheet script compile error: \n" + FormatErrorMessage (res) /*+ "Code :\n" + source*/, null, scriptNode);
138                                         throw new XsltException ("Stylesheet script compile error: \n" + FormatErrorMessage (res) /*+ "Code :\n" + source*/, null, scriptNode);
139
140                         if (res.CompiledAssembly == null)
141                                 throw new XsltCompileException ("Cannot compile stylesheet script", null, scriptNode);
142                         return res.CompiledAssembly.GetType (typename);
143                 }
144
145                 private string FormatErrorMessage (CompilerResults res)
146                 {
147                         string s = String.Empty;
148                         foreach (CompilerError e in res.Errors) {
149                                 object [] parameters = new object [] {"\n",
150                                         e.FileName,
151                                         e.Line > 0 ? " line " + e.Line : String.Empty,
152                                         e.IsWarning ? " WARNING: " : " ERROR: ",
153                                         e.ErrorNumber,
154                                         ": ",
155                                         e.ErrorText};
156                                 s += String.Concat (parameters);
157                         }
158                         return s;
159                 }
160         }
161
162         internal class CSharpCompilerInfo : ScriptCompilerInfo
163         {
164                 public CSharpCompilerInfo ()
165                 {
166                         this.CompilerCommand = "mcs";
167 #if MS_NET
168                         this.CompilerCommand = "csc.exe";
169 #endif
170                         this.DefaultCompilerOptions = "/t:library /r:System.dll /r:System.Xml.dll /r:Microsoft.VisualBasic.dll";
171                 }
172
173                 public override CodeDomProvider CodeDomProvider {
174                         get { return new CSharpCodeProvider (); }
175                 }
176
177                 public override string Extension {
178                         get { return ".cs"; }
179                 }
180
181                 public override string SourceTemplate {
182                         get {
183                                 return @"// This file is automatically created by Mono managed XSLT engine.
184 // Created time: {0}
185 using System;
186 using System.Collections;
187 using System.Text;
188 using System.Text.RegularExpressions;
189 using System.Xml;
190 using System.Xml.XPath;
191 using System.Xml.Xsl;
192 using Microsoft.VisualBasic;
193
194 namespace GeneratedAssembly
195 {
196 public class Script{1}
197 {
198         {2}
199 }
200 }";
201                         }
202                 }
203
204                 public override string FormatSource (IXmlLineInfo li, string file, string source)
205                 {
206                         if (li == null)
207                                 return source;
208                         return String.Format (CultureInfo.InvariantCulture, "#line {0} \"{1}\"\n{2}", li.LineNumber, file, source);
209                 }
210         }
211
212         internal class VBCompilerInfo : ScriptCompilerInfo
213         {
214                 public VBCompilerInfo ()
215                 {
216                         this.CompilerCommand = "mbas";
217                         this.DefaultCompilerOptions = "/t:library";
218 #if MS_NET
219                         this.CompilerCommand = "vbc.exe";
220                         this.DefaultCompilerOptions = "/t:library  /r:System.dll /r:System.Xml.dll /r:Microsoft.VisualBasic.dll";
221 #endif
222                 }
223
224                 public override CodeDomProvider CodeDomProvider {
225                         get { return new VBCodeProvider (); }
226                 }
227
228                 public override string Extension {
229                         get { return ".vb"; }
230                 }
231
232                 public override string SourceTemplate {
233                         get {
234                                 return @"' This file is automatically created by Mono managed XSLT engine.
235 ' Created time: {0}
236 imports System
237 imports System.Collections
238 imports System.Text
239 imports System.Text.RegularExpressions
240 imports System.Xml
241 imports System.Xml.XPath
242 imports System.Xml.Xsl
243 imports Microsoft.VisualBasic
244
245 namespace GeneratedAssembly
246 public Class Script{1}
247         {2}
248 end Class
249 end namespace
250 ";
251                         }
252                 }
253
254                 public override string FormatSource (IXmlLineInfo li, string file, string source)
255                 {
256                         if (li == null)
257                                 return source;
258                         return String.Format (CultureInfo.InvariantCulture,
259                                 "#ExternalSource (\"{1}\", {0})\n{2}\n#end ExternalSource",
260                                 li.LineNumber, new FileInfo (file).Name, source);
261                 }
262         }
263
264         internal class JScriptCompilerInfo : ScriptCompilerInfo
265         {
266                 static Type providerType;
267
268                 public JScriptCompilerInfo ()
269                 {
270                         this.CompilerCommand = "mjs";
271 #if MS_NET
272                         this.CompilerCommand = "jsc.exe";
273 #endif
274                         this.DefaultCompilerOptions = "/t:library /r:Microsoft.VisualBasic.dll";
275                 }
276
277                 public override CodeDomProvider CodeDomProvider {
278                         get {
279                                 // no need for locking
280                                 if (providerType == null) {
281                                         Assembly jsasm = Assembly.LoadWithPartialName ("Microsoft.JScript", null);
282                                         if (jsasm != null)
283                                                 providerType = jsasm.GetType ("Microsoft.JScript.JScriptCodeProvider");
284                                 }
285                                 return (CodeDomProvider) Activator.CreateInstance (providerType); 
286                         }
287                 }
288
289                 public override string Extension {
290                         get { return ".js"; }
291                 }
292
293                 public override string SourceTemplate {
294                         get {
295                                 return @"// This file is automatically created by Mono managed XSLT engine.
296 // Created time: {0}
297 import System;
298 import System.Collections;
299 import System.Text;
300 import System.Text.RegularExpressions;
301 import System.Xml;
302 import System.Xml.XPath;
303 import System.Xml.Xsl;
304 import Microsoft.VisualBasic;
305
306 package GeneratedAssembly
307 {
308 class Script{1} {
309         {2}
310 }
311 }
312 ";
313                         }
314                 }
315
316                 public override string FormatSource (IXmlLineInfo li, string file, string source)
317                 {
318 #if true // remove when mjs got @set @position support
319                         return source;
320 #else
321                         if (li == null)
322                                 return source;
323                         return String.Format (CultureInfo.InvariantCulture,
324                                 "@set @position ({0}{1}{2}line={3};column={4})\n{5}",
325                                 file != null ? "file=" : String.Empty,
326                                 file,
327                                 file != null ? "; " : String.Empty,
328                                 li.LineNumber,
329                                 li.LinePosition,
330                                 source);
331 #endif
332                 }
333         }
334 }
335