2003-10-21 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[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) 2002,2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 using System;
11 using System.CodeDom;
12 using System.CodeDom.Compiler;
13 using System.Collections;
14 using System.Reflection;
15 using System.Text;
16 using System.Web.UI;
17 using System.Web.Configuration;
18 using System.IO;
19
20 namespace System.Web.Compilation
21 {
22         abstract class BaseCompiler
23         {
24                 TemplateParser parser;
25                 CodeDomProvider provider;
26                 ICodeCompiler compiler;
27                 CodeCompileUnit unit;
28                 CodeNamespace mainNS;
29                 CompilerParameters compilerParameters;
30                 protected CodeTypeDeclaration mainClass;
31                 protected CodeTypeReferenceExpression mainClassExpr;
32                 protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
33
34                 protected BaseCompiler (TemplateParser parser)
35                 {
36                         compilerParameters = new CompilerParameters ();
37                         this.parser = parser;
38                 }
39
40                 void Init ()
41                 {
42                         unit = new CodeCompileUnit ();
43                         mainNS = new CodeNamespace ("ASP");
44                         unit.Namespaces.Add (mainNS);
45                         mainClass = new CodeTypeDeclaration (parser.ClassName);
46                         mainClass.TypeAttributes = TypeAttributes.Public;
47                         mainNS.Types.Add (mainClass);
48                         mainClass.BaseTypes.Add (new CodeTypeReference (parser.BaseType.FullName));
49                         mainClassExpr = new CodeTypeReferenceExpression ("ASP." + parser.ClassName);
50                         foreach (object o in parser.Imports) {
51                                 if (o is string)
52                                         mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
53                         }
54
55                         if (parser.Assemblies != null) {
56                                 foreach (object o in parser.Assemblies) {
57                                         if (o is string)
58                                                 unit.ReferencedAssemblies.Add ((string) o);
59                                 }
60                         }
61
62                         AddInterfaces ();
63                         CreateStaticFields ();
64                         AddScripts ();
65                         CreateConstructor (null, null);
66                 }
67
68                 protected virtual void CreateStaticFields ()
69                 {
70                         CodeMemberField fld = new CodeMemberField (typeof (bool), "__intialized");
71                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
72                         fld.InitExpression = new CodePrimitiveExpression (false);
73                         mainClass.Members.Add (fld);
74                 }
75
76                 protected virtual void CreateConstructor (CodeStatementCollection localVars, CodeStatementCollection trueStmt)
77                 {
78                         CodeConstructor ctor = new CodeConstructor ();
79                         ctor.Attributes = MemberAttributes.Public;
80                         mainClass.Members.Add (ctor);
81
82                         if (localVars != null)
83                                 ctor.Statements.AddRange (localVars);
84
85                         CodeTypeReferenceExpression r = new CodeTypeReferenceExpression (mainNS.Name + "." + mainClass.Name);
86                         CodeFieldReferenceExpression intialized = new CodeFieldReferenceExpression (r, "__intialized");
87                         
88                         CodeBinaryOperatorExpression bin = new CodeBinaryOperatorExpression (intialized,
89                                                                                              CodeBinaryOperatorType.ValueEquality,
90                                                                                              new CodePrimitiveExpression (false));
91
92                         CodeAssignStatement assign = new CodeAssignStatement (intialized,
93                                                                               new CodePrimitiveExpression (true));
94
95                         CodeConditionStatement cond = new CodeConditionStatement (bin, assign);
96                         if (trueStmt != null)
97                                 cond.TrueStatements.AddRange (trueStmt);
98                         
99                         ctor.Statements.Add (cond);
100                 }
101                 
102                 void AddScripts ()
103                 {
104                         if (parser.Scripts == null || parser.Scripts.Count == 0)
105                                 return;
106
107                         foreach (object o in parser.Scripts) {
108                                 if (o is string)
109                                         mainClass.Members.Add (new CodeSnippetTypeMember ((string) o));
110                         }
111                 }
112                 
113                 protected virtual void CreateMethods ()
114                 {
115                 }
116
117                 protected virtual void AddInterfaces ()
118                 {
119                         if (parser.Interfaces == null)
120                                 return;
121
122                         foreach (object o in parser.Interfaces) {
123                                 if (o is string)
124                                         mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
125                         }
126                 }
127
128                 protected virtual void ProcessObjectTag (ObjectTagBuilder tag)
129                 {
130                 }
131
132                 void CheckCompilerErrors (CompilerResults results)
133                 {
134                         if (results.NativeCompilerReturnValue == 0)
135                                 return;
136
137                         StringWriter writer = new StringWriter();
138                         provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
139                         throw new CompilationException (parser.InputFile, results.Errors, writer.ToString ());
140                 }
141
142                 public virtual Type GetCompiledType () 
143                 {
144                         Init ();
145                         CompilationCacheItem item = CachingCompiler.GetCached (parser.InputFile);
146                         if (item != null) {
147                                 Assembly a = item.Result.CompiledAssembly;
148                                 if (a != null)
149                                         return a.GetType (mainClassExpr.Type.BaseType, true);
150                         }
151
152                         string lang = parser.Language;
153                         CompilationConfiguration config;
154
155                         config = CompilationConfiguration.GetInstance (parser.Context);
156                         provider = config.GetProvider (lang);
157                         if (provider == null)
158                                 throw new HttpException ("Configuration error. Language not supported: " +
159                                                           lang, 500);
160
161                         compiler = provider.CreateCompiler ();
162
163                         CreateMethods ();
164                         compilerParameters.IncludeDebugInformation = parser.Debug;
165                         compilerParameters.CompilerOptions = config.GetCompilerOptions (lang) + " " +
166                                                              parser.CompilerOptions;
167
168                         compilerParameters.WarningLevel = config.GetWarningLevel (lang);
169                         CompilerResults results = CachingCompiler.Compile (this);
170                         CheckCompilerErrors (results);
171                         if (results.CompiledAssembly == null)
172                                 throw new CompilationException (parser.InputFile, results.Errors,
173                                         "No assembly returned after compilation!?");
174
175                         return results.CompiledAssembly.GetType (mainClassExpr.Type.BaseType, true);
176                 }
177
178                 internal CompilerParameters CompilerParameters {
179                         get { return compilerParameters; }
180                 }
181
182                 internal CodeCompileUnit Unit {
183                         get { return unit; }
184                 }
185
186                 internal virtual ICodeCompiler Compiler {
187                         get { return compiler; }
188                 }
189
190                 internal TemplateParser Parser {
191                         get { return parser; }
192                 }
193         }
194 }
195