ExpressionPrinter.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //
  2. // ExpressionPrinter.cs
  3. //
  4. // Author:
  5. // Jb Evain ([email protected])
  6. //
  7. // (C) 2008 Novell, Inc. (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Collections.ObjectModel;
  31. using System.Text;
  32. namespace System.Linq.Expressions {
  33. class ExpressionPrinter : ExpressionVisitor {
  34. StringBuilder builder;
  35. const string ListSeparator = ", ";
  36. ExpressionPrinter (StringBuilder builder)
  37. {
  38. this.builder = builder;
  39. }
  40. ExpressionPrinter () : this (new StringBuilder ())
  41. {
  42. }
  43. public static string ToString (Expression expression)
  44. {
  45. var printer = new ExpressionPrinter ();
  46. printer.Visit (expression);
  47. return printer.builder.ToString ();
  48. }
  49. public static string ToString (ElementInit init)
  50. {
  51. var printer = new ExpressionPrinter ();
  52. printer.VisitElementInitializer (init);
  53. return printer.builder.ToString ();
  54. }
  55. public static string ToString (MemberBinding binding)
  56. {
  57. var printer = new ExpressionPrinter ();
  58. printer.VisitBinding (binding);
  59. return printer.builder.ToString ();
  60. }
  61. void Print (string str)
  62. {
  63. builder.Append (str);
  64. }
  65. void Print (object obj)
  66. {
  67. builder.Append (obj);
  68. }
  69. void Print (string str, params object [] objs)
  70. {
  71. builder.AppendFormat (str, objs);
  72. }
  73. protected override void VisitElementInitializer (ElementInit initializer)
  74. {
  75. Print (initializer.AddMethod);
  76. Print ("(");
  77. VisitExpressionList (initializer.Arguments);
  78. Print (")");
  79. }
  80. protected override void VisitUnary (UnaryExpression unary)
  81. {
  82. switch (unary.NodeType) {
  83. case ExpressionType.ArrayLength:
  84. case ExpressionType.Convert:
  85. case ExpressionType.ConvertChecked:
  86. case ExpressionType.Not:
  87. Print ("{0}(", unary.NodeType);
  88. Visit (unary.Operand);
  89. Print (")");
  90. return;
  91. case ExpressionType.Negate:
  92. Print ("-");
  93. Visit (unary.Operand);
  94. return;
  95. case ExpressionType.Quote:
  96. Visit (unary.Operand);
  97. return;
  98. case ExpressionType.TypeAs:
  99. Print ("(");
  100. Visit (unary.Operand);
  101. Print (" As {0})", unary.Type.Name);
  102. return;
  103. case ExpressionType.UnaryPlus:
  104. Print ("+");
  105. Visit (unary.Operand);
  106. return;
  107. }
  108. throw new NotImplementedException ();
  109. }
  110. static string OperatorToString (BinaryExpression binary)
  111. {
  112. switch (binary.NodeType) {
  113. case ExpressionType.Add:
  114. case ExpressionType.AddChecked:
  115. return "+";
  116. case ExpressionType.AndAlso:
  117. return "&&";
  118. case ExpressionType.Coalesce:
  119. return "??";
  120. case ExpressionType.Divide:
  121. return "/";
  122. case ExpressionType.Equal:
  123. return "=";
  124. case ExpressionType.ExclusiveOr:
  125. return "^";
  126. case ExpressionType.GreaterThan:
  127. return ">";
  128. case ExpressionType.GreaterThanOrEqual:
  129. return ">=";
  130. case ExpressionType.LeftShift:
  131. return "<<";
  132. case ExpressionType.LessThan:
  133. return "<";
  134. case ExpressionType.LessThanOrEqual:
  135. return "<=";
  136. case ExpressionType.Modulo:
  137. return "%";
  138. case ExpressionType.Multiply:
  139. case ExpressionType.MultiplyChecked:
  140. return "*";
  141. case ExpressionType.NotEqual:
  142. return "!=";
  143. case ExpressionType.OrElse:
  144. return "||";
  145. case ExpressionType.Power:
  146. return "^";
  147. case ExpressionType.RightShift:
  148. return ">>";
  149. case ExpressionType.Subtract:
  150. case ExpressionType.SubtractChecked:
  151. return "-";
  152. case ExpressionType.And:
  153. return IsBoolean (binary) ? "And" : "&";
  154. case ExpressionType.Or:
  155. return IsBoolean (binary) ? "Or" : "|";
  156. default:
  157. return null;
  158. }
  159. }
  160. static bool IsBoolean (Expression expression)
  161. {
  162. return expression.Type == typeof (bool) || expression.Type == typeof (bool?);
  163. }
  164. void PrintArrayIndex (BinaryExpression index)
  165. {
  166. Visit (index.Left);
  167. Print ("[");
  168. Visit (index.Right);
  169. Print ("]");
  170. }
  171. protected override void VisitBinary (BinaryExpression binary)
  172. {
  173. switch (binary.NodeType) {
  174. case ExpressionType.ArrayIndex:
  175. PrintArrayIndex (binary);
  176. return;
  177. default:
  178. Print ("(");
  179. Visit (binary.Left);
  180. Print (" {0} ", OperatorToString (binary));
  181. Visit (binary.Right);
  182. Print (")");
  183. return;
  184. }
  185. }
  186. protected override void VisitTypeIs (TypeBinaryExpression type)
  187. {
  188. switch (type.NodeType) {
  189. case ExpressionType.TypeIs:
  190. Print ("(");
  191. Visit (type.Expression);
  192. Print (" Is {0})", type.TypeOperand.Name);
  193. return;
  194. }
  195. throw new NotImplementedException ();
  196. }
  197. protected override void VisitConstant (ConstantExpression constant)
  198. {
  199. var value = constant.Value;
  200. if (value == null) {
  201. Print ("null");
  202. } else if (value is string) {
  203. Print ("\"");
  204. Print (value);
  205. Print ("\"");
  206. } else if (!HasStringRepresentation (value)) {
  207. Print ("value(");
  208. Print (value);
  209. Print (")");
  210. } else
  211. Print (value);
  212. }
  213. static bool HasStringRepresentation (object obj)
  214. {
  215. return obj.ToString () != obj.GetType ().ToString ();
  216. }
  217. protected override void VisitConditional (ConditionalExpression conditional)
  218. {
  219. Print ("IIF(");
  220. Visit (conditional.Test);
  221. Print (ListSeparator);
  222. Visit (conditional.IfTrue);
  223. Print (ListSeparator);
  224. Visit (conditional.IfFalse);
  225. Print (")");
  226. }
  227. protected override void VisitParameter (ParameterExpression parameter)
  228. {
  229. Print (parameter.Name ?? "<param>");
  230. }
  231. protected override void VisitMemberAccess (MemberExpression access)
  232. {
  233. if (access.Expression == null)
  234. Print (access.Member.DeclaringType.Name);
  235. else
  236. Visit (access.Expression);
  237. Print (".{0}", access.Member.Name);
  238. }
  239. protected override void VisitMethodCall (MethodCallExpression call)
  240. {
  241. if (call.Object != null) {
  242. Visit (call.Object);
  243. Print (".");
  244. }
  245. Print (call.Method.Name);
  246. Print ("(");
  247. VisitExpressionList (call.Arguments);
  248. Print (")");
  249. }
  250. protected override void VisitMemberAssignment (MemberAssignment assignment)
  251. {
  252. Print ("{0} = ", assignment.Member.Name);
  253. Visit (assignment.Expression);
  254. }
  255. protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
  256. {
  257. Print (binding.Member.Name);
  258. Print (" = {");
  259. // VisitBindingList (binding.Bindings);
  260. VisitList (binding.Bindings, VisitBinding);
  261. Print ("}");
  262. }
  263. protected override void VisitMemberListBinding (MemberListBinding binding)
  264. {
  265. Print (binding.Member.Name);
  266. Print (" = {");
  267. // replace when the patch to the visitor is in
  268. // VisitElementInitializerList (binding.Initializers);
  269. VisitList (binding.Initializers, VisitElementInitializer);
  270. Print ("}");
  271. }
  272. protected override void VisitList<T> (ReadOnlyCollection<T> list, Action<T> visitor)
  273. {
  274. for (int i = 0; i < list.Count; i++) {
  275. if (i > 0)
  276. Print (ListSeparator);
  277. visitor (list [i]);
  278. }
  279. }
  280. protected override void VisitLambda (LambdaExpression lambda)
  281. {
  282. if (lambda.Parameters.Count != 1) {
  283. Print ("(");
  284. // replace when the patch to the visitor is in
  285. // VisitExpressionList (lambda.Parameters);
  286. VisitList (lambda.Parameters, Visit);
  287. Print (")");
  288. } else
  289. Visit (lambda.Parameters [0]);
  290. Print (" => ");
  291. Visit (lambda.Body);
  292. }
  293. protected override void VisitNew (NewExpression nex)
  294. {
  295. Print ("new {0}(", nex.Type.Name);
  296. if (nex.Members != null && nex.Members.Count > 0) {
  297. for (int i = 0; i < nex.Members.Count; i++) {
  298. if (i > 0)
  299. Print (ListSeparator);
  300. Print ("{0} = ", nex.Members [i].Name);
  301. Visit (nex.Arguments [i]);
  302. }
  303. } else
  304. VisitExpressionList (nex.Arguments);
  305. Print (")");
  306. }
  307. protected override void VisitMemberInit (MemberInitExpression init)
  308. {
  309. Visit (init.NewExpression);
  310. Print (" {");
  311. // VisitBindingList (init.Bindings)
  312. VisitList (init.Bindings, VisitBinding);
  313. Print ("}");
  314. }
  315. protected override void VisitListInit (ListInitExpression init)
  316. {
  317. Visit (init.NewExpression);
  318. Print (" {");
  319. // VisitElementInitializerList
  320. VisitList (init.Initializers, VisitElementInitializer);
  321. Print ("}");
  322. }
  323. protected override void VisitNewArray (NewArrayExpression newArray)
  324. {
  325. Print ("new ");
  326. switch (newArray.NodeType) {
  327. case ExpressionType.NewArrayBounds:
  328. Print (newArray.Type);
  329. Print ("(");
  330. VisitExpressionList (newArray.Expressions);
  331. Print (")");
  332. return;
  333. case ExpressionType.NewArrayInit:
  334. Print ("[] {");
  335. VisitExpressionList (newArray.Expressions);
  336. Print ("}");
  337. return;
  338. }
  339. throw new NotSupportedException ();
  340. }
  341. protected override void VisitInvocation (InvocationExpression invocation)
  342. {
  343. Print ("Invoke(");
  344. Visit (invocation.Expression);
  345. if (invocation.Arguments.Count != 0) {
  346. Print (ListSeparator);
  347. VisitExpressionList (invocation.Arguments);
  348. }
  349. Print (")");
  350. }
  351. }
  352. }