2 // System.Web.Compilation.TemplateControlCompiler
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.ComponentModel;
35 using System.Globalization;
36 using System.Reflection;
41 namespace System.Web.Compilation
43 class TemplateControlCompiler : BaseCompiler
45 static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
46 BindingFlags.Instance | BindingFlags.IgnoreCase;
48 static Type styleType = typeof (System.Web.UI.WebControls.Style);
49 static Type fontinfoType = typeof (System.Web.UI.WebControls.FontInfo);
51 TemplateControlParser parser;
53 ILocation currentLocation;
55 static TypeConverter colorConverter;
57 static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
58 static Type [] arrayString = new Type [] {typeof (string)};
59 static Type [] arrayStringCultureInfo = new Type [] {typeof (string), typeof (CultureInfo)};
61 public TemplateControlCompiler (TemplateControlParser parser)
67 void EnsureID (ControlBuilder builder)
69 if (builder.ID == null || builder.ID.Trim () == "")
70 builder.ID = builder.GetNextID (null);
73 void CreateField (ControlBuilder builder, bool check)
75 currentLocation = builder.location;
76 if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType))
77 return; // The field or property already exists in a base class and is accesible.
79 CodeMemberField field;
80 field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
81 field.Attributes = MemberAttributes.Family;
82 mainClass.Members.Add (field);
85 bool CheckBaseFieldOrProperty (string id, Type type)
87 FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
90 if (fld == null || fld.IsPrivate) {
91 PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
93 MethodInfo setm = prop.GetSetMethod (true);
95 other = prop.PropertyType;
98 other = fld.FieldType;
104 if (!other.IsAssignableFrom (type)) {
105 string msg = String.Format ("The base class includes the field '{0}', but its " +
106 "type '{1}' is not compatible with {2}",
108 throw new ParseException (currentLocation, msg);
114 void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr)
116 if (!builder.haveParserVariable) {
117 CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
119 p.Type = new CodeTypeReference (typeof (IParserAccessor));
120 p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
121 builder.method.Statements.Add (p);
122 builder.haveParserVariable = true;
125 CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
126 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
127 invoke.Parameters.Add (expr);
128 builder.method.Statements.Add (invoke);
131 void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
133 string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
134 CodeMemberMethod method = new CodeMemberMethod ();
135 builder.method = method;
136 method.Name = "__BuildControl" + tailname;
137 method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
138 Type type = builder.ControlType;
140 if (builder.HasAspCode) {
141 CodeMemberMethod renderMethod = new CodeMemberMethod ();
142 builder.renderMethod = renderMethod;
143 renderMethod.Name = "__Render" + tailname;
144 renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
145 CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
146 arg1.Type = new CodeTypeReference (typeof (HtmlTextWriter));
147 arg1.Name = "__output";
148 CodeParameterDeclarationExpression arg2 = new CodeParameterDeclarationExpression ();
149 arg2.Type = new CodeTypeReference (typeof (Control));
150 arg2.Name = "parameterContainer";
151 renderMethod.Parameters.Add (arg1);
152 renderMethod.Parameters.Add (arg2);
153 mainClass.Members.Add (renderMethod);
156 if (childrenAsProperties || builder.ControlType == null) {
158 if (builder.ControlType != null && builder.isProperty &&
159 !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
160 typeString = builder.ControlType.FullName;
162 typeString = "System.Web.UI.Control";
164 method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
167 if (typeof (Control).IsAssignableFrom (type))
168 method.ReturnType = new CodeTypeReference (typeof (Control));
170 CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
172 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
173 if (atts != null && atts.Length > 0) {
174 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
176 newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
177 } else if (builder is DataBindingBuilder) {
178 newExpr.Parameters.Add (new CodePrimitiveExpression (0));
179 newExpr.Parameters.Add (new CodePrimitiveExpression (1));
182 method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
183 CodeAssignStatement assign = new CodeAssignStatement ();
184 assign.Left = ctrlVar;
185 assign.Right = newExpr;
186 method.Statements.Add (assign);
188 CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
189 builderID.TargetObject = thisRef;
190 builderID.FieldName = builder.ID;
191 assign = new CodeAssignStatement ();
192 assign.Left = builderID;
193 assign.Right = ctrlVar;
194 method.Statements.Add (assign);
195 if (typeof (UserControl).IsAssignableFrom (type)) {
196 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
197 mref.TargetObject = builderID;
198 mref.MethodName = "InitializeAsUserControl";
199 CodeMethodInvokeExpression initAsControl = new CodeMethodInvokeExpression (mref);
200 initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
201 method.Statements.Add (initAsControl);
204 if (typeof (System.Web.UI.WebControls.ContentPlaceHolder).IsAssignableFrom (type)) {
205 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
206 CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
207 addPlaceholder.Parameters.Add (ctrlVar);
208 method.Statements.Add (addPlaceholder);
213 mainClass.Members.Add (method);
216 void AddLiteralSubObject (ControlBuilder builder, string str)
218 if (!builder.HasAspCode) {
219 CodeObjectCreateExpression expr;
220 expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
221 AddParsedSubObjectStmt (builder, expr);
223 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
224 methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
225 methodRef.MethodName = "Write";
227 CodeMethodInvokeExpression expr;
228 expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
229 builder.renderMethod.Statements.Add (expr);
233 string TrimDB (string value)
235 string str = value.Trim ();
236 str = str.Substring (3);
237 return str.Substring (0, str.Length - 2);
240 string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
242 value = TrimDB (value);
243 CodeMemberMethod method;
244 string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
246 method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
248 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
250 // This should be a CodePropertyReferenceExpression for properties... but it works anyway
251 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
254 if (type == typeof (string)) {
255 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
256 CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
257 tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
258 tostring.Parameters.Add (new CodeSnippetExpression (value));
261 CodeSnippetExpression snippet = new CodeSnippetExpression (value);
262 expr = new CodeCastExpression (type, snippet);
265 method.Statements.Add (new CodeAssignStatement (field, expr));
266 mainClass.Members.Add (method);
270 void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, bool isDataBound)
272 CodeMemberMethod method = builder.method;
274 string dbMethodName = DataBoundProperty (builder, type, var_name, att);
275 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
279 CodeAssignStatement assign = new CodeAssignStatement ();
280 assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
281 currentLocation = builder.location;
282 assign.Right = GetExpressionFromString (type, att);
284 method.Statements.Add (assign);
287 bool IsDataBound (string value)
289 if (value == null || value == "")
292 string str = value.Trim ();
293 return (str.StartsWith ("<%#") && str.EndsWith ("%>"));
296 bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id, string attValue)
298 int hyphen = id.IndexOf ('-');
300 bool isPropertyInfo = (member is PropertyInfo);
301 bool is_processed = false;
302 bool isDataBound = IsDataBound (attValue);
305 if (isPropertyInfo) {
306 type = ((PropertyInfo) member).PropertyType;
307 if (hyphen == -1 && ((PropertyInfo) member).CanWrite == false)
310 type = ((FieldInfo) member).FieldType;
313 if (0 == String.Compare (member.Name, id, true)){
314 AddCodeForPropertyOrField (builder, type, member.Name, attValue, isDataBound);
321 string prop_field = id.Replace ("-", ".");
322 string [] parts = prop_field.Split (new char [] {'.'});
323 if (parts.Length != 2 || 0 != String.Compare (member.Name, parts [0], true))
326 PropertyInfo [] subprops = type.GetProperties ();
327 foreach (PropertyInfo subprop in subprops) {
328 if (0 != String.Compare (subprop.Name, parts [1], true))
331 if (subprop.CanWrite == false)
334 bool is_bool = subprop.PropertyType == typeof (bool);
335 if (!is_bool && attValue == null)
336 return false; // Font-Size -> Font-Size="" as html
339 if (attValue == null && is_bool)
340 value = "true"; // Font-Bold <=> Font-Bold="true"
344 AddCodeForPropertyOrField (builder, subprop.PropertyType,
345 member.Name + "." + subprop.Name,
353 void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
355 //"__ctrl.{0} += new {1} (this.{2});"
356 CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
358 CodeDelegateCreateExpression create;
359 create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
361 CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
362 method.Statements.Add (attach);
365 void CreateAssignStatementsFromAttributes (ControlBuilder builder)
367 this.dataBoundAtts = 0;
368 IDictionary atts = builder.attribs;
369 if (atts == null || atts.Count == 0)
372 EventInfo [] ev_info = null;
373 PropertyInfo [] prop_info = null;
374 FieldInfo [] field_info = null;
375 bool is_processed = false;
376 Type type = builder.ControlType;
378 foreach (string id in atts.Keys){
379 if (0 == String.Compare (id, "runat", true))
382 is_processed = false;
383 string attvalue = atts [id] as string;
384 if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
386 ev_info = type.GetEvents ();
388 string id_as_event = id.Substring (2);
389 foreach (EventInfo ev in ev_info){
390 if (0 == String.Compare (ev.Name, id_as_event, true)){
391 AddEventAssign (builder.method,
405 if (prop_info == null)
406 prop_info = type.GetProperties ();
408 foreach (PropertyInfo prop in prop_info) {
409 is_processed = ProcessPropertiesAndFields (builder, prop, id, attvalue);
417 if (field_info == null)
418 field_info = type.GetFields ();
420 foreach (FieldInfo field in field_info){
421 is_processed = ProcessPropertiesAndFields (builder, field, id, attvalue);
429 if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
430 throw new ParseException (builder.location, "Unrecognized attribute: " + id);
433 CodeCastExpression cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
434 CodeMethodReferenceExpression methodExpr;
435 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
436 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr);
437 expr.Parameters.Add (new CodePrimitiveExpression (id));
438 expr.Parameters.Add (new CodePrimitiveExpression ((string) atts [id]));
439 builder.method.Statements.Add (expr);
443 void AddRenderControl (ControlBuilder builder)
445 CodeIndexerExpression indexer = new CodeIndexerExpression ();
446 indexer.TargetObject = new CodePropertyReferenceExpression (
447 new CodeArgumentReferenceExpression ("parameterContainer"),
450 indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
452 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
453 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
454 builder.renderMethod.Statements.Add (invoke);
455 builder.renderIndex++;
458 void AddChildCall (ControlBuilder parent, ControlBuilder child)
460 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
461 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
463 object [] atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
464 if (atts != null && atts.Length > 0) {
465 PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
466 CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
467 CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
468 build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
469 build.Parameters.Add (new CodePrimitiveExpression (child.ID));
472 build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
475 build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
477 build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
478 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
479 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
480 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
481 build.Parameters.Add (new CodeDelegateCreateExpression (
482 new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
483 thisRef, child.method.Name));
485 parent.method.Statements.Add (build);
486 if (parent.HasAspCode)
487 AddRenderControl (parent);
491 if (child.isProperty || parent.ChildrenAsProperties) {
492 expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
493 parent.method.Statements.Add (expr);
497 parent.method.Statements.Add (expr);
498 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
499 if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
500 AddParsedSubObjectStmt (parent, field);
502 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
503 invoke.Parameters.Add (field);
504 parent.method.Statements.Add (invoke);
507 if (parent.HasAspCode)
508 AddRenderControl (parent);
511 void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
513 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
515 CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
516 newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
518 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
519 newCompiled.Parameters.Add (newBuild);
521 CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
522 method.Statements.Add (assign);
526 void AddContentTemplateInvocation (ContentControlBuilder cbuilder, CodeMemberMethod method, string methodName)
528 CodePropertyReferenceExpression pag = new CodePropertyReferenceExpression (ctrlVar, "Page");
529 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (pag, "Master");
531 CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
532 newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
534 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
535 newCompiled.Parameters.Add (newBuild);
537 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (prop, "AddContentTemplate");
538 invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
539 invoke.Parameters.Add (newCompiled);
541 method.Statements.Add (invoke);
545 void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
547 if (cr.Code == null || cr.Code.Trim () == "")
551 CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
552 parent.renderMethod.Statements.Add (code);
556 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
557 expr.Method = new CodeMethodReferenceExpression (
558 new CodeArgumentReferenceExpression ("__output"),
561 expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
562 parent.renderMethod.Statements.Add (expr);
565 static Type GetContainerType (ControlBuilder builder)
567 TemplateBuilder tb = builder as TemplateBuilder;
568 if (tb != null && tb.ContainerType != null)
569 return tb.ContainerType;
571 Type type = builder.NamingContainerType;
573 PropertyInfo prop = type.GetProperty ("Items", noCaseFlags);
577 Type ptype = prop.PropertyType;
578 if (!typeof (ICollection).IsAssignableFrom (ptype))
581 prop = ptype.GetProperty ("Item", noCaseFlags);
585 return prop.PropertyType;
588 CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
590 CodeMemberMethod method = new CodeMemberMethod ();
591 method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
593 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
594 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
596 CodeTypeReference containerRef = new CodeTypeReference (container);
597 CodeTypeReference targetRef = new CodeTypeReference (target);
599 CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
600 decl.Name = "Container";
601 decl.Type = containerRef;
602 method.Statements.Add (decl);
604 decl = new CodeVariableDeclarationStatement();
605 decl.Name = "target";
606 decl.Type = targetRef;
607 method.Statements.Add (decl);
609 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
610 CodeAssignStatement assign = new CodeAssignStatement ();
611 assign.Left = targetExpr;
612 assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
613 method.Statements.Add (assign);
615 assign = new CodeAssignStatement ();
616 assign.Left = new CodeVariableReferenceExpression ("Container");
617 assign.Right = new CodeCastExpression (containerRef,
618 new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
619 method.Statements.Add (assign);
624 void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
626 if (db.Code == null || db.Code.Trim () == "")
630 CreateField (db, false);
632 string dbMethodName = "__DataBind_" + db.ID;
633 // Add the method that builds the DataBoundLiteralControl
634 InitMethod (db, false, false);
635 CodeMemberMethod method = db.method;
636 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
637 method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
639 // Add the DataBind handler
640 method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
642 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
643 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
644 invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
645 invoke.Parameters.Add (new CodePrimitiveExpression (0));
647 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
648 tostring.Method = new CodeMethodReferenceExpression (
649 new CodeTypeReferenceExpression (typeof (Convert)),
651 tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
652 invoke.Parameters.Add (tostring);
653 method.Statements.Add (invoke);
655 mainClass.Members.Add (method);
657 AddChildCall (builder, db);
660 void FlushText (ControlBuilder builder, StringBuilder sb)
663 AddLiteralSubObject (builder, sb.ToString ());
668 void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
671 bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
672 if (!isTemplate && !inTemplate) {
673 CreateField (builder, true);
674 } else if (!isTemplate) {
675 builder.ID = builder.GetNextID (null);
676 CreateField (builder, false);
679 InitMethod (builder, isTemplate, childrenAsProperties);
680 if (!isTemplate || builder.GetType () == typeof (RootBuilder))
681 CreateAssignStatementsFromAttributes (builder);
683 if (builder.Children != null && builder.Children.Count > 0) {
684 ArrayList templates = null;
686 StringBuilder sb = new StringBuilder ();
687 foreach (object b in builder.Children) {
690 sb.Append ((string) b);
694 FlushText (builder, sb);
695 if (b is ObjectTagBuilder) {
696 ProcessObjectTag ((ObjectTagBuilder) b);
701 if (b is ContentControlBuilder) {
702 ContentControlBuilder cb = (ContentControlBuilder) b;
703 CreateControlTree (cb, true, true);
704 AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
709 if (b is TemplateBuilder) {
710 if (templates == null)
711 templates = new ArrayList ();
717 if (b is CodeRenderBuilder) {
718 AddCodeRender (builder, (CodeRenderBuilder) b);
722 if (b is DataBindingBuilder) {
723 AddDataBindingLiteral (builder, (DataBindingBuilder) b);
727 if (b is ControlBuilder) {
728 ControlBuilder child = (ControlBuilder) b;
729 CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
730 AddChildCall (builder, child);
734 throw new Exception ("???");
737 FlushText (builder, sb);
739 if (templates != null) {
740 foreach (ControlBuilder b in templates) {
741 CreateControlTree (b, true, false);
742 AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
748 if (builder.defaultPropertyBuilder != null) {
749 ControlBuilder b = builder.defaultPropertyBuilder;
750 CreateControlTree (b, false, true);
751 AddChildCall (builder, b);
754 if (builder.HasAspCode) {
755 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
756 m.TargetObject = thisRef;
757 m.MethodName = builder.renderMethod.Name;
759 CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
760 create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
761 create.TargetObject = thisRef;
762 create.MethodName = builder.renderMethod.Name;
764 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
765 invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
766 invoke.Parameters.Add (create);
768 builder.method.Statements.Add (invoke);
771 if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
772 builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
775 protected override void CreateMethods ()
777 base.CreateMethods ();
780 CreateControlTree (parser.RootBuilder, false, false);
781 CreateFrameworkInitializeMethod ();
784 void CreateFrameworkInitializeMethod ()
786 CodeMemberMethod method = new CodeMemberMethod ();
787 method.Name = "FrameworkInitialize";
788 method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
789 AddStatementsToFrameworkInitialize (method);
790 mainClass.Members.Add (method);
793 protected virtual void AddStatementsToFrameworkInitialize (CodeMemberMethod method)
795 if (!parser.EnableViewState) {
796 CodeAssignStatement stmt = new CodeAssignStatement ();
797 stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
798 stmt.Right = new CodePrimitiveExpression (false);
799 method.Statements.Add (stmt);
802 CodeMethodReferenceExpression methodExpr;
803 methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
804 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
805 method.Statements.Add (new CodeExpressionStatement (expr));
808 protected override void AddApplicationAndSessionObjects ()
810 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
811 CreateFieldForObject (tag.Type, tag.ObjectID);
812 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
815 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
816 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
820 protected void ProcessObjectTag (ObjectTagBuilder tag)
822 string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
823 CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
826 void CreateProperties ()
828 if (!parser.AutoEventWireup) {
829 CreateAutoEventWireup ();
831 CreateAutoHandlers ();
834 CreateApplicationInstance ();
835 CreateTemplateSourceDirectory ();
838 void CreateTemplateSourceDirectory ()
840 CodeMemberProperty prop = new CodeMemberProperty ();
841 prop.Type = new CodeTypeReference (typeof (string));
842 prop.Name = "TemplateSourceDirectory";
843 prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
845 CodePrimitiveExpression expr = new CodePrimitiveExpression (parser.BaseVirtualDir);
846 prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
847 mainClass.Members.Add (prop);
850 void CreateApplicationInstance ()
852 CodeMemberProperty prop = new CodeMemberProperty ();
853 Type appType = typeof (HttpApplication);
854 prop.Type = new CodeTypeReference (appType);
855 prop.Name = "ApplicationInstance";
856 prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
858 CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
860 propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
862 CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
863 prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
864 mainClass.Members.Add (prop);
867 void CreateAutoHandlers ()
869 // Create AutoHandlers property
870 CodeMemberProperty prop = new CodeMemberProperty ();
871 prop.Type = new CodeTypeReference (typeof (int));
872 prop.Name = "AutoHandlers";
873 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
875 CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
876 CodeFieldReferenceExpression fldRef ;
877 fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
878 ret.Expression = fldRef;
879 prop.GetStatements.Add (ret);
881 prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
883 mainClass.Members.Add (prop);
885 // Add the __autoHandlers field
886 CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
887 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
888 mainClass.Members.Add (fld);
891 void CreateAutoEventWireup ()
893 // The getter returns false
894 CodeMemberProperty prop = new CodeMemberProperty ();
895 prop.Type = new CodeTypeReference (typeof (bool));
896 prop.Name = "SupportAutoEvents";
897 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
898 prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
899 mainClass.Members.Add (prop);
902 CodeExpression GetExpressionFromString (Type type, string str)
904 if (type == typeof (string))
905 return new CodePrimitiveExpression (str);
907 if (type == typeof (bool)) {
908 if (str == null || str == "" || 0 == String.Compare (str, "true", true))
909 return new CodePrimitiveExpression (true);
910 else if (0 == String.Compare (str, "false", true))
911 return new CodePrimitiveExpression (false);
913 throw new ParseException (currentLocation,
914 "Value '" + str + "' is not a valid boolean.");
918 return new CodePrimitiveExpression (null);
920 if (type.IsPrimitive)
921 return new CodePrimitiveExpression (Convert.ChangeType (str, type));
926 val = Enum.Parse (type, str, true);
927 } catch (Exception) {
928 throw new ParseException (currentLocation,
929 str + " is not a valid value for enum '" + type + "'");
931 CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
932 expr.TargetObject = new CodeTypeReferenceExpression (type);
933 expr.FieldName = val.ToString ();
937 if (type == typeof (string [])) {
938 string [] subs = str.Split (',');
939 CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
940 expr.CreateType = new CodeTypeReference (typeof (string));
941 foreach (string v in subs) {
942 expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
948 if (type == typeof (Size)) {
949 string [] subs = str.Split (',');
950 if (subs.Length != 2)
951 throw new ParseException (currentLocation,
952 String.Format ("Cannot create {0} from '{1}'", type, str));
957 width = Int32.Parse (subs [0]);
958 height = Int32.Parse (subs [0]);
959 new Size (width, height);
961 throw new ParseException (currentLocation,
962 String.Format ("Cannot create {0} from '{1}'", type, str));
965 CodeObjectCreateExpression expr = new CodeObjectCreateExpression ();
966 expr.CreateType = new CodeTypeReference (type);
967 expr.Parameters.Add (new CodePrimitiveExpression (width));
968 expr.Parameters.Add (new CodePrimitiveExpression (height));
972 if (type == typeof (Color)){
973 if (colorConverter == null)
974 colorConverter = TypeDescriptor.GetConverter (typeof (Color));
978 if (str.IndexOf (',') == -1) {
979 c = (Color) colorConverter.ConvertFromString (str);
981 int [] argb = new int [4];
984 string [] parts = str.Split (',');
985 int length = parts.Length;
987 throw new Exception ();
989 int basei = (length == 4) ? 0 : 1;
990 for (int i = length - 1; i >= 0; i--) {
991 argb [basei + i] = (int) Byte.Parse (parts [i]);
993 c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
995 } catch (Exception e){
996 throw new ParseException (currentLocation,
997 "Color " + str + " is not a valid color.", e);
1000 if (c.IsKnownColor){
1001 CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
1002 if (c.IsSystemColor)
1003 type = typeof (SystemColors);
1005 expr.TargetObject = new CodeTypeReferenceExpression (type);
1006 expr.FieldName = c.Name;
1009 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1010 m.TargetObject = new CodeTypeReferenceExpression (type);
1011 m.MethodName = "FromArgb";
1012 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1013 invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
1014 invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
1015 invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
1016 invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
1021 TypeConverter converter = TypeDescriptor.GetConverter (type);
1022 if (converter != null && converter.CanConvertFrom (typeof (string))) {
1023 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
1024 m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
1025 m.MethodName = "GetConverter";
1026 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
1027 CodeTypeReference tref = new CodeTypeReference (type);
1028 invoke.Parameters.Add (new CodeTypeOfExpression (tref));
1030 invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
1031 invoke.Parameters.Add (new CodePrimitiveExpression (str));
1033 return new CodeCastExpression (tref, invoke);
1037 BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
1038 MethodInfo parse = type.GetMethod ("Parse", flags, null, arrayStringCultureInfo, null);
1039 if (parse != null) {
1042 parse = type.GetMethod ("Parse", flags, null, arrayString, null);
1045 if (parse != null) {
1049 o = parse.Invoke (null, new object [] { str, CultureInfo.InvariantCulture });
1051 o = parse.Invoke (null, new object [] { str });
1052 } catch (Exception e) {
1053 throw new ParseException (currentLocation, "Cannot parse " + str + " as " + type, e);
1057 throw new ParseException (currentLocation, str + " as " + type + " is null");
1059 CodeTypeReferenceExpression exprType = new CodeTypeReferenceExpression (type);
1060 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (exprType, "Parse");
1061 //FIXME: may be we gotta ensure roundtrip between o.ToString and Parse
1062 invoke.Parameters.Add (new CodePrimitiveExpression (o.ToString ()));
1064 CodeTypeReferenceExpression texp = new CodeTypeReferenceExpression (typeof (CultureInfo));
1065 CodePropertyReferenceExpression pexp = new CodePropertyReferenceExpression ();
1066 pexp.TargetObject = texp;
1067 pexp.PropertyName = "InvariantCulture";
1068 invoke.Parameters.Add (pexp);
1074 Console.WriteLine ("Unknown type: " + type + " value: " + str);
1076 return new CodePrimitiveExpression (str);