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
);