2 // ExpressionPrinter.cs
5 // Jb Evain (jbevain@novell.com)
7 // (C) 2008 Novell, Inc. (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
34 namespace System.Linq.Expressions {
36 class ExpressionPrinter : ExpressionVisitor {
38 StringBuilder builder;
40 const string ListSeparator = ", ";
42 ExpressionPrinter (StringBuilder builder)
44 this.builder = builder;
47 ExpressionPrinter () : this (new StringBuilder ())
51 public static string ToString (Expression expression)
53 var printer = new ExpressionPrinter ();
54 printer.Visit (expression);
55 return printer.builder.ToString ();
58 public static string ToString (ElementInit init)
60 var printer = new ExpressionPrinter ();
61 printer.VisitElementInitializer (init);
62 return printer.builder.ToString ();
65 public static string ToString (MemberBinding binding)
67 var printer = new ExpressionPrinter ();
68 printer.VisitBinding (binding);
69 return printer.builder.ToString ();
72 void Print (string str)
77 void Print (object obj)
82 void Print (string str, params object [] objs)
84 builder.AppendFormat (str, objs);
87 protected override void VisitElementInitializer (ElementInit initializer)
89 Print (initializer.AddMethod);
91 VisitExpressionList (initializer.Arguments);
95 protected override void VisitUnary (UnaryExpression unary)
97 switch (unary.NodeType) {
98 case ExpressionType.ArrayLength:
99 case ExpressionType.Convert:
100 case ExpressionType.ConvertChecked:
101 case ExpressionType.Not:
102 Print ("{0}(", unary.NodeType);
103 Visit (unary.Operand);
106 case ExpressionType.Negate:
108 Visit (unary.Operand);
110 case ExpressionType.Quote:
111 Visit (unary.Operand);
113 case ExpressionType.TypeAs:
115 Visit (unary.Operand);
116 Print (" As {0})", unary.Type.Name);
118 case ExpressionType.UnaryPlus:
120 Visit (unary.Operand);
124 throw new NotImplementedException ();
127 static string OperatorToString (BinaryExpression binary)
129 switch (binary.NodeType) {
130 case ExpressionType.Add:
131 case ExpressionType.AddChecked:
133 case ExpressionType.AndAlso:
135 case ExpressionType.Coalesce:
137 case ExpressionType.Divide:
139 case ExpressionType.Equal:
141 case ExpressionType.ExclusiveOr:
143 case ExpressionType.GreaterThan:
145 case ExpressionType.GreaterThanOrEqual:
147 case ExpressionType.LeftShift:
149 case ExpressionType.LessThan:
151 case ExpressionType.LessThanOrEqual:
153 case ExpressionType.Modulo:
155 case ExpressionType.Multiply:
156 case ExpressionType.MultiplyChecked:
158 case ExpressionType.NotEqual:
160 case ExpressionType.OrElse:
162 case ExpressionType.Power:
164 case ExpressionType.RightShift:
166 case ExpressionType.Subtract:
167 case ExpressionType.SubtractChecked:
169 case ExpressionType.And:
170 return IsBoolean (binary) ? "And" : "&";
171 case ExpressionType.Or:
172 return IsBoolean (binary) ? "Or" : "|";
178 static bool IsBoolean (Expression expression)
180 return expression.Type == typeof (bool) || expression.Type == typeof (bool?);
183 void PrintArrayIndex (BinaryExpression index)
191 protected override void VisitBinary (BinaryExpression binary)
193 switch (binary.NodeType) {
194 case ExpressionType.ArrayIndex:
195 PrintArrayIndex (binary);
200 Print (" {0} ", OperatorToString (binary));
201 Visit (binary.Right);
207 protected override void VisitTypeIs (TypeBinaryExpression type)
209 switch (type.NodeType) {
210 case ExpressionType.TypeIs:
212 Visit (type.Expression);
213 Print (" Is {0})", type.TypeOperand.Name);
217 throw new NotImplementedException ();
220 protected override void VisitConstant (ConstantExpression constant)
222 var value = constant.Value;
226 } else if (value is string) {
230 } else if (!HasStringRepresentation (value)) {
238 static bool HasStringRepresentation (object obj)
240 return obj.ToString () != obj.GetType ().ToString ();
243 protected override void VisitConditional (ConditionalExpression conditional)
246 Visit (conditional.Test);
247 Print (ListSeparator);
248 Visit (conditional.IfTrue);
249 Print (ListSeparator);
250 Visit (conditional.IfFalse);
254 protected override void VisitParameter (ParameterExpression parameter)
256 Print (parameter.Name ?? "<param>");
259 protected override void VisitMemberAccess (MemberExpression access)
261 if (access.Expression == null)
262 Print (access.Member.DeclaringType.Name);
264 Visit (access.Expression);
266 Print (".{0}", access.Member.Name);
269 protected override void VisitMethodCall (MethodCallExpression call)
271 if (call.Object != null) {
275 Print (call.Method.Name);
277 VisitExpressionList (call.Arguments);
281 protected override void VisitMemberAssignment (MemberAssignment assignment)
283 Print ("{0} = ", assignment.Member.Name);
284 Visit (assignment.Expression);
287 protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
289 Print (binding.Member.Name);
291 // VisitBindingList (binding.Bindings);
292 VisitList (binding.Bindings, VisitBinding);
296 protected override void VisitMemberListBinding (MemberListBinding binding)
298 Print (binding.Member.Name);
300 // replace when the patch to the visitor is in
301 // VisitElementInitializerList (binding.Initializers);
302 VisitList (binding.Initializers, VisitElementInitializer);
306 protected override void VisitList<T> (ReadOnlyCollection<T> list, Action<T> visitor)
308 for (int i = 0; i < list.Count; i++) {
310 Print (ListSeparator);
316 protected override void VisitLambda (LambdaExpression lambda)
318 if (lambda.Parameters.Count != 1) {
320 // replace when the patch to the visitor is in
321 // VisitExpressionList (lambda.Parameters);
322 VisitList (lambda.Parameters, Visit);
325 Visit (lambda.Parameters [0]);
331 protected override void VisitNew (NewExpression nex)
333 Print ("new {0}(", nex.Type.Name);
334 if (nex.Members != null && nex.Members.Count > 0) {
335 for (int i = 0; i < nex.Members.Count; i++) {
337 Print (ListSeparator);
339 Print ("{0} = ", nex.Members [i].Name);
340 Visit (nex.Arguments [i]);
343 VisitExpressionList (nex.Arguments);
347 protected override void VisitMemberInit (MemberInitExpression init)
349 Visit (init.NewExpression);
351 // VisitBindingList (init.Bindings)
352 VisitList (init.Bindings, VisitBinding);
356 protected override void VisitListInit (ListInitExpression init)
358 Visit (init.NewExpression);
360 // VisitElementInitializerList
361 VisitList (init.Initializers, VisitElementInitializer);
365 protected override void VisitNewArray (NewArrayExpression newArray)
368 switch (newArray.NodeType) {
369 case ExpressionType.NewArrayBounds:
370 Print (newArray.Type);
372 VisitExpressionList (newArray.Expressions);
375 case ExpressionType.NewArrayInit:
377 VisitExpressionList (newArray.Expressions);
382 throw new NotSupportedException ();
385 protected override void VisitInvocation (InvocationExpression invocation)
388 Visit (invocation.Expression);
390 if (invocation.Arguments.Count != 0) {
391 Print (ListSeparator);
392 VisitExpressionList (invocation.Arguments);