2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Core / System.Linq.Expressions / ExpressionPrinter.cs
blobe94d40c6bdfbdde624f087a5869157e661c85762
1 //
2 // ExpressionPrinter.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@novell.com)
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:
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.
29 using System;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Text;
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)
74 builder.Append (str);
77 void Print (object obj)
79 builder.Append (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);
90 Print ("(");
91 VisitExpressionList (initializer.Arguments);
92 Print (")");
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);
104 Print (")");
105 return;
106 case ExpressionType.Negate:
107 Print ("-");
108 Visit (unary.Operand);
109 return;
110 case ExpressionType.Quote:
111 Visit (unary.Operand);
112 return;
113 case ExpressionType.TypeAs:
114 Print ("(");
115 Visit (unary.Operand);
116 Print (" As {0})", unary.Type.Name);
117 return;
118 case ExpressionType.UnaryPlus:
119 Print ("+");
120 Visit (unary.Operand);
121 return;
124 throw new NotImplementedException ();
127 static string OperatorToString (BinaryExpression binary)
129 switch (binary.NodeType) {
130 case ExpressionType.Add:
131 case ExpressionType.AddChecked:
132 return "+";
133 case ExpressionType.AndAlso:
134 return "&&";
135 case ExpressionType.Coalesce:
136 return "??";
137 case ExpressionType.Divide:
138 return "/";
139 case ExpressionType.Equal:
140 return "=";
141 case ExpressionType.ExclusiveOr:
142 return "^";
143 case ExpressionType.GreaterThan:
144 return ">";
145 case ExpressionType.GreaterThanOrEqual:
146 return ">=";
147 case ExpressionType.LeftShift:
148 return "<<";
149 case ExpressionType.LessThan:
150 return "<";
151 case ExpressionType.LessThanOrEqual:
152 return "<=";
153 case ExpressionType.Modulo:
154 return "%";
155 case ExpressionType.Multiply:
156 case ExpressionType.MultiplyChecked:
157 return "*";
158 case ExpressionType.NotEqual:
159 return "!=";
160 case ExpressionType.OrElse:
161 return "||";
162 case ExpressionType.Power:
163 return "^";
164 case ExpressionType.RightShift:
165 return ">>";
166 case ExpressionType.Subtract:
167 case ExpressionType.SubtractChecked:
168 return "-";
169 case ExpressionType.And:
170 return IsBoolean (binary) ? "And" : "&";
171 case ExpressionType.Or:
172 return IsBoolean (binary) ? "Or" : "|";
173 default:
174 return null;
178 static bool IsBoolean (Expression expression)
180 return expression.Type == typeof (bool) || expression.Type == typeof (bool?);
183 void PrintArrayIndex (BinaryExpression index)
185 Visit (index.Left);
186 Print ("[");
187 Visit (index.Right);
188 Print ("]");
191 protected override void VisitBinary (BinaryExpression binary)
193 switch (binary.NodeType) {
194 case ExpressionType.ArrayIndex:
195 PrintArrayIndex (binary);
196 return;
197 default:
198 Print ("(");
199 Visit (binary.Left);
200 Print (" {0} ", OperatorToString (binary));
201 Visit (binary.Right);
202 Print (")");
203 return;
207 protected override void VisitTypeIs (TypeBinaryExpression type)
209 switch (type.NodeType) {
210 case ExpressionType.TypeIs:
211 Print ("(");
212 Visit (type.Expression);
213 Print (" Is {0})", type.TypeOperand.Name);
214 return;
217 throw new NotImplementedException ();
220 protected override void VisitConstant (ConstantExpression constant)
222 var value = constant.Value;
224 if (value == null) {
225 Print ("null");
226 } else if (value is string) {
227 Print ("\"");
228 Print (value);
229 Print ("\"");
230 } else if (!HasStringRepresentation (value)) {
231 Print ("value(");
232 Print (value);
233 Print (")");
234 } else
235 Print (value);
238 static bool HasStringRepresentation (object obj)
240 return obj.ToString () != obj.GetType ().ToString ();
243 protected override void VisitConditional (ConditionalExpression conditional)
245 Print ("IIF(");
246 Visit (conditional.Test);
247 Print (ListSeparator);
248 Visit (conditional.IfTrue);
249 Print (ListSeparator);
250 Visit (conditional.IfFalse);
251 Print (")");
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);
263 else
264 Visit (access.Expression);
266 Print (".{0}", access.Member.Name);
269 protected override void VisitMethodCall (MethodCallExpression call)
271 if (call.Object != null) {
272 Visit (call.Object);
273 Print (".");
275 Print (call.Method.Name);
276 Print ("(");
277 VisitExpressionList (call.Arguments);
278 Print (")");
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);
290 Print (" = {");
291 // VisitBindingList (binding.Bindings);
292 VisitList (binding.Bindings, VisitBinding);
293 Print ("}");
296 protected override void VisitMemberListBinding (MemberListBinding binding)
298 Print (binding.Member.Name);
299 Print (" = {");
300 // replace when the patch to the visitor is in
301 // VisitElementInitializerList (binding.Initializers);
302 VisitList (binding.Initializers, VisitElementInitializer);
303 Print ("}");
306 protected override void VisitList<T> (ReadOnlyCollection<T> list, Action<T> visitor)
308 for (int i = 0; i < list.Count; i++) {
309 if (i > 0)
310 Print (ListSeparator);
312 visitor (list [i]);
316 protected override void VisitLambda (LambdaExpression lambda)
318 if (lambda.Parameters.Count != 1) {
319 Print ("(");
320 // replace when the patch to the visitor is in
321 // VisitExpressionList (lambda.Parameters);
322 VisitList (lambda.Parameters, Visit);
323 Print (")");
324 } else
325 Visit (lambda.Parameters [0]);
327 Print (" => ");
328 Visit (lambda.Body);
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++) {
336 if (i > 0)
337 Print (ListSeparator);
339 Print ("{0} = ", nex.Members [i].Name);
340 Visit (nex.Arguments [i]);
342 } else
343 VisitExpressionList (nex.Arguments);
344 Print (")");
347 protected override void VisitMemberInit (MemberInitExpression init)
349 Visit (init.NewExpression);
350 Print (" {");
351 // VisitBindingList (init.Bindings)
352 VisitList (init.Bindings, VisitBinding);
353 Print ("}");
356 protected override void VisitListInit (ListInitExpression init)
358 Visit (init.NewExpression);
359 Print (" {");
360 // VisitElementInitializerList
361 VisitList (init.Initializers, VisitElementInitializer);
362 Print ("}");
365 protected override void VisitNewArray (NewArrayExpression newArray)
367 Print ("new ");
368 switch (newArray.NodeType) {
369 case ExpressionType.NewArrayBounds:
370 Print (newArray.Type);
371 Print ("(");
372 VisitExpressionList (newArray.Expressions);
373 Print (")");
374 return;
375 case ExpressionType.NewArrayInit:
376 Print ("[] {");
377 VisitExpressionList (newArray.Expressions);
378 Print ("}");
379 return;
382 throw new NotSupportedException ();
385 protected override void VisitInvocation (InvocationExpression invocation)
387 Print ("Invoke(");
388 Visit (invocation.Expression);
390 if (invocation.Arguments.Count != 0) {
391 Print (ListSeparator);
392 VisitExpressionList (invocation.Arguments);
395 Print (")");