2 // System.Web.Compilation.BaseCompiler
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (c) Copyright 2002,2003 Ximian, Inc (http://www.ximian.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Reflection;
38 using System.Web.Configuration;
41 namespace System.Web.Compilation
43 abstract class BaseCompiler
45 protected static string dynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
46 TemplateParser parser;
47 CodeDomProvider provider;
48 ICodeCompiler compiler;
51 CompilerParameters compilerParameters;
52 protected CodeTypeDeclaration mainClass;
53 protected CodeTypeReferenceExpression mainClassExpr;
54 protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
56 protected BaseCompiler (TemplateParser parser)
58 compilerParameters = new CompilerParameters ();
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) {
74 mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
77 if (parser.Assemblies != null) {
78 foreach (object o in parser.Assemblies) {
80 unit.ReferencedAssemblies.Add ((string) o);
85 AddClassAttributes ();
86 CreateStaticFields ();
87 AddApplicationAndSessionObjects ();
89 CreateConstructor (null, null);
92 protected virtual void CreateStaticFields ()
94 CodeMemberField fld = new CodeMemberField (typeof (bool), "__intialized");
95 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
96 fld.InitExpression = new CodePrimitiveExpression (false);
97 mainClass.Members.Add (fld);
100 protected virtual void CreateConstructor (CodeStatementCollection localVars,
101 CodeStatementCollection trueStmt)
103 CodeConstructor ctor = new CodeConstructor ();
104 ctor.Attributes = MemberAttributes.Public;
105 mainClass.Members.Add (ctor);
107 if (localVars != null)
108 ctor.Statements.AddRange (localVars);
110 CodeTypeReferenceExpression r;
111 r = new CodeTypeReferenceExpression (mainNS.Name + "." + mainClass.Name);
112 CodeFieldReferenceExpression intialized;
113 intialized = new CodeFieldReferenceExpression (r, "__intialized");
115 CodeBinaryOperatorExpression bin;
116 bin = new CodeBinaryOperatorExpression (intialized,
117 CodeBinaryOperatorType.ValueEquality,
118 new CodePrimitiveExpression (false));
120 CodeAssignStatement assign = new CodeAssignStatement (intialized,
121 new CodePrimitiveExpression (true));
123 CodeConditionStatement cond = new CodeConditionStatement (bin, assign);
124 if (trueStmt != null)
125 cond.TrueStatements.AddRange (trueStmt);
127 ctor.Statements.Add (cond);
132 if (parser.Scripts == null || parser.Scripts.Count == 0)
135 foreach (object o in parser.Scripts) {
137 mainClass.Members.Add (new CodeSnippetTypeMember ((string) o));
141 protected virtual void CreateMethods ()
145 protected virtual void AddInterfaces ()
147 if (parser.Interfaces == null)
150 foreach (object o in parser.Interfaces) {
152 mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
156 protected virtual void AddClassAttributes ()
160 protected virtual void AddApplicationAndSessionObjects ()
164 /* Utility methods for <object> stuff */
165 protected void CreateApplicationOrSessionPropertyForObject (Type type,
170 /* if isApplication this generates (the 'cachedapp' field is created earlier):
171 private MyNS.MyClass app {
173 if ((this.cachedapp == null)) {
174 this.cachedapp = ((MyNS.MyClass)
175 (this.Application.StaticObjects.GetObject("app")));
177 return this.cachedapp;
181 else, this is for Session:
182 private MyNS.MyClass ses {
184 return ((MyNS.MyClass) (this.Session.StaticObjects.GetObject("ses")));
190 CodeExpression result = null;
192 CodeMemberProperty prop = new CodeMemberProperty ();
193 prop.Type = new CodeTypeReference (type);
194 prop.Name = propName;
196 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
198 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
200 CodePropertyReferenceExpression p1;
202 p1 = new CodePropertyReferenceExpression (thisRef, "Application");
204 p1 = new CodePropertyReferenceExpression (thisRef, "Session");
206 CodePropertyReferenceExpression p2;
207 p2 = new CodePropertyReferenceExpression (p1, "StaticObjects");
209 CodeMethodReferenceExpression getobject;
210 getobject = new CodeMethodReferenceExpression (p2, "GetObject");
212 CodeMethodInvokeExpression invoker;
213 invoker = new CodeMethodInvokeExpression (getobject,
214 new CodePrimitiveExpression (propName));
216 CodeCastExpression cast = new CodeCastExpression (prop.Type, invoker);
219 CodeFieldReferenceExpression field;
220 field = new CodeFieldReferenceExpression (thisRef, "cached" + propName);
222 CodeConditionStatement stmt = new CodeConditionStatement();
223 stmt.Condition = new CodeBinaryOperatorExpression (field,
224 CodeBinaryOperatorType.IdentityEquality,
225 new CodePrimitiveExpression (null));
227 CodeAssignStatement assign = new CodeAssignStatement ();
230 stmt.TrueStatements.Add (assign);
231 prop.GetStatements.Add (stmt);
237 prop.GetStatements.Add (new CodeMethodReturnStatement (result));
238 mainClass.Members.Add (prop);
241 protected string CreateFieldForObject (Type type, string name)
243 string fieldName = "cached" + name;
244 CodeMemberField f = new CodeMemberField (type, fieldName);
245 f.Attributes = MemberAttributes.Private;
246 mainClass.Members.Add (f);
250 protected void CreatePropertyForObject (Type type, string propName, string fieldName, bool isPublic)
252 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, fieldName);
253 CodeMemberProperty prop = new CodeMemberProperty ();
254 prop.Type = new CodeTypeReference (type);
255 prop.Name = propName;
257 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
259 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
261 CodeConditionStatement stmt = new CodeConditionStatement();
262 stmt.Condition = new CodeBinaryOperatorExpression (field,
263 CodeBinaryOperatorType.IdentityEquality,
264 new CodePrimitiveExpression (null));
266 CodeObjectCreateExpression create = new CodeObjectCreateExpression (prop.Type);
267 stmt.TrueStatements.Add (new CodeAssignStatement (field, create));
268 prop.GetStatements.Add (stmt);
269 prop.GetStatements.Add (new CodeMethodReturnStatement (field));
271 mainClass.Members.Add (prop);
275 void CheckCompilerErrors (CompilerResults results)
277 if (results.NativeCompilerReturnValue == 0)
280 StringWriter writer = new StringWriter();
281 provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
282 throw new CompilationException (parser.InputFile, results.Errors, writer.ToString ());
285 public virtual Type GetCompiledType ()
287 Type type = CachingCompiler.GetTypeFromCache (parser.InputFile, parser.ClassName);
292 string lang = parser.Language;
293 CompilationConfiguration config;
295 config = CompilationConfiguration.GetInstance (parser.Context);
296 provider = config.GetProvider (lang);
297 if (provider == null)
298 throw new HttpException ("Configuration error. Language not supported: " +
301 compiler = provider.CreateCompiler ();
304 compilerParameters.IncludeDebugInformation = parser.Debug;
305 compilerParameters.CompilerOptions = config.GetCompilerOptions (lang) + " " +
306 parser.CompilerOptions;
308 compilerParameters.WarningLevel = config.GetWarningLevel (lang);
309 bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
310 TempFileCollection tempcoll = new TempFileCollection (config.TempDirectory, keepFiles);
311 compilerParameters.TempFiles = tempcoll;
312 string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
313 if (!Directory.Exists (dynamicBase))
314 Directory.CreateDirectory (dynamicBase);
316 compilerParameters.OutputAssembly = Path.Combine (dynamicBase, dllfilename);
318 CompilerResults results = CachingCompiler.Compile (this);
319 CheckCompilerErrors (results);
320 if (results.CompiledAssembly == null)
321 throw new CompilationException (parser.InputFile, results.Errors,
322 "No assembly returned after compilation!?");
324 results.TempFiles.Delete ();
325 return results.CompiledAssembly.GetType (mainClassExpr.Type.BaseType, true);
328 internal CompilerParameters CompilerParameters {
329 get { return compilerParameters; }
332 internal CodeCompileUnit Unit {
336 internal virtual ICodeCompiler Compiler {
337 get { return compiler; }
340 internal TemplateParser Parser {
341 get { return parser; }