* PageThemeCompiler.cs: let property builders through, stop the
[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 //
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.CodeDom;
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Drawing;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Text;
38 using System.Web;
39 using System.Web.UI;
40 using System.Web.UI.WebControls;
41 using System.Web.Util;
42 using System.ComponentModel.Design.Serialization;
43 #if NET_2_0
44 using System.Configuration;
45 using System.Collections.Specialized;
46 using System.Text.RegularExpressions;
47 using System.Web.Configuration;
48 #endif
49
50 namespace System.Web.Compilation
51 {
52         class TemplateControlCompiler : BaseCompiler
53         {
54                 static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
55                                                   BindingFlags.Instance | BindingFlags.IgnoreCase;
56
57                 TemplateControlParser parser;
58                 int dataBoundAtts;
59                 ILocation currentLocation;
60
61                 static TypeConverter colorConverter;
62
63                 internal static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
64                 
65 #if NET_2_0
66                 static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled);
67 #endif
68
69                 public TemplateControlCompiler (TemplateControlParser parser)
70                         : base (parser)
71                 {
72                         this.parser = parser;
73                 }
74
75                 protected void EnsureID (ControlBuilder builder)
76                 {
77                         if (builder.ID == null || builder.ID.Trim () == "")
78                                 builder.ID = builder.GetNextID (null);
79                 }
80
81                 void CreateField (ControlBuilder builder, bool check)
82                 {
83                         if (builder == null || builder.ID == null || builder.ControlType == null)
84                                 return;
85 #if NET_2_0
86                         if (partialNameOverride [builder.ID] != null)
87                                 return;
88 #endif
89                         currentLocation = builder.location;
90                         if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType))
91                                 return; // The field or property already exists in a base class and is accesible.
92
93                         CodeMemberField field;
94                         field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
95                         field.Attributes = MemberAttributes.Family;
96 #if NET_2_0
97                         if (partialClass != null)
98                                 partialClass.Members.Add (field);
99                         else
100 #endif
101                                 mainClass.Members.Add (field);
102                 }
103
104                 bool CheckBaseFieldOrProperty (string id, Type type)
105                 {
106                         FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
107
108                         Type other = null;
109                         if (fld == null || fld.IsPrivate) {
110                                 PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
111                                 if (prop != null) {
112                                         MethodInfo setm = prop.GetSetMethod (true);
113                                         if (setm != null)
114                                                 other = prop.PropertyType;
115                                 }
116                         } else {
117                                 other = fld.FieldType;
118                         }
119                         
120                         if (other == null)
121                                 return false;
122
123                         if (!other.IsAssignableFrom (type)) {
124                                 string msg = String.Format ("The base class includes the field '{0}', but its " +
125                                                             "type '{1}' is not compatible with {2}",
126                                                             id, other, type);
127                                 throw new ParseException (currentLocation, msg);
128                         }
129
130                         return true;
131                 }
132
133                 void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr) 
134                 {
135                         if (!builder.haveParserVariable) {
136                                 CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
137                                 p.Name = "__parser";
138                                 p.Type = new CodeTypeReference (typeof (IParserAccessor));
139                                 p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
140                                 builder.methodStatements.Add (p);
141                                 builder.haveParserVariable = true;
142                         }
143
144                         CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
145                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
146                         invoke.Parameters.Add (expr);
147                         builder.methodStatements.Add (invoke);
148                 }
149
150                 void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
151                 {
152                         string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
153                         CodeMemberMethod method = new CodeMemberMethod ();
154                         builder.method = method;
155                         builder.methodStatements = method.Statements;
156
157                         method.Name = "__BuildControl" + tailname;
158                         method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
159                         Type type = builder.ControlType;
160
161                         /* in the case this is the __BuildControlTree
162                          * method, allow subclasses to insert control
163                          * specific code. */
164                         if (builder is RootBuilder)
165                                 AddStatementsToInitMethod (method);
166
167                         if (builder.HasAspCode) {
168                                 CodeMemberMethod renderMethod = new CodeMemberMethod ();
169                                 builder.renderMethod = renderMethod;
170                                 renderMethod.Name = "__Render" + tailname;
171                                 renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
172                                 CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
173                                 arg1.Type = new CodeTypeReference (typeof (HtmlTextWriter));
174                                 arg1.Name = "__output";
175                                 CodeParameterDeclarationExpression arg2 = new CodeParameterDeclarationExpression ();
176                                 arg2.Type = new CodeTypeReference (typeof (Control));
177                                 arg2.Name = "parameterContainer";
178                                 renderMethod.Parameters.Add (arg1);
179                                 renderMethod.Parameters.Add (arg2);
180                                 mainClass.Members.Add (renderMethod);
181                         }
182                         
183                         if (childrenAsProperties || builder.ControlType == null) {
184                                 string typeString;
185                                 if (builder is RootBuilder)
186                                         typeString = parser.ClassName;
187                                 else {
188                                         if (builder.ControlType != null && builder.isProperty &&
189                                             !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
190                                                 typeString = builder.ControlType.FullName;
191                                         else 
192                                                 typeString = "System.Web.UI.Control";
193                                 }
194
195                                 method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
196                         } else {
197                                 
198                                 if (typeof (Control).IsAssignableFrom (type))
199                                         method.ReturnType = new CodeTypeReference (typeof (Control));
200
201                                 // _ctrl = new $controlType ($parameters);
202                                 //
203                                 CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
204
205                                 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
206                                 if (atts != null && atts.Length > 0) {
207                                         ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
208                                         if (att.NeedsTag)
209                                                 newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
210                                 } else if (builder is DataBindingBuilder) {
211                                         newExpr.Parameters.Add (new CodePrimitiveExpression (0));
212                                         newExpr.Parameters.Add (new CodePrimitiveExpression (1));
213                                 }
214
215                                 method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
216                                 CodeAssignStatement assign = new CodeAssignStatement ();
217                                 assign.Left = ctrlVar;
218                                 assign.Right = newExpr;
219                                 method.Statements.Add (assign);
220                                 
221                                 // this.$builderID = _ctrl;
222                                 //
223                                 CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
224                                 builderID.TargetObject = thisRef;
225                                 builderID.FieldName = builder.ID;
226                                 assign = new CodeAssignStatement ();
227                                 assign.Left = builderID;
228                                 assign.Right = ctrlVar;
229                                 method.Statements.Add (assign);
230                                 if (typeof (UserControl).IsAssignableFrom (type)) {
231                                         CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
232                                         mref.TargetObject = builderID;
233                                         mref.MethodName = "InitializeAsUserControl";
234                                         CodeMethodInvokeExpression initAsControl = new CodeMethodInvokeExpression (mref);
235                                         initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
236                                         method.Statements.Add (initAsControl);
237                                 }
238
239 #if NET_2_0
240                                 // _ctrl.SkinID = $value
241                                 // _ctrl.ApplyStyleSheetSkin (this);
242                                 //
243                                 // the SkinID assignment needs to come
244                                 // before the call to
245                                 // ApplyStyleSheetSkin, for obvious
246                                 // reasons.  We skip SkinID in
247                                 // CreateAssignStatementsFromAttributes
248                                 // below.
249                                 // 
250                                 if (builder.attribs != null) {
251                                         string skinid = builder.attribs ["skinid"] as string;
252                                         if (skinid != null)
253                                                 CreateAssignStatementFromAttribute (builder, "skinid");
254                                 }
255                                 if (typeof (WebControl).IsAssignableFrom (type)) {
256                                         CodeMethodInvokeExpression applyStyleSheetSkin = new CodeMethodInvokeExpression (ctrlVar, "ApplyStyleSheetSkin");
257                                         if (typeof (Page).IsAssignableFrom (parser.BaseType))
258                                                 applyStyleSheetSkin.Parameters.Add (thisRef);
259                                         else
260                                                 applyStyleSheetSkin.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
261                                         method.Statements.Add (applyStyleSheetSkin);
262                                 }
263 #endif
264
265 #if NET_2_0
266                                 if (typeof (ContentPlaceHolder).IsAssignableFrom (type)) {
267                                         CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
268                                         CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
269                                         addPlaceholder.Parameters.Add (ctrlVar);
270                                         method.Statements.Add (addPlaceholder);
271
272
273                                         CodeConditionStatement condStatement;
274
275                                         // Add the __Template_* field
276                                         CodeMemberField fld = new CodeMemberField (typeof (ITemplate), "__Template_" + builder.ID);
277                                         fld.Attributes = MemberAttributes.Private;
278                                         mainClass.Members.Add (fld);
279
280                                         CodeFieldReferenceExpression templateID = new CodeFieldReferenceExpression ();
281                                         templateID.TargetObject = thisRef;
282                                         templateID.FieldName = "__Template_" + builder.ID;
283
284                                         // if ((this.ContentTemplates != null)) {
285                                         //      this.__Template_$builder.ID = ((System.Web.UI.ITemplate)(this.ContentTemplates["$builder.ID"]));
286                                         // }
287                                         //
288                                         CodeFieldReferenceExpression contentTemplates = new CodeFieldReferenceExpression ();
289                                         contentTemplates.TargetObject = thisRef;
290                                         contentTemplates.FieldName = "ContentTemplates";
291
292                                         CodeIndexerExpression indexer = new CodeIndexerExpression ();
293                                         indexer.TargetObject = new CodePropertyReferenceExpression (thisRef, "ContentTemplates");
294                                         indexer.Indices.Add (new CodePrimitiveExpression (builder.ID));
295
296                                         assign = new CodeAssignStatement ();
297                                         assign.Left = templateID;
298                                         assign.Right = new CodeCastExpression (new CodeTypeReference (typeof (ITemplate)), indexer);
299
300                                         condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (contentTemplates,
301                                                                                                                       CodeBinaryOperatorType.IdentityInequality,
302                                                                                                                       new CodePrimitiveExpression (null)),
303                                                                                     assign);
304
305                                         method.Statements.Add (condStatement);
306
307                                         // if ((this.__Template_mainContent != null)) {
308                                         //      this.__Template_mainContent.InstantiateIn(__ctrl);
309                                         // }
310                                         // and also set things up such that any additional code ends up in:
311                                         // else {
312                                         //      ...
313                                         // }
314                                         //
315                                         CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
316                                         methodRef.TargetObject = templateID;
317                                         methodRef.MethodName = "InstantiateIn";
318
319                                         CodeMethodInvokeExpression instantiateInInvoke;
320                                         instantiateInInvoke = new CodeMethodInvokeExpression (methodRef, ctrlVar);
321
322                                         condStatement = new CodeConditionStatement (new CodeBinaryOperatorExpression (templateID,
323                                                                                                                       CodeBinaryOperatorType.IdentityInequality,
324                                                                                                                       new CodePrimitiveExpression (null)),
325                                                                                     new CodeExpressionStatement (instantiateInInvoke));
326                                         method.Statements.Add (condStatement);
327
328                                         // this is the bit that causes the following stuff to end up in the else { }
329                                         builder.methodStatements = condStatement.FalseStatements;
330
331                                         // __ctrl.TemplateControl = this;
332                                         assign = new CodeAssignStatement ();
333                                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, "TemplateControl");;
334                                         assign.Right = thisRef;
335
336                                         method.Statements.Add (assign);
337                                 }
338 #endif
339                         }
340
341                         mainClass.Members.Add (method);
342                 }
343
344                 protected virtual void AddStatementsToInitMethod (CodeMemberMethod method)
345                 {
346                 }
347
348                 void AddLiteralSubObject (ControlBuilder builder, string str)
349                 {
350                         if (!builder.HasAspCode) {
351                                 CodeObjectCreateExpression expr;
352                                 expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
353                                 AddParsedSubObjectStmt (builder, expr);
354                         } else {
355                                 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
356                                 methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
357                                 methodRef.MethodName = "Write";
358
359                                 CodeMethodInvokeExpression expr;
360                                 expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
361                                 builder.renderMethod.Statements.Add (expr);
362                         }
363                 }
364
365                 string TrimDB (string value)
366                 {
367                         string str = value.Trim ();
368                         str = str.Substring (3);
369                         return str.Substring (0, str.Length - 2);
370                 }
371
372                 string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
373                 {
374                         value = TrimDB (value);
375                         CodeMemberMethod method;
376                         string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
377 #if NET_2_0
378                         bool need_if = false;
379                         value = value.Trim ();
380                         if (StrUtils.StartsWith (value, "Bind")) {
381                                 value = "Eval" + value.Substring (4);
382                                 need_if = true;
383                         }
384 #endif
385
386                         method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
387
388                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
389
390                         // This should be a CodePropertyReferenceExpression for properties... but it works anyway
391                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
392
393                         CodeExpression expr;
394                         if (type == typeof (string)) {
395                                 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
396                                 CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
397                                 tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
398                                 tostring.Parameters.Add (new CodeSnippetExpression (value));
399                                 expr = tostring;
400                         } else {
401                                 CodeSnippetExpression snippet = new CodeSnippetExpression (value);
402                                 expr = new CodeCastExpression (type, snippet);
403                         }
404
405                         CodeAssignStatement assign = new CodeAssignStatement (field, expr);
406 #if NET_2_0
407                         if (need_if) {
408                                 CodeExpression page = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Page");
409                                 CodeExpression left = new CodeMethodInvokeExpression (page, "GetDataItem");
410                                 CodeBinaryOperatorExpression ce = new CodeBinaryOperatorExpression (left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
411                                 CodeConditionStatement ccs = new CodeConditionStatement (ce, assign);
412                                 method.Statements.Add (ccs);
413                         }
414                         else
415 #endif
416                                 method.Statements.Add (assign);
417
418                         mainClass.Members.Add (method);
419                         return method.Name;
420                 }
421
422                 void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound, bool isExpression)
423                 {
424                         CodeMemberMethod method = builder.method;
425                         bool isWritable = IsWritablePropertyOrField (member);
426                         if (isDataBound && isWritable) {
427                                 string dbMethodName = DataBoundProperty (builder, type, var_name, att);
428                                 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
429                                 return;
430                         }
431 #if NET_2_0
432                         else if (isExpression && isWritable) {
433                                 AddExpressionAssign (method, member, type, var_name, att);
434                                 return;
435                         }
436 #endif
437                         
438                         CodeAssignStatement assign = new CodeAssignStatement ();
439                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
440                         currentLocation = builder.location;
441                         assign.Right = GetExpressionFromString (type, att, member);
442
443                         method.Statements.Add (assign);
444                 }
445
446                 bool IsDataBound (string value)
447                 {
448                         if (value == null || value == "")
449                                 return false;
450
451                         string str = value.Trim ();
452                         return (StrUtils.StartsWith (str, "<%#") && StrUtils.EndsWith (str, "%>"));
453                 }
454
455 #if NET_2_0
456                 bool IsExpression (string value)
457                 {
458                         if (value == null || value == "")
459                                 return false;
460                         string str = value.Trim ();
461                         return (StrUtils.StartsWith (str, "<%$") && StrUtils.EndsWith (str, "%>"));
462                 }               
463
464                 void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
465                 {
466                         string str = value.Trim ();
467                         str = str.Substring (3).Trim ();        // eats "<%#"
468                         if (StrUtils.StartsWith (str, "Bind")) {
469                                 Match match = bindRegex.Match (str);
470                                 if (match.Success) {
471                                         string bindingName = match.Groups [1].Value;
472                                         
473                                         TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
474                                         if (templateBuilder == null || templateBuilder.BindingDirection == BindingDirection.OneWay)
475                                                 throw new HttpException ("Bind expression not allowed in this context.");
476                                                 
477                                         string id = builder.attribs ["ID"] as string;
478                                         if (id == null)
479                                                 throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
480                                         
481                                         templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
482                                 }
483                         }
484                 }
485 #endif
486
487                 /*
488                 static bool InvariantCompare (string a, string b)
489                 {
490                         return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
491                 }
492                 */
493
494                 static bool InvariantCompareNoCase (string a, string b)
495                 {
496                         return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
497                 }
498
499                 static MemberInfo GetFieldOrProperty (Type type, string name)
500                 {
501                         MemberInfo member = null;
502                         try {
503                                 member = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
504                         } catch {}
505                         
506                         if (member != null)
507                                 return member;
508
509                         try {
510                                 member = type.GetField (name, noCaseFlags & ~BindingFlags.NonPublic);
511                         } catch {}
512
513                         return member;
514                 }
515
516                 static bool IsWritablePropertyOrField (MemberInfo member)
517                 {
518                         PropertyInfo pi = member as PropertyInfo;
519                         if (pi != null)
520                                 return pi.CanWrite;
521                         FieldInfo fi = member as FieldInfo;
522                         if (fi != null)
523                                 return !fi.IsInitOnly;
524                         throw new ArgumentException ("Argument must be of PropertyInfo or FieldInfo type", "member");
525                 }
526
527                 bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
528                                                  string attValue, string prefix)
529                 {
530                         int hyphen = id.IndexOf ('-');
531                         bool isPropertyInfo = (member is PropertyInfo);
532                         bool isDataBound = IsDataBound (attValue);
533 #if NET_2_0
534                         bool isExpression = !isDataBound && IsExpression (attValue);
535 #else
536                         bool isExpression = false;
537 #endif
538                         Type type;
539                         if (isPropertyInfo) {
540                                 type = ((PropertyInfo) member).PropertyType;
541                         } else {
542                                 type = ((FieldInfo) member).FieldType;
543                         }
544
545                         if (InvariantCompareNoCase (member.Name, id)) {
546 #if NET_2_0
547                                 if (isDataBound)
548                                         RegisterBindingInfo (builder, member.Name, ref attValue);
549                                 
550 #endif
551                                 if (!IsWritablePropertyOrField (member))
552                                         return false;
553
554                                 AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound, isExpression);
555                                 return true;
556                         }
557                         
558                         if (hyphen == -1)
559                                 return false;
560
561                         string prop_field = id.Replace ("-", ".");
562                         string [] parts = prop_field.Split (new char [] {'.'});
563                         int length = parts.Length;
564                         if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
565                                 return false;
566
567                         if (length > 2) {
568                                 MemberInfo sub_member = GetFieldOrProperty (type, parts [1]);
569                                 if (sub_member == null)
570                                         return false;
571
572                                 string new_prefix = prefix + parts [0] + ".";
573                                 string new_id = id.Substring (hyphen + 1);
574                                 return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
575                         }
576
577                         MemberInfo subpf = GetFieldOrProperty (type, parts [1]);
578                         if (!(subpf is PropertyInfo))
579                                 return false;
580
581                         PropertyInfo subprop = (PropertyInfo) subpf;
582                         if (subprop.CanWrite == false)
583                                 return false;
584
585                         bool is_bool = (subprop.PropertyType == typeof (bool));
586                         if (!is_bool && attValue == null)
587                                 return false; // Font-Size -> Font-Size="" as html
588
589                         string val = attValue;
590                         if (attValue == null && is_bool)
591                                 val = "true"; // Font-Bold <=> Font-Bold="true"
592 #if NET_2_0
593                         if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
594 #endif
595                         AddCodeForPropertyOrField (builder, subprop.PropertyType,
596                                                    prefix + member.Name + "." + subprop.Name,
597                                                    val, subprop, isDataBound, isExpression);
598
599                         return true;
600                 }
601
602 #if NET_2_0
603                 void AddExpressionAssign (CodeMemberMethod method, MemberInfo member, Type type, string name, string value)
604                 {
605                         CodeAssignStatement assign = new CodeAssignStatement ();
606                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, name);
607
608                         // First let's find the correct expression builder
609                         string expr = value.Substring (3, value.Length - 5).Trim ();
610                         int colon = expr.IndexOf (':');
611                         if (colon == -1)
612                                 return;
613                         string prefix = expr.Substring (0, colon).Trim ();
614                         
615                         System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration ("");
616                         if (config == null)
617                                 return;
618                         CompilationSection cs = (CompilationSection)config.GetSection ("system.web/compilation");
619                         if (cs == null)
620                                 return;
621                         if (cs.ExpressionBuilders == null || cs.ExpressionBuilders.Count == 0)
622                                 return;
623
624                         System.Web.Configuration.ExpressionBuilder ceb = cs.ExpressionBuilders[prefix];
625                         if (ceb == null)
626                                 return;
627                         string builderType = ceb.Type;
628
629                         Type t;
630                         try {
631                                 t = System.Type.GetType (builderType, true);
632                         } catch (Exception e) {
633                                 throw new HttpException (
634                                         String.Format ("Failed to load expression builder type `{0}'", builderType), e);
635                         }
636
637                         if (!typeof (System.Web.Compilation.ExpressionBuilder).IsAssignableFrom (t))
638                                 throw new HttpException (
639                                         String.Format (
640                                                 "Type {0} is not descendant from System.Web.Compilation.ExpressionBuilder",
641                                                 builderType));
642
643                         System.Web.Compilation.ExpressionBuilder eb = null;
644                         object parsedData;
645                         ExpressionBuilderContext ctx;
646                         
647                         try {
648                                 eb = Activator.CreateInstance (t) as System.Web.Compilation.ExpressionBuilder;
649                                 ctx = new ExpressionBuilderContext (HttpContext.Current.Request.FilePath);
650                                 parsedData = eb.ParseExpression (expr.Substring (colon + 1).Trim (), type, ctx);
651                         } catch (Exception e) {
652                                 throw new HttpException (
653                                         String.Format ("Failed to create an instance of type `{0}'", builderType), e);
654                         }
655                         // FIXME: create and pass an instance of BoundPropertyEntry
656                         CodeMethodInvokeExpression convert = new CodeMethodInvokeExpression ();
657                         convert.Method = new CodeMethodReferenceExpression (
658                                 new CodeTypeReferenceExpression (typeof(Convert)),
659                                 "ToString");
660                         convert.Parameters.Add (eb.GetCodeExpression (null, parsedData, ctx));
661                         convert.Parameters.Add (
662                                 new CodeFieldReferenceExpression (
663                                         new CodeTypeReferenceExpression ("System.Globalization.CultureInfo"),
664                                         "CurrentCulture"));
665                         assign.Right = convert;
666                         
667                         method.Statements.Add (assign);
668                 }
669
670                 void AssignPropertyFromResources (CodeMemberMethod method, MemberInfo mi, string attvalue, string varname)
671                 {
672                         string resname = String.Format ("{0}.{1}", attvalue, mi.Name);
673                         bool isProperty = mi.MemberType == MemberTypes.Property;
674                         bool isField = !isProperty && (mi.MemberType == MemberTypes.Field);
675
676                         if (!isProperty && !isField || !IsWritablePropertyOrField (mi))
677                                 return;
678                         
679                         Type member_type = null;
680                         if (isProperty) {
681                                 PropertyInfo pi = mi as PropertyInfo;
682                                 member_type = pi.PropertyType;
683                         } else if (isField) { 
684                                 FieldInfo fi = mi as FieldInfo;
685                                 member_type = fi.FieldType;
686                         } else // should never happen
687                                 return;
688
689                         // __ctrl.Text = System.Convert.ToString(HttpContext.GetLocalResourceObject("ButtonResource1.Text"));
690                         string inputFile = parser.InputFile;
691                         string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
692         
693                         if (StrUtils.StartsWith (inputFile, physPath))
694                                 inputFile = parser.InputFile.Substring (physPath.Length - 1);
695                          else
696                                 return;
697                         
698                         object obj = HttpContext.GetLocalResourceObject (inputFile, resname);
699                         if (obj == null)
700                                 return;
701                         
702                         CodeAssignStatement assign = new CodeAssignStatement ();
703                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, mi.Name);
704                         CodeMethodInvokeExpression getlro = new CodeMethodInvokeExpression (
705                                 new CodeThisReferenceExpression (),
706                                 "GetLocalResourceObject",
707                                 new CodeExpression [] { new CodePrimitiveExpression (resname) });
708                         
709                         CodeMethodInvokeExpression convert = new CodeMethodInvokeExpression ();
710                         convert.Method = new CodeMethodReferenceExpression (
711                                 new CodeTypeReferenceExpression (typeof(System.Convert)),
712                                 "ToString");
713                         convert.Parameters.Add (getlro);
714                         assign.Right = convert;
715                         
716 //                      assign.Left = new CodeVariableReferenceExpression (varname);
717 //                      assign.Right = new CodeMethodInvokeExpression (
718 //                              new CodeThisReferenceExpression (),
719 //                              "GetLocalResourceObject",
720 //                              new CodeExpression [] { new CodePrimitiveExpression (resname) });
721 //                      method.Statements.Add (assign);
722
723 //                      // if (localResourceObject != null && localResourceObject.GetType() == typeof(member_type))
724 //                      CodeConditionStatement ccs = new CodeConditionStatement ();
725 //                      CodeBinaryOperatorExpression exp1 = new CodeBinaryOperatorExpression (
726 //                              new CodeVariableReferenceExpression (varname),
727 //                              CodeBinaryOperatorType.IdentityInequality,
728 //                              new CodePrimitiveExpression (null));
729                         
730 //                      CodeBinaryOperatorExpression exp2 = new CodeBinaryOperatorExpression (
731 //                              new CodeMethodInvokeExpression (
732 //                                      new CodeVariableReferenceExpression (varname),
733 //                                      "GetType",
734 //                                      new CodeExpression [] {}),
735 //                              CodeBinaryOperatorType.IdentityEquality,
736 //                              new CodeTypeOfExpression (
737 //                                      new CodeTypeReference (member_type.ToString ())));
738 //                      ccs.Condition = new CodeBinaryOperatorExpression (
739 //                              exp1,
740 //                              CodeBinaryOperatorType.BooleanAnd,
741 //                              exp2);
742                         
743 //                      //   ctrlVar.Property = (member_type)obj;
744 //                      assign = new CodeAssignStatement ();
745 //                      assign.Left = new CodePropertyReferenceExpression (ctrlVar, mi.Name);
746 //                      assign.Right = new CodeCastExpression (
747 //                              member_type.ToString (),
748 //                              new CodeVariableReferenceExpression (varname));
749 //                      ccs.TrueStatements.Add (assign);
750                         method.Statements.Add (assign);
751                 }
752                 
753                 void AssignPropertiesFromResources (ControlBuilder builder, string attvalue)
754                 {
755                         if (attvalue == null || attvalue.Length == 0)
756                                 return;
757                         
758                         Type controlType = builder.ControlType;
759                         if (controlType == null)
760                                 return;
761
762                         // object obj = null;
763                         
764                         // Process all public fields and properties of the control. We don't use GetMembers to make the code
765                         // faster
766                         FieldInfo [] fields = controlType.GetFields (
767                                 BindingFlags.Instance | BindingFlags.Static |
768                                 BindingFlags.Public | BindingFlags.FlattenHierarchy);
769                         PropertyInfo [] properties = controlType.GetProperties (
770                                 BindingFlags.Instance | BindingFlags.Static |
771                                 BindingFlags.Public | BindingFlags.FlattenHierarchy);
772
773                         if (fields.Length > 0 || properties.Length > 0) {
774                                 CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement (
775                                         typeof (object),
776                                         "localResourceObject",
777                                         new CodePrimitiveExpression (null));
778                                 builder.method.Statements.Add (cvds);
779                         }
780                         
781                         foreach (FieldInfo fi in fields)
782                                 AssignPropertyFromResources (builder.method, fi, attvalue, "localResourceObject");
783                         foreach (PropertyInfo pi in properties)
784                                 AssignPropertyFromResources (builder.method, pi, attvalue, "localResourceObject");
785                 }
786 #endif
787                 
788                 void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
789                 {
790                         //"__ctrl.{0} += new {1} (this.{2});"
791                         CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
792
793                         CodeDelegateCreateExpression create;
794                         create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
795
796                         CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
797                         method.Statements.Add (attach);
798                 }
799                 
800                 void CreateAssignStatementFromAttribute (ControlBuilder builder, string id)
801                 {
802                         EventInfo [] ev_info = null;
803                         Type type = builder.ControlType;
804
805                         string attvalue = builder.attribs [id] as string;
806                         if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
807                                 if (ev_info == null)
808                                         ev_info = type.GetEvents ();
809
810                                 string id_as_event = id.Substring (2);
811                                 foreach (EventInfo ev in ev_info){
812                                         if (InvariantCompareNoCase (ev.Name, id_as_event)){
813                                                 AddEventAssign (builder.method,
814                                                                 ev.Name,
815                                                                 ev.EventHandlerType,
816                                                                 attvalue);
817                                                 
818                                                 return;
819                                         }
820                                 }
821
822                         }
823
824 #if NET_2_0
825                         if (id.ToLower () == "meta:resourcekey") {
826                                 AssignPropertiesFromResources (builder, attvalue);
827                                 return;
828                         }
829 #endif
830                         
831                         int hyphen = id.IndexOf ('-');
832                         string alt_id = id;
833                         if (hyphen != -1)
834                                 alt_id = id.Substring (0, hyphen);
835
836                         MemberInfo fop = GetFieldOrProperty (type, alt_id);
837                         if (fop != null) {
838                                 if (ProcessPropertiesAndFields (builder, fop, id, attvalue, null))
839                                         return;
840                         }
841
842                         if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
843                                 throw new ParseException (builder.location, "Unrecognized attribute: " + id);
844
845                         string val;
846                         CodeMemberMethod method = builder.method;
847                         bool databound = IsDataBound (attvalue);
848
849                         if (databound) {
850                                 val = attvalue.Substring (3);
851                                 val = val.Substring (0, val.Length - 2);
852                                 CreateDBAttributeMethod (builder, id, val);
853                         } else {
854                                 CodeCastExpression cast;
855                                 CodeMethodReferenceExpression methodExpr;
856                                 CodeMethodInvokeExpression expr;
857
858                                 cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
859                                 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
860                                 expr = new CodeMethodInvokeExpression (methodExpr);
861                                 expr.Parameters.Add (new CodePrimitiveExpression (id));
862                                 expr.Parameters.Add (new CodePrimitiveExpression (attvalue));
863                                 method.Statements.Add (expr);
864                         }
865
866                 }
867
868                 protected void CreateAssignStatementsFromAttributes (ControlBuilder builder)
869                 {
870                         this.dataBoundAtts = 0;
871                         IDictionary atts = builder.attribs;
872                         if (atts == null || atts.Count == 0)
873                                 return;
874
875                         foreach (string id in atts.Keys) {
876                                 if (InvariantCompareNoCase (id, "runat"))
877                                         continue;
878
879 #if NET_2_0
880                                 /* we skip SkinID here as it's assigned in BuildControlTree */
881                                 if (InvariantCompareNoCase (id, "skinid"))
882                                         continue;
883 #endif
884                                 CreateAssignStatementFromAttribute (builder, id);
885                         }
886                 }
887
888                 void CreateDBAttributeMethod (ControlBuilder builder, string attr, string code)
889                 {
890                         if (code == null || code.Trim () == "")
891                                 return;
892
893                         string id = builder.GetNextID (null);
894                         string dbMethodName = "__DataBind_" + id;
895                         CodeMemberMethod method = builder.method;
896                         AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
897
898                         method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
899                         CodeCastExpression cast;
900                         CodeMethodReferenceExpression methodExpr;
901                         CodeMethodInvokeExpression expr;
902
903                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
904                         cast = new CodeCastExpression (typeof (IAttributeAccessor), targetExpr);
905                         methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
906                         expr = new CodeMethodInvokeExpression (methodExpr);
907                         expr.Parameters.Add (new CodePrimitiveExpression (attr));
908                         CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
909                         tostring.Method = new CodeMethodReferenceExpression (
910                                                         new CodeTypeReferenceExpression (typeof (Convert)),
911                                                         "ToString");
912                         tostring.Parameters.Add (new CodeSnippetExpression (code));
913                         expr.Parameters.Add (tostring);
914                         method.Statements.Add (expr);
915                         mainClass.Members.Add (method);
916                 }
917
918                 void AddRenderControl (ControlBuilder builder)
919                 {
920                         CodeIndexerExpression indexer = new CodeIndexerExpression ();
921                         indexer.TargetObject = new CodePropertyReferenceExpression (
922                                                         new CodeArgumentReferenceExpression ("parameterContainer"),
923                                                         "Controls");
924                                                         
925                         indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
926                         
927                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
928                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
929                         builder.renderMethod.Statements.Add (invoke);
930                         builder.renderIndex++;
931                 }
932
933                 protected void AddChildCall (ControlBuilder parent, ControlBuilder child)
934                 {
935                         if (parent == null || child == null)
936                                 return;
937                         CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
938                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
939
940                         object [] atts = null;
941                         
942                         if (child.ControlType != null)
943                                 child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
944                         if (atts != null && atts.Length > 0) {
945                                 PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
946                                 CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
947                                 CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
948                                 build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
949                                 build.Parameters.Add (new CodePrimitiveExpression (child.ID));
950 #if NET_1_1
951                                 if (pca.Shared)
952                                         build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
953                                 else
954 #endif
955                                         build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
956                                         
957                                 build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
958                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
959                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
960                                 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
961                                 build.Parameters.Add (new CodeDelegateCreateExpression (
962                                                               new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
963                                                               thisRef, child.method.Name));
964                                 
965                                 parent.methodStatements.Add (build);
966                                 if (parent.HasAspCode)
967                                         AddRenderControl (parent);
968                                 return;
969                         }
970                                 
971                         if (child.isProperty || parent.ChildrenAsProperties) {
972                                 expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
973                                 parent.methodStatements.Add (expr);
974                                 return;
975                         }
976
977                         parent.methodStatements.Add (expr);
978                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
979                         if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
980                                 AddParsedSubObjectStmt (parent, field);
981                         } else {
982                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
983                                 invoke.Parameters.Add (field);
984                                 parent.methodStatements.Add (invoke);
985                         }
986                                 
987                         if (parent.HasAspCode)
988                                 AddRenderControl (parent);
989                 }
990
991                 void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
992                 {
993                         CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
994
995                         CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
996                         newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
997
998                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
999                         newCompiled.Parameters.Add (newBuild);
1000
1001                         CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1002                         method.Statements.Add (assign);
1003                 }
1004
1005 #if NET_2_0
1006                 void AddBindableTemplateInvocation (CodeMemberMethod method, string name, string methodName, string extractMethodName)
1007                 {
1008                         CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
1009
1010                         CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
1011                         newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
1012
1013                         CodeObjectCreateExpression newExtract = new CodeObjectCreateExpression (typeof (ExtractTemplateValuesMethod));
1014                         newExtract.Parameters.Add (new CodeMethodReferenceExpression (thisRef, extractMethodName));
1015
1016                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
1017                         newCompiled.Parameters.Add (newBuild);
1018                         newCompiled.Parameters.Add (newExtract);
1019                         
1020                         CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
1021                         method.Statements.Add (assign);
1022                 }
1023                 
1024                 string CreateExtractValuesMethod (TemplateBuilder builder)
1025                 {
1026                         CodeMemberMethod method = new CodeMemberMethod ();
1027                         method.Name = "__ExtractValues_" + builder.ID;
1028                         method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
1029                         method.ReturnType = new CodeTypeReference (typeof(IOrderedDictionary));
1030                         
1031                         CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression ();
1032                         arg.Type = new CodeTypeReference (typeof (Control));
1033                         arg.Name = "__container";
1034                         method.Parameters.Add (arg);
1035                         mainClass.Members.Add (method);
1036                         
1037                         CodeObjectCreateExpression newTable = new CodeObjectCreateExpression ();
1038                         newTable.CreateType = new CodeTypeReference (typeof(OrderedDictionary));
1039                         method.Statements.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary), "__table", newTable));
1040                         CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
1041                         
1042                         if (builder.Bindings != null) {
1043                                 Hashtable hash = new Hashtable ();
1044                                 foreach (TemplateBinding binding in builder.Bindings) {
1045                                         CodeConditionStatement sif;
1046                                         CodeVariableReferenceExpression control;
1047                                         CodeAssignStatement assign;
1048
1049                                         if (hash [binding.ControlId] == null) {
1050
1051                                                 CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
1052                                                 method.Statements.Add (dec);
1053                                                 CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
1054                                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
1055                                                 invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
1056
1057                                                 assign = new CodeAssignStatement ();
1058                                                 control = new CodeVariableReferenceExpression (binding.ControlId);
1059                                                 assign.Left = control;
1060                                                 assign.Right = new CodeCastExpression (binding.ControlType, invoke);
1061                                                 method.Statements.Add (assign);
1062
1063                                                 sif = new CodeConditionStatement ();
1064                                                 sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
1065
1066                                                 method.Statements.Add (sif);
1067
1068                                                 hash [binding.ControlId] = sif;
1069                                         }
1070
1071                                         sif = (CodeConditionStatement) hash [binding.ControlId];
1072                                         control = new CodeVariableReferenceExpression (binding.ControlId);
1073                                         assign = new CodeAssignStatement ();
1074                                         assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
1075                                         assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
1076                                         sif.TrueStatements.Add (assign);
1077                                 }
1078                         }
1079
1080                         method.Statements.Add (new CodeMethodReturnStatement (tableExp));
1081                         return method.Name;
1082                 }
1083
1084                 void AddContentTemplateInvocation (ContentBuilderInternal cbuilder, CodeMemberMethod method, string methodName)
1085                 {
1086                         CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
1087                         newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
1088
1089                         CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
1090                         newCompiled.Parameters.Add (newBuild);
1091                         
1092                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (thisRef, "AddContentTemplate");
1093                         invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
1094                         invoke.Parameters.Add (newCompiled);
1095
1096                         method.Statements.Add (invoke);
1097                 }
1098 #endif
1099
1100                 void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
1101                 {
1102                         if (cr.Code == null || cr.Code.Trim () == "")
1103                                 return;
1104
1105                         if (!cr.IsAssign) {
1106                                 CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
1107                                 parent.renderMethod.Statements.Add (code);
1108                                 return;
1109                         }
1110
1111                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
1112                         expr.Method = new CodeMethodReferenceExpression (
1113                                                         new CodeArgumentReferenceExpression ("__output"),
1114                                                         "Write");
1115
1116                         expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
1117                         parent.renderMethod.Statements.Add (expr);
1118                 }
1119
1120                 static Type GetContainerType (ControlBuilder builder)
1121                 {
1122                         TemplateBuilder tb = builder as TemplateBuilder;
1123                         if (tb != null && tb.ContainerType != null)
1124                                 return tb.ContainerType;
1125
1126                         Type type = builder.BindingContainerType;
1127
1128                         PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
1129                         if (prop == null)
1130                                 return type;
1131
1132                         Type ptype = prop.PropertyType;
1133                         if (!typeof (ICollection).IsAssignableFrom (ptype))
1134                                 return type;
1135
1136                         prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
1137                         if (prop == null)
1138                                 return type;
1139
1140                         return prop.PropertyType;
1141                 }
1142                 
1143                 CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
1144                 {
1145                         CodeMemberMethod method = new CodeMemberMethod ();
1146                         method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
1147                         method.Name = name;
1148                         method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
1149                         method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
1150
1151                         CodeTypeReference containerRef = new CodeTypeReference (container);
1152                         CodeTypeReference targetRef = new CodeTypeReference (target);
1153
1154                         CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
1155                         decl.Name = "Container";
1156                         decl.Type = containerRef;
1157                         method.Statements.Add (decl);
1158
1159                         decl = new CodeVariableDeclarationStatement();
1160                         decl.Name = "target";
1161                         decl.Type = targetRef;
1162                         method.Statements.Add (decl);
1163
1164                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1165                         CodeAssignStatement assign = new CodeAssignStatement ();
1166                         assign.Left = targetExpr;
1167                         assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
1168                         method.Statements.Add (assign);
1169
1170                         assign = new CodeAssignStatement ();
1171                         assign.Left = new CodeVariableReferenceExpression ("Container");
1172                         assign.Right = new CodeCastExpression (containerRef,
1173                                                 new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
1174                         method.Statements.Add (assign);
1175
1176                         return method;
1177                 }
1178
1179                 void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
1180                 {
1181                         if (db.Code == null || db.Code.Trim () == "")
1182                                 return;
1183
1184                         EnsureID (db);
1185                         CreateField (db, false);
1186
1187                         string dbMethodName = "__DataBind_" + db.ID;
1188                         // Add the method that builds the DataBoundLiteralControl
1189                         InitMethod (db, false, false);
1190                         CodeMemberMethod method = db.method;
1191                         AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
1192                         method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1193
1194                         // Add the DataBind handler
1195                         method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
1196
1197                         CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
1198                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1199                         invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
1200                         invoke.Parameters.Add (new CodePrimitiveExpression (0));
1201
1202                         CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
1203                         tostring.Method = new CodeMethodReferenceExpression (
1204                                                         new CodeTypeReferenceExpression (typeof (Convert)),
1205                                                         "ToString");
1206                         tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
1207                         invoke.Parameters.Add (tostring);
1208                         method.Statements.Add (invoke);
1209                         
1210                         mainClass.Members.Add (method);
1211
1212                         AddChildCall (builder, db);
1213                 }
1214
1215                 void FlushText (ControlBuilder builder, StringBuilder sb)
1216                 {
1217                         if (sb.Length > 0) {
1218                                 AddLiteralSubObject (builder, sb.ToString ());
1219                                 sb.Length = 0;
1220                         }
1221                 }
1222
1223                 protected void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
1224                 {
1225                         EnsureID (builder);
1226                         bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
1227                         if (!isTemplate && !inTemplate) {
1228                                 CreateField (builder, true);
1229                         } else if (!isTemplate) {
1230                                 builder.ID = builder.GetNextID (null);
1231                                 CreateField (builder, false);
1232                         }
1233
1234                         InitMethod (builder, isTemplate, childrenAsProperties);
1235                         if (!isTemplate || builder.GetType () == typeof (RootBuilder))
1236                                 CreateAssignStatementsFromAttributes (builder);
1237
1238                         if (builder.Children != null && builder.Children.Count > 0) {
1239                                 ArrayList templates = null;
1240
1241                                 StringBuilder sb = new StringBuilder ();
1242                                 foreach (object b in builder.Children) {
1243
1244                                         if (b is string) {
1245                                                 sb.Append ((string) b);
1246                                                 continue;
1247                                         }
1248
1249                                         FlushText (builder, sb);
1250                                         if (b is ObjectTagBuilder) {
1251                                                 ProcessObjectTag ((ObjectTagBuilder) b);
1252                                                 continue;
1253                                         }
1254
1255                                         StringPropertyBuilder pb = b as StringPropertyBuilder;
1256                                         if (pb != null){
1257                                                 if (pb.Children != null && pb.Children.Count > 0) {
1258                                                         StringBuilder asb = new StringBuilder ();
1259                                                         foreach (string s in pb.Children)
1260                                                                 asb.Append (s);
1261                                                         CodeMemberMethod method = builder.method;
1262                                                         CodeAssignStatement assign = new CodeAssignStatement ();
1263                                                         assign.Left = new CodePropertyReferenceExpression (ctrlVar, pb.PropertyName);
1264                                                         assign.Right = new CodePrimitiveExpression (asb.ToString ());
1265                                                         method.Statements.Add (assign);
1266                                                 }
1267                                                 continue;
1268                                         }
1269
1270 #if NET_2_0
1271                                         if (b is ContentBuilderInternal) {
1272                                                 ContentBuilderInternal cb = (ContentBuilderInternal) b;
1273                                                 CreateControlTree (cb, false, true);
1274                                                 AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
1275                                                 continue;
1276                                         }
1277 #endif
1278
1279                                         if (b is TemplateBuilder) {
1280                                                 if (templates == null)
1281                                                         templates = new ArrayList ();
1282
1283                                                 templates.Add (b);
1284                                                 continue;
1285                                         }
1286
1287                                         if (b is CodeRenderBuilder) {
1288                                                 AddCodeRender (builder, (CodeRenderBuilder) b);
1289                                                 continue;
1290                                         }
1291
1292                                         if (b is DataBindingBuilder) {
1293                                                 AddDataBindingLiteral (builder, (DataBindingBuilder) b);
1294                                                 continue;
1295                                         }
1296                                         
1297                                         if (b is ControlBuilder) {
1298                                                 ControlBuilder child = (ControlBuilder) b;
1299                                                 CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
1300                                                 AddChildCall (builder, child);
1301                                                 continue;
1302                                         }
1303
1304                                         throw new Exception ("???");
1305                                 }
1306
1307                                 FlushText (builder, sb);
1308
1309                                 if (templates != null) {
1310                                         foreach (TemplateBuilder b in templates) {
1311                                                 CreateControlTree (b, true, false);
1312 #if NET_2_0
1313                                                 if (b.BindingDirection == BindingDirection.TwoWay) {
1314                                                         string extractMethod = CreateExtractValuesMethod (b);
1315                                                         AddBindableTemplateInvocation (builder.method, b.TagName, b.method.Name, extractMethod);
1316                                                 }
1317                                                 else
1318 #endif
1319                                                 AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
1320                                         }
1321                                 }
1322
1323                         }
1324
1325                         if (builder.defaultPropertyBuilder != null) {
1326                                 ControlBuilder b = builder.defaultPropertyBuilder;
1327                                 CreateControlTree (b, false, true);
1328                                 AddChildCall (builder, b);
1329                         }
1330
1331                         if (builder.HasAspCode) {
1332                                 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1333                                 m.TargetObject = thisRef;
1334                                 m.MethodName = builder.renderMethod.Name;
1335
1336                                 CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
1337                                 create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
1338                                 create.TargetObject = thisRef;
1339                                 create.MethodName = builder.renderMethod.Name;
1340
1341                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
1342                                 invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
1343                                 invoke.Parameters.Add (create);
1344
1345                                 builder.methodStatements.Add (invoke);
1346                         }
1347                         
1348                         if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
1349                                 builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
1350                 }
1351                 
1352                 protected internal override void CreateMethods ()
1353                 {
1354                         base.CreateMethods ();
1355
1356                         CreateProperties ();
1357                         CreateControlTree (parser.RootBuilder, false, false);
1358                         CreateFrameworkInitializeMethod ();
1359                 }
1360
1361                 void CallBaseFrameworkInitialize (CodeMemberMethod method)
1362                 {
1363                         CodeBaseReferenceExpression baseRef = new CodeBaseReferenceExpression ();
1364                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (baseRef, "FrameworkInitialize");
1365                         method.Statements.Add (invoke);
1366                 }
1367
1368                 void CreateFrameworkInitializeMethod ()
1369                 {
1370                         CodeMemberMethod method = new CodeMemberMethod ();
1371                         method.Name = "FrameworkInitialize";
1372                         method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1373                         PrependStatementsToFrameworkInitialize (method);
1374                         CallBaseFrameworkInitialize (method);
1375                         AppendStatementsToFrameworkInitialize (method);
1376                         mainClass.Members.Add (method);
1377                 }
1378
1379                 protected virtual void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
1380                 {
1381                 }
1382
1383                 protected virtual void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
1384                 {
1385                         if (!parser.EnableViewState) {
1386                                 CodeAssignStatement stmt = new CodeAssignStatement ();
1387                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
1388                                 stmt.Right = new CodePrimitiveExpression (false);
1389                                 method.Statements.Add (stmt);
1390                         }
1391
1392                         CodeMethodReferenceExpression methodExpr;
1393                         methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
1394                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
1395                         method.Statements.Add (new CodeExpressionStatement (expr));
1396                 }
1397
1398                 protected override void AddApplicationAndSessionObjects ()
1399                 {
1400                         foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
1401                                 CreateFieldForObject (tag.Type, tag.ObjectID);
1402                                 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
1403                         }
1404
1405                         foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
1406                                 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
1407                         }
1408                 }
1409
1410                 protected void ProcessObjectTag (ObjectTagBuilder tag)
1411                 {
1412                         string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
1413                         CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
1414                 }
1415
1416                 void CreateProperties ()
1417                 {
1418                         if (!parser.AutoEventWireup) {
1419                                 CreateAutoEventWireup ();
1420                         } else {
1421                                 CreateAutoHandlers ();
1422                         }
1423
1424                         CreateApplicationInstance ();
1425                         CreateTemplateSourceDirectory ();
1426                 }
1427
1428                 void CreateTemplateSourceDirectory ()
1429                 {
1430                         CodeMemberProperty prop = new CodeMemberProperty ();
1431                         prop.Type = new CodeTypeReference (typeof (string));
1432                         prop.Name = "TemplateSourceDirectory";
1433                         prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
1434
1435                         // if ((this.Parent != null))
1436                         //   return this.Parent.TemplateSourceDirectory;
1437                         CodeFieldReferenceExpression parentField = new CodeFieldReferenceExpression ();
1438                         parentField.TargetObject = thisRef;
1439                         parentField.FieldName = "Parent";
1440                         
1441                         CodeFieldReferenceExpression tsdField = new CodeFieldReferenceExpression ();
1442                         tsdField.TargetObject = parentField;
1443                         tsdField.FieldName = "TemplateSourceDirectory";
1444
1445                         CodeMethodReturnStatement parentRet = new CodeMethodReturnStatement (tsdField);
1446                         CodeConditionStatement condStatement = new CodeConditionStatement (
1447                                 new CodeBinaryOperatorExpression (parentField,
1448                                                                   CodeBinaryOperatorType.IdentityInequality,
1449                                                                   new CodePrimitiveExpression (null)),
1450                                 parentRet);
1451                         
1452                         prop.GetStatements.Add (condStatement);
1453                         
1454                         string tsd, bvd = parser.BaseVirtualDir;
1455                         int len = bvd.Length;
1456                         if (len >= 2 && bvd [0] == '~') {
1457                                 if (bvd [1] == '/')
1458                                     tsd = bvd.Substring (1);
1459                                 else
1460                                     tsd = '/' + bvd.Substring (1);
1461                         } else if (len >= 1 && bvd [0] != '/')
1462                                 tsd = '/' + bvd;
1463                         else
1464                                 tsd = bvd;
1465                         CodePrimitiveExpression expr = new CodePrimitiveExpression (tsd);
1466                         prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
1467                         mainClass.Members.Add (prop);
1468                 }
1469
1470                 void CreateApplicationInstance ()
1471                 {
1472                         CodeMemberProperty prop = new CodeMemberProperty ();
1473                         Type appType = typeof (HttpApplication);
1474                         prop.Type = new CodeTypeReference (appType);
1475                         prop.Name = "ApplicationInstance";
1476                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
1477
1478                         CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
1479
1480                         propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
1481
1482                         CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
1483                         prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
1484 #if NET_2_0
1485                         if (partialClass != null)
1486                                 partialClass.Members.Add (prop);
1487                         else
1488 #endif
1489                         mainClass.Members.Add (prop);
1490                 }
1491
1492                 void CreateAutoHandlers ()
1493                 {
1494                         // Create AutoHandlers property
1495                         CodeMemberProperty prop = new CodeMemberProperty ();
1496                         prop.Type = new CodeTypeReference (typeof (int));
1497                         prop.Name = "AutoHandlers";
1498                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1499                         
1500                         CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
1501                         CodeFieldReferenceExpression fldRef ;
1502                         fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
1503                         ret.Expression = fldRef;
1504                         prop.GetStatements.Add (ret);
1505                         prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
1506
1507 #if NET_2_0
1508                         CodeAttributeDeclaration attr = new CodeAttributeDeclaration ("System.Obsolete");
1509                         prop.CustomAttributes.Add (attr);
1510 #endif
1511                         
1512                         mainClass.Members.Add (prop);
1513
1514                         // Add the __autoHandlers field
1515                         CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
1516                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
1517                         mainClass.Members.Add (fld);
1518                 }
1519
1520                 void CreateAutoEventWireup ()
1521                 {
1522                         // The getter returns false
1523                         CodeMemberProperty prop = new CodeMemberProperty ();
1524                         prop.Type = new CodeTypeReference (typeof (bool));
1525                         prop.Name = "SupportAutoEvents";
1526                         prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
1527                         prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
1528                         mainClass.Members.Add (prop);
1529                 }
1530
1531 #if NET_2_0
1532                 protected virtual string HandleUrlProperty (string str, MemberInfo member)
1533                 {
1534                         return str;
1535                 }
1536 #endif
1537     
1538                 CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
1539                 {                       
1540 #if NET_2_0
1541                         bool wasNullable = false;
1542                         
1543                         if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
1544                                 Type[] types = type.GetGenericArguments();
1545                                 type = types[0]; // we're interested only in the first type here
1546                                 wasNullable = true;
1547                         }
1548 #endif
1549
1550                         if (type == typeof (string)) {
1551 #if NET_2_0
1552                                 object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
1553                                 if (urlAttr.Length != 0)
1554                                         str = HandleUrlProperty (str, member);
1555 #endif
1556                                 return new CodePrimitiveExpression (str);
1557                         }
1558
1559                         if (type == typeof (bool)) {
1560                                 if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
1561                                         return new CodePrimitiveExpression (true);
1562                                 else if (InvariantCompareNoCase (str, "false"))
1563                                         return new CodePrimitiveExpression (false);
1564 #if NET_2_0
1565                                 else if (wasNullable && InvariantCompareNoCase(str, "null"))
1566                                         return new CodePrimitiveExpression (null);
1567 #endif
1568                                 else
1569                                         throw new ParseException (currentLocation,
1570                                                         "Value '" + str  + "' is not a valid boolean.");
1571                         }
1572
1573                         if (str == null)
1574                                 return new CodePrimitiveExpression (null);
1575
1576                         if (type.IsPrimitive)
1577                                 return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
1578
1579                         if (type == typeof (string [])) {
1580                                 string [] subs = str.Split (',');
1581                                 CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
1582                                 expr.CreateType = new CodeTypeReference (typeof (string));
1583                                 foreach (string v in subs) {
1584                                         expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
1585                                 }
1586
1587                                 return expr;
1588                         }
1589
1590                         if (type == typeof (Color)){
1591                                 if (colorConverter == null)
1592                                         colorConverter = TypeDescriptor.GetConverter (typeof (Color));
1593
1594                                 if (str.Trim().Length == 0) {
1595                                         CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
1596                                         return new CodeFieldReferenceExpression (ft, "Empty");
1597                                 }
1598                                 
1599                                 Color c;
1600                                 try {
1601                                         if (str.IndexOf (',') == -1) {
1602                                                 c = (Color) colorConverter.ConvertFromString (str);
1603                                         } else {
1604                                                 int [] argb = new int [4];
1605                                                 argb [0] = 255;
1606
1607                                                 string [] parts = str.Split (',');
1608                                                 int length = parts.Length;
1609                                                 if (length < 3)
1610                                                         throw new Exception ();
1611
1612                                                 int basei = (length == 4) ? 0 : 1;
1613                                                 for (int i = length - 1; i >= 0; i--) {
1614                                                         argb [basei + i] = (int) Byte.Parse (parts [i]);
1615                                                 }
1616                                                 c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
1617                                         }
1618                                 } catch (Exception e){
1619                                         // Hack: "LightGrey" is accepted, but only for ASP.NET, as the
1620                                         // TypeConverter for Color fails to ConvertFromString.
1621                                         // Hence this hack...
1622                                         if (InvariantCompareNoCase ("LightGrey", str)) {
1623                                                 c = Color.LightGray;
1624                                         } else {
1625                                                 throw new ParseException (currentLocation,
1626                                                         "Color " + str + " is not a valid color.", e);
1627                                         }
1628                                 }
1629
1630                                 if (c.IsKnownColor){
1631                                         CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
1632                                         if (c.IsSystemColor)
1633                                                 type = typeof (SystemColors);
1634
1635                                         expr.TargetObject = new CodeTypeReferenceExpression (type);
1636                                         expr.FieldName = c.Name;
1637                                         return expr;
1638                                 } else {
1639                                         CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1640                                         m.TargetObject = new CodeTypeReferenceExpression (type);
1641                                         m.MethodName = "FromArgb";
1642                                         CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1643                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
1644                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
1645                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
1646                                         invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
1647                                         return invoke;
1648                                 }
1649                         }
1650
1651                         TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
1652                         
1653                         if (converter != null && converter.CanConvertFrom (typeof (string))) {
1654                                 object value = converter.ConvertFromInvariantString (str);
1655
1656                                 if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
1657                                         InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
1658                                         return GenerateInstance (idesc, true);
1659                                 }
1660
1661                                 CodeExpression exp = GenerateObjectInstance (value, false);
1662                                 if (exp != null) return exp;
1663                                 
1664                                 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1665                                 m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
1666                                 m.MethodName = "GetConverter";
1667                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1668                                 CodeTypeReference tref = new CodeTypeReference (type);
1669                                 invoke.Parameters.Add (new CodeTypeOfExpression (tref));
1670                                 
1671                                 invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
1672                                 invoke.Parameters.Add (new CodePrimitiveExpression (str));
1673
1674                                 return new CodeCastExpression (tref, invoke);
1675                         }
1676                         
1677                         Console.WriteLine ("Unknown type: " + type + " value: " + str);
1678
1679                         return new CodePrimitiveExpression (str);
1680                 }
1681                 
1682                 CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
1683                 {
1684                         CodeExpression[] parameters = new CodeExpression [idesc.Arguments.Count];
1685                         int n = 0;
1686                         foreach (object ob in idesc.Arguments) {
1687                                 CodeExpression exp = GenerateObjectInstance (ob, throwOnError);
1688                                 if (exp == null) return null;
1689                                 parameters [n++] = exp;
1690                         }
1691                         
1692                         switch (idesc.MemberInfo.MemberType) {
1693                         case MemberTypes.Constructor:
1694                                 CodeTypeReference tob = new CodeTypeReference (idesc.MemberInfo.DeclaringType);
1695                                 return new CodeObjectCreateExpression (tob, parameters);
1696
1697                         case MemberTypes.Method:
1698                                 CodeTypeReferenceExpression mt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1699                                 return new CodeMethodInvokeExpression (mt, idesc.MemberInfo.Name, parameters);
1700
1701                         case MemberTypes.Field:
1702                                 CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1703                                 return new CodeFieldReferenceExpression (ft, idesc.MemberInfo.Name);
1704
1705                         case MemberTypes.Property:
1706                                 CodeTypeReferenceExpression pt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
1707                                 return new CodePropertyReferenceExpression (pt, idesc.MemberInfo.Name);
1708                         }
1709                         throw new ParseException (currentLocation, "Invalid instance type.");
1710                 }
1711                 
1712                 CodeExpression GenerateObjectInstance (object value, bool throwOnError)
1713                 {
1714                         if (value == null)
1715                                 return new CodePrimitiveExpression (null);
1716                         
1717                         Type t = value.GetType();
1718                         if (t.IsPrimitive || value is string)
1719                                 return new CodePrimitiveExpression (value);
1720                                 
1721                         if (t.IsArray) {
1722                                 Array ar = (Array) value;
1723                                 CodeExpression[] items = new CodeExpression [ar.Length];
1724                                 for (int n=0; n<ar.Length; n++) {
1725                                         CodeExpression exp = GenerateObjectInstance (ar.GetValue (n), throwOnError);
1726                                         if (exp == null) return null; 
1727                                         items [n] = exp;
1728                                 }
1729                                 return new CodeArrayCreateExpression (new CodeTypeReference (t), items);
1730                         }
1731                         
1732                         TypeConverter converter = TypeDescriptor.GetConverter (t);
1733                         if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
1734                                 InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
1735                                 return GenerateInstance (idesc, throwOnError);
1736                         }
1737                         
1738                         InstanceDescriptor desc = GetDefaultInstanceDescriptor (value);
1739                         if (desc != null) return GenerateInstance (desc, throwOnError);
1740                         
1741                         if (throwOnError)
1742                                 throw new ParseException (currentLocation, "Cannot generate an instance for the type: " + t);
1743                         else
1744                                 return null;
1745                 }
1746                 
1747                 InstanceDescriptor GetDefaultInstanceDescriptor (object value)
1748                 {
1749                         if (value is System.Web.UI.WebControls.Unit) {
1750                                 System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
1751                                 ConstructorInfo c = typeof(System.Web.UI.WebControls.Unit).GetConstructor (
1752                                         BindingFlags.Instance | BindingFlags.Public,
1753                                         null,
1754                                         new Type[] {typeof(double), typeof(System.Web.UI.WebControls.UnitType)},
1755                                         null);
1756                                 
1757                                 return new InstanceDescriptor (c, new object[] {s.Value, s.Type});
1758                         }
1759                         
1760                         if (value is System.Web.UI.WebControls.FontUnit) {
1761                                 System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
1762                                 ConstructorInfo c = typeof(System.Web.UI.WebControls.FontUnit).GetConstructor (
1763                                         BindingFlags.Instance | BindingFlags.Public,
1764                                         null,
1765                                         new Type[] {typeof(System.Web.UI.WebControls.Unit)},
1766                                         null);
1767                                 return new InstanceDescriptor (c, new object[] {s.Unit});
1768                         }
1769                         return null;
1770                 }
1771         }
1772 }
1773
1774
1775