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
);
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
);
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
);
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));
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
);
262 void AddCodeForPropertyOrField (ControlBuilder builder
, Type type
, string var_name
, string att
, bool isDataBound
)
264 CodeMemberMethod method
= builder
.method
;
266 string dbMethodName
= DataBoundProperty (builder
, type
, var_name
, att
);
267 AddEventAssign (method
, "DataBinding", typeof (EventHandler
), dbMethodName
);
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 == "")
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
);
298 if (isPropertyInfo
) {
299 type
= ((PropertyInfo
) member
).PropertyType
;
300 if (hyphen
== -1 && ((PropertyInfo
) member
).CanWrite
== false)
303 type
= ((FieldInfo
) member
).FieldType
;
306 if (0 == String
.Compare (member
.Name
, id
, true)){
307 AddCodeForPropertyOrField (builder
, type
, member
.Name
, attValue
, isDataBound
);
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))
319 PropertyInfo
[] subprops
= type
.GetProperties ();
320 foreach (PropertyInfo subprop
in subprops
) {
321 if (0 != String
.Compare (subprop
.Name
, parts
[1], true))
324 if (subprop
.CanWrite
== false)
327 bool is_bool
= subprop
.PropertyType
== typeof (bool);
328 if (!is_bool
&& attValue
== null)
329 return false; // Font-Size -> Font-Size="" as html
332 if (attValue
== null && is_bool
)
333 value = "true"; // Font-Bold <=> Font-Bold="true"
337 AddCodeForPropertyOrField (builder
, subprop
.PropertyType
,
338 member
.Name
+ "." + subprop
.Name
,
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)
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))
375 is_processed
= false;
376 string attvalue
= atts
[id
] as string;
377 if (id
.Length
> 2 && id
.Substring (0, 2).ToUpper () == "ON"){
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
,
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
);
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
);
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"),
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
));
465 build
.Parameters
.Add (new CodePrimitiveExpression (child
.ControlType
.GetHashCode ().ToString ()));
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
);
484 if (child
.isProperty
|| parent
.ChildrenAsProperties
) {
485 expr
.Parameters
.Add (new CodeFieldReferenceExpression (ctrlVar
, child
.TagName
));
486 parent
.method
.Statements
.Add (expr
);
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
);
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 () == "")
524 CodeSnippetStatement code
= new CodeSnippetStatement (cr
.Code
);
525 parent
.renderMethod
.Statements
.Add (code
);
529 CodeMethodInvokeExpression expr
= new CodeMethodInvokeExpression ();
530 expr
.Method
= new CodeMethodReferenceExpression (
531 new CodeArgumentReferenceExpression ("__output"),
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
);
546 Type ptype
= prop
.PropertyType
;
547 if (!typeof (ICollection
).IsAssignableFrom (ptype
))
550 prop
= ptype
.GetProperty ("Item", noCaseFlags
);
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
;
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
);
593 void AddDataBindingLiteral (ControlBuilder builder
, DataBindingBuilder db
)
595 if (db
.Code
== null || db
.Code
.Trim () == "")
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
)),
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
)
632 AddLiteralSubObject (builder
, sb
.ToString ());
637 void CreateControlTree (ControlBuilder builder
, bool inTemplate
, bool childrenAsProperties
)
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
) {
659 sb
.Append ((string) b
);
663 FlushText (builder
, sb
);
664 if (b
is ObjectTagBuilder
) {
665 ProcessObjectTag ((ObjectTagBuilder
) b
);
669 if (b
is TemplateBuilder
) {
670 if (templates
== null)
671 templates
= new ArrayList ();
677 if (b
is CodeRenderBuilder
) {
678 AddCodeRender (builder
, (CodeRenderBuilder
) b
);
682 if (b
is DataBindingBuilder
) {
683 AddDataBindingLiteral (builder
, (DataBindingBuilder
) b
);
687 if (b
is ControlBuilder
) {
688 ControlBuilder child
= (ControlBuilder
) b
;
689 CreateControlTree (child
, inTemplate
, builder
.ChildrenAsProperties
);
690 AddChildCall (builder
, child
);
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 ();
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 ();
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);
873 throw new ParseException (currentLocation
,
874 "Value '" + str
+ "' is not a valid boolean.");
878 return new CodePrimitiveExpression (null);
880 if (type
.IsPrimitive
)
881 return new CodePrimitiveExpression (Convert
.ChangeType (str
, type
));
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 ();
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 ()));
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
));
917 width
= Int32
.Parse (subs
[0]);
918 height
= Int32
.Parse (subs
[0]);
919 new Size (width
, height
);
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
));
932 if (type
== typeof (Color
)){
933 if (colorConverter
== null)
934 colorConverter
= TypeDescriptor
.GetConverter (typeof (Color
));
938 if (str
.IndexOf (',') == -1) {
939 c
= (Color
) colorConverter
.ConvertFromString (str
);
941 int [] argb
= new int [4];
944 string [] parts
= str
.Split (',');
945 int length
= parts
.Length
;
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
);
961 CodeFieldReferenceExpression expr
= new CodeFieldReferenceExpression ();
963 type
= typeof (SystemColors
);
965 expr
.TargetObject
= new CodeTypeReferenceExpression (type
);
966 expr
.FieldName
= c
.Name
;
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
));
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
);
997 BindingFlags flags
= BindingFlags
.Public
| BindingFlags
.Static
;
998 MethodInfo parse
= type
.GetMethod ("Parse", flags
, null, arrayStringCultureInfo
, null);
1002 parse
= type
.GetMethod ("Parse", flags
, null, arrayString
, null);
1005 if (parse
!= null) {
1009 o
= parse
.Invoke (null, new object [] { str, CultureInfo.InvariantCulture }
);
1011 o
= parse
.Invoke (null, new object [] { str }
);
1012 } catch (Exception e
) {
1013 throw new ParseException (currentLocation
, "Cannot parse " + str
+ " as " + type
, e
);
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 ()));
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
);
1034 Console
.WriteLine ("Unknown type: " + type
+ " value: " + str
);
1036 return new CodePrimitiveExpression (str
);