(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
blob973574087ae33cfaad161f57264b33f8c3a1f000
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 //
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.
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;
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;
52 int dataBoundAtts;
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)
62 : base (parser)
64 this.parser = 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);
89 Type other = null;
90 if (fld == null || fld.IsPrivate) {
91 PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
92 if (prop != null) {
93 MethodInfo setm = prop.GetSetMethod (true);
94 if (setm != null)
95 other = prop.PropertyType;
97 } else {
98 other = fld.FieldType;
101 if (other == null)
102 return false;
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}",
107 id, other, type);
108 throw new ParseException (currentLocation, msg);
111 return true;
114 void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr)
116 if (!builder.haveParserVariable) {
117 CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
118 p.Name = "__parser";
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) {
157 string typeString;
158 if (builder.ControlType != null && builder.isProperty &&
159 !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
160 typeString = builder.ControlType.FullName;
161 else
162 typeString = "System.Web.UI.Control";
164 method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
165 } else {
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];
175 if (att.NeedsTag)
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);
205 mainClass.Members.Add (method);
208 void AddLiteralSubObject (ControlBuilder builder, string str)
210 if (!builder.HasAspCode) {
211 CodeObjectCreateExpression expr;
212 expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
213 AddParsedSubObjectStmt (builder, expr);
214 } else {
215 CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
216 methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
217 methodRef.MethodName = "Write";
219 CodeMethodInvokeExpression expr;
220 expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
221 builder.renderMethod.Statements.Add (expr);
225 string TrimDB (string value)
227 string str = value.Trim ();
228 str = str.Substring (3);
229 return str.Substring (0, str.Length - 2);
232 string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
234 value = TrimDB (value);
235 CodeMemberMethod method;
236 string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
238 method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
240 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
242 // This should be a CodePropertyReferenceExpression for properties... but it works anyway
243 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
245 CodeExpression expr;
246 if (type == typeof (string)) {
247 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
248 CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
249 tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
250 tostring.Parameters.Add (new CodeSnippetExpression (value));
251 expr = tostring;
252 } else {
253 CodeSnippetExpression snippet = new CodeSnippetExpression (value);
254 expr = new CodeCastExpression (type, snippet);
257 method.Statements.Add (new CodeAssignStatement (field, expr));
258 mainClass.Members.Add (method);
259 return method.Name;
262 void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, bool isDataBound)
264 CodeMemberMethod method = builder.method;
265 if (isDataBound) {
266 string dbMethodName = DataBoundProperty (builder, type, var_name, att);
267 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
268 return;
271 CodeAssignStatement assign = new CodeAssignStatement ();
272 assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
273 currentLocation = builder.location;
274 assign.Right = GetExpressionFromString (type, att);
276 method.Statements.Add (assign);
279 bool IsDataBound (string value)
281 if (value == null || value == "")
282 return false;
284 string str = value.Trim ();
285 return (str.StartsWith ("<%#") && str.EndsWith ("%>"));
288 bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id, string attValue)
290 CodeMemberMethod method = builder.method;
291 int hyphen = id.IndexOf ('-');
293 bool isPropertyInfo = (member is PropertyInfo);
294 bool is_processed = false;
295 bool isDataBound = IsDataBound (attValue);
297 Type type;
298 if (isPropertyInfo) {
299 type = ((PropertyInfo) member).PropertyType;
300 if (hyphen == -1 && ((PropertyInfo) member).CanWrite == false)
301 return false;
302 } else {
303 type = ((FieldInfo) member).FieldType;
306 if (0 == String.Compare (member.Name, id, true)){
307 AddCodeForPropertyOrField (builder, type, member.Name, attValue, isDataBound);
308 return true;
311 if (hyphen == -1)
312 return false;
314 string prop_field = id.Replace ("-", ".");
315 string [] parts = prop_field.Split (new char [] {'.'});
316 if (parts.Length != 2 || 0 != String.Compare (member.Name, parts [0], true))
317 return false;
319 PropertyInfo [] subprops = type.GetProperties ();
320 foreach (PropertyInfo subprop in subprops) {
321 if (0 != String.Compare (subprop.Name, parts [1], true))
322 continue;
324 if (subprop.CanWrite == false)
325 return false;
327 bool is_bool = subprop.PropertyType == typeof (bool);
328 if (!is_bool && attValue == null)
329 return false; // Font-Size -> Font-Size="" as html
331 string value;
332 if (attValue == null && is_bool)
333 value = "true"; // Font-Bold <=> Font-Bold="true"
334 else
335 value = attValue;
337 AddCodeForPropertyOrField (builder, subprop.PropertyType,
338 member.Name + "." + subprop.Name,
339 value, isDataBound);
340 is_processed = true;
343 return is_processed;
346 void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
348 //"__ctrl.{0} += new {1} (this.{2});"
349 CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
351 CodeDelegateCreateExpression create;
352 create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
354 CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
355 method.Statements.Add (attach);
358 void CreateAssignStatementsFromAttributes (ControlBuilder builder)
360 this.dataBoundAtts = 0;
361 IDictionary atts = builder.attribs;
362 if (atts == null || atts.Count == 0)
363 return;
365 EventInfo [] ev_info = null;
366 PropertyInfo [] prop_info = null;
367 FieldInfo [] field_info = null;
368 bool is_processed = false;
369 Type type = builder.ControlType;
371 foreach (string id in atts.Keys){
372 if (0 == String.Compare (id, "runat", true))
373 continue;
375 is_processed = false;
376 string attvalue = atts [id] as string;
377 if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
378 if (ev_info == null)
379 ev_info = type.GetEvents ();
381 string id_as_event = id.Substring (2);
382 foreach (EventInfo ev in ev_info){
383 if (0 == String.Compare (ev.Name, id_as_event, true)){
384 AddEventAssign (builder.method,
385 ev.Name,
386 ev.EventHandlerType,
387 attvalue);
389 is_processed = true;
390 break;
394 if (is_processed)
395 continue;
398 if (prop_info == null)
399 prop_info = type.GetProperties ();
401 foreach (PropertyInfo prop in prop_info) {
402 is_processed = ProcessPropertiesAndFields (builder, prop, id, attvalue);
403 if (is_processed)
404 break;
407 if (is_processed)
408 continue;
410 if (field_info == null)
411 field_info = type.GetFields ();
413 foreach (FieldInfo field in field_info){
414 is_processed = ProcessPropertiesAndFields (builder, field, id, attvalue);
415 if (is_processed)
416 break;
419 if (is_processed)
420 continue;
422 if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
423 throw new ParseException (builder.location, "Unrecognized attribute: " + id);
426 CodeCastExpression cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
427 CodeMethodReferenceExpression methodExpr;
428 methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
429 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr);
430 expr.Parameters.Add (new CodePrimitiveExpression (id));
431 expr.Parameters.Add (new CodePrimitiveExpression ((string) atts [id]));
432 builder.method.Statements.Add (expr);
436 void AddRenderControl (ControlBuilder builder)
438 CodeIndexerExpression indexer = new CodeIndexerExpression ();
439 indexer.TargetObject = new CodePropertyReferenceExpression (
440 new CodeArgumentReferenceExpression ("parameterContainer"),
441 "Controls");
443 indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
445 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
446 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
447 builder.renderMethod.Statements.Add (invoke);
448 builder.renderIndex++;
451 void AddChildCall (ControlBuilder parent, ControlBuilder child)
453 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
454 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
456 object [] atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
457 if (atts != null && atts.Length > 0) {
458 PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
459 CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
460 CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
461 build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
462 build.Parameters.Add (new CodePrimitiveExpression (child.ID));
463 #if NET_1_1
464 if (pca.Shared)
465 build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
466 else
467 #endif
468 build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
470 build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
471 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
472 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
473 build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
474 build.Parameters.Add (new CodeDelegateCreateExpression (
475 new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
476 thisRef, child.method.Name));
478 parent.method.Statements.Add (build);
479 if (parent.HasAspCode)
480 AddRenderControl (parent);
481 return;
484 if (child.isProperty || parent.ChildrenAsProperties) {
485 expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
486 parent.method.Statements.Add (expr);
487 return;
490 parent.method.Statements.Add (expr);
491 CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
492 if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
493 AddParsedSubObjectStmt (parent, field);
494 } else {
495 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
496 invoke.Parameters.Add (field);
497 parent.method.Statements.Add (invoke);
500 if (parent.HasAspCode)
501 AddRenderControl (parent);
504 void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
506 CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
508 CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
509 newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
511 CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
512 newCompiled.Parameters.Add (newBuild);
514 CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
515 method.Statements.Add (assign);
518 void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
520 if (cr.Code == null || cr.Code.Trim () == "")
521 return;
523 if (!cr.IsAssign) {
524 CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
525 parent.renderMethod.Statements.Add (code);
526 return;
529 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
530 expr.Method = new CodeMethodReferenceExpression (
531 new CodeArgumentReferenceExpression ("__output"),
532 "Write");
534 expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
535 parent.renderMethod.Statements.Add (expr);
538 static Type GetContainerType (ControlBuilder builder)
540 Type type = builder.NamingContainerType;
542 PropertyInfo prop = type.GetProperty ("Items", noCaseFlags);
543 if (prop == null)
544 return type;
546 Type ptype = prop.PropertyType;
547 if (!typeof (ICollection).IsAssignableFrom (ptype))
548 return type;
550 prop = ptype.GetProperty ("Item", noCaseFlags);
551 if (prop == null)
552 return type;
554 return prop.PropertyType;
557 CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
559 CodeMemberMethod method = new CodeMemberMethod ();
560 method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
561 method.Name = name;
562 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
563 method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
565 CodeTypeReference containerRef = new CodeTypeReference (container);
566 CodeTypeReference targetRef = new CodeTypeReference (target);
568 CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
569 decl.Name = "Container";
570 decl.Type = containerRef;
571 method.Statements.Add (decl);
573 decl = new CodeVariableDeclarationStatement();
574 decl.Name = "target";
575 decl.Type = targetRef;
576 method.Statements.Add (decl);
578 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
579 CodeAssignStatement assign = new CodeAssignStatement ();
580 assign.Left = targetExpr;
581 assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
582 method.Statements.Add (assign);
584 assign = new CodeAssignStatement ();
585 assign.Left = new CodeVariableReferenceExpression ("Container");
586 assign.Right = new CodeCastExpression (containerRef,
587 new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
588 method.Statements.Add (assign);
590 return method;
593 void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
595 if (db.Code == null || db.Code.Trim () == "")
596 return;
598 EnsureID (db);
599 CreateField (db, false);
601 string dbMethodName = "__DataBind_" + db.ID;
602 // Add the method that builds the DataBoundLiteralControl
603 InitMethod (db, false, false);
604 CodeMemberMethod method = db.method;
605 AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
606 method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
608 // Add the DataBind handler
609 method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
611 CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
612 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
613 invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
614 invoke.Parameters.Add (new CodePrimitiveExpression (0));
616 CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
617 tostring.Method = new CodeMethodReferenceExpression (
618 new CodeTypeReferenceExpression (typeof (Convert)),
619 "ToString");
620 tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
621 invoke.Parameters.Add (tostring);
622 method.Statements.Add (invoke);
624 mainClass.Members.Add (method);
626 AddChildCall (builder, db);
629 void FlushText (ControlBuilder builder, StringBuilder sb)
631 if (sb.Length > 0) {
632 AddLiteralSubObject (builder, sb.ToString ());
633 sb.Length = 0;
637 void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
639 EnsureID (builder);
640 bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
641 if (!isTemplate && !inTemplate) {
642 CreateField (builder, true);
643 } else if (!isTemplate) {
644 builder.ID = builder.GetNextID (null);
645 CreateField (builder, false);
648 InitMethod (builder, isTemplate, childrenAsProperties);
649 if (builder.GetType () != typeof (TemplateBuilder))
650 CreateAssignStatementsFromAttributes (builder);
652 if (builder.Children != null && builder.Children.Count > 0) {
653 ArrayList templates = null;
655 StringBuilder sb = new StringBuilder ();
656 foreach (object b in builder.Children) {
658 if (b is string) {
659 sb.Append ((string) b);
660 continue;
663 FlushText (builder, sb);
664 if (b is ObjectTagBuilder) {
665 ProcessObjectTag ((ObjectTagBuilder) b);
666 continue;
669 if (b is TemplateBuilder) {
670 if (templates == null)
671 templates = new ArrayList ();
673 templates.Add (b);
674 continue;
677 if (b is CodeRenderBuilder) {
678 AddCodeRender (builder, (CodeRenderBuilder) b);
679 continue;
682 if (b is DataBindingBuilder) {
683 AddDataBindingLiteral (builder, (DataBindingBuilder) b);
684 continue;
687 if (b is ControlBuilder) {
688 ControlBuilder child = (ControlBuilder) b;
689 CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
690 AddChildCall (builder, child);
691 continue;
694 throw new Exception ("???");
697 FlushText (builder, sb);
699 if (templates != null) {
700 foreach (ControlBuilder b in templates) {
701 CreateControlTree (b, true, false);
702 AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
708 if (builder.defaultPropertyBuilder != null) {
709 ControlBuilder b = builder.defaultPropertyBuilder;
710 CreateControlTree (b, false, true);
711 AddChildCall (builder, b);
714 if (builder.HasAspCode) {
715 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
716 m.TargetObject = thisRef;
717 m.MethodName = builder.renderMethod.Name;
719 CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
720 create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
721 create.TargetObject = thisRef;
722 create.MethodName = builder.renderMethod.Name;
724 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
725 invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
726 invoke.Parameters.Add (create);
728 builder.method.Statements.Add (invoke);
731 if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
732 builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
735 protected override void CreateMethods ()
737 base.CreateMethods ();
739 CreateProperties ();
740 CreateControlTree (parser.RootBuilder, false, false);
741 CreateFrameworkInitializeMethod ();
744 void CreateFrameworkInitializeMethod ()
746 CodeMemberMethod method = new CodeMemberMethod ();
747 method.Name = "FrameworkInitialize";
748 method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
749 AddStatementsToFrameworkInitialize (method);
750 mainClass.Members.Add (method);
753 protected virtual void AddStatementsToFrameworkInitialize (CodeMemberMethod method)
755 if (!parser.EnableViewState) {
756 CodeAssignStatement stmt = new CodeAssignStatement ();
757 stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
758 stmt.Right = new CodePrimitiveExpression (false);
759 method.Statements.Add (stmt);
762 CodeMethodReferenceExpression methodExpr;
763 methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
764 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
765 method.Statements.Add (new CodeExpressionStatement (expr));
768 protected override void AddApplicationAndSessionObjects ()
770 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
771 CreateFieldForObject (tag.Type, tag.ObjectID);
772 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
775 foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
776 CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
780 protected void ProcessObjectTag (ObjectTagBuilder tag)
782 string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
783 CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
786 void CreateProperties ()
788 if (!parser.AutoEventWireup) {
789 CreateAutoEventWireup ();
790 } else {
791 CreateAutoHandlers ();
794 CreateApplicationInstance ();
795 CreateTemplateSourceDirectory ();
798 void CreateTemplateSourceDirectory ()
800 CodeMemberProperty prop = new CodeMemberProperty ();
801 prop.Type = new CodeTypeReference (typeof (string));
802 prop.Name = "TemplateSourceDirectory";
803 prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
805 CodePrimitiveExpression expr = new CodePrimitiveExpression (parser.BaseVirtualDir);
806 prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
807 mainClass.Members.Add (prop);
810 void CreateApplicationInstance ()
812 CodeMemberProperty prop = new CodeMemberProperty ();
813 Type appType = typeof (HttpApplication);
814 prop.Type = new CodeTypeReference (appType);
815 prop.Name = "ApplicationInstance";
816 prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
818 CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
820 propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
822 CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
823 prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
824 mainClass.Members.Add (prop);
827 void CreateAutoHandlers ()
829 // Create AutoHandlers property
830 CodeMemberProperty prop = new CodeMemberProperty ();
831 prop.Type = new CodeTypeReference (typeof (int));
832 prop.Name = "AutoHandlers";
833 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
835 CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
836 CodeFieldReferenceExpression fldRef ;
837 fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
838 ret.Expression = fldRef;
839 prop.GetStatements.Add (ret);
841 prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
843 mainClass.Members.Add (prop);
845 // Add the __autoHandlers field
846 CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
847 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
848 mainClass.Members.Add (fld);
851 void CreateAutoEventWireup ()
853 // The getter returns false
854 CodeMemberProperty prop = new CodeMemberProperty ();
855 prop.Type = new CodeTypeReference (typeof (bool));
856 prop.Name = "SupportAutoEvents";
857 prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
858 prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
859 mainClass.Members.Add (prop);
862 CodeExpression GetExpressionFromString (Type type, string str)
864 if (type == typeof (string))
865 return new CodePrimitiveExpression (str);
867 if (type == typeof (bool)) {
868 if (str == null || str == "" || 0 == String.Compare (str, "true", true))
869 return new CodePrimitiveExpression (true);
870 else if (0 == String.Compare (str, "false", true))
871 return new CodePrimitiveExpression (false);
872 else
873 throw new ParseException (currentLocation,
874 "Value '" + str + "' is not a valid boolean.");
877 if (str == null)
878 return new CodePrimitiveExpression (null);
880 if (type.IsPrimitive)
881 return new CodePrimitiveExpression (Convert.ChangeType (str, type));
883 if (type.IsEnum) {
884 object val = null;
885 try {
886 val = Enum.Parse (type, str, true);
887 } catch (Exception) {
888 throw new ParseException (currentLocation,
889 str + " is not a valid value for enum '" + type + "'");
891 CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
892 expr.TargetObject = new CodeTypeReferenceExpression (type);
893 expr.FieldName = val.ToString ();
894 return expr;
897 if (type == typeof (string [])) {
898 string [] subs = str.Split (',');
899 CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
900 expr.CreateType = new CodeTypeReference (typeof (string));
901 foreach (string v in subs) {
902 expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
905 return expr;
908 if (type == typeof (Size)) {
909 string [] subs = str.Split (',');
910 if (subs.Length != 2)
911 throw new ParseException (currentLocation,
912 String.Format ("Cannot create {0} from '{1}'", type, str));
914 int width = 0;
915 int height = 0;
916 try {
917 width = Int32.Parse (subs [0]);
918 height = Int32.Parse (subs [0]);
919 new Size (width, height);
920 } catch {
921 throw new ParseException (currentLocation,
922 String.Format ("Cannot create {0} from '{1}'", type, str));
925 CodeObjectCreateExpression expr = new CodeObjectCreateExpression ();
926 expr.CreateType = new CodeTypeReference (type);
927 expr.Parameters.Add (new CodePrimitiveExpression (width));
928 expr.Parameters.Add (new CodePrimitiveExpression (height));
929 return expr;
932 if (type == typeof (Color)){
933 if (colorConverter == null)
934 colorConverter = TypeDescriptor.GetConverter (typeof (Color));
936 Color c;
937 try {
938 if (str.IndexOf (',') == -1) {
939 c = (Color) colorConverter.ConvertFromString (str);
940 } else {
941 int [] argb = new int [4];
942 argb [0] = 255;
944 string [] parts = str.Split (',');
945 int length = parts.Length;
946 if (length < 3)
947 throw new Exception ();
949 int basei = (length == 4) ? 0 : 1;
950 for (int i = length - 1; i >= 0; i--) {
951 argb [basei + i] = (int) Byte.Parse (parts [i]);
953 c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
955 } catch (Exception e){
956 throw new ParseException (currentLocation,
957 "Color " + str + " is not a valid color.", e);
960 if (c.IsKnownColor){
961 CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
962 if (c.IsSystemColor)
963 type = typeof (SystemColors);
965 expr.TargetObject = new CodeTypeReferenceExpression (type);
966 expr.FieldName = c.Name;
967 return expr;
968 } else {
969 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
970 m.TargetObject = new CodeTypeReferenceExpression (type);
971 m.MethodName = "FromArgb";
972 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
973 invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
974 invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
975 invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
976 invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
977 return invoke;
981 TypeConverter converter = TypeDescriptor.GetConverter (type);
982 if (converter != null && converter.CanConvertFrom (typeof (string))) {
983 CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
984 m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
985 m.MethodName = "GetConverter";
986 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
987 CodeTypeReference tref = new CodeTypeReference (type);
988 invoke.Parameters.Add (new CodeTypeOfExpression (tref));
990 invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
991 invoke.Parameters.Add (new CodePrimitiveExpression (str));
993 return new CodeCastExpression (tref, invoke);
996 bool parms = false;
997 BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
998 MethodInfo parse = type.GetMethod ("Parse", flags, null, arrayStringCultureInfo, null);
999 if (parse != null) {
1000 parms = true;
1001 } else {
1002 parse = type.GetMethod ("Parse", flags, null, arrayString, null);
1005 if (parse != null) {
1006 object o = null;
1007 try {
1008 if (parms)
1009 o = parse.Invoke (null, new object [] { str, CultureInfo.InvariantCulture });
1010 else
1011 o = parse.Invoke (null, new object [] { str });
1012 } catch (Exception e) {
1013 throw new ParseException (currentLocation, "Cannot parse " + str + " as " + type, e);
1016 if (o == null)
1017 throw new ParseException (currentLocation, str + " as " + type + " is null");
1019 CodeTypeReferenceExpression exprType = new CodeTypeReferenceExpression (type);
1020 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (exprType, "Parse");
1021 //FIXME: may be we gotta ensure roundtrip between o.ToString and Parse
1022 invoke.Parameters.Add (new CodePrimitiveExpression (o.ToString ()));
1023 if (parms) {
1024 CodeTypeReferenceExpression texp = new CodeTypeReferenceExpression (typeof (CultureInfo));
1025 CodePropertyReferenceExpression pexp = new CodePropertyReferenceExpression ();
1026 pexp.TargetObject = texp;
1027 pexp.PropertyName = "InvariantCulture";
1028 invoke.Parameters.Add (pexp);
1030 return invoke;
1033 // FIXME: Arrays
1034 Console.WriteLine ("Unknown type: " + type + " value: " + str);
1036 return new CodePrimitiveExpression (str);