ExpressionPrinter.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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. protected override void VisitBinary (BinaryExpression binary)
  165. {
  166. if (binary.NodeType == ExpressionType.ArrayIndex) {
  167. Visit (binary.Left);
  168. Print ("[");
  169. Visit (binary.Right);
  170. Print ("]");
  171. return;
  172. }
  173. Print ("(");
  174. Visit (binary.Left);
  175. Print (" {0} ", OperatorToString (binary));
  176. Visit (binary.Right);
  177. Print (")");
  178. }
  179. protected override void VisitTypeIs (TypeBinaryExpression type)
  180. {
  181. switch (type.NodeType) {
  182. case ExpressionType.TypeIs:
  183. Print ("(");
  184. Visit (type.Expression);
  185. Print (" Is {0})", type.TypeOperand.Name);
  186. return;
  187. }
  188. throw new NotImplementedException ();
  189. }
  190. protected override void VisitConstant (ConstantExpression constant)
  191. {
  192. var value = constant.Value;
  193. if (value == null) {
  194. Print ("null");
  195. } else if (value is string) {
  196. Print ("\"");
  197. Print (value);
  198. Print ("\"");
  199. } else if (!HasStringRepresentation (value)) {
  200. Print ("value(");
  201. Print (value);
  202. Print (")");
  203. } else
  204. Print (value);
  205. }
  206. static bool HasStringRepresentation (object obj)
  207. {
  208. return obj.ToString () != obj.GetType ().ToString ();
  209. }
  210. protected override void VisitConditional (ConditionalExpression conditional)
  211. {
  212. Print ("IIF(");
  213. Visit (conditional.Test);
  214. Print (", ");
  215. Visit (conditional.IfTrue);
  216. Print (", ");
  217. Visit (conditional.IfFalse);
  218. Print (")");
  219. }
  220. protected override void VisitParameter (ParameterExpression parameter)
  221. {
  222. Print (parameter.Name ?? "<param>");
  223. }
  224. protected override void VisitMemberAccess (MemberExpression access)
  225. {
  226. if (access.Expression == null)
  227. Print (access.Member.DeclaringType.Name);
  228. else
  229. Visit (access.Expression);
  230. Print (".{0}", access.Member.Name);
  231. }
  232. protected override void VisitMethodCall (MethodCallExpression call)
  233. {
  234. if (call.Object != null) {
  235. Visit (call.Object);
  236. Print (".");
  237. }
  238. Print (call.Method.Name);
  239. Print ("(");
  240. VisitExpressionList (call.Arguments);
  241. Print (")");
  242. }
  243. protected override void VisitMemberAssignment (MemberAssignment assignment)
  244. {
  245. Print ("{0} = ", assignment.Member.Name);
  246. Visit (assignment.Expression);
  247. }
  248. protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
  249. {
  250. Print (binding.Member.Name);
  251. Print (" = {");
  252. // VisitBindingList (binding.Bindings);
  253. VisitList (binding.Bindings, VisitBinding);
  254. Print ("}");
  255. }
  256. protected override void VisitMemberListBinding (MemberListBinding binding)
  257. {
  258. Print (binding.Member.Name);
  259. Print (" = {");
  260. // replace when the patch to the visitor is in
  261. // VisitElementInitializerList (binding.Initializers);
  262. VisitList (binding.Initializers, VisitElementInitializer);
  263. Print ("}");
  264. }
  265. protected override void VisitList<T> (ReadOnlyCollection<T> list, Action<T> visitor)
  266. {
  267. for (int i = 0; i < list.Count; i++) {
  268. if (i > 0)
  269. Print (ListSeparator);
  270. visitor (list [i]);
  271. }
  272. }
  273. protected override void VisitLambda (LambdaExpression lambda)
  274. {
  275. if (lambda.Parameters.Count != 1) {
  276. Print ("(");
  277. // replace when the patch to the visitor is in
  278. // VisitExpressionList (lambda.Parameters);
  279. VisitList (lambda.Parameters, Visit);
  280. Print (")");
  281. } else
  282. Visit (lambda.Parameters [0]);
  283. Print (" => ");
  284. Visit (lambda.Body);
  285. }
  286. protected override void VisitNew (NewExpression nex)
  287. {
  288. Print ("new {0}(", nex.Type.Name);
  289. if (nex.Members != null && nex.Members.Count > 0) {
  290. for (int i = 0; i < nex.Members.Count; i++) {
  291. if (i > 0)
  292. Print (ListSeparator);
  293. Print ("{0} = ", nex.Members [i].Name);
  294. Visit (nex.Arguments [i]);
  295. }
  296. } else
  297. VisitExpressionList (nex.Arguments);
  298. Print (")");
  299. }
  300. protected override void VisitMemberInit (MemberInitExpression init)
  301. {
  302. Visit (init.NewExpression);
  303. Print (" {");
  304. // VisitBindingList (init.Bindings)
  305. VisitList (init.Bindings, VisitBinding);
  306. Print ("}");
  307. }
  308. protected override void VisitListInit (ListInitExpression init)
  309. {
  310. Visit (init.NewExpression);
  311. Print (" {");
  312. // VisitElementInitializerList
  313. VisitList (init.Initializers, VisitElementInitializer);
  314. Print ("}");
  315. }
  316. protected override void VisitNewArray (NewArrayExpression newArray)
  317. {
  318. Print ("new ");
  319. switch (newArray.NodeType) {
  320. case ExpressionType.NewArrayBounds:
  321. Print (newArray.Type);
  322. Print ("(");
  323. VisitExpressionList (newArray.Expressions);
  324. Print (")");
  325. return;
  326. case ExpressionType.NewArrayInit:
  327. Print ("[] {");
  328. VisitExpressionList (newArray.Expressions);
  329. Print ("}");
  330. return;
  331. }
  332. throw new NotSupportedException ();
  333. }
  334. protected override void VisitInvocation (InvocationExpression invocation)
  335. {
  336. Print ("Invoke(");
  337. Visit (invocation.Expression);
  338. if (invocation.Arguments.Count != 0) {
  339. Print (ListSeparator);
  340. VisitExpressionList (invocation.Arguments);
  341. }
  342. Print (")");
  343. }
  344. }
  345. }