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 TemplateParser parser;
46 CodeDomProvider provider;
47 ICodeCompiler compiler;
50 CompilerParameters compilerParameters;
51 protected CodeTypeDeclaration mainClass;
52 protected CodeTypeReferenceExpression mainClassExpr;
53 protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
55 protected BaseCompiler (TemplateParser parser)
57 compilerParameters = new CompilerParameters ();
63 unit = new CodeCompileUnit ();
64 mainNS = new CodeNamespace ("ASP");
65 unit.Namespaces.Add (mainNS);
66 mainClass = new CodeTypeDeclaration (parser.ClassName);
67 mainClass.TypeAttributes = TypeAttributes.Public;
68 mainNS.Types.Add (mainClass);
69 mainClass.BaseTypes.Add (new CodeTypeReference (parser.BaseType.FullName));
70 mainClassExpr = new CodeTypeReferenceExpression ("ASP." + parser.ClassName);
71 foreach (object o in parser.Imports) {
73 mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
76 if (parser.Assemblies != null) {
77 foreach (object o in parser.Assemblies) {
79 unit.ReferencedAssemblies.Add ((string) o);
83 // Late-bound generators specifics (as for MonoBASIC/VB.NET)
84 unit.UserData["RequireVariableDeclaration"] = parser.ExplicitOn;
85 unit.UserData["AllowLateBound"] = !parser.StrictOn;
88 AddClassAttributes ();
89 CreateStaticFields ();
90 AddApplicationAndSessionObjects ();
92 CreateConstructor (null, null);
95 protected virtual void CreateStaticFields ()
97 CodeMemberField fld = new CodeMemberField (typeof (bool), "__intialized");
98 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
99 fld.InitExpression = new CodePrimitiveExpression (false);
100 mainClass.Members.Add (fld);
103 protected virtual void CreateConstructor (CodeStatementCollection localVars,
104 CodeStatementCollection trueStmt)
106 CodeConstructor ctor = new CodeConstructor ();
107 ctor.Attributes = MemberAttributes.Public;
108 mainClass.Members.Add (ctor);
110 if (localVars != null)
111 ctor.Statements.AddRange (localVars);
113 CodeTypeReferenceExpression r;
114 r = new CodeTypeReferenceExpression (mainNS.Name + "." + mainClass.Name);
115 CodeFieldReferenceExpression intialized;
116 intialized = new CodeFieldReferenceExpression (r, "__intialized");
118 CodeBinaryOperatorExpression bin;
119 bin = new CodeBinaryOperatorExpression (intialized,
120 CodeBinaryOperatorType.ValueEquality,
121 new CodePrimitiveExpression (false));
123 CodeAssignStatement assign = new CodeAssignStatement (intialized,
124 new CodePrimitiveExpression (true));
126 CodeConditionStatement cond = new CodeConditionStatement (bin, assign);
127 if (trueStmt != null)
128 cond.TrueStatements.AddRange (trueStmt);
130 ctor.Statements.Add (cond);
135 if (parser.Scripts == null || parser.Scripts.Count == 0)
138 foreach (object o in parser.Scripts) {
140 mainClass.Members.Add (new CodeSnippetTypeMember ((string) o));
144 protected virtual void CreateMethods ()
148 protected virtual void AddInterfaces ()
150 if (parser.Interfaces == null)
153 foreach (object o in parser.Interfaces) {
155 mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
159 protected virtual void AddClassAttributes ()
163 protected virtual void AddApplicationAndSessionObjects ()
167 /* Utility methods for <object> stuff */
168 protected void CreateApplicationOrSessionPropertyForObject (Type type,
173 /* if isApplication this generates (the 'cachedapp' field is created earlier):
174 private MyNS.MyClass app {
176 if ((this.cachedapp == null)) {
177 this.cachedapp = ((MyNS.MyClass)
178 (this.Application.StaticObjects.GetObject("app")));
180 return this.cachedapp;
184 else, this is for Session:
185 private MyNS.MyClass ses {
187 return ((MyNS.MyClass) (this.Session.StaticObjects.GetObject("ses")));
193 CodeExpression result = null;
195 CodeMemberProperty prop = new CodeMemberProperty ();
196 prop.Type = new CodeTypeReference (type);
197 prop.Name = propName;
199 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
201 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
203 CodePropertyReferenceExpression p1;
205 p1 = new CodePropertyReferenceExpression (thisRef, "Application");
207 p1 = new CodePropertyReferenceExpression (thisRef, "Session");
209 CodePropertyReferenceExpression p2;
210 p2 = new CodePropertyReferenceExpression (p1, "StaticObjects");
212 CodeMethodReferenceExpression getobject;
213 getobject = new CodeMethodReferenceExpression (p2, "GetObject");
215 CodeMethodInvokeExpression invoker;
216 invoker = new CodeMethodInvokeExpression (getobject,
217 new CodePrimitiveExpression (propName));
219 CodeCastExpression cast = new CodeCastExpression (prop.Type, invoker);
222 CodeFieldReferenceExpression field;
223 field = new CodeFieldReferenceExpression (thisRef, "cached" + propName);
225 CodeConditionStatement stmt = new CodeConditionStatement();
226 stmt.Condition = new CodeBinaryOperatorExpression (field,
227 CodeBinaryOperatorType.IdentityEquality,
228 new CodePrimitiveExpression (null));
230 CodeAssignStatement assign = new CodeAssignStatement ();
233 stmt.TrueStatements.Add (assign);
234 prop.GetStatements.Add (stmt);
240 prop.GetStatements.Add (new CodeMethodReturnStatement (result));
241 mainClass.Members.Add (prop);
244 protected string CreateFieldForObject (Type type, string name)
246 string fieldName = "cached" + name;
247 CodeMemberField f = new CodeMemberField (type, fieldName);
248 f.Attributes = MemberAttributes.Private;
249 mainClass.Members.Add (f);
253 protected void CreatePropertyForObject (Type type, string propName, string fieldName, bool isPublic)
255 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, fieldName);
256 CodeMemberProperty prop = new CodeMemberProperty ();
257 prop.Type = new CodeTypeReference (type);
258 prop.Name = propName;
260 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
262 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
264 CodeConditionStatement stmt = new CodeConditionStatement();
265 stmt.Condition = new CodeBinaryOperatorExpression (field,
266 CodeBinaryOperatorType.IdentityEquality,
267 new CodePrimitiveExpression (null));
269 CodeObjectCreateExpression create = new CodeObjectCreateExpression (prop.Type);
270 stmt.TrueStatements.Add (new CodeAssignStatement (field, create));
271 prop.GetStatements.Add (stmt);
272 prop.GetStatements.Add (new CodeMethodReturnStatement (field));
274 mainClass.Members.Add (prop);
278 void CheckCompilerErrors (CompilerResults results)
280 if (results.NativeCompilerReturnValue == 0)
283 StringWriter writer = new StringWriter();
284 provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
285 throw new CompilationException (parser.InputFile, results.Errors, writer.ToString ());
288 protected string DynamicDir ()
290 return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
293 public virtual Type GetCompiledType ()
295 Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
300 string lang = parser.Language;
301 CompilationConfiguration config;
303 config = CompilationConfiguration.GetInstance (parser.Context);
304 provider = config.GetProvider (lang);
305 if (provider == null)
306 throw new HttpException ("Configuration error. Language not supported: " +
309 compiler = provider.CreateCompiler ();
312 compilerParameters.IncludeDebugInformation = parser.Debug;
313 compilerParameters.CompilerOptions = config.GetCompilerOptions (lang) + " " +
314 parser.CompilerOptions;
316 compilerParameters.WarningLevel = config.GetWarningLevel (lang);
317 bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
319 string tempdir = config.TempDirectory;
320 if (tempdir == null || tempdir == "")
321 tempdir = DynamicDir ();
323 TempFileCollection tempcoll = new TempFileCollection (tempdir, keepFiles);
324 compilerParameters.TempFiles = tempcoll;
325 string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
326 compilerParameters.OutputAssembly = Path.Combine (DynamicDir (), dllfilename);
328 CompilerResults results = CachingCompiler.Compile (this);
329 CheckCompilerErrors (results);
330 Assembly assembly = results.CompiledAssembly;
331 if (assembly == null) {
332 if (!File.Exists (compilerParameters.OutputAssembly))
333 throw new CompilationException (parser.InputFile, results.Errors,
334 "No assembly returned after compilation!?");
336 assembly = Assembly.LoadFrom (compilerParameters.OutputAssembly);
339 results.TempFiles.Delete ();
340 return assembly.GetType (mainClassExpr.Type.BaseType, true);
343 internal CompilerParameters CompilerParameters {
344 get { return compilerParameters; }
347 internal CodeCompileUnit Unit {
351 internal virtual ICodeCompiler Compiler {
352 get { return compiler; }
355 internal TemplateParser Parser {
356 get { return parser; }