1 // 2 // cfold.cs: Constant Folding 3 // 4 // Author: 5 // Miguel de Icaza (miguel@ximian.com) 6 // Marek Safar (marek.safar@seznam.cz) 7 // 8 // Copyright 2002, 2003 Ximian, Inc. 9 // Copyright 2003-2011, Novell, Inc. 10 // 11 using System; 12 13 namespace Mono.CSharp { 14 15 public static class ConstantFold 16 { CreateBinaryPromotionsTypes(BuiltinTypes types)17 public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types) 18 { 19 return new TypeSpec[] { 20 types.Decimal, types.Double, types.Float, 21 types.ULong, types.Long, types.UInt 22 }; 23 } 24 25 // 26 // Performs the numeric promotions on the left and right expresions 27 // and deposits the results on `lc' and `rc'. 28 // 29 // On success, the types of `lc' and `rc' on output will always match, 30 // and the pair will be one of: 31 // 32 // TODO: BinaryFold should be called as an optimization step only, 33 // error checking here is weak 34 // DoBinaryNumericPromotions(ResolveContext rc, ref Constant left, ref Constant right)35 static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right) 36 { 37 TypeSpec ltype = left.Type; 38 TypeSpec rtype = right.Type; 39 40 foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) { 41 if (t == ltype) 42 return t == rtype || ConvertPromotion (rc, ref right, ref left, t); 43 44 if (t == rtype) 45 return t == ltype || ConvertPromotion (rc, ref left, ref right, t); 46 } 47 48 left = left.ConvertImplicitly (rc.BuiltinTypes.Int); 49 right = right.ConvertImplicitly (rc.BuiltinTypes.Int); 50 return left != null && right != null; 51 } 52 ConvertPromotion(ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)53 static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type) 54 { 55 Constant c = prim.ConvertImplicitly (type); 56 if (c != null) { 57 prim = c; 58 return true; 59 } 60 61 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) { 62 type = rc.BuiltinTypes.Long; 63 prim = prim.ConvertImplicitly (type); 64 second = second.ConvertImplicitly (type); 65 return prim != null && second != null; 66 } 67 68 return false; 69 } 70 Error_CompileTimeOverflow(ResolveContext rc, Location loc)71 internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc) 72 { 73 rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode"); 74 } 75 76 /// <summary> 77 /// Constant expression folder for binary operations. 78 /// 79 /// Returns null if the expression can not be folded. 80 /// </summary> BinaryFold(ResolveContext ec, Binary.Operator oper, Constant left, Constant right, Location loc)81 static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper, 82 Constant left, Constant right, Location loc) 83 { 84 Constant result = null; 85 86 if (left is EmptyConstantCast) 87 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc); 88 89 if (left is SideEffectConstant) { 90 result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc); 91 if (result == null) 92 return null; 93 return new SideEffectConstant (result, left, loc); 94 } 95 96 if (right is EmptyConstantCast) 97 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc); 98 99 if (right is SideEffectConstant) { 100 result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc); 101 if (result == null) 102 return null; 103 return new SideEffectConstant (result, right, loc); 104 } 105 106 TypeSpec lt = left.Type; 107 TypeSpec rt = right.Type; 108 bool bool_res; 109 110 if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) { 111 bool lv = (bool) left.GetValue (); 112 bool rv = (bool) right.GetValue (); 113 switch (oper) { 114 case Binary.Operator.BitwiseAnd: 115 case Binary.Operator.LogicalAnd: 116 return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location); 117 case Binary.Operator.BitwiseOr: 118 case Binary.Operator.LogicalOr: 119 return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location); 120 case Binary.Operator.ExclusiveOr: 121 return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location); 122 case Binary.Operator.Equality: 123 return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location); 124 case Binary.Operator.Inequality: 125 return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location); 126 } 127 return null; 128 } 129 130 // 131 // During an enum evaluation, none of the rules are valid 132 // Not sure whether it is bug in csc or in documentation 133 // 134 if (ec.HasSet (ResolveContext.Options.EnumScope)){ 135 if (left is EnumConstant) 136 left = ((EnumConstant) left).Child; 137 138 if (right is EnumConstant) 139 right = ((EnumConstant) right).Child; 140 } else if (left is EnumConstant && rt == lt) { 141 switch (oper){ 142 /// 143 /// E operator |(E x, E y); 144 /// E operator &(E x, E y); 145 /// E operator ^(E x, E y); 146 /// 147 case Binary.Operator.BitwiseOr: 148 case Binary.Operator.BitwiseAnd: 149 case Binary.Operator.ExclusiveOr: 150 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); 151 if (result != null) 152 result = result.Reduce (ec, lt); 153 return result; 154 155 /// 156 /// U operator -(E x, E y); 157 /// 158 case Binary.Operator.Subtraction: 159 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); 160 if (result != null) 161 result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt)); 162 return result; 163 164 /// 165 /// bool operator ==(E x, E y); 166 /// bool operator !=(E x, E y); 167 /// bool operator <(E x, E y); 168 /// bool operator >(E x, E y); 169 /// bool operator <=(E x, E y); 170 /// bool operator >=(E x, E y); 171 /// 172 case Binary.Operator.Equality: 173 case Binary.Operator.Inequality: 174 case Binary.Operator.LessThan: 175 case Binary.Operator.GreaterThan: 176 case Binary.Operator.LessThanOrEqual: 177 case Binary.Operator.GreaterThanOrEqual: 178 return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); 179 } 180 return null; 181 } 182 183 switch (oper){ 184 case Binary.Operator.BitwiseOr: 185 // 186 // bool? operator |(bool? x, bool? y); 187 // 188 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) || 189 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) { 190 var b = new Binary (oper, left, right).ResolveOperator (ec); 191 192 // false | null => null 193 // null | false => null 194 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue)) 195 return Nullable.LiftedNull.CreateFromExpression (ec, b); 196 197 // true | null => true 198 // null | true => true 199 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b); 200 } 201 202 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 203 return null; 204 205 if (left is IntConstant){ 206 int res = ((IntConstant) left).Value | ((IntConstant) right).Value; 207 208 return new IntConstant (ec.BuiltinTypes, res, left.Location); 209 } 210 if (left is UIntConstant){ 211 uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value; 212 213 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 214 } 215 if (left is LongConstant){ 216 long res = ((LongConstant)left).Value | ((LongConstant)right).Value; 217 218 return new LongConstant (ec.BuiltinTypes, res, left.Location); 219 } 220 if (left is ULongConstant){ 221 ulong res = ((ULongConstant)left).Value | 222 ((ULongConstant)right).Value; 223 224 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 225 } 226 break; 227 228 case Binary.Operator.BitwiseAnd: 229 // 230 // bool? operator &(bool? x, bool? y); 231 // 232 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) || 233 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) { 234 var b = new Binary (oper, left, right).ResolveOperator (ec); 235 236 // false & null => false 237 // null & false => false 238 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue)) 239 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b); 240 241 // true & null => null 242 // null & true => null 243 return Nullable.LiftedNull.CreateFromExpression (ec, b); 244 } 245 246 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 247 return null; 248 249 /// 250 /// int operator &(int x, int y); 251 /// uint operator &(uint x, uint y); 252 /// long operator &(long x, long y); 253 /// ulong operator &(ulong x, ulong y); 254 /// 255 if (left is IntConstant){ 256 int res = ((IntConstant) left).Value & ((IntConstant) right).Value; 257 return new IntConstant (ec.BuiltinTypes, res, left.Location); 258 } 259 if (left is UIntConstant){ 260 uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value; 261 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 262 } 263 if (left is LongConstant){ 264 long res = ((LongConstant)left).Value & ((LongConstant)right).Value; 265 return new LongConstant (ec.BuiltinTypes, res, left.Location); 266 } 267 if (left is ULongConstant){ 268 ulong res = ((ULongConstant)left).Value & 269 ((ULongConstant)right).Value; 270 271 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 272 } 273 break; 274 275 case Binary.Operator.ExclusiveOr: 276 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 277 return null; 278 279 if (left is IntConstant){ 280 int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value; 281 return new IntConstant (ec.BuiltinTypes, res, left.Location); 282 } 283 if (left is UIntConstant){ 284 uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value; 285 286 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 287 } 288 if (left is LongConstant){ 289 long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value; 290 291 return new LongConstant (ec.BuiltinTypes, res, left.Location); 292 } 293 if (left is ULongConstant){ 294 ulong res = ((ULongConstant)left).Value ^ 295 ((ULongConstant)right).Value; 296 297 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 298 } 299 break; 300 301 case Binary.Operator.Addition: 302 // 303 // If both sides are strings, then concatenate 304 // 305 // string operator + (string x, string y) 306 // 307 if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){ 308 if (lt == rt) 309 return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (), 310 left.Location); 311 312 if (lt == InternalType.NullLiteral || left.IsNull) 313 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location); 314 315 if (rt == InternalType.NullLiteral || right.IsNull) 316 return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location); 317 318 return null; 319 } 320 321 // 322 // string operator + (string x, object y) 323 // 324 if (lt == InternalType.NullLiteral) { 325 if (rt.BuiltinType == BuiltinTypeSpec.Type.Object) 326 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location); 327 328 if (lt == rt) { 329 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'", 330 "+", lt.GetSignatureForError (), rt.GetSignatureForError ()); 331 return null; 332 } 333 334 return right; 335 } 336 337 // 338 // string operator + (object x, string y) 339 // 340 if (rt == InternalType.NullLiteral) { 341 if (lt.BuiltinType == BuiltinTypeSpec.Type.Object) 342 return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location); 343 344 return left; 345 } 346 347 // 348 // handle "E operator + (E x, U y)" 349 // handle "E operator + (Y y, E x)" 350 // 351 EnumConstant lc = left as EnumConstant; 352 EnumConstant rc = right as EnumConstant; 353 if (lc != null || rc != null){ 354 if (lc == null) { 355 lc = rc; 356 lt = lc.Type; 357 right = left; 358 } 359 360 // U has to be implicitly convetible to E.base 361 right = right.ConvertImplicitly (lc.Child.Type); 362 if (right == null) 363 return null; 364 365 result = BinaryFold (ec, oper, lc.Child, right, loc); 366 if (result == null) 367 return null; 368 369 result = result.Reduce (ec, lt); 370 if (result == null || lt.IsEnum) 371 return result; 372 373 return new EnumConstant (result, lt); 374 } 375 376 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 377 return null; 378 379 try { 380 if (left is DoubleConstant){ 381 double res; 382 383 if (ec.ConstantCheckState) 384 res = checked (((DoubleConstant) left).Value + 385 ((DoubleConstant) right).Value); 386 else 387 res = unchecked (((DoubleConstant) left).Value + 388 ((DoubleConstant) right).Value); 389 390 return new DoubleConstant (ec.BuiltinTypes, res, left.Location); 391 } 392 if (left is FloatConstant){ 393 double a, b, res; 394 a = ((FloatConstant) left).DoubleValue; 395 b = ((FloatConstant) right).DoubleValue; 396 397 if (ec.ConstantCheckState) 398 res = checked (a + b); 399 else 400 res = unchecked (a + b); 401 402 result = new FloatConstant (ec.BuiltinTypes, res, left.Location); 403 } else if (left is ULongConstant){ 404 ulong res; 405 406 if (ec.ConstantCheckState) 407 res = checked (((ULongConstant) left).Value + 408 ((ULongConstant) right).Value); 409 else 410 res = unchecked (((ULongConstant) left).Value + 411 ((ULongConstant) right).Value); 412 413 result = new ULongConstant (ec.BuiltinTypes, res, left.Location); 414 } else if (left is LongConstant){ 415 long res; 416 417 if (ec.ConstantCheckState) 418 res = checked (((LongConstant) left).Value + 419 ((LongConstant) right).Value); 420 else 421 res = unchecked (((LongConstant) left).Value + 422 ((LongConstant) right).Value); 423 424 result = new LongConstant (ec.BuiltinTypes, res, left.Location); 425 } else if (left is UIntConstant){ 426 uint res; 427 428 if (ec.ConstantCheckState) 429 res = checked (((UIntConstant) left).Value + 430 ((UIntConstant) right).Value); 431 else 432 res = unchecked (((UIntConstant) left).Value + 433 ((UIntConstant) right).Value); 434 435 result = new UIntConstant (ec.BuiltinTypes, res, left.Location); 436 } else if (left is IntConstant){ 437 int res; 438 439 if (ec.ConstantCheckState) 440 res = checked (((IntConstant) left).Value + 441 ((IntConstant) right).Value); 442 else 443 res = unchecked (((IntConstant) left).Value + 444 ((IntConstant) right).Value); 445 446 result = new IntConstant (ec.BuiltinTypes, res, left.Location); 447 } else if (left is DecimalConstant) { 448 decimal res; 449 450 if (ec.ConstantCheckState) 451 res = checked (((DecimalConstant) left).Value + 452 ((DecimalConstant) right).Value); 453 else 454 res = unchecked (((DecimalConstant) left).Value + 455 ((DecimalConstant) right).Value); 456 457 result = new DecimalConstant (ec.BuiltinTypes, res, left.Location); 458 } 459 } catch (OverflowException){ 460 Error_CompileTimeOverflow (ec, loc); 461 } 462 463 return result; 464 465 case Binary.Operator.Subtraction: 466 // 467 // handle "E operator - (E x, U y)" 468 // handle "E operator - (Y y, E x)" 469 // 470 lc = left as EnumConstant; 471 rc = right as EnumConstant; 472 if (lc != null || rc != null) { 473 TypeSpec res_type; 474 if (lc == null) { 475 res_type = right.Type; 476 477 // Y has to be implicitly convertible to E.base 478 left = left.ConvertImplicitly (rc.Child.Type); 479 if (left == null) 480 return null; 481 482 right = rc.Child; 483 } else { 484 res_type = left.Type; 485 486 // U has to be implicitly convertible to E.base 487 right = right.ConvertImplicitly (lc.Child.Type); 488 if (right == null) 489 return null; 490 491 left = lc.Child; 492 } 493 494 result = BinaryFold (ec, oper, left, right, loc); 495 if (result == null) 496 return null; 497 498 result = result.Reduce (ec, res_type); 499 if (result == null) 500 return null; 501 502 return new EnumConstant (result, res_type); 503 } 504 505 if (left is NullLiteral && right is NullLiteral) { 506 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 507 lifted_int.ResolveAsType (ec); 508 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 509 } 510 511 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 512 return null; 513 514 try { 515 if (left is DoubleConstant){ 516 double res; 517 518 if (ec.ConstantCheckState) 519 res = checked (((DoubleConstant) left).Value - 520 ((DoubleConstant) right).Value); 521 else 522 res = unchecked (((DoubleConstant) left).Value - 523 ((DoubleConstant) right).Value); 524 525 result = new DoubleConstant (ec.BuiltinTypes, res, left.Location); 526 } else if (left is FloatConstant){ 527 double a, b, res; 528 a = ((FloatConstant) left).DoubleValue; 529 b = ((FloatConstant) right).DoubleValue; 530 531 if (ec.ConstantCheckState) 532 res = checked (a - b); 533 else 534 res = unchecked (a - b); 535 536 result = new FloatConstant (ec.BuiltinTypes, res, left.Location); 537 } else if (left is ULongConstant){ 538 ulong res; 539 540 if (ec.ConstantCheckState) 541 res = checked (((ULongConstant) left).Value - 542 ((ULongConstant) right).Value); 543 else 544 res = unchecked (((ULongConstant) left).Value - 545 ((ULongConstant) right).Value); 546 547 result = new ULongConstant (ec.BuiltinTypes, res, left.Location); 548 } else if (left is LongConstant){ 549 long res; 550 551 if (ec.ConstantCheckState) 552 res = checked (((LongConstant) left).Value - 553 ((LongConstant) right).Value); 554 else 555 res = unchecked (((LongConstant) left).Value - 556 ((LongConstant) right).Value); 557 558 result = new LongConstant (ec.BuiltinTypes, res, left.Location); 559 } else if (left is UIntConstant){ 560 uint res; 561 562 if (ec.ConstantCheckState) 563 res = checked (((UIntConstant) left).Value - 564 ((UIntConstant) right).Value); 565 else 566 res = unchecked (((UIntConstant) left).Value - 567 ((UIntConstant) right).Value); 568 569 result = new UIntConstant (ec.BuiltinTypes, res, left.Location); 570 } else if (left is IntConstant){ 571 int res; 572 573 if (ec.ConstantCheckState) 574 res = checked (((IntConstant) left).Value - 575 ((IntConstant) right).Value); 576 else 577 res = unchecked (((IntConstant) left).Value - 578 ((IntConstant) right).Value); 579 580 result = new IntConstant (ec.BuiltinTypes, res, left.Location); 581 } else if (left is DecimalConstant) { 582 decimal res; 583 584 if (ec.ConstantCheckState) 585 res = checked (((DecimalConstant) left).Value - 586 ((DecimalConstant) right).Value); 587 else 588 res = unchecked (((DecimalConstant) left).Value - 589 ((DecimalConstant) right).Value); 590 591 return new DecimalConstant (ec.BuiltinTypes, res, left.Location); 592 } else { 593 throw new Exception ( "Unexepected subtraction input: " + left); 594 } 595 } catch (OverflowException){ 596 Error_CompileTimeOverflow (ec, loc); 597 } 598 599 return result; 600 601 case Binary.Operator.Multiply: 602 if (left is NullLiteral && right is NullLiteral) { 603 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 604 lifted_int.ResolveAsType (ec); 605 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 606 } 607 608 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 609 return null; 610 611 try { 612 if (left is DoubleConstant){ 613 double res; 614 615 if (ec.ConstantCheckState) 616 res = checked (((DoubleConstant) left).Value * 617 ((DoubleConstant) right).Value); 618 else 619 res = unchecked (((DoubleConstant) left).Value * 620 ((DoubleConstant) right).Value); 621 622 return new DoubleConstant (ec.BuiltinTypes, res, left.Location); 623 } else if (left is FloatConstant){ 624 double a, b, res; 625 a = ((FloatConstant) left).DoubleValue; 626 b = ((FloatConstant) right).DoubleValue; 627 628 if (ec.ConstantCheckState) 629 res = checked (a * b); 630 else 631 res = unchecked (a * b); 632 633 return new FloatConstant (ec.BuiltinTypes, res, left.Location); 634 } else if (left is ULongConstant){ 635 ulong res; 636 637 if (ec.ConstantCheckState) 638 res = checked (((ULongConstant) left).Value * 639 ((ULongConstant) right).Value); 640 else 641 res = unchecked (((ULongConstant) left).Value * 642 ((ULongConstant) right).Value); 643 644 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 645 } else if (left is LongConstant){ 646 long res; 647 648 if (ec.ConstantCheckState) 649 res = checked (((LongConstant) left).Value * 650 ((LongConstant) right).Value); 651 else 652 res = unchecked (((LongConstant) left).Value * 653 ((LongConstant) right).Value); 654 655 return new LongConstant (ec.BuiltinTypes, res, left.Location); 656 } else if (left is UIntConstant){ 657 uint res; 658 659 if (ec.ConstantCheckState) 660 res = checked (((UIntConstant) left).Value * 661 ((UIntConstant) right).Value); 662 else 663 res = unchecked (((UIntConstant) left).Value * 664 ((UIntConstant) right).Value); 665 666 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 667 } else if (left is IntConstant){ 668 int res; 669 670 if (ec.ConstantCheckState) 671 res = checked (((IntConstant) left).Value * 672 ((IntConstant) right).Value); 673 else 674 res = unchecked (((IntConstant) left).Value * 675 ((IntConstant) right).Value); 676 677 return new IntConstant (ec.BuiltinTypes, res, left.Location); 678 } else if (left is DecimalConstant) { 679 decimal res; 680 681 if (ec.ConstantCheckState) 682 res = checked (((DecimalConstant) left).Value * 683 ((DecimalConstant) right).Value); 684 else 685 res = unchecked (((DecimalConstant) left).Value * 686 ((DecimalConstant) right).Value); 687 688 return new DecimalConstant (ec.BuiltinTypes, res, left.Location); 689 } else { 690 throw new Exception ( "Unexepected multiply input: " + left); 691 } 692 } catch (OverflowException){ 693 Error_CompileTimeOverflow (ec, loc); 694 } 695 break; 696 697 case Binary.Operator.Division: 698 if (left is NullLiteral && right is NullLiteral) { 699 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 700 lifted_int.ResolveAsType (ec); 701 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 702 } 703 704 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 705 return null; 706 707 try { 708 if (left is DoubleConstant){ 709 double res; 710 711 if (ec.ConstantCheckState) 712 res = checked (((DoubleConstant) left).Value / 713 ((DoubleConstant) right).Value); 714 else 715 res = unchecked (((DoubleConstant) left).Value / 716 ((DoubleConstant) right).Value); 717 718 return new DoubleConstant (ec.BuiltinTypes, res, left.Location); 719 } else if (left is FloatConstant){ 720 double a, b, res; 721 a = ((FloatConstant) left).DoubleValue; 722 b = ((FloatConstant) right).DoubleValue; 723 724 if (ec.ConstantCheckState) 725 res = checked (a / b); 726 else 727 res = unchecked (a / b); 728 729 return new FloatConstant (ec.BuiltinTypes, res, left.Location); 730 } else if (left is ULongConstant){ 731 ulong res; 732 733 if (ec.ConstantCheckState) 734 res = checked (((ULongConstant) left).Value / 735 ((ULongConstant) right).Value); 736 else 737 res = unchecked (((ULongConstant) left).Value / 738 ((ULongConstant) right).Value); 739 740 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 741 } else if (left is LongConstant){ 742 long res; 743 744 if (ec.ConstantCheckState) 745 res = checked (((LongConstant) left).Value / 746 ((LongConstant) right).Value); 747 else 748 res = unchecked (((LongConstant) left).Value / 749 ((LongConstant) right).Value); 750 751 return new LongConstant (ec.BuiltinTypes, res, left.Location); 752 } else if (left is UIntConstant){ 753 uint res; 754 755 if (ec.ConstantCheckState) 756 res = checked (((UIntConstant) left).Value / 757 ((UIntConstant) right).Value); 758 else 759 res = unchecked (((UIntConstant) left).Value / 760 ((UIntConstant) right).Value); 761 762 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 763 } else if (left is IntConstant){ 764 int res; 765 766 if (ec.ConstantCheckState) 767 res = checked (((IntConstant) left).Value / 768 ((IntConstant) right).Value); 769 else 770 res = unchecked (((IntConstant) left).Value / 771 ((IntConstant) right).Value); 772 773 return new IntConstant (ec.BuiltinTypes, res, left.Location); 774 } else if (left is DecimalConstant) { 775 decimal res; 776 777 if (ec.ConstantCheckState) 778 res = checked (((DecimalConstant) left).Value / 779 ((DecimalConstant) right).Value); 780 else 781 res = unchecked (((DecimalConstant) left).Value / 782 ((DecimalConstant) right).Value); 783 784 return new DecimalConstant (ec.BuiltinTypes, res, left.Location); 785 } else { 786 throw new Exception ( "Unexepected division input: " + left); 787 } 788 } catch (OverflowException){ 789 Error_CompileTimeOverflow (ec, loc); 790 791 } catch (DivideByZeroException) { 792 ec.Report.Error (20, loc, "Division by constant zero"); 793 } 794 795 break; 796 797 case Binary.Operator.Modulus: 798 if (left is NullLiteral && right is NullLiteral) { 799 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 800 lifted_int.ResolveAsType (ec); 801 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 802 } 803 804 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 805 return null; 806 807 try { 808 if (left is DoubleConstant){ 809 double res; 810 811 if (ec.ConstantCheckState) 812 res = checked (((DoubleConstant) left).Value % 813 ((DoubleConstant) right).Value); 814 else 815 res = unchecked (((DoubleConstant) left).Value % 816 ((DoubleConstant) right).Value); 817 818 return new DoubleConstant (ec.BuiltinTypes, res, left.Location); 819 } else if (left is FloatConstant){ 820 double a, b, res; 821 a = ((FloatConstant) left).DoubleValue; 822 b = ((FloatConstant) right).DoubleValue; 823 824 if (ec.ConstantCheckState) 825 res = checked (a % b); 826 else 827 res = unchecked (a % b); 828 829 return new FloatConstant (ec.BuiltinTypes, res, left.Location); 830 } else if (left is ULongConstant){ 831 ulong res; 832 833 if (ec.ConstantCheckState) 834 res = checked (((ULongConstant) left).Value % 835 ((ULongConstant) right).Value); 836 else 837 res = unchecked (((ULongConstant) left).Value % 838 ((ULongConstant) right).Value); 839 840 return new ULongConstant (ec.BuiltinTypes, res, left.Location); 841 } else if (left is LongConstant){ 842 long res; 843 844 if (ec.ConstantCheckState) 845 res = checked (((LongConstant) left).Value % 846 ((LongConstant) right).Value); 847 else 848 res = unchecked (((LongConstant) left).Value % 849 ((LongConstant) right).Value); 850 851 return new LongConstant (ec.BuiltinTypes, res, left.Location); 852 } else if (left is UIntConstant){ 853 uint res; 854 855 if (ec.ConstantCheckState) 856 res = checked (((UIntConstant) left).Value % 857 ((UIntConstant) right).Value); 858 else 859 res = unchecked (((UIntConstant) left).Value % 860 ((UIntConstant) right).Value); 861 862 return new UIntConstant (ec.BuiltinTypes, res, left.Location); 863 } else if (left is IntConstant){ 864 int res; 865 866 if (ec.ConstantCheckState) 867 res = checked (((IntConstant) left).Value % 868 ((IntConstant) right).Value); 869 else 870 res = unchecked (((IntConstant) left).Value % 871 ((IntConstant) right).Value); 872 873 return new IntConstant (ec.BuiltinTypes, res, left.Location); 874 } 875 876 if (left is DecimalConstant) { 877 decimal res; 878 879 if (ec.ConstantCheckState) 880 res = checked (((DecimalConstant) left).Value % 881 ((DecimalConstant) right).Value); 882 else 883 res = unchecked (((DecimalConstant) left).Value % 884 ((DecimalConstant) right).Value); 885 886 return new DecimalConstant (ec.BuiltinTypes, res, left.Location); 887 } 888 889 throw new Exception ( "Unexepected modulus input: " + left); 890 } catch (DivideByZeroException){ 891 ec.Report.Error (20, loc, "Division by constant zero"); 892 } catch (OverflowException){ 893 Error_CompileTimeOverflow (ec, loc); 894 } 895 break; 896 897 // 898 // There is no overflow checking on left shift 899 // 900 case Binary.Operator.LeftShift: 901 if (left is NullLiteral && right is NullLiteral) { 902 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 903 lifted_int.ResolveAsType (ec); 904 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 905 } 906 907 IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant; 908 if (ic == null){ 909 return null; 910 } 911 912 int lshift_val = ic.Value; 913 switch (left.Type.BuiltinType) { 914 case BuiltinTypeSpec.Type.ULong: 915 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location); 916 case BuiltinTypeSpec.Type.Long: 917 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location); 918 case BuiltinTypeSpec.Type.UInt: 919 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location); 920 } 921 922 // null << value => null 923 if (left is NullLiteral) 924 return (Constant) new Binary (oper, left, right).ResolveOperator (ec); 925 926 left = left.ConvertImplicitly (ec.BuiltinTypes.Int); 927 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int) 928 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location); 929 930 return null; 931 932 // 933 // There is no overflow checking on right shift 934 // 935 case Binary.Operator.RightShift: 936 if (left is NullLiteral && right is NullLiteral) { 937 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 938 lifted_int.ResolveAsType (ec); 939 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 940 } 941 942 IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant; 943 if (sic == null){ 944 return null; 945 } 946 int rshift_val = sic.Value; 947 switch (left.Type.BuiltinType) { 948 case BuiltinTypeSpec.Type.ULong: 949 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location); 950 case BuiltinTypeSpec.Type.Long: 951 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location); 952 case BuiltinTypeSpec.Type.UInt: 953 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location); 954 } 955 956 // null >> value => null 957 if (left is NullLiteral) 958 return (Constant) new Binary (oper, left, right).ResolveOperator (ec); 959 960 left = left.ConvertImplicitly (ec.BuiltinTypes.Int); 961 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int) 962 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location); 963 964 return null; 965 966 case Binary.Operator.Equality: 967 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) || 968 (left is Nullable.LiftedNull && right.IsNull) || 969 (right is Nullable.LiftedNull && left.IsNull)) { 970 if (left.IsNull || right.IsNull) { 971 return ReducedExpression.Create ( 972 new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location), 973 new Binary (oper, left, right)); 974 } 975 976 if (left is StringConstant && right is StringConstant) 977 return new BoolConstant (ec.BuiltinTypes, 978 ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location); 979 980 return null; 981 } 982 983 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 984 return null; 985 986 bool_res = false; 987 if (left is DoubleConstant) 988 bool_res = ((DoubleConstant) left).Value == 989 ((DoubleConstant) right).Value; 990 else if (left is FloatConstant) 991 bool_res = ((FloatConstant) left).DoubleValue == 992 ((FloatConstant) right).DoubleValue; 993 else if (left is ULongConstant) 994 bool_res = ((ULongConstant) left).Value == 995 ((ULongConstant) right).Value; 996 else if (left is LongConstant) 997 bool_res = ((LongConstant) left).Value == 998 ((LongConstant) right).Value; 999 else if (left is UIntConstant) 1000 bool_res = ((UIntConstant) left).Value == 1001 ((UIntConstant) right).Value; 1002 else if (left is IntConstant) 1003 bool_res = ((IntConstant) left).Value == 1004 ((IntConstant) right).Value; 1005 else 1006 return null; 1007 1008 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1009 1010 case Binary.Operator.Inequality: 1011 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) || 1012 (left is Nullable.LiftedNull && right.IsNull) || 1013 (right is Nullable.LiftedNull && left.IsNull)) { 1014 if (left.IsNull || right.IsNull) { 1015 return ReducedExpression.Create ( 1016 new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location), 1017 new Binary (oper, left, right)); 1018 } 1019 1020 if (left is StringConstant && right is StringConstant) 1021 return new BoolConstant (ec.BuiltinTypes, 1022 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location); 1023 1024 return null; 1025 } 1026 1027 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 1028 return null; 1029 1030 bool_res = false; 1031 if (left is DoubleConstant) 1032 bool_res = ((DoubleConstant) left).Value != 1033 ((DoubleConstant) right).Value; 1034 else if (left is FloatConstant) 1035 bool_res = ((FloatConstant) left).DoubleValue != 1036 ((FloatConstant) right).DoubleValue; 1037 else if (left is ULongConstant) 1038 bool_res = ((ULongConstant) left).Value != 1039 ((ULongConstant) right).Value; 1040 else if (left is LongConstant) 1041 bool_res = ((LongConstant) left).Value != 1042 ((LongConstant) right).Value; 1043 else if (left is UIntConstant) 1044 bool_res = ((UIntConstant) left).Value != 1045 ((UIntConstant) right).Value; 1046 else if (left is IntConstant) 1047 bool_res = ((IntConstant) left).Value != 1048 ((IntConstant) right).Value; 1049 else 1050 return null; 1051 1052 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1053 1054 case Binary.Operator.LessThan: 1055 if (right is NullLiteral) { 1056 if (left is NullLiteral) { 1057 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 1058 lifted_int.ResolveAsType (ec); 1059 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 1060 } 1061 } 1062 1063 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 1064 return null; 1065 1066 bool_res = false; 1067 if (left is DoubleConstant) 1068 bool_res = ((DoubleConstant) left).Value < 1069 ((DoubleConstant) right).Value; 1070 else if (left is FloatConstant) 1071 bool_res = ((FloatConstant) left).DoubleValue < 1072 ((FloatConstant) right).DoubleValue; 1073 else if (left is ULongConstant) 1074 bool_res = ((ULongConstant) left).Value < 1075 ((ULongConstant) right).Value; 1076 else if (left is LongConstant) 1077 bool_res = ((LongConstant) left).Value < 1078 ((LongConstant) right).Value; 1079 else if (left is UIntConstant) 1080 bool_res = ((UIntConstant) left).Value < 1081 ((UIntConstant) right).Value; 1082 else if (left is IntConstant) 1083 bool_res = ((IntConstant) left).Value < 1084 ((IntConstant) right).Value; 1085 else 1086 return null; 1087 1088 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1089 1090 case Binary.Operator.GreaterThan: 1091 if (right is NullLiteral) { 1092 if (left is NullLiteral) { 1093 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 1094 lifted_int.ResolveAsType (ec); 1095 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 1096 } 1097 } 1098 1099 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 1100 return null; 1101 1102 bool_res = false; 1103 if (left is DoubleConstant) 1104 bool_res = ((DoubleConstant) left).Value > 1105 ((DoubleConstant) right).Value; 1106 else if (left is FloatConstant) 1107 bool_res = ((FloatConstant) left).DoubleValue > 1108 ((FloatConstant) right).DoubleValue; 1109 else if (left is ULongConstant) 1110 bool_res = ((ULongConstant) left).Value > 1111 ((ULongConstant) right).Value; 1112 else if (left is LongConstant) 1113 bool_res = ((LongConstant) left).Value > 1114 ((LongConstant) right).Value; 1115 else if (left is UIntConstant) 1116 bool_res = ((UIntConstant) left).Value > 1117 ((UIntConstant) right).Value; 1118 else if (left is IntConstant) 1119 bool_res = ((IntConstant) left).Value > 1120 ((IntConstant) right).Value; 1121 else 1122 return null; 1123 1124 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1125 1126 case Binary.Operator.GreaterThanOrEqual: 1127 if (right is NullLiteral) { 1128 if (left is NullLiteral) { 1129 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 1130 lifted_int.ResolveAsType (ec); 1131 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 1132 } 1133 } 1134 1135 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 1136 return null; 1137 1138 bool_res = false; 1139 if (left is DoubleConstant) 1140 bool_res = ((DoubleConstant) left).Value >= 1141 ((DoubleConstant) right).Value; 1142 else if (left is FloatConstant) 1143 bool_res = ((FloatConstant) left).DoubleValue >= 1144 ((FloatConstant) right).DoubleValue; 1145 else if (left is ULongConstant) 1146 bool_res = ((ULongConstant) left).Value >= 1147 ((ULongConstant) right).Value; 1148 else if (left is LongConstant) 1149 bool_res = ((LongConstant) left).Value >= 1150 ((LongConstant) right).Value; 1151 else if (left is UIntConstant) 1152 bool_res = ((UIntConstant) left).Value >= 1153 ((UIntConstant) right).Value; 1154 else if (left is IntConstant) 1155 bool_res = ((IntConstant) left).Value >= 1156 ((IntConstant) right).Value; 1157 else 1158 return null; 1159 1160 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1161 1162 case Binary.Operator.LessThanOrEqual: 1163 if (right is NullLiteral) { 1164 if (left is NullLiteral) { 1165 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); 1166 lifted_int.ResolveAsType (ec); 1167 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec); 1168 } 1169 } 1170 1171 if (!DoBinaryNumericPromotions (ec, ref left, ref right)) 1172 return null; 1173 1174 bool_res = false; 1175 if (left is DoubleConstant) 1176 bool_res = ((DoubleConstant) left).Value <= 1177 ((DoubleConstant) right).Value; 1178 else if (left is FloatConstant) 1179 bool_res = ((FloatConstant) left).DoubleValue <= 1180 ((FloatConstant) right).DoubleValue; 1181 else if (left is ULongConstant) 1182 bool_res = ((ULongConstant) left).Value <= 1183 ((ULongConstant) right).Value; 1184 else if (left is LongConstant) 1185 bool_res = ((LongConstant) left).Value <= 1186 ((LongConstant) right).Value; 1187 else if (left is UIntConstant) 1188 bool_res = ((UIntConstant) left).Value <= 1189 ((UIntConstant) right).Value; 1190 else if (left is IntConstant) 1191 bool_res = ((IntConstant) left).Value <= 1192 ((IntConstant) right).Value; 1193 else 1194 return null; 1195 1196 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); 1197 } 1198 1199 return null; 1200 } 1201 } 1202 } 1203