TARGET_J2EE compilation & integration fixes.
[mono.git] / mcs / class / System.Web / System.Web.Compilation / BaseCompiler.cs
1 //
2 // System.Web.Compilation.BaseCompiler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (c) Copyright 2002,2003 Ximian, Inc (http://www.ximian.com)
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
31 using System;
32 using System.CodeDom;
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Reflection;
36 using System.Text;
37 using System.Web.UI;
38 using System.Web.Configuration;
39 using System.IO;
40
41 namespace System.Web.Compilation
42 {
43         abstract class BaseCompiler
44         {
45                 protected static string dynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
46                 TemplateParser parser;
47                 CodeDomProvider provider;
48                 ICodeCompiler compiler;
49                 CodeCompileUnit unit;
50                 CodeNamespace mainNS;
51                 CompilerParameters compilerParameters;
52                 protected CodeTypeDeclaration mainClass;
53                 protected CodeTypeReferenceExpression mainClassExpr;
54                 protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
55
56                 protected BaseCompiler (TemplateParser parser)
57                 {
58                         compilerParameters = new CompilerParameters ();
59                         this.parser = parser;
60                 }
61
62                 void Init ()
63                 {
64                         unit = new CodeCompileUnit ();
65                         mainNS = new CodeNamespace ("ASP");
66                         unit.Namespaces.Add (mainNS);
67                         mainClass = new CodeTypeDeclaration (parser.ClassName);
68                         mainClass.TypeAttributes = TypeAttributes.Public;
69                         mainNS.Types.Add (mainClass);
70                         mainClass.BaseTypes.Add (new CodeTypeReference (parser.BaseType.FullName));
71                         mainClassExpr = new CodeTypeReferenceExpression ("ASP." + parser.ClassName);
72                         foreach (object o in parser.Imports) {
73                                 if (o is string)
74                                         mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
75                         }
76
77                         if (parser.Assemblies != null) {
78                                 foreach (object o in parser.Assemblies) {
79                                         if (o is string)
80                                                 unit.ReferencedAssemblies.Add ((string) o);
81                                 }
82                         }
83
84                         // Late-bound generators specifics (as for MonoBASIC/VB.NET)
85                         unit.UserData["RequireVariableDeclaration"] = parser.ExplicitOn;
86                         unit.UserData["AllowLateBound"] = !parser.StrictOn;
87                         
88                         AddInterfaces ();
89                         AddClassAttributes ();
90                         CreateStaticFields ();
91                         AddApplicationAndSessionObjects ();
92                         AddScripts ();
93                         CreateConstructor (null, null);
94                 }
95
96                 protected virtual void CreateStaticFields ()
97                 {
98                         CodeMemberField fld = new CodeMemberField (typeof (bool), "__intialized");
99                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
100                         fld.InitExpression = new CodePrimitiveExpression (false);
101                         mainClass.Members.Add (fld);
102                 }
103
104                 protected virtual void CreateConstructor (CodeStatementCollection localVars,
105                                                           CodeStatementCollection trueStmt)
106                 {
107                         CodeConstructor ctor = new CodeConstructor ();
108                         ctor.Attributes = MemberAttributes.Public;
109                         mainClass.Members.Add (ctor);
110
111                         if (localVars != null)
112                                 ctor.Statements.AddRange (localVars);
113
114                         CodeTypeReferenceExpression r;
115                         r = new CodeTypeReferenceExpression (mainNS.Name + "." + mainClass.Name);
116                         CodeFieldReferenceExpression intialized;
117                         intialized = new CodeFieldReferenceExpression (r, "__intialized");
118                         
119                         CodeBinaryOperatorExpression bin;
120                         bin = new CodeBinaryOperatorExpression (intialized,
121                                                                 CodeBinaryOperatorType.ValueEquality,
122                                                                 new CodePrimitiveExpression (false));
123
124                         CodeAssignStatement assign = new CodeAssignStatement (intialized,
125                                                                               new CodePrimitiveExpression (true));
126
127                         CodeConditionStatement cond = new CodeConditionStatement (bin, assign);
128                         if (trueStmt != null)
129                                 cond.TrueStatements.AddRange (trueStmt);
130                         
131                         ctor.Statements.Add (cond);
132                 }
133                 
134                 void AddScripts ()
135                 {
136                         if (parser.Scripts == null || parser.Scripts.Count == 0)
137                                 return;
138
139                         foreach (object o in parser.Scripts) {
140                                 if (o is string)
141                                         mainClass.Members.Add (new CodeSnippetTypeMember ((string) o));
142                         }
143                 }
144                 
145                 protected virtual void CreateMethods ()
146                 {
147                 }
148
149                 protected virtual void AddInterfaces ()
150                 {
151                         if (parser.Interfaces == null)
152                                 return;
153
154                         foreach (object o in parser.Interfaces) {
155                                 if (o is string)
156                                         mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
157                         }
158                 }
159
160                 protected virtual void AddClassAttributes ()
161                 {
162                 }
163                 
164                 protected virtual void AddApplicationAndSessionObjects ()
165                 {
166                 }
167
168                 /* Utility methods for <object> stuff */
169                 protected void CreateApplicationOrSessionPropertyForObject (Type type,
170                                                                             string propName,
171                                                                             bool isApplication,
172                                                                             bool isPublic)
173                 {
174                         /* if isApplication this generates (the 'cachedapp' field is created earlier):
175                         private MyNS.MyClass app {
176                                 get {
177                                         if ((this.cachedapp == null)) {
178                                                 this.cachedapp = ((MyNS.MyClass)
179                                                         (this.Application.StaticObjects.GetObject("app")));
180                                         }
181                                         return this.cachedapp;
182                                 }
183                         }
184
185                         else, this is for Session:
186                         private MyNS.MyClass ses {
187                                 get {
188                                         return ((MyNS.MyClass) (this.Session.StaticObjects.GetObject("ses")));
189                                 }
190                         }
191
192                         */
193
194                         CodeExpression result = null;
195
196                         CodeMemberProperty prop = new CodeMemberProperty ();
197                         prop.Type = new CodeTypeReference (type);
198                         prop.Name = propName;
199                         if (isPublic)
200                                 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
201                         else
202                                 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
203
204                         CodePropertyReferenceExpression p1;
205                         if (isApplication)
206                                 p1 = new CodePropertyReferenceExpression (thisRef, "Application");
207                         else
208                                 p1 = new CodePropertyReferenceExpression (thisRef, "Session");
209
210                         CodePropertyReferenceExpression p2;
211                         p2 = new CodePropertyReferenceExpression (p1, "StaticObjects");
212
213                         CodeMethodReferenceExpression getobject;
214                         getobject = new CodeMethodReferenceExpression (p2, "GetObject");
215
216                         CodeMethodInvokeExpression invoker;
217                         invoker = new CodeMethodInvokeExpression (getobject,
218                                                 new CodePrimitiveExpression (propName));
219
220                         CodeCastExpression cast = new CodeCastExpression (prop.Type, invoker);
221
222                         if (isApplication) {
223                                 CodeFieldReferenceExpression field;
224                                 field = new CodeFieldReferenceExpression (thisRef, "cached" + propName);
225
226                                 CodeConditionStatement stmt = new CodeConditionStatement();
227                                 stmt.Condition = new CodeBinaryOperatorExpression (field,
228                                                         CodeBinaryOperatorType.IdentityEquality,
229                                                         new CodePrimitiveExpression (null));
230
231                                 CodeAssignStatement assign = new CodeAssignStatement ();
232                                 assign.Left = field;
233                                 assign.Right = cast;
234                                 stmt.TrueStatements.Add (assign);
235                                 prop.GetStatements.Add (stmt);
236                                 result = field;
237                         } else {
238                                 result = cast;
239                         }
240                                                 
241                         prop.GetStatements.Add (new CodeMethodReturnStatement (result));
242                         mainClass.Members.Add (prop);
243                 }
244
245                 protected string CreateFieldForObject (Type type, string name)
246                 {
247                         string fieldName = "cached" + name;
248                         CodeMemberField f = new CodeMemberField (type, fieldName);
249                         f.Attributes = MemberAttributes.Private;
250                         mainClass.Members.Add (f);
251                         return fieldName;
252                 }
253
254                 protected void CreatePropertyForObject (Type type, string propName, string fieldName, bool isPublic)
255                 {
256                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, fieldName);
257                         CodeMemberProperty prop = new CodeMemberProperty ();
258                         prop.Type = new CodeTypeReference (type);
259                         prop.Name = propName;
260                         if (isPublic)
261                                 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
262                         else
263                                 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
264
265                         CodeConditionStatement stmt = new CodeConditionStatement();
266                         stmt.Condition = new CodeBinaryOperatorExpression (field,
267                                                 CodeBinaryOperatorType.IdentityEquality,
268                                                 new CodePrimitiveExpression (null));
269
270                         CodeObjectCreateExpression create = new CodeObjectCreateExpression (prop.Type); 
271                         stmt.TrueStatements.Add (new CodeAssignStatement (field, create));
272                         prop.GetStatements.Add (stmt);
273                         prop.GetStatements.Add (new CodeMethodReturnStatement (field));
274
275                         mainClass.Members.Add (prop);
276                 }
277                 /******/
278
279                 void CheckCompilerErrors (CompilerResults results)
280                 {
281                         if (results.NativeCompilerReturnValue == 0)
282                                 return;
283
284                         StringWriter writer = new StringWriter();
285                         provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
286                         throw new CompilationException (parser.InputFile, results.Errors, writer.ToString ());
287                 }
288
289                 public virtual Type GetCompiledType () 
290                 {
291                         Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
292                         if (type != null)
293                                 return type;
294
295                         Init ();
296                         string lang = parser.Language;
297                         CompilationConfiguration config;
298
299                         config = CompilationConfiguration.GetInstance (parser.Context);
300                         provider = config.GetProvider (lang);
301                         if (provider == null)
302                                 throw new HttpException ("Configuration error. Language not supported: " +
303                                                           lang, 500);
304
305                         compiler = provider.CreateCompiler ();
306
307                         CreateMethods ();
308                         compilerParameters.IncludeDebugInformation = parser.Debug;
309                         compilerParameters.CompilerOptions = config.GetCompilerOptions (lang) + " " +
310                                                              parser.CompilerOptions;
311
312                         compilerParameters.WarningLevel = config.GetWarningLevel (lang);
313                         bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
314                         if (!Directory.Exists (dynamicBase))
315                                 Directory.CreateDirectory (dynamicBase);
316
317                         TempFileCollection tempcoll = new TempFileCollection (config.TempDirectory, keepFiles);
318                         compilerParameters.TempFiles = tempcoll;
319                         string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
320                         compilerParameters.OutputAssembly = Path.Combine (dynamicBase, dllfilename);
321
322                         CompilerResults results = CachingCompiler.Compile (this);
323                         CheckCompilerErrors (results);
324                         Assembly assembly = results.CompiledAssembly;
325                         if (assembly == null) {
326                                 if (!File.Exists (compilerParameters.OutputAssembly))
327                                         throw new CompilationException (parser.InputFile, results.Errors,
328                                                 "No assembly returned after compilation!?");
329
330                                 assembly = Assembly.LoadFrom (compilerParameters.OutputAssembly);
331                         }
332
333                         results.TempFiles.Delete ();
334                         return assembly.GetType (mainClassExpr.Type.BaseType, true);
335                 }
336
337                 internal CompilerParameters CompilerParameters {
338                         get { return compilerParameters; }
339                 }
340
341                 internal CodeCompileUnit Unit {
342                         get { return unit; }
343                 }
344
345                 internal virtual ICodeCompiler Compiler {
346                         get { return compiler; }
347                 }
348
349                 internal TemplateParser Parser {
350                         get { return parser; }
351                 }
352         }
353 }
354