ExpressionPrinter.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. Print ("{0}(", unary.NodeType);
  85. Visit (unary.Operand);
  86. Print (")");
  87. return;
  88. case ExpressionType.Negate:
  89. Print ("-");
  90. Visit (unary.Operand);
  91. return;
  92. case ExpressionType.Not:
  93. Print ("Not(");
  94. Visit (unary.Operand);
  95. Print (")");
  96. return;
  97. case ExpressionType.Quote:
  98. Visit (unary.Operand);
  99. return;
  100. case ExpressionType.TypeAs:
  101. Print ("(");
  102. Visit (unary.Operand);
  103. Print (" As {0})", unary.Type.Name);
  104. return;
  105. case ExpressionType.UnaryPlus:
  106. Print ("+");
  107. Visit (unary.Operand);
  108. return;
  109. }
  110. throw new NotImplementedException ();
  111. }
  112. static string OperatorToString (BinaryExpression binary)
  113. {
  114. switch (binary.NodeType) {
  115. case ExpressionType.Add:
  116. case ExpressionType.AddChecked:
  117. return "+";
  118. case ExpressionType.AndAlso:
  119. return "&&";
  120. case ExpressionType.Coalesce:
  121. return "??";
  122. case ExpressionType.Divide:
  123. return "/";
  124. case ExpressionType.Equal:
  125. return "=";
  126. case ExpressionType.ExclusiveOr:
  127. return "^";
  128. case ExpressionType.GreaterThan:
  129. return ">";
  130. case ExpressionType.GreaterThanOrEqual:
  131. return ">=";
  132. case ExpressionType.LeftShift:
  133. return "<<";
  134. case ExpressionType.LessThan:
  135. return "<";
  136. case ExpressionType.LessThanOrEqual:
  137. return "<=";
  138. case ExpressionType.Modulo:
  139. return "%";
  140. case ExpressionType.Multiply:
  141. case ExpressionType.MultiplyChecked:
  142. return "*";
  143. case ExpressionType.NotEqual:
  144. return "!=";
  145. case ExpressionType.OrElse:
  146. return "||";
  147. case ExpressionType.Power:
  148. return "^";
  149. case ExpressionType.RightShift:
  150. return ">>";
  151. case ExpressionType.Subtract:
  152. case ExpressionType.SubtractChecked:
  153. return "-";
  154. case ExpressionType.And:
  155. return IsBoolean (binary) ? "And" : "&";
  156. case ExpressionType.Or:
  157. return IsBoolean (binary) ? "Or" : "|";
  158. default:
  159. return null;
  160. }
  161. }
  162. static bool IsBoolean (Expression expression)
  163. {
  164. return expression.Type == typeof (bool) || expression.Type == typeof (bool?);
  165. }
  166. protected override void VisitBinary (BinaryExpression binary)
  167. {
  168. if (binary.NodeType == ExpressionType.ArrayIndex) {
  169. Visit (binary.Left);
  170. Print ("[");
  171. Visit (binary.Right);
  172. Print ("]");
  173. return;
  174. }
  175. Print ("(");
  176. Visit (binary.Left);
  177. Print (" {0} ", OperatorToString (binary));
  178. Visit (binary.Right);
  179. Print (")");
  180. }
  181. protected override void VisitTypeIs (TypeBinaryExpression type)
  182. {
  183. switch (type.NodeType) {
  184. case ExpressionType.TypeIs:
  185. Print ("(");
  186. Visit (type.Expression);
  187. Print (" Is {0})", type.TypeOperand.Name);
  188. return;
  189. }
  190. throw new NotImplementedException ();
  191. }
  192. protected override void VisitConstant (ConstantExpression constant)
  193. {
  194. var value = constant.Value;
  195. if (value == null) {
  196. Print ("null");
  197. } else if (value is string) {
  198. Print ("\"");
  199. Print (value);
  200. Print ("\"");
  201. } else if (!HasStringRepresentation (value)) {
  202. Print ("value(");
  203. Print (value);
  204. Print (")");
  205. } else
  206. Print (value);
  207. }
  208. static bool HasStringRepresentation (object obj)
  209. {
  210. return obj.ToString () != obj.GetType ().ToString ();
  211. }
  212. protected override void VisitConditional (ConditionalExpression conditional)
  213. {
  214. Print ("IIF(");
  215. Visit (conditional.Test);
  216. Print (", ");
  217. Visit (conditional.IfTrue);
  218. Print (", ");
  219. Visit (conditional.IfFalse);
  220. Print (")");
  221. }
  222. protected override void VisitParameter (ParameterExpression parameter)
  223. {
  224. Print (parameter.Name ?? "<param>");
  225. }
  226. protected override void VisitMemberAccess (MemberExpression access)
  227. {
  228. if (access.Expression == null)
  229. Print (access.Member.DeclaringType.Name);
  230. else
  231. Visit (access.Expression);
  232. Print (".{0}", access.Member.Name);
  233. }
  234. protected override void VisitMethodCall (MethodCallExpression call)
  235. {
  236. if (call.Object != null) {
  237. Visit (call.Object);
  238. Print (".");
  239. }
  240. Print (call.Method.Name);
  241. Print ("(");
  242. VisitExpressionList (call.Arguments);
  243. Print (")");
  244. }
  245. protected override void VisitMemberAssignment (MemberAssignment assignment)
  246. {
  247. Print ("{0} = ", assignment.Member.Name);
  248. Visit (assignment.Expression);
  249. }
  250. protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
  251. {
  252. throw new NotImplementedException ();
  253. }
  254. protected override void VisitMemberListBinding (MemberListBinding binding)
  255. {
  256. Print (binding.Member.Name);
  257. Print (" = {");
  258. // replace when the patch to the visitor is in
  259. // VisitElementInitializerList (binding.Initializers);
  260. VisitList (binding.Initializers, VisitElementInitializer);
  261. Print ("}");
  262. }
  263. protected override void VisitList<T> (ReadOnlyCollection<T> list, Action<T> visitor)
  264. {
  265. for (int i = 0; i < list.Count; i++) {
  266. if (i > 0)
  267. Print (ListSeparator);
  268. visitor (list [i]);
  269. }
  270. }
  271. protected override void VisitLambda (LambdaExpression lambda)
  272. {
  273. if (lambda.Parameters.Count != 1) {
  274. Print ("(");
  275. // replace when the patch to the visitor is in
  276. // VisitExpressionList (lambda.Parameters);
  277. VisitList (lambda.Parameters, Visit);
  278. Print (")");
  279. } else
  280. Visit (lambda.Parameters [0]);
  281. Print (" => ");
  282. Visit (lambda.Body);
  283. }
  284. protected override void VisitNew (NewExpression nex)
  285. {
  286. Print ("new {0}(", nex.Type.Name);
  287. VisitExpressionList (nex.Arguments);
  288. Print (")");
  289. }
  290. protected override void VisitMemberInit (MemberInitExpression init)
  291. {
  292. throw new NotImplementedException ();
  293. }
  294. protected override void VisitListInit (ListInitExpression init)
  295. {
  296. throw new NotImplementedException ();
  297. }
  298. protected override void VisitNewArray (NewArrayExpression newArray)
  299. {
  300. Print ("new ");
  301. switch (newArray.NodeType) {
  302. case ExpressionType.NewArrayBounds:
  303. Print (newArray.Type);
  304. Print ("(");
  305. VisitExpressionList (newArray.Expressions);
  306. Print (")");
  307. return;
  308. case ExpressionType.NewArrayInit:
  309. Print ("[] {");
  310. VisitExpressionList (newArray.Expressions);
  311. Print ("}");
  312. return;
  313. }
  314. throw new NotSupportedException ();
  315. }
  316. protected override void VisitInvocation (InvocationExpression invocation)
  317. {
  318. Print ("Invoke(");
  319. Visit (invocation.Expression);
  320. if (invocation.Arguments.Count != 0) {
  321. Print (ListSeparator);
  322. VisitExpressionList (invocation.Arguments);
  323. }
  324. Print (")");
  325. }
  326. }
  327. }