2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
1 //
2 // System.Web.Compilation.TemplateControlCompiler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //      Marek Habersack (mhabersack@novell.com)
7 //
8 // (C) 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004-2008 Novell, Inc (http://novell.com)
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.CodeDom;
33 using System.Collections;
34 using System.ComponentModel;
35 using System.Drawing;
36 using System.Globalization;
37 using System.Reflection;
38 using System.Text;
39 using System.Web;
40 using System.Web.UI;
41 using System.Web.UI.WebControls;
42 using System.Web.Util;
43 using System.ComponentModel.Design.Serialization;
44 using System.Text.RegularExpressions;
45 #if NET_2_0
46 using System.Configuration;
47 using System.Collections.Specialized;
48 using System.Collections.Generic;
49 using System.Web.Configuration;
50 using System.Resources;
51 #endif
52
53 namespace System.Web.Compilation
54 {
55         class TemplateControlCompiler : BaseCompiler
56         {
57                 static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
58                                                   BindingFlags.Instance | BindingFlags.IgnoreCase;
59                 static Type monoTypeType = Type.GetType ("System.MonoType");
60                 
61                 TemplateControlParser parser;
62                 int dataBoundAtts;
63                 internal ILocation currentLocation;
64
65                 static TypeConverter colorConverter;
66
67                 internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
68                 
69 #if NET_2_0
70                 List <string> masterPageContentPlaceHolders;
71                 static Regex startsWithBindRegex = new Regex (@"^Bind\s*\(", RegexOptions.Compiled | RegexOptions.IgnoreCase);
72                 // When modifying those, make sure to look at the SanitizeBindCall to make sure it
73                 // picks up correct groups.
74                 static Regex bindRegex = new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*%>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
75                 static Regex bindRegexInValue = new Regex (@"Bind\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
76 #endif
77                 static Regex evalRegexInValue = new Regex (@"(.*)Eval\s*\(\s*[""']+(.*?)[""']+((\s*,\s*[""']+(.*?)[""']+)?)\s*\)(.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
78
79 #if NET_2_0
80                 List <string> MasterPageContentPlaceHolders {
81                         get {
82                                 if (masterPageContentPlaceHolders == null)
83                                         masterPageContentPlaceHolders = new List <string> ();
84                                 return masterPageContentPlaceHolders;
85                         }
86                 }
87 #endif
88                 public TemplateControlCompiler (TemplateControlParser parser)
89                         : base (parser)
90                 {
91                         this.parser = parser;
92                 }
93
94                 protected void EnsureID (ControlBuilder builder)
95                 {
96                         if (builder.ID == null || builder.ID.Trim () == "")
97                                 builder.ID = builder.GetNextID (null);
98                 }
99
100                 void CreateField (ControlBuilder builder, bool check)
101                 {
102                         if (builder == null || builder.ID == null || builder.ControlType == null)
103                                 return;
104 #if NET_2_0
105                         if (partialNameOverride [builder.ID] != null)
106                                 return;
107 #endif
108
109                         MemberAttributes ma = MemberAttributes.Family;
110                         currentLocation = builder.Location;
111                         if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType, ref ma))
112                                 return; // The field or property already exists in a base class and is accesible.
113
114                         CodeMemberField field;
115                         field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
116                         field.Attributes = ma;
117 #if NET_2_0
118                         field.Type.Options |= CodeTypeReferenceOptions.GlobalReference;
119
120                         if (partialClass != null)
121                                 partialClass.Members.Add (AddLinePragma (field, builder));
122                         else
123 #endif
124                                 mainClass.Members.Add (AddLinePragma (field, builder));
125                 }
126
127                 bool CheckBaseFieldOrProperty (string id, Type type, ref MemberAttributes ma)
128                 {
129                         FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
130
131                         Type other = null;
132                         if (fld == null || fld.IsPrivate) {
133                                 PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
134                                 if (prop != null) {
135                                         MethodInfo setm = prop.GetSetMethod (true);
136                                         if (setm != null)
137                                                 other = prop.PropertyType;
138                                 }
139                         } else {
140                                 other = fld.FieldType;
141                         }
142                         
143                         if (other == null)
144                                 return false;
145
146                         if (!other.IsAssignableFrom (type)) {
147 #if NET_2_0
148                                 ma |= MemberAttributes.New;
149                                 return false;
150 #else
151                                 string msg = String.Format ("The base class includes the field '{0}', but its " +
152                                                             "type '{1}' is not compatible with {2}",
153                                                             id, other, type);
154                                 throw new ParseException (currentLocation, msg);
155 #endif
156                         }
157
158                         return true;
159                 }
160                 
161                 void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr) 
162                 {
163                         if (!builder.HaveParserVariable) {
164                                 CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
165                                 p.Name = "__parser";
166                                 p.Type = new CodeTypeReference (typeof (IParserAccessor));
167                                 p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
168                                 builder.MethodStatements.Add (p);
169                                 builder.HaveParserVariable = true;
170                         }
171
172                         CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
173                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
174                         invoke.Parameters.Add (expr);
175                         builder.MethodStatements.Add (AddLinePragma (invoke, builder));
176                 }
177                 
178                 void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
179                 {
180                         currentLocation = builder.Location;
181                         
182                         string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
183                         CodeMemberMethod method = new CodeMemberMethod ();
184                         builder.Method = method;
185                         builder.MethodStatements = method.Statements;
186
187                         method.Name = "__BuildControl" + tailname;
188                         method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
189                         Type type = builder.ControlType;
190
191                         /* in the case this is the __BuildControlTree
192                          * method, allow subclasses to insert control
193                          * specific code. */
194                         if (builder is RootBuilder) {
195 #if NET_2_0
196                                 SetCustomAttributes (method);
197 #endif
198                                 AddStatementsToInitMethod (method);
199                         }
200                         
201                         if (builder.HasAspCode) {
202                                 CodeMemberMethod renderMethod = new CodeMemberMethod ();
203                                 builder.RenderMethod = renderMethod;
204                                 renderMethod.Name = "__Render" + tailname;
205                                 renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
206                                 CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
207                                 arg1.Type = new CodeTypeReference (typeof (HtmlTextWriter));
208                                 arg1.Name = "__output";
209                                 CodeParameterDeclarationExpression arg2 = new CodeParameterDeclarationExpression ();
210                                 arg2.Type = new CodeTypeReference (typeof (Control));
211                                 arg2.Name = "parameterContainer";
212                                 renderMethod.Parameters.Add (arg1);
213                                 renderMethod.Parameters.Add (arg2);
214                                 mainClass.Members.Add (renderMethod);
215                         }
216                         
217                         if (childrenAsProperties || builder.ControlType == null) {
218                                 string typeString;
219                                 if (builder is RootBuilder)
220                                         typeString = parser.ClassName;
221                                 else {
222                                         if (builder.ControlType != null && builder.IsProperty &&
223                                             !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
224                                                 typeString = builder.ControlType.FullName;
225                                         else 
226                                                 typeString = "System.Web.UI.Control";
227                                         ProcessTemplateChildren (builder);
228                                 }
229
230                                 method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
231                         } else {
232                                 
233                                 if (typeof (Control).IsAssignableFrom (type))
234                                         method.ReturnType = new CodeTypeReference (typeof (Control));
235
236                                 // _ctrl = new $controlType ($parameters);
237                                 //
238                                 CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
239
240                                 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
241                                 if (atts != null && atts.Length > 0) {
242                                         ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
243                                         if (att.NeedsTag)
244                                                 newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
245                                 } else if (builder is DataBindingBuilder) {
246                                         newExpr.Parameters.Add (new CodePrimitiveExpression (0));
247                                         newExpr.Parameters.Add (new CodePrimitiveExpression (1));
248                                 }
249
250                                 method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
251                                 CodeAssignStatement assign = new CodeAssignStatement ();
252                                 assign.Left = ctrlVar;
253                                 assign.Right = newExpr;
254                                 method.Statements.Add (AddLinePragma (assign, builder));
255                                                                 
256                                 // this.$builderID = _ctrl;
257                                 //
258                                 CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
259                                 builderID.TargetObject = thisRef;
260                                 builderID.FieldName = builder.ID;
261                                 assign = new CodeAssignStatement ();
262                                 assign.Left = builderID;
263                                 assign.Right = ctrlVar;
264                                 method.Statements.Add (AddLinePragma (assign, builder));
265
266                                 if (typeof (UserControl).IsAssignableFrom (type)) {
267                                         CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
268                                         mref.TargetObject = builderID;
269                                         mref.MethodName = "InitializeAsUserControl";
270                                         CodeMethodInvokeExpression initAsControl = new CodeMethodInvokeExpression (mref);
271                                         initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
272                                         method.Statements.Add (initAsControl);
273                                 }
274
275 #if NET_2_0
276                                 if (builder.ParentTemplateBuilder is System.Web.UI.WebControls.ContentBuilderInternal) {
277                                         PropertyInfo pi;
278
279                                         try {
280                                                 pi = type.GetProperty ("TemplateControl");
281                                         } catch (Exception) {
282                                                 pi = null;
283                                         }
284
285                                         if (pi != null && pi.CanWrite) {
286                                                 // __ctrl.TemplateControl = this;
287                                                 assign = new CodeAssignStatement ();
288                                                 assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
289                                                 assign.Right = thisRef;
290                                                 method.Statements.Add (assign);
291                                         }
292                                 }
293                                 
294                                 // _ctrl.SkinID = $value
295                                 // _ctrl.ApplyStyleSheetSkin (this);
296                                 //
297                                 // the SkinID assignment needs to come
298                                 // before the call to
299                                 // ApplyStyleSheetSkin, for obvious
300                                 // reasons.  We skip SkinID in
301                                 // CreateAssignStatementsFromAttributes
302                                 // below.
303                                 // 
304                                 string skinid = builder.GetAttribute ("skinid");
305                                 if (!String.IsNullOrEmpty (skinid))
306                                         CreateAssignStatementFromAttribute (builder, "skinid");
307
308                                 if (typeof (WebControl).IsAssignableFrom (type)) {
309                                         CodeMethodInvokeExpression applyStyleSheetSkin = new CodeMethodInvokeExpression (ctrlVar, "ApplyStyleSheetSkin");
310                                         if (typeof (Page).IsAssignableFrom (parser.BaseType))
311                                                 applyStyleSheetSkin.Parameters.Add (thisRef);
312                                         else
313                                                 applyStyleSheetSkin.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
314                                         method.Statements.Add (applyStyleSheetSkin);
315                                 }
316 #endif
317
318                                 // Process template children before anything else
319                                 ProcessTemplateChildren (builder);
320
321                                 // process ID here. It should be set before any other attributes are
322                                 // assigned, since the control code may rely on ID being set. We
323                                 // skip ID in CreateAssignStatementsFromAttributes
324                                 string ctl_id = builder.GetAttribute ("id");
325                                 if (ctl_id != null && ctl_id.Length != 0)
326                                         CreateAssignStatementFromAttribute (builder, "id");
327
328                                 
329 #if NET_2_0
330                                 if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
331                                         List <string> placeHolderIds = MasterPageContentPlaceHolders;
332                                         string cphID = builder.ID;
333                                         
334                                         if (!placeHolderIds.Contains (cphID))
335                                                 placeHolderIds.Add (cphID);
336
337                                         CodeConditionStatement condStatement;
338
339                                         // Add the __Template_* field
340                                         string templateField = "__Template_" + cphID;
341                                         CodeMemberField fld = new CodeMemberField (typeof (ITemplate), templateField);
342                                         fld.Attributes = MemberAttributes.Private;
343                                         mainClass.Members.Add (fld);
344
345                                         CodeFieldReferenceExpression templateID = new CodeFieldReferenceExpression ();
346                                         templateID.TargetObject = thisRef;
347                                         templateID.FieldName = templateField;
348
349                                         CreateContentPlaceHolderTemplateProperty (templateField, "Template_" + cphID);
350                                         
351                                         // if ((this.ContentTemplates != null)) {
352                                         //      this.__Template_$builder.ID = ((System.Web.UI.ITemplate)(this.ContentTemplates["$builder.ID"]));
353                                         // }
354                                         //
355                                         CodeFieldReferenceExpression contentTemplates = new CodeFieldReferenceExpression ();
356                                         contentTemplates.TargetObject = thisRef;
357                                         contentTemplates.FieldName = "ContentTemplates";
358
359                                         CodeIndexerExpression indexer = new CodeIndexerExpression ();
360                                         indexer.TargetObject = new CodePropertyReferenceExpression (thisRef, "ContentTemplates");
361                                         indexer.Indices.Add (new CodePrimitiveExpression (cphID));
362
363                                         assign = new CodeAssignStatement ();
364                                         assign.Left = templateID;
365                                         assign.Right = new CodeCastExpression (new CodeTypeReference (typeof (ITemplate)), indexer);
366
367                                         condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (contentTemplates,
368                                                                                                                       CodeBinaryOperatorType.IdentityInequality,
369                                                                                                                       new CodePrimitiveExpression (null)),
370                                                                                     assign);
371
372                                         method.Statements.Add (condStatement);
373
374                                         // if ((this.__Template_mainContent != null)) {
375                                         //      this.__Template_mainContent.InstantiateIn(__ctrl);
376                                         // }
377                                         // and also set things up such that any additional code ends up in:
378                                         // else {
379                                         //      ...
380                                         // }
381                                         //
382                                         CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
383                                         methodRef.TargetObject = templateID;
384                                         methodRef.MethodName = "InstantiateIn";
385
386                                         CodeMethodInvokeExpression instantiateInInvoke;
387                                         instantiateInInvoke = new CodeMethodInvokeExpression (methodRef, ctrlVar);
388
389                                         condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (templateID,
390                                                                                                                       CodeBinaryOperatorType.IdentityInequality,
391                                                                                                                       new CodePrimitiveExpression (null)),
392                                                                                     new CodeExpressionStatement (instantiateInInvoke));
393                                         method.Statements.Add (condStatement);
394
395                                         // this is the bit that causes the following stuff to end up in the else { }
396                                         builder.MethodStatements = condStatement.FalseStatements;
397                                 }
398 #endif
399                         }
400                         
401                         mainClass.Members.Add (method);
402                 }
403
404                 void ProcessTemplateChildren (ControlBuilder builder)
405                 {
406                         ArrayList templates = builder.TemplateChildren;
407                         if (templates != null && templates.Count > 0) {
408                                 foreach (TemplateBuilder tb in templates) {
409                                         CreateControlTree (tb, true, false);
410 #if NET_2_0
411                                         if (tb.BindingDirection == BindingDirection.TwoWay) {
412                                                 string extractMethod = CreateExtractValuesMethod (tb);
413                                                 AddBindableTemplateInvocation (builder, tb.TagName, tb.Method.Name, extractMethod);
414                                         } else
415 #endif
416                                                 AddTemplateInvocation (builder, tb.TagName, tb.Method.Name);
417                                 }
418                         }
419                 }
420                 
421 #if NET_2_0
422                 void SetCustomAttribute (CodeMemberMethod method, UnknownAttributeDescriptor uad)
423                 {
424                         CodeAssignStatement assign = new CodeAssignStatement ();
425                         assign.Left = new CodePropertyReferenceExpression (
426                                 new CodeArgumentReferenceExpression("__ctrl"),
427                                 uad.Info.Name);
428                         assign.Right = GetExpressionFromString (uad.Value.GetType (), uad.Value.ToString (), uad.Info);
429                         
430                         method.Statements.Add (assign);
431                 }
432                 
433                 void SetCustomAttributes (CodeMemberMethod method)
434                 {
435                         Type baseType = parser.BaseType;
436                         if (baseType == null)
437                                 return;
438                         
439                         List <UnknownAttributeDescriptor> attrs = parser.UnknownMainAttributes;
440                         if (attrs == null || attrs.Count == 0)
441                                 return;
442
443                         foreach (UnknownAttributeDescriptor uad in attrs)
444                                 SetCustomAttribute (method, uad);
445                 }
446 #endif
447                 
448                 protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
449                 {
450                 }
451
452                 void AddLiteralSubObject (ControlBuilder builder, string str)
453                 {
454                         if (!builder.HasAspCode) {
455                                 CodeObjectCreateExpression expr;
456                                 expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
457                                 AddParsedSubObjectStmt (builder, expr);
458                         } else {
459                                 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
460                                 methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
461                                 methodRef.MethodName = "Write";
462
463                                 CodeMethodInvokeExpression expr;
464                                 expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
465                                 builder.RenderMethod.Statements.Add (expr);
466                         }
467                 }
468
469                 string TrimDB (string value, bool trimTail)
470                 {
471                         string str = value.Trim ();
472                         int len = str.Length;
473                         int idx = str.IndexOf ('#', 2) + 1;
474                         if (idx >= len)
475                                 return String.Empty;
476                         if (trimTail)
477                                 len -= 2;
478                         
479                         return str.Substring (idx, len - idx).Trim ();
480                 }
481
482                 CodeExpression CreateEvalInvokeExpression (Regex regex, string value, bool isBind)
483                 {
484                         Match match = regex.Match (value);
485                         if (!match.Success) {
486 #if NET_2_0
487                                 if (isBind)
488                                         throw new HttpParseException ("Bind invocation wasn't formatted properly.");
489 #endif
490                                 return null;
491                         }
492                         
493                         string sanitizedSnippet;
494                         if (isBind)
495                                 sanitizedSnippet = SanitizeBindCall (match);
496                         else
497                                 sanitizedSnippet = value;
498                         
499                         return new CodeSnippetExpression (sanitizedSnippet);
500                 }
501
502                 string SanitizeBindCall (Match match)
503                 {
504                         GroupCollection groups = match.Groups;
505                         StringBuilder sb = new StringBuilder ("Eval(\"" + groups [1] + "\"");
506                         Group second = groups [4];
507                         if (second != null) {
508                                 string v = second.Value;
509                                 if (v != null && v.Length > 0)
510                                         sb.Append (",\"" + second + "\"");
511                         }
512                         
513                         sb.Append (")");
514                         return sb.ToString ();
515                 }
516                 
517                 string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
518                 {
519                         value = TrimDB (value, true);
520                         CodeMemberMethod method;
521                         string dbMethodName = builder.Method.Name + "_DB_" + dataBoundAtts++;
522                         CodeExpression valueExpression = null;
523                         value = value.Trim ();
524                         
525 #if NET_2_0
526                         bool need_if = false;
527                         if (startsWithBindRegex.Match (value).Success) {
528                                 valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
529                                 if (valueExpression != null)
530                                         need_if = true;
531                         } else
532 #endif
533                                 if (StrUtils.StartsWith (value, "Eval", true))
534                                         valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
535                         
536                         if (valueExpression == null)
537                                 valueExpression = new CodeSnippetExpression (value);
538                         
539                         method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), builder.ControlType);
540                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
541
542                         // This should be a CodePropertyReferenceExpression for properties... but it works anyway
543                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
544
545                         CodeExpression expr;
546                         if (type == typeof (string)) {
547                                 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
548                                 CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
549                                 tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
550                                 tostring.Parameters.Add (valueExpression);
551                                 expr = tostring;
552                         } else
553                                 expr = new CodeCastExpression (type, valueExpression);
554
555                         CodeAssignStatement assign = new CodeAssignStatement (field, expr);
556 #if NET_2_0
557                         if (need_if) {
558                                 CodeExpression page = new CodePropertyReferenceExpression (thisRef, "Page");
559                                 CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
560                                 CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
561                                 CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
562                                 method.Statements.Add (ccs);
563                         }
564                         else
565 #endif
566                                 method.Statements.Add (assign);
567
568                         mainClass.Members.Add (method);
569                         return method.Name;
570                 }
571
572                 void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
573                 {
574                         CodeMemberMethod method = builder.Method;
575                         bool isWritable = IsWritablePropertyOrField (member);
576                         
577                         if (isDataBound && isWritable) {
578                                 string dbMethodName = DataBoundProperty (builder, type, var_name, att);
579                                 AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
580                                 return;
581                         }
582 #if NET_2_0
583                         else if (isExpression && isWritable) {
584                                 AddExpressionAssign (method, builder, member, type, var_name, att);
585                                 return;
586                         }
587 #endif
588
589                         CodeAssignStatement assign = new CodeAssignStatement ();
590                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
591                         currentLocation = builder.Location;
592                         assign.Right = GetExpressionFromString (type, att, member);
593
594                         method.Statements.Add (AddLinePragma (assign, builder));
595                 }
596
597                 bool IsDirective (string value, char directiveChar)
598                 {
599                         if (value == null || value == String.Empty)
600                                 return false;
601                         
602                         value = value.Trim ();
603                         if (!StrUtils.StartsWith (value, "<%") || !StrUtils.EndsWith (value, "%>"))
604                                 return false;
605
606                         int dcIndex = value.IndexOf (directiveChar, 2);
607                         if (dcIndex == -1)
608                                 return false;
609
610                         if (dcIndex == 2)
611                                 return true;
612                         dcIndex--;
613                         
614                         while (dcIndex >= 2) {
615                                 if (!Char.IsWhiteSpace (value [dcIndex]))
616                                         return false;
617                                 dcIndex--;
618                         }
619
620                         return true;
621                 }
622                 
623                 bool IsDataBound (string value)
624                 {
625                         return IsDirective (value, '#');
626                 }
627
628 #if NET_2_0
629                 bool IsExpression (string value)
630                 {
631                         return IsDirective (value, '$');
632                 }               
633
634                 void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
635                 {
636                         string str = TrimDB (value, false);
637                         if (StrUtils.StartsWith (str, "Bind", true)) {
638                                 Match match = bindRegex.Match (str);
639                                 if (match.Success) {
640                                         string bindingName = match.Groups [1].Value;
641                                         TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
642                                         
643                                         if (templateBuilder == null)
644                                                 throw new HttpException ("Bind expression not allowed in this context.");
645
646                                         if (templateBuilder.BindingDirection == BindingDirection.OneWay)
647                                                 return;
648                                         
649                                         string id = builder.GetAttribute ("ID");
650                                         if (String.IsNullOrEmpty (id))
651                                                 throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
652                                         
653                                         templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
654                                 }
655                         }
656                 }
657 #endif
658
659                 /*
660                 static bool InvariantCompare (string a, string b)
661                 {
662                         return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
663                 }
664                 */
665
666                 static bool InvariantCompareNoCase (string a, string b)
667                 {
668                         return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
669                 }
670
671                 static MemberInfo GetFieldOrProperty (Type type, string name)
672                 {
673                         MemberInfo member = null;
674                         try {
675                                 member = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
676                         } catch {}
677                         
678                         if (member != null)
679                                 return member;
680
681                         try {
682                                 member = type.GetField (name, noCaseFlags & ~BindingFlags.NonPublic);
683                         } catch {}
684
685                         return member;
686                 }
687
688                 static bool IsWritablePropertyOrField (MemberInfo member)
689                 {
690                         PropertyInfo pi = member as PropertyInfo;
691                         if (pi != null)
692                                 return pi.GetSetMethod (false) != null;
693                         FieldInfo fi = member as FieldInfo;
694                         if (fi != null)
695                                 return !fi.IsInitOnly;
696                         throw new ArgumentException ("Argument must be of PropertyInfo or FieldInfo type", "member");
697                 }
698
699                 bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
700                                                  string attValue, string prefix)
701                 {
702                         int hyphen = id.IndexOf ('-');
703                         bool isPropertyInfo = (member is PropertyInfo);
704                         bool isDataBound = IsDataBound (attValue);
705 #if NET_2_0
706                         bool isExpression = !isDataBound && IsExpression (attValue);
707 #else
708                         bool isExpression = false;
709 #endif
710                         Type type;
711                         if (isPropertyInfo) {
712                                 type = ((PropertyInfo) member).PropertyType;
713                         } else {
714                                 type = ((FieldInfo) member).FieldType;
715                         }
716
717                         if (InvariantCompareNoCase (member.Name, id)) {
718 #if NET_2_0
719                                 if (isDataBound)
720                                         RegisterBindingInfo (builder, member.Name, ref attValue);
721                                 
722 #endif
723                                 if (!IsWritablePropertyOrField (member))
724                                         return false;
725                                 
726                                 AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
727                                 return true;
728                         }
729                         
730                         if (hyphen == -1)
731                                 return false;
732
733                         string prop_field = id.Replace ('-', '.');
734                         string [] parts = prop_field.Split (new char [] {'.'});
735                         int length = parts.Length;
736                         
737                         if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
738                                 return false;
739
740                         if (length > 2) {
741                                 MemberInfo sub_member = GetFieldOrProperty (type, parts [1]);
742                                 if (sub_member == null)
743                                         return false;
744
745                                 string new_prefix = prefix + member.Name + ".";
746                                 string new_id = id.Substring (hyphen + 1);
747                                 return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
748                         }
749
750                         MemberInfo subpf = GetFieldOrProperty (type, parts [1]);
751                         if (!(subpf is PropertyInfo))
752                                 return false;
753
754                         PropertyInfo subprop = (PropertyInfo) subpf;
755                         if (subprop.CanWrite == false)
756                                 return false;
757
758                         bool is_bool = (subprop.PropertyType == typeof (bool));
759                         if (!is_bool && attValue == null)
760                                 return false; // Font-Size -> Font-Size="" as html
761
762                         string val = attValue;
763                         if (attValue == null && is_bool)
764                                 val = "true"; // Font-Bold <=> Font-Bold="true"
765 #if NET_2_0
766                         if (isDataBound)
767                                 RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
768 #endif
769                         AddCodeForPropertyOrField (builder, subprop.PropertyType,
770                                                    prefix + member.Name + "." + subprop.Name,
771                                                    val, subprop, isDataBound, isExpression);
772
773                         return true;
774                 }
775
776 #if NET_2_0
777                 CodeExpression CompileExpression (MemberInfo member, Type type, string value, bool useSetAttribute)
778                 {
779                         // First let's find the correct expression builder
780                         value = value.Substring (3, value.Length - 5).Trim ();
781                         int colon = value.IndexOf (':');
782                         if (colon == -1)
783                                 return null;
784                         string prefix = value.Substring (0, colon).Trim ();
785                         string expr = value.Substring (colon + 1).Trim ();
786                         
787                         CompilationSection cs = (CompilationSection)WebConfigurationManager.GetWebApplicationSection ("system.web/compilation");
788                         if (cs == null)
789                                 return null;
790                         
791                         if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
792                                 return null;
793
794                         System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
795                         if (ceb == null)
796                                 return null;
797                         
798                         string builderType = ceb.Type;
799                         Type t;
800                         
801                         try {
802                                 t = HttpApplication.LoadType (builderType, true);
803                         } catch (Exception e) {
804                                 throw new HttpException (String.Format ("Failed to load expression builder type `{0}'", builderType), e);
805                         }
806
807                         if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
808                                 throw new HttpException (String.Format ("Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder", builderType));
809
810                         System.Web.Compilation.ExpressionBuilder eb = null;
811                         object parsedData;
812                         ExpressionBuilderContext ctx;
813                         
814                         try {
815                                 eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
816                                 ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
817                                 parsedData = eb.ParseExpression (expr, type, ctx);
818                         } catch (Exception e) {
819                                 throw new HttpException (String.Format ("Failed to create an instance of type `{0}'", builderType), e);
820                         }
821                         
822                         BoundPropertyEntry bpe = CreateBoundPropertyEntry (member as PropertyInfo, prefix, expr, useSetAttribute);
823                         return eb.GetCodeExpression (bpe, parsedData, ctx);
824                 }
825                 
826                 void AddExpressionAssign (CodeMemberMethod method, ControlBuilder builder, MemberInfo member, Type type, string name, string value)
827                 {
828                         CodeExpression expr = CompileExpression (member, type, value, false);
829
830                         if (expr == null)
831                                 return;
832                         
833                         CodeAssignStatement assign = new CodeAssignStatement ();
834                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
835                         assign.Right = expr;
836                         
837                         builder.Method.Statements.Add (AddLinePragma (assign, builder));
838                 }
839
840                 BoundPropertyEntry CreateBoundPropertyEntry (PropertyInfo pi, string prefix, string expr, bool useSetAttribute)
841                 {
842                         BoundPropertyEntry ret = new BoundPropertyEntry ();
843                         ret.Expression = expr;
844                         ret.ExpressionPrefix = prefix;
845                         ret.Generated = false;
846                         if (pi != null) {
847                                 ret.Name = pi.Name;
848                                 ret.PropertyInfo = pi;
849                                 ret.Type = pi.PropertyType;
850                         }
851                         ret.UseSetAttribute = useSetAttribute;
852                         
853                         return ret;
854                 }
855
856                 bool ResourceProviderHasObject (string key)
857                 {
858                         IResourceProvider rp = HttpContext.GetResourceProvider (key, true);
859                         if (rp == null)
860                                 return false;
861
862                         IResourceReader rr = rp.ResourceReader;
863                         if (rr == null)
864                                 return false;
865
866                         IDictionaryEnumerator ide = rr.GetEnumerator ();
867                         if (ide == null)
868                                 return false;
869                         
870                         string dictKey;
871                         while (ide.MoveNext ()) {
872                                 dictKey = ide.Key as string;
873                                 if (String.IsNullOrEmpty (dictKey))
874                                         continue;
875                                 if (String.Compare (key, dictKey, StringComparison.Ordinal) == 0)
876                                         return true;
877                         }
878
879                         return false;
880                 }
881                 
882                 void AssignPropertyFromResources (ControlBuilder builder, MemberInfo mi, string attvalue)
883                 {
884                         bool isProperty = mi.MemberType == MemberTypes.Property;
885                         bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
886
887                         if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
888                                 return;                 
889
890                         object[] attrs = mi.GetCustomAttributes (typeof (LocalizableAttribute), true);
891                         if (attrs == null || attrs.Length == 0 || !((LocalizableAttribute)attrs [0]).IsLocalizable)
892                                 return;
893                         
894                         string memberName = mi.Name;
895                         string resname = String.Concat (attvalue, ".", memberName);
896
897                         if (!ResourceProviderHasObject (resname))
898                                 return;
899                         
900                         // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
901                         string inputFile = parser.InputFile;
902                         string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
903         
904                         if (StrUtils.StartsWith (inputFile, physPath))
905                                 inputFile = parser.InputFile.Substring (physPath.Length - 1);
906                         else
907                                 return;
908
909                         char dsc = System.IO.Path.DirectorySeparatorChar;
910                         if (dsc != '/')
911                                 inputFile = inputFile.Replace (dsc, '/');
912
913                         object obj = HttpContext.GetLocalResourceObject (inputFile, resname);
914                         if (obj == null)
915                                 return;
916
917                         if (!isProperty && !isField)
918                                 return; // an "impossible" case
919                         
920                         CodeAssignStatement assign = new CodeAssignStatement ();
921                         
922                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, memberName);
923                         assign.Right = ResourceExpressionBuilder.CreateGetLocalResourceObject (mi, resname);
924                         
925                         builder.Method.Statements.Add (AddLinePragma (assign, builder));
926                 }
927
928                 void AssignPropertiesFromResources (ControlBuilder builder, Type controlType, string attvalue)
929                 {
930                         // Process all public fields and properties of the control. We don't use GetMembers to make the code
931                         // faster
932                         FieldInfo [] fields = controlType.GetFields (
933                                 BindingFlags.Instance | BindingFlags.Static |
934                                 BindingFlags.Public | BindingFlags.FlattenHierarchy);
935                         PropertyInfo [] properties = controlType.GetProperties (
936                                 BindingFlags.Instance | BindingFlags.Static |
937                                 BindingFlags.Public | BindingFlags.FlattenHierarchy);
938
939                         foreach (FieldInfo fi in fields)
940                                 AssignPropertyFromResources (builder, fi, attvalue);
941                         foreach (PropertyInfo pi in properties)
942                                 AssignPropertyFromResources (builder, pi, attvalue);
943                 }
944                 
945                 void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
946                 {
947                         if (attvalue == null || attvalue.Length == 0)
948                                 return;
949                         
950                         Type controlType = builder.ControlType;
951                         if (controlType == null)
952                                 return;
953
954                         AssignPropertiesFromResources (builder, controlType, attvalue);
955                 }
956 #endif
957                 
958                 void AddEventAssign (CodeMemberMethod method, ControlBuilder builder, string name, Type type, string value)
959                 {
960                         //"__ctrl.{0} += new {1} (this.{2});"
961                         CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
962
963                         CodeDelegateCreateExpression create;
964                         create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
965
966                         CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
967                         method.Statements.Add (attach);
968                 }
969                 
970                 void CreateAssignStatementFromAttribute (ControlBuilder builder, string id)
971                 {
972                         EventInfo [] ev_info = null;
973                         Type type = builder.ControlType;
974                         
975                         string attvalue = builder.GetAttribute (id);
976                         if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
977                                 if (ev_info == null)
978                                         ev_info = type.GetEvents ();
979
980                                 string id_as_event = id.Substring (2);
981                                 foreach (EventInfo ev in ev_info){
982                                         if (InvariantCompareNoCase (ev.Name, id_as_event)){
983                                                 AddEventAssign (builder.Method,
984                                                                 builder,
985                                                                 ev.Name,
986                                                                 ev.EventHandlerType,
987                                                                 attvalue);
988                                                 
989                                                 return;
990                                         }
991                                 }
992
993                         }
994
995 #if NET_2_0
996                         if (id.ToLower () == "meta:resourcekey") {
997                                 AssignPropertiesFromResources (builder, attvalue);
998                                 return;
999                         }
1000 #endif
1001                         
1002                         int hyphen = id.IndexOf ('-');
1003                         string alt_id = id;
1004                         if (hyphen != -1)
1005                                 alt_id = id.Substring (0, hyphen);
1006
1007                         MemberInfo fop = GetFieldOrProperty (type, alt_id);
1008                         if (fop != null) {
1009                                 if (ProcessPropertiesAndFields (builder, fop, id, attvalue, null))
1010                                         return;
1011                         }
1012
1013                         if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
1014                                 throw new ParseException (builder.Location, "Unrecognized attribute: " + id);
1015
1016                         CodeMemberMethod method = builder.Method;
1017                         bool isDatabound = IsDataBound (attvalue);
1018 #if NET_2_0
1019                         bool isExpression = !isDatabound && IsExpression (attvalue);
1020 #endif
1021
1022                         if (isDatabound) {
1023                                 string value = attvalue.Substring (3, attvalue.Length - 5).Trim ();
1024                                 CodeExpression valueExpression = null;
1025 #if NET_2_0
1026                                 if (startsWithBindRegex.Match (value).Success)
1027                                         valueExpression = CreateEvalInvokeExpression (bindRegexInValue, value, true);
1028                                 else
1029 #endif
1030                                 if (StrUtils.StartsWith (value, "Eval", true))
1031                                         valueExpression = CreateEvalInvokeExpression (evalRegexInValue, value, false);
1032                                 
1033                                 if (valueExpression == null && value != null && value.Trim () != String.Empty)
1034                                         valueExpression = new CodeSnippetExpression (value);
1035                                 
1036                                 CreateDBAttributeMethod (builder, id, valueExpression);
1037                         } else {
1038                                 CodeCastExpression cast;
1039                                 CodeMethodReferenceExpression methodExpr;
1040                                 CodeMethodInvokeExpression expr;
1041
1042                                 cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
1043                                 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
1044                                 expr = new CodeMethodInvokeExpression (methodExpr);
1045                                 expr.Parameters.Add (new CodePrimitiveExpression (id));
1046
1047                                 CodeExpression valueExpr = null;
1048 #if NET_2_0
1049                                 if (isExpression)
1050                                         valueExpr = CompileExpression (null, typeof (string), attvalue, true);
1051
1052                                 if (valueExpr == null)
1053 #endif
1054                                         valueExpr = new CodePrimitiveExpression (attvalue);
1055                                 
1056                                 expr.Parameters.Add (valueExpr);
1057                                 method.Statements.Add (AddLinePragma (expr, builder));
1058                         }
1059                 }
1060
1061                 protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
1062                 {
1063                         this.dataBoundAtts = 0;
1064                         IDictionary atts = builder.Attributes;
1065                         if (atts == null || atts.Count == 0)
1066                                 return;
1067                         
1068                         foreach (string id in atts.Keys) {
1069                                 if (InvariantCompareNoCase (id, "runat"))
1070                                         continue;
1071                                 // ID is assigned in BuildControltree
1072                                 if (InvariantCompareNoCase (id, "id"))
1073                                         continue;
1074                                 
1075 #if NET_2_0
1076                                 /* we skip SkinID here as it's assigned in BuildControlTree */
1077                                 if (InvariantCompareNoCase (id, "skinid"))
1078                                         continue;
1079                                 if (InvariantCompareNoCase (id, "meta:resourcekey"))
1080                                         continue; // ignore, this one's processed at the very end of
1081                                                   // the method
1082 #endif
1083                                 CreateAssignStatementFromAttribute (builder, id);
1084                         }
1085                 }
1086
1087                 void CreateDBAttributeMethod (ControlBuilder builder, string attr, CodeExpression code)
1088                 {
1089                         if (code == null)
1090                                 return;
1091
1092                         string id = builder.GetNextID (null);
1093                         string dbMethodName = "__DataBind_" + id;
1094                         CodeMemberMethod method = builder.Method;
1095                         AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
1096
1097                         method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), builder.ControlType);
1098 #if NET_2_0
1099                         builder.DataBindingMethod = method;
1100 #endif
1101                         CodeCastExpression cast;
1102                         CodeMethodReferenceExpression methodExpr;
1103                         CodeMethodInvokeExpression expr;
1104
1105                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1106                         cast = new CodeCastExpression (typeof (IAttributeAccessor), targetExpr);
1107                         methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
1108                         expr = new CodeMethodInvokeExpression (methodExpr);
1109                         expr.Parameters.Add (new CodePrimitiveExpression (attr));
1110                         CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
1111                         tostring.Method = new CodeMethodReferenceExpression (
1112                                                         new CodeTypeReferenceExpression (typeof (Convert)),
1113                                                         "ToString");
1114                         tostring.Parameters.Add (code);
1115                         expr.Parameters.Add (tostring);
1116                         method.Statements.Add (expr);
1117                         mainClass.Members.Add (method);
1118                 }
1119
1120                 void AddRenderControl (ControlBuilder builder)
1121                 {
1122                         CodeIndexerExpression indexer = new CodeIndexerExpression ();
1123                         indexer.TargetObject = new CodePropertyReferenceExpression (
1124                                                         new CodeArgumentReferenceExpression ("parameterContainer"),
1125                                                         "Controls");
1126                                                         
1127                         indexer.Indices.Add (new CodePrimitiveExpression (builder.RenderIndex));
1128                         
1129                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
1130                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
1131                         builder.RenderMethod.Statements.Add (invoke);
1132                         builder.IncreaseRenderIndex ();
1133                 }
1134
1135                 protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
1136                 {
1137                         if (parent == null || child == null)
1138                                 return;
1139                         
1140                         CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.Method.Name);
1141                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
1142
1143                         object [] atts = null;
1144
1145                         if (child.ControlType != null)
1146                                 atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
1147                         
1148                         if (atts != null && atts.Length > 0) {
1149                                 PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
1150                                 CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
1151                                 CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
1152                                 build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
1153                                 build.Parameters.Add (new CodePrimitiveExpression (child.ID));
1154 #if NET_1_1
1155                                 if (pca.Shared)
1156                                         build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
1157                                 else
1158 #endif
1159                                         build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
1160                                         
1161                                 build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
1162                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
1163                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
1164                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
1165                                 build.Parameters.Add (new CodeDelegateCreateExpression (
1166                                                               new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
1167                                                               thisRef, child.Method.Name));
1168
1169                                 parent.MethodStatements.Add (AddLinePragma (build, parent));
1170                                 if (parent.HasAspCode)
1171                                         AddRenderControl (parent);
1172                                 return;
1173                         }
1174                                 
1175                         if (child.IsProperty || parent.ChildrenAsProperties) {
1176                                 expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
1177                                 parent.MethodStatements.Add (AddLinePragma (expr, parent));
1178                                 return;
1179                         }
1180
1181                         parent.MethodStatements.Add (AddLinePragma (expr, parent));
1182                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
1183                         if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType))
1184                                 AddParsedSubObjectStmt (parent, field);
1185                         else {
1186                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
1187                                 invoke.Parameters.Add (field);
1188                                 parent.MethodStatements.Add (AddLinePragma (invoke, parent));
1189                         }
1190                                 
1191                         if (parent.HasAspCode)
1192                                 AddRenderControl (parent);
1193                 }
1194
1195                 void AddTemplateInvocation (ControlBuilder builder, string name, string methodName)
1196                 {
1197                         CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
1198
1199                         CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1200                                 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1201
1202                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
1203                         newCompiled.Parameters.Add (newBuild);
1204
1205                         CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1206                         builder.Method.Statements.Add (AddLinePragma (assign, builder));
1207                 }
1208
1209 #if NET_2_0
1210                 void AddBindableTemplateInvocation (ControlBuilder builder, string name, string methodName, string extractMethodName)
1211                 {
1212                         CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
1213
1214                         CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1215                                 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1216
1217                         CodeDelegateCreateExpression newExtract = new CodeDelegateCreateExpression (
1218                                 new CodeTypeReference (typeof (ExtractTemplateValuesMethod)), thisRef, extractMethodName);
1219
1220                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
1221                         newCompiled.Parameters.Add (newBuild);
1222                         newCompiled.Parameters.Add (newExtract);
1223                         
1224                         CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1225                         builder.Method.Statements.Add (AddLinePragma (assign, builder));
1226                 }
1227                 
1228                 string CreateExtractValuesMethod (TemplateBuilder builder)
1229                 {
1230                         CodeMemberMethod method = new CodeMemberMethod ();
1231                         method.Name = "__ExtractValues_" + builder.ID;
1232                         method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
1233                         method.ReturnType = new CodeTypeReference (typeof(IOrderedDictionary));
1234                         
1235                         CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression ();
1236                         arg.Type = new CodeTypeReference (typeof (Control));
1237                         arg.Name = "__container";
1238                         method.Parameters.Add (arg);
1239                         mainClass.Members.Add (method);
1240                         
1241                         CodeObjectCreateExpression newTable = new CodeObjectCreateExpression ();
1242                         newTable.CreateType = new CodeTypeReference (typeof(OrderedDictionary));
1243                         method.Statements.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary), "__table", newTable));
1244                         CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
1245                         
1246                         if (builder.Bindings != null) {
1247                                 Hashtable hash = new Hashtable ();
1248                                 foreach (TemplateBinding binding in builder.Bindings) {
1249                                         CodeConditionStatement sif;
1250                                         CodeVariableReferenceExpression control;
1251                                         CodeAssignStatement assign;
1252
1253                                         if (hash [binding.ControlId] == null) {
1254
1255                                                 CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
1256                                                 method.Statements.Add (dec);
1257                                                 CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
1258                                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
1259                                                 invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
1260
1261                                                 assign = new CodeAssignStatement ();
1262                                                 control = new CodeVariableReferenceExpression (binding.ControlId);
1263                                                 assign.Left = control;
1264                                                 assign.Right = new CodeCastExpression (binding.ControlType, invoke);
1265                                                 method.Statements.Add (assign);
1266
1267                                                 sif = new CodeConditionStatement ();
1268                                                 sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
1269
1270                                                 method.Statements.Add (sif);
1271
1272                                                 hash [binding.ControlId] = sif;
1273                                         }
1274
1275                                         sif = (CodeConditionStatement) hash [binding.ControlId];
1276                                         control = new CodeVariableReferenceExpression (binding.ControlId);
1277                                         assign = new CodeAssignStatement ();
1278                                         assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
1279                                         assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
1280                                         sif.TrueStatements.Add (assign);
1281                                 }
1282                         }
1283
1284                         method.Statements.Add (new CodeMethodReturnStatement (tableExp));
1285                         return method.Name;
1286                 }
1287
1288                 void AddContentTemplateInvocation (ContentBuilderInternal cbuilder, CodeMemberMethod method, string methodName)
1289                 {
1290                         CodeDelegateCreateExpression newBuild = new CodeDelegateCreateExpression (
1291                                 new CodeTypeReference (typeof (BuildTemplateMethod)), thisRef, methodName);
1292
1293                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
1294                         newCompiled.Parameters.Add (newBuild);
1295                         
1296                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (thisRef, "AddContentTemplate");
1297                         invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
1298                         invoke.Parameters.Add (newCompiled);
1299
1300                         method.Statements.Add (AddLinePragma (invoke, cbuilder));
1301                 }
1302 #endif
1303
1304                 void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
1305                 {
1306                         if (cr.Code == null || cr.Code.Trim () == "")
1307                                 return;
1308
1309                         if (!cr.IsAssign) {
1310                                 CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
1311                                 parent.RenderMethod.Statements.Add (AddLinePragma (code, cr));
1312                                 return;
1313                         }
1314
1315                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
1316                         expr.Method = new CodeMethodReferenceExpression (
1317                                                         new CodeArgumentReferenceExpression ("__output"),
1318                                                         "Write");
1319
1320                         expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
1321                         parent.RenderMethod.Statements.Add (AddLinePragma (expr, cr));
1322                 }
1323
1324 #if !NET_2_0
1325                 static PropertyInfo GetContainerProperty (Type type, string[] propNames)
1326                 {
1327                         PropertyInfo prop;
1328                         
1329                         foreach (string name in propNames) {
1330                                 prop = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
1331                                 if (prop != null)
1332                                         return prop;
1333                         }
1334
1335                         return null;
1336                 }
1337
1338                 static string[] containerPropNames = {"Items", "Rows"};
1339 #endif
1340                 
1341                 static Type GetContainerType (ControlBuilder builder)
1342                 {
1343                         Type type = builder.BindingContainerType;
1344                         
1345 #if NET_2_0
1346                         return type;
1347 #else
1348                         
1349                         PropertyInfo prop = GetContainerProperty (type, containerPropNames);
1350                         if (prop == null)
1351                                 return type;
1352
1353                         Type ptype = prop.PropertyType;
1354                         if (!typeof (ICollection).IsAssignableFrom (ptype))
1355                                 return type;
1356
1357                         prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
1358                         if (prop == null)
1359                                 return type;
1360
1361                         return prop.PropertyType;
1362 #endif
1363                 }
1364                 
1365                 CodeMemberMethod CreateDBMethod (ControlBuilder builder, string name, Type container, Type target)
1366                 {
1367                         CodeMemberMethod method = new CodeMemberMethod ();
1368                         method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1369                         method.Name = name;
1370                         method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
1371                         method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
1372
1373                         CodeTypeReference containerRef = new CodeTypeReference (container);
1374                         CodeTypeReference targetRef = new CodeTypeReference (target);
1375
1376                         CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
1377                         decl.Name = "Container";
1378                         decl.Type = containerRef;
1379                         method.Statements.Add (decl);
1380                         
1381                         decl = new CodeVariableDeclarationStatement();
1382                         decl.Name = "target";
1383                         decl.Type = targetRef;
1384                         method.Statements.Add (decl);
1385
1386                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1387                         CodeAssignStatement assign = new CodeAssignStatement ();
1388                         assign.Left = targetExpr;
1389                         assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
1390                         method.Statements.Add (AddLinePragma (assign, builder));
1391
1392                         assign = new CodeAssignStatement ();
1393                         assign.Left = new CodeVariableReferenceExpression ("Container");
1394                         assign.Right = new CodeCastExpression (containerRef,
1395                                                 new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
1396                         method.Statements.Add (AddLinePragma (assign, builder));
1397
1398                         return method;
1399                 }
1400
1401                 void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
1402                 {
1403                         if (db.Code == null || db.Code.Trim () == "")
1404                                 return;
1405
1406                         EnsureID (db);
1407                         CreateField (db, false);
1408
1409                         string dbMethodName = "__DataBind_" + db.ID;
1410                         // Add the method that builds the DataBoundLiteralControl
1411                         InitMethod (db, false, false);
1412                         CodeMemberMethod method = db.Method;
1413                         AddEventAssign (method, builder, "DataBinding", typeof (EventHandler), dbMethodName);
1414                         method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1415
1416                         // Add the DataBind handler
1417                         method = CreateDBMethod (builder, dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
1418 #if NET_2_0
1419                         builder.DataBindingMethod = method;
1420 #endif
1421                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1422                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1423                         invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
1424                         invoke.Parameters.Add (new CodePrimitiveExpression (0));
1425
1426                         CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
1427                         tostring.Method = new CodeMethodReferenceExpression (
1428                                                         new CodeTypeReferenceExpression (typeof (Convert)),
1429                                                         "ToString");
1430                         tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
1431                         invoke.Parameters.Add (tostring);
1432                         method.Statements.Add (AddLinePragma (invoke, builder));
1433                         
1434                         mainClass.Members.Add (method);
1435                         
1436                         AddChildCall (builder, db);
1437                 }
1438
1439                 void FlushText (ControlBuilder builder, StringBuilder sb)
1440                 {
1441                         if (sb.Length > 0) {
1442                                 AddLiteralSubObject (builder, sb.ToString ());
1443                                 sb.Length = 0;
1444                         }
1445                 }
1446
1447                 protected void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
1448                 {
1449                         EnsureID (builder);
1450                         bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
1451                         
1452                         if (!isTemplate && !inTemplate) {
1453                                 CreateField (builder, true);
1454                         } else if (!isTemplate) {
1455                                 bool doCheck = false;
1456                                 
1457 #if NET_2_0
1458                                 bool singleInstance = false;
1459                                 ControlBuilder pb = builder.ParentBuilder;
1460                                 TemplateBuilder tpb;
1461                                 while (pb != null) {
1462                                         tpb = pb as TemplateBuilder;
1463                                         if (tpb == null) {
1464                                                 pb = pb.ParentBuilder;
1465                                                 continue;
1466                                         }
1467                                         
1468                                         if (tpb.TemplateInstance == TemplateInstance.Single)
1469                                                 singleInstance = true;
1470                                         break;
1471                                 }
1472                                 
1473                                 if (!singleInstance)
1474 #endif
1475                                         builder.ID = builder.GetNextID (null);
1476 #if NET_2_0
1477                                 else
1478                                         doCheck = true;
1479 #endif
1480                                 CreateField (builder, doCheck);
1481                         }
1482
1483                         InitMethod (builder, isTemplate, childrenAsProperties);
1484                         if (!isTemplate || builder.GetType () == typeof (RootBuilder))
1485                                 CreateAssignStatementsFromAttributes (builder);
1486
1487                         if (builder.Children != null && builder.Children.Count > 0) {
1488                                 StringBuilder sb = new StringBuilder ();
1489                                 foreach (object b in builder.Children) {
1490                                         if (b is string) {
1491                                                 sb.Append ((string) b);
1492                                                 continue;
1493                                         }
1494
1495                                         FlushText (builder, sb);
1496                                         if (b is ObjectTagBuilder) {
1497                                                 ProcessObjectTag ((ObjectTagBuilder) b);
1498                                         } else if (b is StringPropertyBuilder) {
1499                                                 StringPropertyBuilder pb = b as StringPropertyBuilder;
1500                                                 if (pb.Children != null && pb.Children.Count > 0) {
1501                                                         StringBuilder asb = new StringBuilder ();
1502                                                         foreach (string s in pb.Children)
1503                                                                 asb.Append (s);
1504                                                         CodeMemberMethod method = builder.Method;
1505                                                         CodeAssignStatement assign = new CodeAssignStatement ();
1506                                                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, pb.PropertyName);
1507                                                         assign.Right = new CodePrimitiveExpression (asb.ToString ());
1508                                                         method.Statements.Add (AddLinePragma (assign, builder));
1509                                                 }
1510                                         }
1511 #if NET_2_0
1512                                         else if (b is ContentBuilderInternal) {
1513                                                 ContentBuilderInternal cb = (ContentBuilderInternal) b;
1514                                                 CreateControlTree (cb, false, true);
1515                                                 AddContentTemplateInvocation (cb, builder.Method, cb.Method.Name);
1516                                                 continue;
1517                                         }
1518 #endif
1519                                         // Ignore TemplateBuilders - they are processed in InitMethod
1520                                         else if (b is TemplateBuilder) {
1521                                         } else if (b is CodeRenderBuilder) {
1522                                                 AddCodeRender (builder, (CodeRenderBuilder) b);
1523                                         } else if (b is DataBindingBuilder) {
1524                                                 AddDataBindingLiteral (builder, (DataBindingBuilder) b);
1525                                         } else if (b is ControlBuilder) {
1526                                                 ControlBuilder child = (ControlBuilder) b;
1527                                                 CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
1528                                                 AddChildCall (builder, child);
1529                                                 continue;
1530                                         } else
1531                                                 throw new Exception ("???");
1532
1533 #if NET_2_0
1534                                         ControlBuilder bldr = b as ControlBuilder;
1535                                         bldr.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, bldr.Method, bldr.DataBindingMethod);
1536 #endif
1537                                 }
1538
1539                                 FlushText (builder, sb);
1540                         }
1541
1542                         ControlBuilder defaultPropertyBuilder = builder.DefaultPropertyBuilder;
1543                         if (defaultPropertyBuilder != null) {
1544                                 CreateControlTree (defaultPropertyBuilder, false, true);
1545                                 AddChildCall (builder, defaultPropertyBuilder);
1546                         }
1547                         
1548                         if (builder.HasAspCode) {
1549                                 CodeMemberMethod renderMethod = builder.RenderMethod;
1550                                 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1551                                 m.TargetObject = thisRef;
1552                                 m.MethodName = renderMethod.Name;
1553
1554                                 CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
1555                                 create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
1556                                 create.TargetObject = thisRef;
1557                                 create.MethodName = renderMethod.Name;
1558
1559                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1560                                 invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
1561                                 invoke.Parameters.Add (create);
1562
1563                                 builder.MethodStatements.Add (invoke);
1564                         }
1565
1566 #if NET_2_0
1567                         if (builder is RootBuilder)
1568                                 if (!String.IsNullOrEmpty (parser.MetaResourceKey))
1569                                         AssignPropertiesFromResources (builder, parser.BaseType, parser.MetaResourceKey);
1570                         
1571                         if ((!isTemplate || builder is RootBuilder) && !String.IsNullOrEmpty (builder.GetAttribute ("meta:resourcekey")))
1572                                 CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
1573 #endif
1574
1575                         if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
1576                                 builder.Method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1577
1578 #if NET_2_0
1579                         builder.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, builder.Method, builder.DataBindingMethod);
1580 #endif
1581                 }
1582
1583 #if NET_2_0
1584                 protected override void AddStatementsToConstructor (CodeConstructor ctor)
1585                 {
1586                         if (masterPageContentPlaceHolders == null || masterPageContentPlaceHolders.Count == 0)
1587                                 return;
1588                         
1589                         var ilist = new CodeVariableDeclarationStatement ();
1590                         ilist.Name = "__contentPlaceHolders";
1591                         ilist.Type = new CodeTypeReference (typeof (IList));
1592                         ilist.InitExpression = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
1593                         
1594                         var ilistRef = new CodeVariableReferenceExpression ("__contentPlaceHolders");
1595                         CodeStatementCollection statements = ctor.Statements;
1596                         statements.Add (ilist);
1597
1598                         CodeMethodInvokeExpression mcall;
1599                         foreach (string id in masterPageContentPlaceHolders) {
1600                                 mcall = new CodeMethodInvokeExpression (ilistRef, "Add");
1601                                 mcall.Parameters.Add (new CodePrimitiveExpression (id.ToLowerInvariant ()));
1602                                 statements.Add (mcall);
1603                         }
1604                 }
1605 #endif
1606                 
1607                 protected internal override void CreateMethods ()
1608                 {
1609                         base.CreateMethods ();
1610
1611                         CreateProperties ();
1612                         CreateControlTree (parser.RootBuilder, false, false);
1613                         CreateFrameworkInitializeMethod ();
1614                 }
1615
1616 #if NET_2_0
1617                 protected override void InitializeType ()
1618                 {
1619                         List <string> registeredTagNames = parser.RegisteredTagNames;
1620                         RootBuilder rb = parser.RootBuilder;
1621                         if (rb == null || registeredTagNames == null || registeredTagNames.Count == 0)
1622                                 return;
1623
1624                         AspComponent component;
1625                         foreach (string tagName in registeredTagNames) {
1626                                 component = rb.Foundry.GetComponent (tagName);
1627                                 if (component == null || component.Type == null) // unlikely
1628                                         throw new HttpException ("Custom control '" + tagName + "' cannot be found.");
1629                                 if (!(typeof (UserControl).IsAssignableFrom (component.Type)))
1630                                         throw new ParseException (parser.Location, "Type '" + component.Type.ToString () + "' does not derive from 'System.Web.UI.UserControl'.");
1631                                 AddReferencedAssembly (component.Type.Assembly);
1632                         }
1633                 }
1634                 
1635                 void CallBaseFrameworkInitialize (CodeMemberMethod method)
1636                 {
1637                         CodeBaseReferenceExpression baseRef = new CodeBaseReferenceExpression ();
1638                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (baseRef, "FrameworkInitialize");
1639                         method.Statements.Add (invoke);
1640                 }
1641 #endif
1642                 
1643                 void CallSetStringResourcePointer (CodeMemberMethod method)
1644                 {
1645                         CodeFieldReferenceExpression stringResource = GetMainClassFieldReferenceExpression ("__stringResource");
1646                         method.Statements.Add (
1647                                 new CodeMethodInvokeExpression (
1648                                         thisRef,
1649                                         "SetStringResourcePointer",
1650                                         new CodeExpression[] {stringResource, new CodePrimitiveExpression (0)})
1651                         );
1652                 }
1653                 
1654                 void CreateFrameworkInitializeMethod ()
1655                 {
1656                         CodeMemberMethod method = new CodeMemberMethod ();
1657                         method.Name = "FrameworkInitialize";
1658                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1659                         PrependStatementsToFrameworkInitialize (method);
1660 #if NET_2_0
1661                         CallBaseFrameworkInitialize (method);
1662 #endif
1663                         CallSetStringResourcePointer (method);
1664                         AppendStatementsToFrameworkInitialize (method);
1665                         mainClass.Members.Add (method);
1666                 }
1667
1668                 protected virtual void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
1669                 {
1670                 }
1671
1672                 protected virtual void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
1673                 {
1674                         if (!parser.EnableViewState) {
1675                                 CodeAssignStatement stmt = new CodeAssignStatement ();
1676                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
1677                                 stmt.Right = new CodePrimitiveExpression (false);
1678                                 method.Statements.Add (stmt);
1679                         }
1680
1681                         CodeMethodReferenceExpression methodExpr;
1682                         methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
1683                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
1684                         method.Statements.Add (new CodeExpressionStatement (expr));
1685                 }
1686
1687                 protected override void AddApplicationAndSessionObjects ()
1688                 {
1689                         foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
1690                                 CreateFieldForObject (tag.Type, tag.ObjectID);
1691                                 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
1692                         }
1693
1694                         foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
1695                                 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
1696                         }
1697                 }
1698
1699                 protected override void CreateStaticFields ()
1700                 {
1701                         base.CreateStaticFields ();
1702
1703                         CodeMemberField fld = new CodeMemberField (typeof (object), "__stringResource");
1704                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
1705                         fld.InitExpression = new CodePrimitiveExpression (null);
1706                         mainClass.Members.Add (fld);
1707                 }
1708                 
1709                 protected void ProcessObjectTag (ObjectTagBuilder tag)
1710                 {
1711                         string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
1712                         CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
1713                 }
1714
1715                 void CreateProperties ()
1716                 {
1717                         if (!parser.AutoEventWireup) {
1718                                 CreateAutoEventWireup ();
1719                         } else {
1720                                 CreateAutoHandlers ();
1721                         }
1722
1723                         CreateApplicationInstance ();
1724                 }
1725                 
1726                 void CreateApplicationInstance ()
1727                 {
1728                         CodeMemberProperty prop = new CodeMemberProperty ();
1729                         Type appType = typeof (HttpApplication);
1730                         prop.Type = new CodeTypeReference (appType);
1731                         prop.Name = "ApplicationInstance";
1732                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
1733
1734                         CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
1735
1736                         propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
1737
1738                         CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
1739                         prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
1740 #if NET_2_0
1741                         if (partialClass != null)
1742                                 partialClass.Members.Add (prop);
1743                         else
1744 #endif
1745                         mainClass.Members.Add (prop);
1746                 }
1747
1748 #if NET_2_0
1749                 void CreateContentPlaceHolderTemplateProperty (string backingField, string name)
1750                 {
1751                         CodeMemberProperty prop = new CodeMemberProperty ();
1752                         prop.Type = new CodeTypeReference (typeof (ITemplate));
1753                         prop.Name = name;
1754                         prop.Attributes = MemberAttributes.Public;
1755
1756                         var ret = new CodeMethodReturnStatement ();
1757                         var fldRef = new CodeFieldReferenceExpression (thisRef, backingField);
1758                         ret.Expression = fldRef;
1759                         prop.GetStatements.Add (ret);
1760                         prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
1761
1762                         prop.CustomAttributes.Add (new CodeAttributeDeclaration ("TemplateContainer", new CodeAttributeArgument [] {
1763                                                 new CodeAttributeArgument (new CodeTypeOfExpression (new CodeTypeReference (typeof (MasterPage))))
1764                                         }
1765                                 )
1766                         );
1767
1768                         var enumValueRef = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (typeof (TemplateInstance)), "Single");
1769                         prop.CustomAttributes.Add (new CodeAttributeDeclaration ("TemplateInstanceAttribute", new CodeAttributeArgument [] {
1770                                                 new CodeAttributeArgument (enumValueRef)
1771                                         }
1772                                 )
1773                         );
1774
1775                         mainClass.Members.Add (prop);
1776                 }
1777 #endif
1778                 
1779                 void CreateAutoHandlers ()
1780                 {
1781                         // Create AutoHandlers property
1782                         CodeMemberProperty prop = new CodeMemberProperty ();
1783                         prop.Type = new CodeTypeReference (typeof (int));
1784                         prop.Name = "AutoHandlers";
1785                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1786                         
1787                         CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
1788                         CodeFieldReferenceExpression fldRef ;
1789                         fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
1790                         ret.Expression = fldRef;
1791                         prop.GetStatements.Add (ret);
1792                         prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
1793
1794 #if NET_2_0
1795                         CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
1796                         prop.CustomAttributes.Add (attr);
1797 #endif
1798                         
1799                         mainClass.Members.Add (prop);
1800
1801                         // Add the __autoHandlers field
1802                         CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
1803                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
1804                         mainClass.Members.Add (fld);
1805                 }
1806
1807                 void CreateAutoEventWireup ()
1808                 {
1809                         // The getter returns false
1810                         CodeMemberProperty prop = new CodeMemberProperty ();
1811                         prop.Type = new CodeTypeReference (typeof (bool));
1812                         prop.Name = "SupportAutoEvents";
1813                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1814                         prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
1815                         mainClass.Members.Add (prop);
1816                 }
1817
1818 #if NET_2_0
1819                 protected virtual string HandleUrlProperty (string str, MemberInfo member)
1820                 {
1821                         return str;
1822                 }
1823 #endif
1824
1825                 TypeConverter GetConverterForMember (MemberInfo member)
1826                 {
1827                         TypeConverterAttribute tca = null;
1828                         object[] attrs;
1829                         
1830 #if NET_2_0
1831                         attrs = member.GetCustomAttributes (typeof (TypeConverterAttribute), true);
1832                         if (attrs.Length > 0)
1833                                 tca = attrs [0] as TypeConverterAttribute;
1834 #else
1835                         attrs = member.GetCustomAttributes (true);
1836                         
1837                         foreach (object attr in attrs) {
1838                                 tca = attr as TypeConverterAttribute;
1839                                 
1840                                 if (tca != null)
1841                                         break;
1842                         }
1843 #endif
1844
1845                         if (tca == TypeConverterAttribute.Default)
1846                                 tca = null;
1847                         
1848                         if (tca == null)
1849                                 return null;
1850
1851                         string typeName = tca.ConverterTypeName;
1852                         if (typeName == null || typeName.Length == 0)
1853                                 return null;
1854
1855                         Type t = null;
1856                         try {
1857                                 t = HttpApplication.LoadType (typeName);
1858                         } catch (Exception) {
1859                                 // ignore
1860                         }
1861
1862                         if (t == null)
1863                                 return null;
1864
1865                         return (TypeConverter) Activator.CreateInstance (t);
1866                 }
1867                 
1868                 CodeExpression CreateNullableExpression (Type type, CodeExpression inst, bool nullable)
1869                 {
1870 #if NET_2_0
1871                         if (!nullable)
1872                                 return inst;
1873                         
1874                         return new CodeObjectCreateExpression (
1875                                 type,
1876                                 new CodeExpression[] {inst}
1877                         );
1878 #else
1879                         return inst;
1880 #endif
1881                 }
1882
1883                 bool SafeCanConvertFrom (Type type, TypeConverter cvt)
1884                 {
1885                         try {
1886                                 return cvt.CanConvertFrom (type);
1887                         } catch (NotImplementedException) {
1888                                 return false;
1889                         }
1890                 }
1891
1892                 bool SafeCanConvertTo (Type type, TypeConverter cvt)
1893                 {
1894                         try {
1895                                 return cvt.CanConvertTo (type);
1896                         } catch (NotImplementedException) {
1897                                 return false;
1898                         }
1899                 }
1900                 
1901                 CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
1902                 {
1903                         TypeConverter cvt = GetConverterForMember (member);
1904                         if (cvt != null && !SafeCanConvertFrom (typeof (string), cvt))
1905                                 cvt = null;
1906                         
1907                         object convertedFromAttr = null;
1908                         bool preConverted = false;
1909                         if (cvt != null && str != null) {
1910                                 convertedFromAttr = cvt.ConvertFromInvariantString (str);
1911                                 if (convertedFromAttr != null) {
1912                                         type = convertedFromAttr.GetType ();
1913                                         preConverted = true;
1914                                 }
1915                         }
1916
1917                         bool wasNullable = false;
1918                         Type originalType = type;
1919 #if NET_2_0
1920                         if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
1921                                 Type[] types = type.GetGenericArguments();
1922                                 originalType = type;
1923                                 type = types[0]; // we're interested only in the first type here
1924                                 wasNullable = true;
1925                         }
1926 #endif
1927                         if (type == typeof (string)) {
1928                                 if (preConverted)
1929                                         return CreateNullableExpression (originalType,
1930                                                                          new CodePrimitiveExpression ((string) convertedFromAttr),
1931                                                                          wasNullable);
1932                                 
1933 #if NET_2_0
1934                                 object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
1935                                 if (urlAttr.Length != 0)
1936                                         str = HandleUrlProperty (str, member);
1937 #endif
1938                                 return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
1939                         } else if (type == typeof (bool)) {
1940                                 if (preConverted)
1941                                         return CreateNullableExpression (originalType,
1942                                                                          new CodePrimitiveExpression ((bool) convertedFromAttr),
1943                                                                          wasNullable);
1944                                 
1945                                 if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
1946                                         return CreateNullableExpression (originalType, new CodePrimitiveExpression (true), wasNullable);
1947                                 else if (InvariantCompareNoCase (str, "false"))
1948                                         return CreateNullableExpression (originalType, new CodePrimitiveExpression (false), wasNullable);
1949 #if NET_2_0
1950                                 else if (wasNullable && InvariantCompareNoCase(str, "null"))
1951                                         return new CodePrimitiveExpression (null);
1952 #endif
1953                                 else
1954                                         throw new ParseException (currentLocation,
1955                                                         "Value '" + str  + "' is not a valid boolean.");
1956                         } else if (type == monoTypeType)
1957                                 type = typeof (System.Type);
1958                         
1959                         if (str == null)
1960                                 return new CodePrimitiveExpression (null);
1961
1962                         if (type.IsPrimitive)
1963                                 return CreateNullableExpression (originalType,
1964                                                                  new CodePrimitiveExpression (
1965                                                                          Convert.ChangeType (preConverted ? convertedFromAttr : str,
1966                                                                                              type, CultureInfo.InvariantCulture)),
1967                                                                  wasNullable);
1968
1969                         if (type == typeof (string [])) {
1970                                 string [] subs;
1971
1972                                 if (preConverted)
1973                                         subs = (string[])convertedFromAttr;
1974                                 else
1975                                         subs = str.Split (',');
1976                                 CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
1977                                 expr.CreateType = new CodeTypeReference (typeof (string));
1978                                 foreach (string v in subs)
1979                                         expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
1980
1981                                 return CreateNullableExpression (originalType, expr, wasNullable);
1982                         }
1983                         
1984                         if (type == typeof (Color)) {
1985                                 Color c;
1986                                 
1987                                 if (!preConverted) {
1988                                         if (colorConverter == null)
1989                                                 colorConverter = TypeDescriptor.GetConverter (typeof (Color));
1990                                 
1991                                         if (str.Trim().Length == 0) {
1992                                                 CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
1993                                                 return CreateNullableExpression (originalType,
1994                                                                                  new CodeFieldReferenceExpression (ft, "Empty"),
1995                                                                                  wasNullable);
1996                                         }
1997
1998                                         try {
1999                                                 if (str.IndexOf (',') == -1) {
2000                                                         c = (Color) colorConverter.ConvertFromString (str);
2001                                                 } else {
2002                                                         int [] argb = new int [4];
2003                                                         argb [0] = 255;
2004
2005                                                         string [] parts = str.Split (',');
2006                                                         int length = parts.Length;
2007                                                         if (length < 3)
2008                                                                 throw new Exception ();
2009
2010                                                         int basei = (length == 4) ? 0 : 1;
2011                                                         for (int i = length - 1; i >= 0; i--) {
2012                                                                 argb [basei + i] = (int) Byte.Parse (parts [i]);
2013                                                         }
2014                                                         c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
2015                                                 }
2016                                         } catch (Exception e) {
2017                                                 // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
2018                                                 // TypeConverter for Color fails to ConvertFromString.
2019                                                 // Hence this hack...
2020                                                 if (InvariantCompareNoCase ("LightGrey", str)) {
2021                                                         c = Color.LightGray;
2022                                                 } else {
2023                                                         throw new ParseException (currentLocation,
2024                                                                                   "Color " + str + " is not a valid color.", e);
2025                                                 }
2026                                         }
2027                                 } else
2028                                         c = (Color)convertedFromAttr;
2029                                 
2030                                 if (c.IsKnownColor) {
2031                                         CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
2032                                         if (c.IsSystemColor)
2033                                                 type = typeof (SystemColors);
2034
2035                                         expr.TargetObject = new CodeTypeReferenceExpression (type);
2036                                         expr.FieldName = c.Name;
2037                                         return CreateNullableExpression (originalType, expr, wasNullable);
2038                                 } else {
2039                                         CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
2040                                         m.TargetObject = new CodeTypeReferenceExpression (type);
2041                                         m.MethodName = "FromArgb";
2042                                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
2043                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
2044                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
2045                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
2046                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
2047                                         return CreateNullableExpression (originalType, invoke, wasNullable);
2048                                 }
2049                         }
2050
2051                         TypeConverter converter = preConverted ? cvt : wasNullable ? TypeDescriptor.GetConverter (type) : null;
2052                         if (converter == null) {
2053                                 PropertyDescriptor pdesc = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name];
2054                                 if (pdesc != null)
2055                                         converter = pdesc.Converter;
2056                                 else {
2057                                         Type memberType;
2058                                         switch (member.MemberType) {
2059                                                 case MemberTypes.Field:
2060                                                         memberType = ((FieldInfo)member).FieldType;
2061                                                         break;
2062
2063                                                 case MemberTypes.Property:
2064                                                         memberType = ((PropertyInfo)member).PropertyType;
2065                                                         break;
2066
2067                                                 default:
2068                                                         memberType = null;
2069                                                         break;
2070                                         }
2071
2072                                         if (memberType == null)
2073                                                 return null;
2074
2075                                         converter = TypeDescriptor.GetConverter (memberType);
2076                                 }
2077                         }
2078                         
2079                         if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
2080                                 object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
2081
2082                                 if (SafeCanConvertTo (typeof (InstanceDescriptor), converter)) {
2083                                         InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
2084                                         if (wasNullable)
2085                                                 return CreateNullableExpression (originalType, GenerateInstance (idesc, true),
2086                                                                                  wasNullable);
2087
2088                                         return new CodeCastExpression (type, GenerateInstance (idesc, true));
2089                                 }
2090
2091                                 CodeExpression exp = GenerateObjectInstance (value, false);
2092                                 if (exp != null)
2093                                         return CreateNullableExpression (originalType, exp, wasNullable);
2094                                 
2095                                 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
2096                                 m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
2097                                 m.MethodName = "GetConverter";
2098                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
2099                                 CodeTypeReference tref = new CodeTypeReference (type);
2100                                 invoke.Parameters.Add (new CodeTypeOfExpression (tref));
2101                                 
2102                                 invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
2103                                 invoke.Parameters.Add (new CodePrimitiveExpression (str));
2104
2105                                 if (wasNullable)
2106                                         return CreateNullableExpression (originalType, invoke, wasNullable);
2107
2108                                 return new CodeCastExpression (type, invoke);
2109                         }
2110
2111                         Console.WriteLine ("Unknown type: " + type + " value: " + str);
2112                         
2113                         return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
2114                 }
2115                 
2116                 CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
2117                 {
2118                         CodeExpression[] parameters = new CodeExpression [idesc.Arguments.Count];
2119                         int n = 0;
2120                         foreach (object ob in idesc.Arguments) {
2121                                 CodeExpression exp = GenerateObjectInstance (ob, throwOnError);
2122                                 if (exp == null) return null;
2123                                 parameters [n++] = exp;
2124                         }
2125                         
2126                         switch (idesc.MemberInfo.MemberType) {
2127                         case MemberTypes.Constructor:
2128                                 CodeTypeReference tob = new CodeTypeReference (idesc.MemberInfo.DeclaringType);
2129                                 return new CodeObjectCreateExpression (tob, parameters);
2130
2131                         case MemberTypes.Method:
2132                                 CodeTypeReferenceExpression mt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
2133                                 return new CodeMethodInvokeExpression (mt, idesc.MemberInfo.Name, parameters);
2134
2135                         case MemberTypes.Field:
2136                                 CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
2137                                 return new CodeFieldReferenceExpression (ft, idesc.MemberInfo.Name);
2138
2139                         case MemberTypes.Property:
2140                                 CodeTypeReferenceExpression pt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
2141                                 return new CodePropertyReferenceExpression (pt, idesc.MemberInfo.Name);
2142                         }
2143                         throw new ParseException (currentLocation, "Invalid instance type.");
2144                 }
2145                 
2146                 CodeExpression GenerateObjectInstance (object value, bool throwOnError)
2147                 {
2148                         if (value == null)
2149                                 return new CodePrimitiveExpression (null);
2150
2151                         if (value is System.Type) {
2152                                 CodeTypeReference tref = new CodeTypeReference (value.ToString ());
2153                                 return new CodeTypeOfExpression (tref);
2154                         }
2155                         
2156                         Type t = value.GetType ();
2157
2158                         if (t.IsPrimitive || value is string)
2159                                 return new CodePrimitiveExpression (value);
2160                         
2161                         if (t.IsArray) {
2162                                 Array ar = (Array) value;
2163                                 CodeExpression[] items = new CodeExpression [ar.Length];
2164                                 for (int n=0; n<ar.Length; n++) {
2165                                         CodeExpression exp = GenerateObjectInstance (ar.GetValue (n), throwOnError);
2166                                         if (exp == null) return null; 
2167                                         items [n] = exp;
2168                                 }
2169                                 return new CodeArrayCreateExpression (new CodeTypeReference (t), items);
2170                         }
2171                         
2172                         TypeConverter converter = TypeDescriptor.GetConverter (t);
2173                         if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
2174                                 InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
2175                                 return GenerateInstance (idesc, throwOnError);
2176                         }
2177                         
2178                         InstanceDescriptor desc = GetDefaultInstanceDescriptor (value);
2179                         if (desc != null) return GenerateInstance (desc, throwOnError);
2180                         
2181                         if (throwOnError)
2182                                 throw new ParseException (currentLocation, "Cannot generate an instance for the type: " + t);
2183                         else
2184                                 return null;
2185                 }
2186                 
2187                 InstanceDescriptor GetDefaultInstanceDescriptor (object value)
2188                 {
2189                         if (value is System.Web.UI.WebControls.Unit) {
2190                                 System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
2191                                 ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
2192                                         BindingFlags.Instance | BindingFlags.Public,
2193                                         null,
2194                                         new Type[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)},
2195                                         null);
2196                                 
2197                                 return new InstanceDescriptor (c, new object[] {s.Value, s.Type});
2198                         }
2199                         
2200                         if (value is System.Web.UI.WebControls.FontUnit) {
2201                                 System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
2202
2203                                 Type cParamType = null;
2204                                 object cParam = null;
2205
2206                                 switch (s.Type) {
2207                                         case FontSize.AsUnit:
2208                                         case FontSize.NotSet:
2209                                                 cParamType = typeof (System.Web.UI.WebControls.Unit);
2210                                                 cParam = s.Unit;
2211                                                 break;
2212
2213                                         default:
2214                                                 cParamType = typeof (string);
2215                                                 cParam = s.Type.ToString ();
2216                                                 break;
2217                                 }
2218                                 
2219                                 ConstructorInfo c = typeof(System.Web.UI.WebControls.FontUnit).GetConstructor (
2220                                         BindingFlags.Instance | BindingFlags.Public,
2221                                         null,
2222                                         new Type[] {cParamType},
2223                                         null);
2224                                 if (c != null)
2225                                         return new InstanceDescriptor (c, new object[] {cParam});
2226                         }
2227                         return null;
2228                 }
2229
2230 #if DEBUG
2231                 CodeMethodInvokeExpression CreateConsoleWriteLineCall (string format, params CodeExpression[] parms)
2232                 {
2233                         CodeMethodReferenceExpression cwl = new CodeMethodReferenceExpression (new CodeTypeReferenceExpression (typeof (System.Console)), "WriteLine");
2234                         CodeMethodInvokeExpression cwlCall = new CodeMethodInvokeExpression (cwl);
2235
2236                         cwlCall.Parameters.Add (new CodePrimitiveExpression (format));
2237                         if (parms != null && parms.Length > 0)
2238                                 foreach (CodeExpression expr in parms)
2239                                         cwlCall.Parameters.Add (expr);
2240
2241                         return cwlCall;
2242                 }
2243 #endif
2244         }
2245 }
2246
2247
2248