5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
8 // Contains code from the Mono C# compiler:
9 // Marek Safar (marek.safar@seznam.cz)
10 // Martin Baulig (martin@ximian.com)
11 // Raja Harinath (harinath@gmail.com)
13 // (C) 2001-2003 Ximian, Inc.
14 // (C) 2004-2008 Novell, Inc. (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Reflection;
38 using System.Reflection.Emit;
40 namespace System.Linq.Expressions {
42 public sealed class BinaryExpression : Expression {
46 LambdaExpression conversion;
48 bool lift_to_null, is_lifted;
50 public Expression Left {
54 public Expression Right {
58 public MethodInfo Method {
59 get { return method; }
62 public bool IsLifted {
63 get { return is_lifted; }
66 public bool IsLiftedToNull {
67 get { return lift_to_null; }
70 public LambdaExpression Conversion {
71 get { return conversion; }
74 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right)
75 : base (node_type, type)
81 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, MethodInfo method)
82 : base (node_type, type)
89 internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, bool lift_to_null,
90 bool is_lifted, MethodInfo method, LambdaExpression conversion) : base (node_type, type)
95 this.conversion = conversion;
96 this.lift_to_null = lift_to_null;
97 this.is_lifted = is_lifted;
100 void EmitArrayAccess (EmitContext ec)
104 ec.ig.Emit (OpCodes.Ldelem, this.Type);
107 void EmitLogicalBinary (EmitContext ec)
110 case ExpressionType.And:
111 case ExpressionType.Or:
114 else if (Type == typeof (bool?))
115 EmitLiftedLogical (ec);
117 EmitLiftedArithmeticBinary (ec);
119 case ExpressionType.AndAlso:
120 case ExpressionType.OrElse:
122 EmitLogicalShortCircuit (ec);
124 EmitLiftedLogicalShortCircuit (ec);
129 void EmitLogical (EmitContext ec)
131 EmitNonLiftedBinary (ec);
134 void EmitLiftedLogical (EmitContext ec)
137 var and = NodeType == ExpressionType.And;
138 var left = ec.EmitStored (this.left);
139 var right = ec.EmitStored (this.right);
141 var ret_from_left = ig.DefineLabel ();
142 var ret_from_right = ig.DefineLabel ();
143 var done = ig.DefineLabel ();
145 ec.EmitNullableGetValueOrDefault (left);
146 ig.Emit (OpCodes.Brtrue, ret_from_left);
147 ec.EmitNullableGetValueOrDefault (right);
148 ig.Emit (OpCodes.Brtrue, ret_from_right);
150 ec.EmitNullableHasValue (left);
151 ig.Emit (OpCodes.Brfalse, ret_from_left);
153 ig.MarkLabel (ret_from_right);
154 ec.EmitLoad (and ? left : right);
155 ig.Emit (OpCodes.Br, done);
157 ig.MarkLabel (ret_from_left);
158 ec.EmitLoad (and ? right : left);
163 void EmitLogicalShortCircuit (EmitContext ec)
166 var and = NodeType == ExpressionType.AndAlso;
167 var ret = ig.DefineLabel ();
168 var done = ig.DefineLabel ();
171 ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret);
175 ig.Emit (OpCodes.Br, done);
178 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
183 MethodInfo GetFalseOperator ()
185 return left.Type.GetMethod ("op_False", AllStatic);
188 MethodInfo GetTrueOperator ()
190 return left.Type.GetMethod ("op_True", AllStatic);
193 void EmitUserDefinedLogicalShortCircuit (EmitContext ec)
196 var and = NodeType == ExpressionType.AndAlso;
198 var done = ig.DefineLabel ();
200 var left = ec.EmitStored (this.left);
203 ig.Emit (OpCodes.Dup);
204 ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
205 ig.Emit (OpCodes.Brtrue, done);
207 ec.Emit (this.right);
208 ec.EmitCall (method);
213 void EmitLiftedLogicalShortCircuit (EmitContext ec)
216 var and = NodeType == ExpressionType.AndAlso;
217 var left_is_null = ig.DefineLabel ();
218 var ret_from_left = ig.DefineLabel ();
219 var ret_null = ig.DefineLabel ();
220 var ret_new = ig.DefineLabel();
221 var done = ig.DefineLabel();
223 var left = ec.EmitStored (this.left);
225 ec.EmitNullableHasValue (left);
226 ig.Emit (OpCodes.Brfalse, left_is_null);
228 ec.EmitNullableGetValueOrDefault (left);
230 ig.Emit (OpCodes.Ldc_I4_0);
231 ig.Emit (OpCodes.Ceq);
232 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
234 ig.MarkLabel (left_is_null);
235 var right = ec.EmitStored (this.right);
237 ec.EmitNullableHasValue (right);
238 ig.Emit (OpCodes.Brfalse_S, ret_null);
240 ec.EmitNullableGetValueOrDefault (right);
242 ig.Emit (OpCodes.Ldc_I4_0);
243 ig.Emit (OpCodes.Ceq);
245 ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
247 ec.EmitNullableHasValue (left);
248 ig.Emit (OpCodes.Brfalse, ret_null);
250 ig.Emit (and ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
251 ig.Emit (OpCodes.Br_S, ret_new);
253 ig.MarkLabel (ret_from_left);
254 ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
256 ig.MarkLabel (ret_new);
257 ec.EmitNullableNew (typeof (bool?));
258 ig.Emit (OpCodes.Br, done);
260 ig.MarkLabel (ret_null);
261 var ret = ig.DeclareLocal (typeof (bool?));
262 ec.EmitNullableInitialize (ret);
267 void EmitCoalesce (EmitContext ec)
270 var done = ig.DefineLabel ();
271 var load_right = ig.DefineLabel ();
273 var left = ec.EmitStored (this.left);
274 var left_is_nullable = left.LocalType.IsNullable ();
276 if (left_is_nullable)
277 ec.EmitNullableHasValue (left);
281 ig.Emit (OpCodes.Brfalse, load_right);
283 if (left_is_nullable && !Type.IsNullable ())
284 ec.EmitNullableGetValue (left);
288 ig.Emit (OpCodes.Br, done);
290 ig.MarkLabel (load_right);
291 ec.Emit (this.right);
296 void EmitConvertedCoalesce (EmitContext ec)
298 throw new NotImplementedException ();
301 static bool IsInt32OrInt64 (Type type)
303 return type == typeof (int) || type == typeof (long);
306 static bool IsSingleOrDouble (Type type)
308 return type == typeof (float) || type == typeof (double);
311 void EmitBinaryOperator (EmitContext ec)
314 bool is_unsigned = IsUnsigned (left.Type);
317 case ExpressionType.Add:
318 ig.Emit (OpCodes.Add);
320 case ExpressionType.AddChecked:
321 if (IsInt32OrInt64 (left.Type))
322 ig.Emit (OpCodes.Add_Ovf);
324 ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
326 case ExpressionType.Subtract:
327 ig.Emit (OpCodes.Sub);
329 case ExpressionType.SubtractChecked:
330 if (IsInt32OrInt64 (left.Type))
331 ig.Emit (OpCodes.Sub_Ovf);
333 ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
335 case ExpressionType.Multiply:
336 ig.Emit (OpCodes.Mul);
338 case ExpressionType.MultiplyChecked:
339 if (IsInt32OrInt64 (left.Type))
340 ig.Emit (OpCodes.Mul_Ovf);
342 ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
344 case ExpressionType.Divide:
345 ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
347 case ExpressionType.Modulo:
348 ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
350 case ExpressionType.RightShift:
351 ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
353 case ExpressionType.LeftShift:
354 ig.Emit (OpCodes.Shl);
356 case ExpressionType.And:
357 ig.Emit (OpCodes.And);
359 case ExpressionType.Or:
360 ig.Emit (OpCodes.Or);
362 case ExpressionType.ExclusiveOr:
363 ig.Emit (OpCodes.Xor);
365 case ExpressionType.GreaterThan:
366 ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
368 case ExpressionType.GreaterThanOrEqual:
369 if (is_unsigned || IsSingleOrDouble (left.Type))
370 ig.Emit (OpCodes.Clt_Un);
372 ig.Emit (OpCodes.Clt);
374 ig.Emit (OpCodes.Ldc_I4_0);
375 ig.Emit (OpCodes.Ceq);
377 case ExpressionType.LessThan:
378 ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
380 case ExpressionType.LessThanOrEqual:
381 if (is_unsigned || IsSingleOrDouble (left.Type))
382 ig.Emit (OpCodes.Cgt_Un);
384 ig.Emit (OpCodes.Cgt);
386 ig.Emit (OpCodes.Ldc_I4_0);
387 ig.Emit (OpCodes.Ceq);
389 case ExpressionType.Equal:
390 ig.Emit (OpCodes.Ceq);
392 case ExpressionType.NotEqual:
393 ig.Emit (OpCodes.Ceq);
394 ig.Emit (OpCodes.Ldc_I4_0);
395 ig.Emit (OpCodes.Ceq);
397 case ExpressionType.Power:
398 ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
401 throw new InvalidOperationException (
402 string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
406 bool IsLeftLiftedBinary ()
408 return left.Type.IsNullable () && !right.Type.IsNullable ();
411 void EmitLeftLiftedToNullBinary (EmitContext ec)
415 var ret = ig.DefineLabel ();
416 var done = ig.DefineLabel ();
418 var left = ec.EmitStored (this.left);
420 ec.EmitNullableHasValue (left);
421 ig.Emit (OpCodes.Brfalse, ret);
423 ec.EmitNullableGetValueOrDefault (left);
426 EmitBinaryOperator (ec);
428 ec.EmitNullableNew (Type);
430 ig.Emit (OpCodes.Br, done);
434 var temp = ig.DeclareLocal (Type);
435 ec.EmitNullableInitialize (temp);
440 void EmitLiftedArithmeticBinary (EmitContext ec)
442 if (IsLeftLiftedBinary ())
443 EmitLeftLiftedToNullBinary (ec);
445 EmitLiftedToNullBinary (ec);
448 void EmitLiftedToNullBinary (EmitContext ec)
451 var left = ec.EmitStored (this.left);
452 var right = ec.EmitStored (this.right);
453 var result = ig.DeclareLocal (Type);
455 var has_value = ig.DefineLabel ();
456 var done = ig.DefineLabel ();
458 ec.EmitNullableHasValue (left);
459 ec.EmitNullableHasValue (right);
460 ig.Emit (OpCodes.And);
461 ig.Emit (OpCodes.Brtrue, has_value);
463 ec.EmitNullableInitialize (result);
465 ig.Emit (OpCodes.Br, done);
467 ig.MarkLabel (has_value);
469 ec.EmitNullableGetValueOrDefault (left);
470 ec.EmitNullableGetValueOrDefault (right);
472 EmitBinaryOperator (ec);
474 ec.EmitNullableNew (result.LocalType);
479 void EmitLiftedRelationalBinary (EmitContext ec)
482 var left = ec.EmitStored (this.left);
483 var right = ec.EmitStored (this.right);
485 var ret = ig.DefineLabel ();
486 var done = ig.DefineLabel ();
488 ec.EmitNullableGetValueOrDefault (left);
489 ec.EmitNullableGetValueOrDefault (right);
492 case ExpressionType.Equal:
493 case ExpressionType.NotEqual:
494 ig.Emit (OpCodes.Bne_Un, ret);
497 EmitBinaryOperator (ec);
498 ig.Emit (OpCodes.Brfalse, ret);
502 ec.EmitNullableHasValue (left);
503 ec.EmitNullableHasValue (right);
506 case ExpressionType.Equal:
507 ig.Emit (OpCodes.Ceq);
509 case ExpressionType.NotEqual:
510 ig.Emit (OpCodes.Ceq);
511 ig.Emit (OpCodes.Ldc_I4_0);
512 ig.Emit (OpCodes.Ceq);
515 ig.Emit (OpCodes.And);
519 ig.Emit (OpCodes.Br, done);
523 ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
528 void EmitArithmeticBinary (EmitContext ec)
531 EmitNonLiftedBinary (ec);
533 EmitLiftedArithmeticBinary (ec);
536 void EmitNonLiftedBinary (EmitContext ec)
540 EmitBinaryOperator (ec);
543 void EmitRelationalBinary (EmitContext ec)
546 EmitNonLiftedBinary (ec);
547 else if (IsLiftedToNull)
548 EmitLiftedToNullBinary (ec);
550 EmitLiftedRelationalBinary (ec);
553 void EmitLiftedUserDefinedOperator (EmitContext ec)
557 var ret_true = ig.DefineLabel ();
558 var ret_false = ig.DefineLabel ();
559 var done = ig.DefineLabel ();
561 var left = ec.EmitStored (this.left);
562 var right = ec.EmitStored (this.right);
564 ec.EmitNullableHasValue (left);
565 ec.EmitNullableHasValue (right);
567 case ExpressionType.Equal:
568 ig.Emit (OpCodes.Bne_Un, ret_false);
569 ec.EmitNullableHasValue (left);
570 ig.Emit (OpCodes.Brfalse, ret_true);
572 case ExpressionType.NotEqual:
573 ig.Emit (OpCodes.Bne_Un, ret_true);
574 ec.EmitNullableHasValue (left);
575 ig.Emit (OpCodes.Brfalse, ret_false);
578 ig.Emit (OpCodes.And);
579 ig.Emit (OpCodes.Brfalse, ret_false);
583 ec.EmitNullableGetValueOrDefault (left);
584 ec.EmitNullableGetValueOrDefault (right);
585 ec.EmitCall (method);
586 ig.Emit (OpCodes.Br, done);
588 ig.MarkLabel (ret_true);
589 ig.Emit (OpCodes.Ldc_I4_1);
590 ig.Emit (OpCodes.Br, done);
592 ig.MarkLabel (ret_false);
593 ig.Emit (OpCodes.Ldc_I4_0);
594 ig.Emit (OpCodes.Br, done);
599 void EmitLiftedToNullUserDefinedOperator (EmitContext ec)
603 var ret = ig.DefineLabel ();
604 var done = ig.DefineLabel ();
606 var left = ec.EmitStored (this.left);
607 var right = ec.EmitStored (this.right);
609 ec.EmitNullableHasValue (left);
610 ec.EmitNullableHasValue (right);
611 ig.Emit (OpCodes.And);
612 ig.Emit (OpCodes.Brfalse, ret);
614 ec.EmitNullableGetValueOrDefault (left);
615 ec.EmitNullableGetValueOrDefault (right);
616 ec.EmitCall (method);
617 ec.EmitNullableNew (Type);
618 ig.Emit (OpCodes.Br, done);
621 var temp = ig.DeclareLocal (Type);
622 ec.EmitNullableInitialize (temp);
627 void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
629 throw new NotImplementedException ();
632 void EmitUserDefinedOperator (EmitContext ec)
636 case ExpressionType.AndAlso:
637 case ExpressionType.OrElse:
638 EmitUserDefinedLogicalShortCircuit (ec);
643 ec.EmitCall (method);
646 } else if (IsLiftedToNull) {
648 case ExpressionType.AndAlso:
649 case ExpressionType.OrElse:
650 EmitUserDefinedLiftedLogicalShortCircuit (ec);
653 EmitLiftedToNullUserDefinedOperator (ec);
657 EmitLiftedUserDefinedOperator (ec);
660 internal override void Emit (EmitContext ec)
663 EmitUserDefinedOperator (ec);
668 case ExpressionType.ArrayIndex:
669 EmitArrayAccess (ec);
671 case ExpressionType.Coalesce:
672 if (conversion != null)
673 EmitConvertedCoalesce (ec);
677 case ExpressionType.Power:
678 case ExpressionType.Add:
679 case ExpressionType.AddChecked:
680 case ExpressionType.Divide:
681 case ExpressionType.ExclusiveOr:
682 case ExpressionType.LeftShift:
683 case ExpressionType.Modulo:
684 case ExpressionType.Multiply:
685 case ExpressionType.MultiplyChecked:
686 case ExpressionType.RightShift:
687 case ExpressionType.Subtract:
688 case ExpressionType.SubtractChecked:
689 EmitArithmeticBinary (ec);
691 case ExpressionType.Equal:
692 case ExpressionType.GreaterThan:
693 case ExpressionType.GreaterThanOrEqual:
694 case ExpressionType.LessThan:
695 case ExpressionType.LessThanOrEqual:
696 case ExpressionType.NotEqual:
697 EmitRelationalBinary (ec);
699 case ExpressionType.And:
700 case ExpressionType.Or:
701 case ExpressionType.AndAlso:
702 case ExpressionType.OrElse:
703 EmitLogicalBinary (ec);
706 throw new NotSupportedException (this.NodeType.ToString ());