TemplateControlCompiler.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. //
  2. // System.Web.Compilation.TemplateControlCompiler
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2003 Ximian, Inc (http://www.ximian.com)
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.CodeDom;
  31. using System.Collections;
  32. using System.ComponentModel;
  33. using System.Drawing;
  34. using System.Globalization;
  35. using System.Reflection;
  36. using System.Text;
  37. using System.Web;
  38. using System.Web.UI;
  39. using System.Web.Util;
  40. using System.ComponentModel.Design.Serialization;
  41. #if NET_2_0
  42. using System.Collections.Specialized;
  43. using System.Text.RegularExpressions;
  44. #endif
  45. namespace System.Web.Compilation
  46. {
  47. class TemplateControlCompiler : BaseCompiler
  48. {
  49. static BindingFlags noCaseFlags = BindingFlags.Public | BindingFlags.NonPublic |
  50. BindingFlags.Instance | BindingFlags.IgnoreCase;
  51. TemplateControlParser parser;
  52. int dataBoundAtts;
  53. ILocation currentLocation;
  54. static TypeConverter colorConverter;
  55. static CodeVariableReferenceExpression ctrlVar = new CodeVariableReferenceExpression ("__ctrl");
  56. #if NET_2_0
  57. static Regex bindRegex = new Regex (@"Bind\s*\(""(.*?)""\)\s*%>", RegexOptions.Compiled);
  58. #endif
  59. public TemplateControlCompiler (TemplateControlParser parser)
  60. : base (parser)
  61. {
  62. this.parser = parser;
  63. }
  64. void EnsureID (ControlBuilder builder)
  65. {
  66. if (builder.ID == null || builder.ID.Trim () == "")
  67. builder.ID = builder.GetNextID (null);
  68. }
  69. void CreateField (ControlBuilder builder, bool check)
  70. {
  71. currentLocation = builder.location;
  72. if (check && CheckBaseFieldOrProperty (builder.ID, builder.ControlType))
  73. return; // The field or property already exists in a base class and is accesible.
  74. CodeMemberField field;
  75. field = new CodeMemberField (builder.ControlType.FullName, builder.ID);
  76. field.Attributes = MemberAttributes.Family;
  77. mainClass.Members.Add (field);
  78. }
  79. bool CheckBaseFieldOrProperty (string id, Type type)
  80. {
  81. FieldInfo fld = parser.BaseType.GetField (id, noCaseFlags);
  82. Type other = null;
  83. if (fld == null || fld.IsPrivate) {
  84. PropertyInfo prop = parser.BaseType.GetProperty (id, noCaseFlags);
  85. if (prop != null) {
  86. MethodInfo setm = prop.GetSetMethod (true);
  87. if (setm != null)
  88. other = prop.PropertyType;
  89. }
  90. } else {
  91. other = fld.FieldType;
  92. }
  93. if (other == null)
  94. return false;
  95. if (!other.IsAssignableFrom (type)) {
  96. string msg = String.Format ("The base class includes the field '{0}', but its " +
  97. "type '{1}' is not compatible with {2}",
  98. id, other, type);
  99. throw new ParseException (currentLocation, msg);
  100. }
  101. return true;
  102. }
  103. void AddParsedSubObjectStmt (ControlBuilder builder, CodeExpression expr)
  104. {
  105. if (!builder.haveParserVariable) {
  106. CodeVariableDeclarationStatement p = new CodeVariableDeclarationStatement();
  107. p.Name = "__parser";
  108. p.Type = new CodeTypeReference (typeof (IParserAccessor));
  109. p.InitExpression = new CodeCastExpression (typeof (IParserAccessor), ctrlVar);
  110. builder.method.Statements.Add (p);
  111. builder.haveParserVariable = true;
  112. }
  113. CodeVariableReferenceExpression var = new CodeVariableReferenceExpression ("__parser");
  114. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (var, "AddParsedSubObject");
  115. invoke.Parameters.Add (expr);
  116. builder.method.Statements.Add (invoke);
  117. }
  118. void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
  119. {
  120. string tailname = ((builder is RootBuilder) ? "Tree" : ("_" + builder.ID));
  121. CodeMemberMethod method = new CodeMemberMethod ();
  122. builder.method = method;
  123. method.Name = "__BuildControl" + tailname;
  124. method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
  125. Type type = builder.ControlType;
  126. if (builder.HasAspCode) {
  127. CodeMemberMethod renderMethod = new CodeMemberMethod ();
  128. builder.renderMethod = renderMethod;
  129. renderMethod.Name = "__Render" + tailname;
  130. renderMethod.Attributes = MemberAttributes.Private | MemberAttributes.Final;
  131. CodeParameterDeclarationExpression arg1 = new CodeParameterDeclarationExpression ();
  132. arg1.Type = new CodeTypeReference (typeof (HtmlTextWriter));
  133. arg1.Name = "__output";
  134. CodeParameterDeclarationExpression arg2 = new CodeParameterDeclarationExpression ();
  135. arg2.Type = new CodeTypeReference (typeof (Control));
  136. arg2.Name = "parameterContainer";
  137. renderMethod.Parameters.Add (arg1);
  138. renderMethod.Parameters.Add (arg2);
  139. mainClass.Members.Add (renderMethod);
  140. }
  141. if (childrenAsProperties || builder.ControlType == null) {
  142. string typeString;
  143. if (builder.ControlType != null && builder.isProperty &&
  144. !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
  145. typeString = builder.ControlType.FullName;
  146. else
  147. typeString = "System.Web.UI.Control";
  148. method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
  149. } else {
  150. if (typeof (Control).IsAssignableFrom (type))
  151. method.ReturnType = new CodeTypeReference (typeof (Control));
  152. CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
  153. object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
  154. if (atts != null && atts.Length > 0) {
  155. ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
  156. if (att.NeedsTag)
  157. newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
  158. } else if (builder is DataBindingBuilder) {
  159. newExpr.Parameters.Add (new CodePrimitiveExpression (0));
  160. newExpr.Parameters.Add (new CodePrimitiveExpression (1));
  161. }
  162. method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
  163. CodeAssignStatement assign = new CodeAssignStatement ();
  164. assign.Left = ctrlVar;
  165. assign.Right = newExpr;
  166. method.Statements.Add (assign);
  167. CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
  168. builderID.TargetObject = thisRef;
  169. builderID.FieldName = builder.ID;
  170. assign = new CodeAssignStatement ();
  171. assign.Left = builderID;
  172. assign.Right = ctrlVar;
  173. method.Statements.Add (assign);
  174. if (typeof (UserControl).IsAssignableFrom (type)) {
  175. CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression ();
  176. mref.TargetObject = builderID;
  177. mref.MethodName = "InitializeAsUserControl";
  178. CodeMethodInvokeExpression initAsControl = new CodeMethodInvokeExpression (mref);
  179. initAsControl.Parameters.Add (new CodePropertyReferenceExpression (thisRef, "Page"));
  180. method.Statements.Add (initAsControl);
  181. }
  182. #if NET_2_0
  183. if (typeof (System.Web.UI.WebControls.ContentPlaceHolder).IsAssignableFrom (type)) {
  184. CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (thisRef, "ContentPlaceHolders");
  185. CodeMethodInvokeExpression addPlaceholder = new CodeMethodInvokeExpression (prop, "Add");
  186. addPlaceholder.Parameters.Add (ctrlVar);
  187. method.Statements.Add (addPlaceholder);
  188. }
  189. #endif
  190. }
  191. mainClass.Members.Add (method);
  192. }
  193. void AddLiteralSubObject (ControlBuilder builder, string str)
  194. {
  195. if (!builder.HasAspCode) {
  196. CodeObjectCreateExpression expr;
  197. expr = new CodeObjectCreateExpression (typeof (LiteralControl), new CodePrimitiveExpression (str));
  198. AddParsedSubObjectStmt (builder, expr);
  199. } else {
  200. CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression ();
  201. methodRef.TargetObject = new CodeArgumentReferenceExpression ("__output");
  202. methodRef.MethodName = "Write";
  203. CodeMethodInvokeExpression expr;
  204. expr = new CodeMethodInvokeExpression (methodRef, new CodePrimitiveExpression (str));
  205. builder.renderMethod.Statements.Add (expr);
  206. }
  207. }
  208. string TrimDB (string value)
  209. {
  210. string str = value.Trim ();
  211. str = str.Substring (3);
  212. return str.Substring (0, str.Length - 2);
  213. }
  214. string DataBoundProperty (ControlBuilder builder, Type type, string varName, string value)
  215. {
  216. value = TrimDB (value);
  217. CodeMemberMethod method;
  218. string dbMethodName = builder.method.Name + "_DB_" + dataBoundAtts++;
  219. method = CreateDBMethod (dbMethodName, GetContainerType (builder), builder.ControlType);
  220. CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
  221. // This should be a CodePropertyReferenceExpression for properties... but it works anyway
  222. CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (targetExpr, varName);
  223. CodeExpression expr;
  224. if (type == typeof (string)) {
  225. CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
  226. CodeTypeReferenceExpression conv = new CodeTypeReferenceExpression (typeof (Convert));
  227. tostring.Method = new CodeMethodReferenceExpression (conv, "ToString");
  228. tostring.Parameters.Add (new CodeSnippetExpression (value));
  229. expr = tostring;
  230. } else {
  231. CodeSnippetExpression snippet = new CodeSnippetExpression (value);
  232. expr = new CodeCastExpression (type, snippet);
  233. }
  234. method.Statements.Add (new CodeAssignStatement (field, expr));
  235. mainClass.Members.Add (method);
  236. return method.Name;
  237. }
  238. void AddCodeForPropertyOrField (ControlBuilder builder, Type type, string var_name, string att, MemberInfo member, bool isDataBound)
  239. {
  240. CodeMemberMethod method = builder.method;
  241. if (isDataBound) {
  242. string dbMethodName = DataBoundProperty (builder, type, var_name, att);
  243. AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
  244. return;
  245. }
  246. CodeAssignStatement assign = new CodeAssignStatement ();
  247. assign.Left = new CodePropertyReferenceExpression (ctrlVar, var_name);
  248. currentLocation = builder.location;
  249. assign.Right = GetExpressionFromString (type, att, member);
  250. method.Statements.Add (assign);
  251. }
  252. bool IsDataBound (string value)
  253. {
  254. if (value == null || value == "")
  255. return false;
  256. string str = value.Trim ();
  257. return (StrUtils.StartsWith (str, "<%#") && StrUtils.EndsWith (str, "%>"));
  258. }
  259. #if NET_2_0
  260. void RegisterBindingInfo (ControlBuilder builder, string propName, ref string value)
  261. {
  262. string str = value.Trim ();
  263. str = str.Substring (3).Trim (); // eats "<%#"
  264. if (StrUtils.StartsWith (str, "Bind")) {
  265. Match match = bindRegex.Match (str);
  266. if (match.Success) {
  267. string bindingName = match.Groups [1].Value;
  268. TemplateBuilder templateBuilder = builder.ParentTemplateBuilder;
  269. if (templateBuilder == null || templateBuilder.BindingDirection == BindingDirection.OneWay)
  270. throw new HttpException ("Bind expression not allowed in this context.");
  271. string id = builder.attribs ["ID"] as string;
  272. if (id == null)
  273. throw new HttpException ("Control of type '" + builder.ControlType + "' using two-way binding on property '" + propName + "' must have an ID.");
  274. templateBuilder.RegisterBoundProperty (builder.ControlType, propName, id, bindingName);
  275. value = "<%# Eval" + str.Substring (4);
  276. }
  277. }
  278. }
  279. #endif
  280. static bool InvariantCompare (string a, string b)
  281. {
  282. return (0 == String.Compare (a, b, false, CultureInfo.InvariantCulture));
  283. }
  284. static bool InvariantCompareNoCase (string a, string b)
  285. {
  286. return (0 == String.Compare (a, b, true, CultureInfo.InvariantCulture));
  287. }
  288. static MemberInfo GetFieldOrProperty (Type type, string name)
  289. {
  290. MemberInfo member = null;
  291. try {
  292. member = type.GetProperty (name, noCaseFlags & ~BindingFlags.NonPublic);
  293. } catch {}
  294. if (member != null)
  295. return member;
  296. try {
  297. member = type.GetField (name, noCaseFlags & ~BindingFlags.NonPublic);
  298. } catch {}
  299. return member;
  300. }
  301. bool ProcessPropertiesAndFields (ControlBuilder builder, MemberInfo member, string id,
  302. string attValue, string prefix)
  303. {
  304. int hyphen = id.IndexOf ('-');
  305. bool isPropertyInfo = (member is PropertyInfo);
  306. bool isDataBound = IsDataBound (attValue);
  307. Type type;
  308. if (isPropertyInfo) {
  309. type = ((PropertyInfo) member).PropertyType;
  310. if (hyphen == -1 && ((PropertyInfo) member).CanWrite == false)
  311. return false;
  312. } else {
  313. type = ((FieldInfo) member).FieldType;
  314. }
  315. if (InvariantCompareNoCase (member.Name, id)) {
  316. #if NET_2_0
  317. if (isDataBound) RegisterBindingInfo (builder, member.Name, ref attValue);
  318. #endif
  319. AddCodeForPropertyOrField (builder, type, member.Name, attValue, member, isDataBound);
  320. return true;
  321. }
  322. if (hyphen == -1)
  323. return false;
  324. string prop_field = id.Replace ("-", ".");
  325. string [] parts = prop_field.Split (new char [] {'.'});
  326. int length = parts.Length;
  327. if (length < 2 || !InvariantCompareNoCase (member.Name, parts [0]))
  328. return false;
  329. if (length > 2) {
  330. MemberInfo sub_member = GetFieldOrProperty (type, parts [1]);
  331. if (sub_member == null)
  332. return false;
  333. string new_prefix = prefix + parts [0] + ".";
  334. string new_id = id.Substring (hyphen + 1);
  335. return ProcessPropertiesAndFields (builder, sub_member, new_id, attValue, new_prefix);
  336. }
  337. MemberInfo subpf = GetFieldOrProperty (type, parts [1]);
  338. if (!(subpf is PropertyInfo))
  339. return false;
  340. PropertyInfo subprop = (PropertyInfo) subpf;
  341. if (subprop.CanWrite == false)
  342. return false;
  343. bool is_bool = (subprop.PropertyType == typeof (bool));
  344. if (!is_bool && attValue == null)
  345. return false; // Font-Size -> Font-Size="" as html
  346. string val = attValue;
  347. if (attValue == null && is_bool)
  348. val = "true"; // Font-Bold <=> Font-Bold="true"
  349. #if NET_2_0
  350. if (isDataBound) RegisterBindingInfo (builder, prefix + member.Name + "." + subprop.Name, ref attValue);
  351. #endif
  352. AddCodeForPropertyOrField (builder, subprop.PropertyType,
  353. prefix + member.Name + "." + subprop.Name,
  354. val, subprop, isDataBound);
  355. return true;
  356. }
  357. void AddEventAssign (CodeMemberMethod method, string name, Type type, string value)
  358. {
  359. //"__ctrl.{0} += new {1} (this.{2});"
  360. CodeEventReferenceExpression evtID = new CodeEventReferenceExpression (ctrlVar, name);
  361. CodeDelegateCreateExpression create;
  362. create = new CodeDelegateCreateExpression (new CodeTypeReference (type), thisRef, value);
  363. CodeAttachEventStatement attach = new CodeAttachEventStatement (evtID, create);
  364. method.Statements.Add (attach);
  365. }
  366. void CreateAssignStatementsFromAttributes (ControlBuilder builder)
  367. {
  368. this.dataBoundAtts = 0;
  369. IDictionary atts = builder.attribs;
  370. if (atts == null || atts.Count == 0)
  371. return;
  372. EventInfo [] ev_info = null;
  373. bool is_processed = false;
  374. Type type = builder.ControlType;
  375. foreach (string id in atts.Keys) {
  376. if (InvariantCompareNoCase (id, "runat"))
  377. continue;
  378. is_processed = false;
  379. string attvalue = atts [id] as string;
  380. if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
  381. if (ev_info == null)
  382. ev_info = type.GetEvents ();
  383. string id_as_event = id.Substring (2);
  384. foreach (EventInfo ev in ev_info){
  385. if (InvariantCompareNoCase (ev.Name, id_as_event)){
  386. AddEventAssign (builder.method,
  387. ev.Name,
  388. ev.EventHandlerType,
  389. attvalue);
  390. is_processed = true;
  391. break;
  392. }
  393. }
  394. if (is_processed)
  395. continue;
  396. }
  397. int hyphen = id.IndexOf ('-');
  398. string alt_id = id;
  399. if (hyphen != -1)
  400. alt_id = id.Substring (0, hyphen);
  401. MemberInfo fop = GetFieldOrProperty (type, alt_id);
  402. if (fop != null) {
  403. is_processed = ProcessPropertiesAndFields (builder, fop, id, attvalue, null);
  404. if (is_processed)
  405. continue;
  406. }
  407. if (is_processed)
  408. continue;
  409. if (!typeof (IAttributeAccessor).IsAssignableFrom (type))
  410. throw new ParseException (builder.location, "Unrecognized attribute: " + id);
  411. CodeCastExpression cast = new CodeCastExpression (typeof (IAttributeAccessor), ctrlVar);
  412. CodeMethodReferenceExpression methodExpr;
  413. methodExpr = new CodeMethodReferenceExpression (cast, "SetAttribute");
  414. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr);
  415. expr.Parameters.Add (new CodePrimitiveExpression (id));
  416. expr.Parameters.Add (new CodePrimitiveExpression ((string) atts [id]));
  417. builder.method.Statements.Add (expr);
  418. }
  419. }
  420. void AddRenderControl (ControlBuilder builder)
  421. {
  422. CodeIndexerExpression indexer = new CodeIndexerExpression ();
  423. indexer.TargetObject = new CodePropertyReferenceExpression (
  424. new CodeArgumentReferenceExpression ("parameterContainer"),
  425. "Controls");
  426. indexer.Indices.Add (new CodePrimitiveExpression (builder.renderIndex));
  427. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (indexer, "RenderControl");
  428. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("__output"));
  429. builder.renderMethod.Statements.Add (invoke);
  430. builder.renderIndex++;
  431. }
  432. void AddChildCall (ControlBuilder parent, ControlBuilder child)
  433. {
  434. CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.method.Name);
  435. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
  436. object [] atts = child.ControlType.GetCustomAttributes (typeof (PartialCachingAttribute), true);
  437. if (atts != null && atts.Length > 0) {
  438. PartialCachingAttribute pca = (PartialCachingAttribute) atts [0];
  439. CodeTypeReferenceExpression cc = new CodeTypeReferenceExpression("System.Web.UI.StaticPartialCachingControl");
  440. CodeMethodInvokeExpression build = new CodeMethodInvokeExpression (cc, "BuildCachedControl");
  441. build.Parameters.Add (new CodeArgumentReferenceExpression("__ctrl"));
  442. build.Parameters.Add (new CodePrimitiveExpression (child.ID));
  443. #if NET_1_1
  444. if (pca.Shared)
  445. build.Parameters.Add (new CodePrimitiveExpression (child.ControlType.GetHashCode ().ToString ()));
  446. else
  447. #endif
  448. build.Parameters.Add (new CodePrimitiveExpression (Guid.NewGuid ().ToString ()));
  449. build.Parameters.Add (new CodePrimitiveExpression (pca.Duration));
  450. build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByParams));
  451. build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByControls));
  452. build.Parameters.Add (new CodePrimitiveExpression (pca.VaryByCustom));
  453. build.Parameters.Add (new CodeDelegateCreateExpression (
  454. new CodeTypeReference (typeof (System.Web.UI.BuildMethod)),
  455. thisRef, child.method.Name));
  456. parent.method.Statements.Add (build);
  457. if (parent.HasAspCode)
  458. AddRenderControl (parent);
  459. return;
  460. }
  461. if (child.isProperty || parent.ChildrenAsProperties) {
  462. expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
  463. parent.method.Statements.Add (expr);
  464. return;
  465. }
  466. parent.method.Statements.Add (expr);
  467. CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
  468. if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType)) {
  469. AddParsedSubObjectStmt (parent, field);
  470. } else {
  471. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
  472. invoke.Parameters.Add (field);
  473. parent.method.Statements.Add (invoke);
  474. }
  475. if (parent.HasAspCode)
  476. AddRenderControl (parent);
  477. }
  478. void AddTemplateInvocation (CodeMemberMethod method, string name, string methodName)
  479. {
  480. CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
  481. CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
  482. newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
  483. CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
  484. newCompiled.Parameters.Add (newBuild);
  485. CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
  486. method.Statements.Add (assign);
  487. }
  488. #if NET_2_0
  489. void AddBindableTemplateInvocation (CodeMemberMethod method, string name, string methodName, string extractMethodName)
  490. {
  491. CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression (ctrlVar, name);
  492. CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
  493. newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
  494. CodeObjectCreateExpression newExtract = new CodeObjectCreateExpression (typeof (ExtractTemplateValuesMethod));
  495. newExtract.Parameters.Add (new CodeMethodReferenceExpression (thisRef, extractMethodName));
  496. CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledBindableTemplateBuilder));
  497. newCompiled.Parameters.Add (newBuild);
  498. newCompiled.Parameters.Add (newExtract);
  499. CodeAssignStatement assign = new CodeAssignStatement (prop, newCompiled);
  500. method.Statements.Add (assign);
  501. }
  502. string CreateExtractValuesMethod (TemplateBuilder builder)
  503. {
  504. CodeMemberMethod method = new CodeMemberMethod ();
  505. method.Name = "__ExtractValues_" + builder.ID;
  506. method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
  507. method.ReturnType = new CodeTypeReference (typeof(IOrderedDictionary));
  508. CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression ();
  509. arg.Type = new CodeTypeReference (typeof (Control));
  510. arg.Name = "__container";
  511. method.Parameters.Add (arg);
  512. mainClass.Members.Add (method);
  513. CodeObjectCreateExpression newTable = new CodeObjectCreateExpression ();
  514. newTable.CreateType = new CodeTypeReference (typeof(OrderedDictionary));
  515. method.Statements.Add (new CodeVariableDeclarationStatement (typeof(OrderedDictionary), "__table", newTable));
  516. CodeVariableReferenceExpression tableExp = new CodeVariableReferenceExpression ("__table");
  517. if (builder.Bindings != null) {
  518. foreach (TemplateBinding binding in builder.Bindings) {
  519. CodeVariableDeclarationStatement dec = new CodeVariableDeclarationStatement (binding.ControlType, binding.ControlId);
  520. method.Statements.Add (dec);
  521. CodeVariableReferenceExpression cter = new CodeVariableReferenceExpression ("__container");
  522. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (cter, "FindControl");
  523. invoke.Parameters.Add (new CodePrimitiveExpression (binding.ControlId));
  524. CodeAssignStatement assign = new CodeAssignStatement ();
  525. CodeVariableReferenceExpression control = new CodeVariableReferenceExpression (binding.ControlId);
  526. assign.Left = control;
  527. assign.Right = new CodeCastExpression (binding.ControlType, invoke);
  528. method.Statements.Add (assign);
  529. CodeConditionStatement sif = new CodeConditionStatement ();
  530. sif.Condition = new CodeBinaryOperatorExpression (control, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression (null));
  531. assign = new CodeAssignStatement ();
  532. assign.Left = new CodeIndexerExpression (tableExp, new CodePrimitiveExpression (binding.FieldName));
  533. assign.Right = new CodePropertyReferenceExpression (control, binding.ControlProperty);
  534. sif.TrueStatements.Add (assign);
  535. method.Statements.Add (sif);
  536. }
  537. }
  538. method.Statements.Add (new CodeMethodReturnStatement (tableExp));
  539. return method.Name;
  540. }
  541. void AddContentTemplateInvocation (ContentControlBuilder cbuilder, CodeMemberMethod method, string methodName)
  542. {
  543. CodeObjectCreateExpression newBuild = new CodeObjectCreateExpression (typeof (BuildTemplateMethod));
  544. newBuild.Parameters.Add (new CodeMethodReferenceExpression (thisRef, methodName));
  545. CodeObjectCreateExpression newCompiled = new CodeObjectCreateExpression (typeof (CompiledTemplateBuilder));
  546. newCompiled.Parameters.Add (newBuild);
  547. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (thisRef, "AddContentTemplate");
  548. invoke.Parameters.Add (new CodePrimitiveExpression (cbuilder.ContentPlaceHolderID));
  549. invoke.Parameters.Add (newCompiled);
  550. method.Statements.Add (invoke);
  551. }
  552. #endif
  553. void AddCodeRender (ControlBuilder parent, CodeRenderBuilder cr)
  554. {
  555. if (cr.Code == null || cr.Code.Trim () == "")
  556. return;
  557. if (!cr.IsAssign) {
  558. CodeSnippetStatement code = new CodeSnippetStatement (cr.Code);
  559. parent.renderMethod.Statements.Add (code);
  560. return;
  561. }
  562. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
  563. expr.Method = new CodeMethodReferenceExpression (
  564. new CodeArgumentReferenceExpression ("__output"),
  565. "Write");
  566. expr.Parameters.Add (new CodeSnippetExpression (cr.Code));
  567. parent.renderMethod.Statements.Add (expr);
  568. }
  569. static Type GetContainerType (ControlBuilder builder)
  570. {
  571. TemplateBuilder tb = builder as TemplateBuilder;
  572. if (tb != null && tb.ContainerType != null)
  573. return tb.ContainerType;
  574. Type type = builder.BindingContainerType;
  575. PropertyInfo prop = type.GetProperty ("Items", noCaseFlags & ~BindingFlags.NonPublic);
  576. if (prop == null)
  577. return type;
  578. Type ptype = prop.PropertyType;
  579. if (!typeof (ICollection).IsAssignableFrom (ptype))
  580. return type;
  581. prop = ptype.GetProperty ("Item", noCaseFlags & ~BindingFlags.NonPublic);
  582. if (prop == null)
  583. return type;
  584. return prop.PropertyType;
  585. }
  586. CodeMemberMethod CreateDBMethod (string name, Type container, Type target)
  587. {
  588. CodeMemberMethod method = new CodeMemberMethod ();
  589. method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
  590. method.Name = name;
  591. method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object), "sender"));
  592. method.Parameters.Add (new CodeParameterDeclarationExpression (typeof (EventArgs), "e"));
  593. CodeTypeReference containerRef = new CodeTypeReference (container);
  594. CodeTypeReference targetRef = new CodeTypeReference (target);
  595. CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement();
  596. decl.Name = "Container";
  597. decl.Type = containerRef;
  598. method.Statements.Add (decl);
  599. decl = new CodeVariableDeclarationStatement();
  600. decl.Name = "target";
  601. decl.Type = targetRef;
  602. method.Statements.Add (decl);
  603. CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
  604. CodeAssignStatement assign = new CodeAssignStatement ();
  605. assign.Left = targetExpr;
  606. assign.Right = new CodeCastExpression (targetRef, new CodeArgumentReferenceExpression ("sender"));
  607. method.Statements.Add (assign);
  608. assign = new CodeAssignStatement ();
  609. assign.Left = new CodeVariableReferenceExpression ("Container");
  610. assign.Right = new CodeCastExpression (containerRef,
  611. new CodePropertyReferenceExpression (targetExpr, "BindingContainer"));
  612. method.Statements.Add (assign);
  613. return method;
  614. }
  615. void AddDataBindingLiteral (ControlBuilder builder, DataBindingBuilder db)
  616. {
  617. if (db.Code == null || db.Code.Trim () == "")
  618. return;
  619. EnsureID (db);
  620. CreateField (db, false);
  621. string dbMethodName = "__DataBind_" + db.ID;
  622. // Add the method that builds the DataBoundLiteralControl
  623. InitMethod (db, false, false);
  624. CodeMemberMethod method = db.method;
  625. AddEventAssign (method, "DataBinding", typeof (EventHandler), dbMethodName);
  626. method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
  627. // Add the DataBind handler
  628. method = CreateDBMethod (dbMethodName, GetContainerType (builder), typeof (DataBoundLiteralControl));
  629. CodeVariableReferenceExpression targetExpr = new CodeVariableReferenceExpression ("target");
  630. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
  631. invoke.Method = new CodeMethodReferenceExpression (targetExpr, "SetDataBoundString");
  632. invoke.Parameters.Add (new CodePrimitiveExpression (0));
  633. CodeMethodInvokeExpression tostring = new CodeMethodInvokeExpression ();
  634. tostring.Method = new CodeMethodReferenceExpression (
  635. new CodeTypeReferenceExpression (typeof (Convert)),
  636. "ToString");
  637. tostring.Parameters.Add (new CodeSnippetExpression (db.Code));
  638. invoke.Parameters.Add (tostring);
  639. method.Statements.Add (invoke);
  640. mainClass.Members.Add (method);
  641. AddChildCall (builder, db);
  642. }
  643. void FlushText (ControlBuilder builder, StringBuilder sb)
  644. {
  645. if (sb.Length > 0) {
  646. AddLiteralSubObject (builder, sb.ToString ());
  647. sb.Length = 0;
  648. }
  649. }
  650. void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
  651. {
  652. EnsureID (builder);
  653. bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
  654. if (!isTemplate && !inTemplate) {
  655. CreateField (builder, true);
  656. } else if (!isTemplate) {
  657. builder.ID = builder.GetNextID (null);
  658. CreateField (builder, false);
  659. }
  660. InitMethod (builder, isTemplate, childrenAsProperties);
  661. if (!isTemplate || builder.GetType () == typeof (RootBuilder))
  662. CreateAssignStatementsFromAttributes (builder);
  663. if (builder.Children != null && builder.Children.Count > 0) {
  664. ArrayList templates = null;
  665. StringBuilder sb = new StringBuilder ();
  666. foreach (object b in builder.Children) {
  667. if (b is string) {
  668. sb.Append ((string) b);
  669. continue;
  670. }
  671. FlushText (builder, sb);
  672. if (b is ObjectTagBuilder) {
  673. ProcessObjectTag ((ObjectTagBuilder) b);
  674. continue;
  675. }
  676. #if NET_2_0
  677. if (b is ContentControlBuilder) {
  678. ContentControlBuilder cb = (ContentControlBuilder) b;
  679. CreateControlTree (cb, false, true);
  680. AddContentTemplateInvocation (cb, builder.method, cb.method.Name);
  681. continue;
  682. }
  683. #endif
  684. if (b is TemplateBuilder) {
  685. if (templates == null)
  686. templates = new ArrayList ();
  687. templates.Add (b);
  688. continue;
  689. }
  690. if (b is CodeRenderBuilder) {
  691. AddCodeRender (builder, (CodeRenderBuilder) b);
  692. continue;
  693. }
  694. if (b is DataBindingBuilder) {
  695. AddDataBindingLiteral (builder, (DataBindingBuilder) b);
  696. continue;
  697. }
  698. if (b is ControlBuilder) {
  699. ControlBuilder child = (ControlBuilder) b;
  700. CreateControlTree (child, inTemplate, builder.ChildrenAsProperties);
  701. AddChildCall (builder, child);
  702. continue;
  703. }
  704. throw new Exception ("???");
  705. }
  706. FlushText (builder, sb);
  707. if (templates != null) {
  708. foreach (TemplateBuilder b in templates) {
  709. CreateControlTree (b, true, false);
  710. #if NET_2_0
  711. if (b.BindingDirection == BindingDirection.TwoWay) {
  712. string extractMethod = CreateExtractValuesMethod (b);
  713. AddBindableTemplateInvocation (builder.method, b.TagName, b.method.Name, extractMethod);
  714. }
  715. else
  716. #endif
  717. AddTemplateInvocation (builder.method, b.TagName, b.method.Name);
  718. }
  719. }
  720. }
  721. if (builder.defaultPropertyBuilder != null) {
  722. ControlBuilder b = builder.defaultPropertyBuilder;
  723. CreateControlTree (b, false, true);
  724. AddChildCall (builder, b);
  725. }
  726. if (builder.HasAspCode) {
  727. CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
  728. m.TargetObject = thisRef;
  729. m.MethodName = builder.renderMethod.Name;
  730. CodeDelegateCreateExpression create = new CodeDelegateCreateExpression ();
  731. create.DelegateType = new CodeTypeReference (typeof (RenderMethod));
  732. create.TargetObject = thisRef;
  733. create.MethodName = builder.renderMethod.Name;
  734. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression ();
  735. invoke.Method = new CodeMethodReferenceExpression (ctrlVar, "SetRenderMethodDelegate");
  736. invoke.Parameters.Add (create);
  737. builder.method.Statements.Add (invoke);
  738. }
  739. if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
  740. builder.method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
  741. }
  742. protected override void CreateMethods ()
  743. {
  744. base.CreateMethods ();
  745. CreateProperties ();
  746. CreateControlTree (parser.RootBuilder, false, false);
  747. CreateFrameworkInitializeMethod ();
  748. }
  749. void CreateFrameworkInitializeMethod ()
  750. {
  751. CodeMemberMethod method = new CodeMemberMethod ();
  752. method.Name = "FrameworkInitialize";
  753. method.Attributes = MemberAttributes.Family | MemberAttributes.Override;
  754. AddStatementsToFrameworkInitialize (method);
  755. mainClass.Members.Add (method);
  756. }
  757. protected virtual void AddStatementsToFrameworkInitialize (CodeMemberMethod method)
  758. {
  759. if (!parser.EnableViewState) {
  760. CodeAssignStatement stmt = new CodeAssignStatement ();
  761. stmt.Left = new CodePropertyReferenceExpression (thisRef, "EnableViewState");
  762. stmt.Right = new CodePrimitiveExpression (false);
  763. method.Statements.Add (stmt);
  764. }
  765. CodeMethodReferenceExpression methodExpr;
  766. methodExpr = new CodeMethodReferenceExpression (thisRef, "__BuildControlTree");
  767. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (methodExpr, thisRef);
  768. method.Statements.Add (new CodeExpressionStatement (expr));
  769. }
  770. protected override void AddApplicationAndSessionObjects ()
  771. {
  772. foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.ApplicationObjects) {
  773. CreateFieldForObject (tag.Type, tag.ObjectID);
  774. CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, true, false);
  775. }
  776. foreach (ObjectTagBuilder tag in GlobalAsaxCompiler.SessionObjects) {
  777. CreateApplicationOrSessionPropertyForObject (tag.Type, tag.ObjectID, false, false);
  778. }
  779. }
  780. protected void ProcessObjectTag (ObjectTagBuilder tag)
  781. {
  782. string fieldName = CreateFieldForObject (tag.Type, tag.ObjectID);
  783. CreatePropertyForObject (tag.Type, tag.ObjectID, fieldName, false);
  784. }
  785. void CreateProperties ()
  786. {
  787. if (!parser.AutoEventWireup) {
  788. CreateAutoEventWireup ();
  789. } else {
  790. CreateAutoHandlers ();
  791. }
  792. CreateApplicationInstance ();
  793. CreateTemplateSourceDirectory ();
  794. }
  795. void CreateTemplateSourceDirectory ()
  796. {
  797. CodeMemberProperty prop = new CodeMemberProperty ();
  798. prop.Type = new CodeTypeReference (typeof (string));
  799. prop.Name = "TemplateSourceDirectory";
  800. prop.Attributes = MemberAttributes.Public | MemberAttributes.Override;
  801. CodePrimitiveExpression expr = new CodePrimitiveExpression (parser.BaseVirtualDir);
  802. prop.GetStatements.Add (new CodeMethodReturnStatement (expr));
  803. mainClass.Members.Add (prop);
  804. }
  805. void CreateApplicationInstance ()
  806. {
  807. CodeMemberProperty prop = new CodeMemberProperty ();
  808. Type appType = typeof (HttpApplication);
  809. prop.Type = new CodeTypeReference (appType);
  810. prop.Name = "ApplicationInstance";
  811. prop.Attributes = MemberAttributes.Family | MemberAttributes.Final;
  812. CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression (thisRef, "Context");
  813. propRef = new CodePropertyReferenceExpression (propRef, "ApplicationInstance");
  814. CodeCastExpression cast = new CodeCastExpression (appType.FullName, propRef);
  815. prop.GetStatements.Add (new CodeMethodReturnStatement (cast));
  816. mainClass.Members.Add (prop);
  817. }
  818. void CreateAutoHandlers ()
  819. {
  820. // Create AutoHandlers property
  821. CodeMemberProperty prop = new CodeMemberProperty ();
  822. prop.Type = new CodeTypeReference (typeof (int));
  823. prop.Name = "AutoHandlers";
  824. prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
  825. CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
  826. CodeFieldReferenceExpression fldRef ;
  827. fldRef = new CodeFieldReferenceExpression (mainClassExpr, "__autoHandlers");
  828. ret.Expression = fldRef;
  829. prop.GetStatements.Add (ret);
  830. prop.SetStatements.Add (new CodeAssignStatement (fldRef, new CodePropertySetValueReferenceExpression ()));
  831. mainClass.Members.Add (prop);
  832. // Add the __autoHandlers field
  833. CodeMemberField fld = new CodeMemberField (typeof (int), "__autoHandlers");
  834. fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
  835. mainClass.Members.Add (fld);
  836. }
  837. void CreateAutoEventWireup ()
  838. {
  839. // The getter returns false
  840. CodeMemberProperty prop = new CodeMemberProperty ();
  841. prop.Type = new CodeTypeReference (typeof (bool));
  842. prop.Name = "SupportAutoEvents";
  843. prop.Attributes = MemberAttributes.Family | MemberAttributes.Override;
  844. prop.GetStatements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (false)));
  845. mainClass.Members.Add (prop);
  846. }
  847. CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
  848. {
  849. if (type == typeof (string))
  850. return new CodePrimitiveExpression (str);
  851. if (type == typeof (bool)) {
  852. if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
  853. return new CodePrimitiveExpression (true);
  854. else if (InvariantCompareNoCase (str, "false"))
  855. return new CodePrimitiveExpression (false);
  856. else
  857. throw new ParseException (currentLocation,
  858. "Value '" + str + "' is not a valid boolean.");
  859. }
  860. if (str == null)
  861. return new CodePrimitiveExpression (null);
  862. if (type.IsPrimitive)
  863. return new CodePrimitiveExpression (Convert.ChangeType (str, type, CultureInfo.InvariantCulture));
  864. if (type == typeof (string [])) {
  865. string [] subs = str.Split (',');
  866. CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
  867. expr.CreateType = new CodeTypeReference (typeof (string));
  868. foreach (string v in subs) {
  869. expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
  870. }
  871. return expr;
  872. }
  873. if (type == typeof (Color)){
  874. if (colorConverter == null)
  875. colorConverter = TypeDescriptor.GetConverter (typeof (Color));
  876. if (str.Trim().Length == 0) {
  877. CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
  878. return new CodeFieldReferenceExpression (ft, "Empty");
  879. }
  880. Color c;
  881. try {
  882. if (str.IndexOf (',') == -1) {
  883. c = (Color) colorConverter.ConvertFromString (str);
  884. } else {
  885. int [] argb = new int [4];
  886. argb [0] = 255;
  887. string [] parts = str.Split (',');
  888. int length = parts.Length;
  889. if (length < 3)
  890. throw new Exception ();
  891. int basei = (length == 4) ? 0 : 1;
  892. for (int i = length - 1; i >= 0; i--) {
  893. argb [basei + i] = (int) Byte.Parse (parts [i]);
  894. }
  895. c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
  896. }
  897. } catch (Exception e){
  898. throw new ParseException (currentLocation,
  899. "Color " + str + " is not a valid color.", e);
  900. }
  901. if (c.IsKnownColor){
  902. CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
  903. if (c.IsSystemColor)
  904. type = typeof (SystemColors);
  905. expr.TargetObject = new CodeTypeReferenceExpression (type);
  906. expr.FieldName = c.Name;
  907. return expr;
  908. } else {
  909. CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
  910. m.TargetObject = new CodeTypeReferenceExpression (type);
  911. m.MethodName = "FromArgb";
  912. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
  913. invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
  914. invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
  915. invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
  916. invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
  917. return invoke;
  918. }
  919. }
  920. TypeConverter converter = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name].Converter;
  921. if (converter != null && converter.CanConvertFrom (typeof (string))) {
  922. object value = converter.ConvertFrom (str);
  923. if (converter.CanConvertTo (typeof (InstanceDescriptor))) {
  924. InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
  925. return GenerateInstance (idesc, true);
  926. }
  927. CodeExpression exp = GenerateObjectInstance (value, false);
  928. if (exp != null) return exp;
  929. CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
  930. m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
  931. m.MethodName = "GetConverter";
  932. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
  933. CodeTypeReference tref = new CodeTypeReference (type);
  934. invoke.Parameters.Add (new CodeTypeOfExpression (tref));
  935. invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
  936. invoke.Parameters.Add (new CodePrimitiveExpression (str));
  937. return new CodeCastExpression (tref, invoke);
  938. }
  939. Console.WriteLine ("Unknown type: " + type + " value: " + str);
  940. return new CodePrimitiveExpression (str);
  941. }
  942. CodeExpression GenerateInstance (InstanceDescriptor idesc, bool throwOnError)
  943. {
  944. CodeExpression[] parameters = new CodeExpression [idesc.Arguments.Count];
  945. int n = 0;
  946. foreach (object ob in idesc.Arguments) {
  947. CodeExpression exp = GenerateObjectInstance (ob, throwOnError);
  948. if (exp == null) return null;
  949. parameters [n++] = exp;
  950. }
  951. switch (idesc.MemberInfo.MemberType) {
  952. case MemberTypes.Constructor:
  953. CodeTypeReference tob = new CodeTypeReference (idesc.MemberInfo.DeclaringType);
  954. return new CodeObjectCreateExpression (tob, parameters);
  955. case MemberTypes.Method:
  956. CodeTypeReferenceExpression mt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
  957. return new CodeMethodInvokeExpression (mt, idesc.MemberInfo.Name, parameters);
  958. case MemberTypes.Field:
  959. CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
  960. return new CodeFieldReferenceExpression (ft, idesc.MemberInfo.Name);
  961. case MemberTypes.Property:
  962. CodeTypeReferenceExpression pt = new CodeTypeReferenceExpression (idesc.MemberInfo.DeclaringType);
  963. return new CodePropertyReferenceExpression (pt, idesc.MemberInfo.Name);
  964. }
  965. throw new ParseException (currentLocation, "Invalid instance type.");
  966. }
  967. CodeExpression GenerateObjectInstance (object value, bool throwOnError)
  968. {
  969. if (value == null)
  970. return new CodePrimitiveExpression (null);
  971. Type t = value.GetType();
  972. if (t.IsPrimitive || value is string)
  973. return new CodePrimitiveExpression (value);
  974. if (t.IsArray) {
  975. Array ar = (Array) value;
  976. CodeExpression[] items = new CodeExpression [ar.Length];
  977. for (int n=0; n<ar.Length; n++) {
  978. CodeExpression exp = GenerateObjectInstance (ar.GetValue (n), throwOnError);
  979. if (exp == null) return null;
  980. items [n] = exp;
  981. }
  982. return new CodeArrayCreateExpression (new CodeTypeReference (t), items);
  983. }
  984. TypeConverter converter = TypeDescriptor.GetConverter (t);
  985. if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
  986. InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
  987. return GenerateInstance (idesc, throwOnError);
  988. }
  989. InstanceDescriptor desc = GetDefaultInstanceDescriptor (value);
  990. if (desc != null) return GenerateInstance (desc, throwOnError);
  991. if (throwOnError)
  992. throw new ParseException (currentLocation, "Cannot generate an instance for the type: " + t);
  993. else
  994. return null;
  995. }
  996. InstanceDescriptor GetDefaultInstanceDescriptor (object value)
  997. {
  998. if (value is System.Web.UI.WebControls.Unit) {
  999. System.Web.UI.WebControls.Unit s = (System.Web.UI.WebControls.Unit) value;
  1000. MethodInfo met = typeof(System.Web.UI.WebControls.Unit).GetMethod ("Parse", new Type[] {typeof(string)});
  1001. return new InstanceDescriptor (met, new object[] {s.ToString ()});
  1002. }
  1003. if (value is System.Web.UI.WebControls.FontUnit) {
  1004. System.Web.UI.WebControls.FontUnit s = (System.Web.UI.WebControls.FontUnit) value;
  1005. MethodInfo met = typeof(System.Web.UI.WebControls.FontUnit).GetMethod ("Parse", new Type[] {typeof(string)});
  1006. return new InstanceDescriptor (met, new object[] {s.ToString ()});
  1007. }
  1008. return null;
  1009. }
  1010. }
  1011. }