/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs

http://github.com/icsharpcode/ILSpy · C# · 1192 lines · 908 code · 190 blank · 94 comment · 358 complexity · dcc4683bdbc6ea48816d7066cf5abe82 MD5 · raw file

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