2005-09-13 Sureshkumar T <tsureshkumar@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
index f78648e666301c12be40f8a6c07531f166c33f24..2eb3e87a46681f7df20daa6bd18842ee90389308 100644 (file)
@@ -6,6 +6,27 @@
 //
 // (C) 2003 Ximian, Inc (http://www.ximian.com)
 //
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 using System;
 using System.CodeDom;
 using System.Collections;
@@ -16,6 +37,12 @@ using System.Reflection;
 using System.Text;
 using System.Web;
 using System.Web.UI;
+using System.Web.Util;
+using System.ComponentModel.Design.Serialization;
+#if NET_2_0
+using System.Collections.Specialized;
+using System.Text.RegularExpressions;
+#endif
 
 namespace System.Web.Compilation
 {
@@ -24,9 +51,6 @@ namespace System.Web.Compilation
                static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
                                                  BindingFlags.Instance | BindingFlags.IgnoreCase;
 
-               static Type styleType = typeof (System.Web.UI.WebControls.Style);
-               static Type fontinfoType = typeof (System.Web.UI.WebControls.FontInfo);
-
                TemplateControlParser parser;
                int dataBoundAtts;
                ILocation currentLocation;
@@ -34,8 +58,10 @@ namespace System.Web.Compilation
                static TypeConverter colorConverter;
 
                static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
-               static Type [] arrayString = new Type [] {typeof (string)};
-               static Type [] arrayStringCultureInfo = new Type [] {typeof (string), typeof (CultureInfo)};
+               
+#if NET_2_0
+               static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled);
+#endif
 
                public TemplateControlCompiler (TemplateControlParser parser)
                        : base (parser)
@@ -179,6 +205,14 @@ namespace System.Web.Compilation
                                        initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
                                        method.Statements.Add (initAsControl);
                                }
+#if NET_2_0
+                               if (typeof (System.Web.UI.WebControls.ContentPlaceHolder).IsAssignableFrom (type)) {
+                                       CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
+                                       CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
+                                       addPlaceholder.Parameters.Add (ctrlVar);
+                                       method.Statements.Add (addPlaceholder);
+                               }
+#endif
                        }
 
                        mainClass.Members.Add (method);
@@ -238,7 +272,7 @@ namespace System.Web.Compilation
                        return method.Name;
                }
 
-               void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, bool isDataBound)
+               void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound)
                {
                        CodeMemberMethod method = builder.method;
                        if (isDataBound) {
@@ -250,7 +284,7 @@ namespace System.Web.Compilation
                        CodeAssignStatement assign = new CodeAssignStatement ();
                        assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
                        currentLocation = builder.location;
-                       assign.Right = GetExpressionFromString (type, att);
+                       assign.Right = GetExpressionFromString (type, att, member);
 
                        method.Statements.Add (assign);
                }
@@ -261,16 +295,68 @@ namespace System.Web.Compilation
                                return false;
 
                        string str = value.Trim ();
-                       return (str.StartsWith ("<%#") && str.EndsWith ("%>"));
+                       return (StrUtils.StartsWith (str, "<%#") && StrUtils.EndsWith (str, "%>"));
                }
-               
-               bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id, string attValue)
+
+#if NET_2_0
+               void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
                {
-                       CodeMemberMethod method = builder.method;
-                       int hyphen = id.IndexOf ('-');
+                       string str = value.Trim ();
+                       str = str.Substring (3).Trim ();        // eats "<%#"
+                       if (StrUtils.StartsWith (str, "Bind")) {
+                               Match match = bindRegex.Match (str);
+                               if (match.Success) {
+                                       string bindingName = match.Groups [1].Value;
+                                       
+                                       TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
+                                       if (templateBuilder == null || templateBuilder.BindingDirection == BindingDirection.OneWay)
+                                               throw new HttpException ("Bind expression not allowed in this context.");
+                                               
+                                       string id = builder.attribs ["ID"] as string;
+                                       if (id == null)
+                                               throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
+                                       
+                                       templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
+                                       value = "<%# Eval" + str.Substring (4);
+                               }
+                       }
+               }
+#endif
 
+               /*
+               static bool InvariantCompare (string a, string b)
+               {
+                       return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
+               }
+               */
+
+               static bool InvariantCompareNoCase (string a, string b)
+               {
+                       return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
+               }
+
+               static MemberInfo GetFieldOrProperty (Type type, string name)
+               {
+                       MemberInfo member = null;
+                       try {
+                               member = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
+                       } catch {}
+                       
+                       if (member != null)
+                               return member;
+
+                       try {
+                               member = type.GetField (name, noCaseFlags & ~BindingFlags.NonPublic);
+                       } catch {}
+
+                       return member;
+               }
+
+               bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
+                                               string attValue, string prefix)
+               {
+                       int hyphen = id.IndexOf ('-');
                        bool isPropertyInfo = (member is PropertyInfo);
-                       bool is_processed = false;
                        bool isDataBound = IsDataBound (attValue);
 
                        Type type;
@@ -282,8 +368,11 @@ namespace System.Web.Compilation
                                type = ((FieldInfo) member).FieldType;
                        }
 
-                       if (0 == String.Compare (member.Name, id, true)){
-                               AddCodeForPropertyOrField (builder, type, member.Name, attValue, isDataBound);
+                       if (InvariantCompareNoCase (member.Name, id)) {
+#if NET_2_0
+                               if (isDataBound) RegisterBindingInfo (builder, member.Name, ref attValue);
+#endif
+                               AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound);
                                return true;
                        }
                        
@@ -292,34 +381,43 @@ namespace System.Web.Compilation
 
                        string prop_field = id.Replace ("-", ".");
                        string [] parts = prop_field.Split (new char [] {'.'});
-                       if (parts.Length != 2 || 0 != String.Compare (member.Name, parts [0], true))
+                       int length = parts.Length;
+                       if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
                                return false;
 
-                       PropertyInfo [] subprops = type.GetProperties ();
-                       foreach (PropertyInfo subprop in subprops) {
-                               if (0 != String.Compare (subprop.Name, parts [1], true))
-                                       continue;
-
-                               if (subprop.CanWrite == false)
+                       if (length > 2) {
+                               MemberInfo sub_member = GetFieldOrProperty (type, parts [1]);
+                               if (sub_member == null)
                                        return false;
 
-                               bool is_bool = subprop.PropertyType == typeof (bool);
-                               if (!is_bool && attValue == null)
-                                       return false; // Font-Size -> Font-Size="" as html
+                               string new_prefix = prefix + parts [0] + ".";
+                               string new_id = id.Substring (hyphen + 1);
+                               return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
+                       }
 
-                               string value;
-                               if (attValue == null && is_bool)
-                                       value = "true"; // Font-Bold <=> Font-Bold="true"
-                               else
-                                       value = attValue;
+                       MemberInfo subpf = GetFieldOrProperty (type, parts [1]);
+                       if (!(subpf is PropertyInfo))
+                               return false;
 
-                               AddCodeForPropertyOrField (builder, subprop.PropertyType,
-                                                member.Name + "." + subprop.Name,
-                                                value, isDataBound);
-                               is_processed = true;
-                       }
+                       PropertyInfo subprop = (PropertyInfo) subpf;
+                       if (subprop.CanWrite == false)
+                               return false;
+
+                       bool is_bool = (subprop.PropertyType == typeof (bool));
+                       if (!is_bool && attValue == null)
+                               return false; // Font-Size -> Font-Size="" as html
+
+                       string val = attValue;
+                       if (attValue == null && is_bool)
+                               val = "true"; // Font-Bold <=> Font-Bold="true"
+#if NET_2_0
+                       if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
+#endif
+                       AddCodeForPropertyOrField (builder, subprop.PropertyType,
+                                               prefix + member.Name + "." + subprop.Name,
+                                               val, subprop, isDataBound);
 
-                       return is_processed;
+                       return true;
                }
 
                void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
@@ -342,13 +440,11 @@ namespace System.Web.Compilation
                                return;
 
                        EventInfo [] ev_info = null;
-                       PropertyInfo [] prop_info = null;
-                       FieldInfo [] field_info = null;
                        bool is_processed = false;
                        Type type = builder.ControlType;
 
-                       foreach (string id in atts.Keys){
-                               if (0 == String.Compare (id, "runat", true))
+                       foreach (string id in atts.Keys) {
+                               if (InvariantCompareNoCase (id, "runat"))
                                        continue;
 
                                is_processed = false;
@@ -359,7 +455,7 @@ namespace System.Web.Compilation
 
                                        string id_as_event = id.Substring (2);
                                        foreach (EventInfo ev in ev_info){
-                                               if (0 == String.Compare (ev.Name, id_as_event, true)){
+                                               if (InvariantCompareNoCase (ev.Name, id_as_event)){
                                                        AddEventAssign (builder.method,
                                                                        ev.Name,
                                                                        ev.EventHandlerType,
@@ -374,25 +470,16 @@ namespace System.Web.Compilation
                                                continue;
                                } 
 
-                               if (prop_info == null)
-                                       prop_info = type.GetProperties ();
-
-                               foreach (PropertyInfo prop in prop_info) {
-                                       is_processed = ProcessPropertiesAndFields (builder, prop, id, attvalue);
-                                       if (is_processed)
-                                               break;
-                               }
-
-                               if (is_processed)
-                                       continue;
-
-                               if (field_info == null)
-                                       field_info = type.GetFields ();
-
-                               foreach (FieldInfo field in field_info){
-                                       is_processed = ProcessPropertiesAndFields (builder, field, id, attvalue);
+                               int hyphen = id.IndexOf ('-');
+                               string alt_id = id;
+                               if (hyphen != -1)
+                                       alt_id = id.Substring (0, hyphen);
+                                       
+                               MemberInfo fop = GetFieldOrProperty (type, alt_id);
+                               if (fop != null) {
+                                       is_processed = ProcessPropertiesAndFields (builder, fop, id, attvalue, null);
                                        if (is_processed)
-                                               break;
+                                               continue;
                                }
 
                                if (is_processed)
@@ -494,6 +581,88 @@ namespace System.Web.Compilation
                        method.Statements.Add (assign);
                }
 
+#if NET_2_0
+               void AddBindableTemplateInvocation (CodeMemberMethod method, string name, string methodName, string extractMethodName)
+               {
+                       CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
+
+                       CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
+                       newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+
+                       CodeObjectCreateExpression newExtract = new CodeObjectCreateExpression (typeof (ExtractTemplateValuesMethod));
+                       newExtract.Parameters.Add (new CodeMethodReferenceExpression (thisRef, extractMethodName));
+
+                       CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
+                       newCompiled.Parameters.Add (newBuild);
+                       newCompiled.Parameters.Add (newExtract);
+                       
+                       CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
+                       method.Statements.Add (assign);
+               }
+               
+               string CreateExtractValuesMethod (TemplateBuilder builder)
+               {
+                       CodeMemberMethod method = new CodeMemberMethod ();
+                       method.Name = "__ExtractValues_" + builder.ID;
+                       method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
+                       method.ReturnType = new CodeTypeReference (typeof(IOrderedDictionary));
+                       
+                       CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression ();
+                       arg.Type = new CodeTypeReference (typeof (Control));
+                       arg.Name = "__container";
+                       method.Parameters.Add (arg);
+                       mainClass.Members.Add (method);
+                       
+                       CodeObjectCreateExpression newTable = new CodeObjectCreateExpression ();
+                       newTable.CreateType = new CodeTypeReference (typeof(OrderedDictionary));
+                       method.Statements.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary), "__table", newTable));
+                       CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
+                       
+                       if (builder.Bindings != null) {
+                               foreach (TemplateBinding binding in builder.Bindings) {
+                                       CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
+                                       method.Statements.Add (dec);
+                                       CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
+                                       CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
+                                       invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
+                                       
+                                       CodeAssignStatement assign = new CodeAssignStatement ();
+                                       CodeVariableReferenceExpression control = new CodeVariableReferenceExpression (binding.ControlId); 
+                                       assign.Left = control;
+                                       assign.Right = new CodeCastExpression (binding.ControlType, invoke);
+                                       method.Statements.Add (assign);
+                                       
+                                       CodeConditionStatement sif = new CodeConditionStatement ();
+                                       sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
+                                       
+                                       assign = new CodeAssignStatement ();
+                                       assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
+                                       assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
+                                       sif.TrueStatements.Add (assign);
+                                       method.Statements.Add (sif);
+                               }
+                       }
+
+                       method.Statements.Add (new CodeMethodReturnStatement (tableExp));
+                       return method.Name;
+               }
+
+               void AddContentTemplateInvocation (ContentControlBuilder cbuilder, CodeMemberMethod method, string methodName)
+               {
+                       CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
+                       newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
+
+                       CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
+                       newCompiled.Parameters.Add (newBuild);
+                       
+                       CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (thisRef, "AddContentTemplate");
+                       invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
+                       invoke.Parameters.Add (newCompiled);
+
+                       method.Statements.Add (invoke);
+               }
+#endif
+
                void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
                {
                        if (cr.Code == null || cr.Code.Trim () == "")
@@ -516,9 +685,13 @@ namespace System.Web.Compilation
 
                static Type GetContainerType (ControlBuilder builder)
                {
-                       Type type = builder.NamingContainerType;
+                       TemplateBuilder tb = builder as TemplateBuilder;
+                       if (tb != null && tb.ContainerType != null)
+                               return tb.ContainerType;
+
+                       Type type = builder.BindingContainerType;
 
-                       PropertyInfo prop = type.GetProperty ("Items", noCaseFlags);
+                       PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
                        if (prop == null)
                                return type;
 
@@ -526,7 +699,7 @@ namespace System.Web.Compilation
                        if (!typeof (ICollection).IsAssignableFrom (ptype))
                                return type;
 
-                       prop = ptype.GetProperty ("Item", noCaseFlags);
+                       prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
                        if (prop == null)
                                return type;
 
@@ -625,7 +798,7 @@ namespace System.Web.Compilation
                        }
 
                        InitMethod (builder, isTemplate, childrenAsProperties);
-                       if (builder.GetType () != typeof (TemplateBuilder))
+                       if (!isTemplate || builder.GetType () == typeof (RootBuilder))
                                CreateAssignStatementsFromAttributes (builder);
 
                        if (builder.Children != null && builder.Children.Count > 0) {
@@ -645,6 +818,15 @@ namespace System.Web.Compilation
                                                continue;
                                        }
 
+#if NET_2_0
+                                       if (b is ContentControlBuilder) {
+                                               ContentControlBuilder cb = (ContentControlBuilder) b;
+                                               CreateControlTree (cb, false, true);
+                                               AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
+                                               continue;
+                                       }
+#endif
+
                                        if (b is TemplateBuilder) {
                                                if (templates == null)
                                                        templates = new ArrayList ();
@@ -662,7 +844,7 @@ namespace System.Web.Compilation
                                                AddDataBindingLiteral (builder, (DataBindingBuilder) b);
                                                continue;
                                        }
-
+                                       
                                        if (b is ControlBuilder) {
                                                ControlBuilder child = (ControlBuilder) b;
                                                CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
@@ -676,8 +858,15 @@ namespace System.Web.Compilation
                                FlushText (builder, sb);
 
                                if (templates != null) {
-                                       foreach (ControlBuilder b in templates) {
+                                       foreach (TemplateBuilder b in templates) {
                                                CreateControlTree (b, true, false);
+#if NET_2_0
+                                               if (b.BindingDirection == BindingDirection.TwoWay) {
+                                                       string extractMethod = CreateExtractValuesMethod (b);
+                                                       AddBindableTemplateInvocation (builder.method, b.TagName, b.method.Name, extractMethod);
+                                               }
+                                               else
+#endif
                                                AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
                                        }
                                }
@@ -838,15 +1027,15 @@ namespace System.Web.Compilation
                        mainClass.Members.Add (prop);
                }
                
-               CodeExpression GetExpressionFromString (Type type, string str)
+               CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
                {
                        if (type == typeof (string))
                                return new CodePrimitiveExpression (str);
 
                        if (type == typeof (bool)) {
-                               if (str == null || str == "" || 0 == String.Compare (str, "true", true))
+                               if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
                                        return new CodePrimitiveExpression (true);
-                               else if (0 == String.Compare (str, "false", true))
+                               else if (InvariantCompareNoCase (str, "false"))
                                        return new CodePrimitiveExpression (false);
                                else
                                        throw new ParseException (currentLocation,
@@ -857,21 +1046,7 @@ namespace System.Web.Compilation
                                return new CodePrimitiveExpression (null);
 
                        if (type.IsPrimitive)
-                               return new CodePrimitiveExpression (Convert.ChangeType (str, type));
-
-                       if (type.IsEnum) {
-                               object val = null;
-                               try {
-                                       val = Enum.Parse (type, str, true);
-                               } catch (Exception) {
-                                       throw new ParseException (currentLocation,
-                                                       str + " is not a valid value for enum '" + type + "'");
-                               }
-                               CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
-                               expr.TargetObject = new CodeTypeReferenceExpression (type);
-                               expr.FieldName = val.ToString ();
-                               return expr;
-                       }
+                               return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
 
                        if (type == typeof (string [])) {
                                string [] subs = str.Split (',');
@@ -884,34 +1059,15 @@ namespace System.Web.Compilation
                                return expr;
                        }
 
-                       if (type == typeof (Size)) {
-                               string [] subs = str.Split (',');
-                               if (subs.Length != 2)
-                                       throw new ParseException (currentLocation,
-                                               String.Format ("Cannot create {0} from '{1}'", type, str));
-
-                               int width = 0;
-                               int height = 0;
-                               try {
-                                       width = Int32.Parse (subs [0]);
-                                       height = Int32.Parse (subs [0]);
-                                       new Size (width, height);
-                               } catch {
-                                       throw new ParseException (currentLocation,
-                                               String.Format ("Cannot create {0} from '{1}'", type, str));
-                               }
-                               
-                               CodeObjectCreateExpression expr = new CodeObjectCreateExpression ();
-                               expr.CreateType = new CodeTypeReference (type);
-                               expr.Parameters.Add (new CodePrimitiveExpression (width));
-                               expr.Parameters.Add (new CodePrimitiveExpression (height));
-                               return expr;
-                       }
-
                        if (type == typeof (Color)){
                                if (colorConverter == null)
                                        colorConverter = TypeDescriptor.GetConverter (typeof (Color));
 
+                               if (str.Trim().Length == 0) {
+                                       CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
+                                       return new CodeFieldReferenceExpression (ft, "Empty");
+                               }
+                               
                                Color c;
                                try {
                                        if (str.IndexOf (',') == -1) {
@@ -957,8 +1113,19 @@ namespace System.Web.Compilation
                                }
                        }
 
-                       TypeConverter converter = TypeDescriptor.GetConverter (type);
+                       TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
+                       
                        if (converter != null && converter.CanConvertFrom (typeof (string))) {
+                               object value = converter.ConvertFrom (str);
+
+                               if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
+                                       InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
+                                       return GenerateInstance (idesc, true);
+                               }
+
+                               CodeExpression exp = GenerateObjectInstance (value, false);
+                               if (exp != null) return exp;
+                               
                                CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
                                m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
                                m.MethodName = "GetConverter";
@@ -971,48 +1138,91 @@ namespace System.Web.Compilation
 
                                return new CodeCastExpression (tref, invoke);
                        }
+                       
+                       Console.WriteLine ("Unknown type: " + type + " value: " + str);
 
-                       bool parms = false;
-                       BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
-                       MethodInfo parse = type.GetMethod ("Parse", flags, null, arrayStringCultureInfo, null);
-                       if (parse != null) {
-                               parms = true;
-                       } else {
-                               parse = type.GetMethod ("Parse", flags, null, arrayString, null);
+                       return new CodePrimitiveExpression (str);
+               }
+               
+               CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
+               {
+                       CodeExpression[] parameters = new CodeExpression [idesc.Arguments.Count];
+                       int n = 0;
+                       foreach (object ob in idesc.Arguments) {
+                               CodeExpression exp = GenerateObjectInstance (ob, throwOnError);
+                               if (exp == null) return null;
+                               parameters [n++] = exp;
                        }
-
-                       if (parse != null) {
-                               object o = null;
-                               try {
-                                       if (parms)
-                                               o = parse.Invoke (null, new object [] { str, CultureInfo.InvariantCulture });
-                                       else
-                                               o = parse.Invoke (null, new object [] { str });
-                               } catch (Exception e) {
-                                       throw new ParseException (currentLocation, "Cannot parse " + str + " as " + type, e);
-                               }
+                       
+                       switch (idesc.MemberInfo.MemberType) {
+                       case MemberTypes.Constructor:
+                               CodeTypeReference tob = new CodeTypeReference (idesc.MemberInfo.DeclaringType);
+                               return new CodeObjectCreateExpression (tob, parameters);
+
+                       case MemberTypes.Method:
+                               CodeTypeReferenceExpression mt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
+                               return new CodeMethodInvokeExpression (mt, idesc.MemberInfo.Name, parameters);
+
+                       case MemberTypes.Field:
+                               CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
+                               return new CodeFieldReferenceExpression (ft, idesc.MemberInfo.Name);
+
+                       case MemberTypes.Property:
+                               CodeTypeReferenceExpression pt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
+                               return new CodePropertyReferenceExpression (pt, idesc.MemberInfo.Name);
+                       }
+                       throw new ParseException (currentLocation, "Invalid instance type.");
+               }
+               
+               CodeExpression GenerateObjectInstance (object value, bool throwOnError)
+               {
+                       if (value == null)
+                               return new CodePrimitiveExpression (null);
+                       
+                       Type t = value.GetType();
+                       if (t.IsPrimitive || value is string)
+                               return new CodePrimitiveExpression (value);
                                
-                               if (o == null)
-                                       throw new ParseException (currentLocation, str + " as " + type + " is null");
-
-                               CodeTypeReferenceExpression exprType = new CodeTypeReferenceExpression (type);
-                               CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (exprType, "Parse");
-                               //FIXME: may be we gotta ensure roundtrip between o.ToString and Parse
-                               invoke.Parameters.Add (new CodePrimitiveExpression (o.ToString ()));
-                               if (parms) {
-                                       CodeTypeReferenceExpression texp = new CodeTypeReferenceExpression (typeof (CultureInfo));
-                                       CodePropertyReferenceExpression pexp = new CodePropertyReferenceExpression ();
-                                       pexp.TargetObject = texp;
-                                       pexp.PropertyName = "InvariantCulture";
-                                       invoke.Parameters.Add (pexp);
+                       if (t.IsArray) {
+                               Array ar = (Array) value;
+                               CodeExpression[] items = new CodeExpression [ar.Length];
+                               for (int n=0; n<ar.Length; n++) {
+                                       CodeExpression exp = GenerateObjectInstance (ar.GetValue (n), throwOnError);
+                                       if (exp == null) return null; 
+                                       items [n] = exp;
                                }
-                               return invoke;
+                               return new CodeArrayCreateExpression (new CodeTypeReference (t), items);
                        }
-
-                       // FIXME: Arrays
-                       Console.WriteLine ("Unknown type: " + type + " value: " + str);
-
-                       return new CodePrimitiveExpression (str);
+                       
+                       TypeConverter converter = TypeDescriptor.GetConverter (t);
+                       if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
+                               InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
+                               return GenerateInstance (idesc, throwOnError);
+                       }
+                       
+                       InstanceDescriptor desc = GetDefaultInstanceDescriptor (value);
+                       if (desc != null) return GenerateInstance (desc, throwOnError);
+                       
+                       if (throwOnError)
+                               throw new ParseException (currentLocation, "Cannot generate an instance for the type: " + t);
+                       else
+                               return null;
+               }
+               
+               InstanceDescriptor GetDefaultInstanceDescriptor (object value)
+               {
+                       if (value is System.Web.UI.WebControls.Unit) {
+                               System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
+                               MethodInfo met = typeof(System.Web.UI.WebControls.Unit).GetMethod ("Parse", new Type[] {typeof(string)});
+                               return new InstanceDescriptor (met, new object[] {s.ToString ()});
+                       }
+                       
+                       if (value is System.Web.UI.WebControls.FontUnit) {
+                               System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
+                               MethodInfo met = typeof(System.Web.UI.WebControls.FontUnit).GetMethod ("Parse", new Type[] {typeof(string)});
+                               return new InstanceDescriptor (met, new object[] {s.ToString ()});
+                       }
+                       return null;
                }
        }
 }