You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
6.6 KiB

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Linq;
  21. using ICSharpCode.NRefactory.CSharp;
  22. using ICSharpCode.NRefactory.PatternMatching;
  23. namespace ICSharpCode.Decompiler.Ast.Transforms
  24. {
  25. public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
  26. {
  27. sealed class LiftedOperator { }
  28. /// <summary>
  29. /// Annotation for lifted operators that cannot be transformed by PushNegation
  30. /// </summary>
  31. public static readonly object LiftedOperatorAnnotation = new LiftedOperator();
  32. public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
  33. {
  34. // lifted operators can't be transformed
  35. if (unary.Annotation<LiftedOperator>() != null || unary.Expression.Annotation<LiftedOperator>() != null)
  36. return base.VisitUnaryOperatorExpression(unary, data);
  37. // Remove double negation
  38. // !!a
  39. if (unary.Operator == UnaryOperatorType.Not &&
  40. unary.Expression is UnaryOperatorExpression &&
  41. (unary.Expression as UnaryOperatorExpression).Operator == UnaryOperatorType.Not)
  42. {
  43. AstNode newNode = (unary.Expression as UnaryOperatorExpression).Expression;
  44. unary.ReplaceWith(newNode);
  45. return newNode.AcceptVisitor(this, data);
  46. }
  47. // Push through binary operation
  48. // !((a) op (b))
  49. BinaryOperatorExpression binaryOp = unary.Expression as BinaryOperatorExpression;
  50. if (unary.Operator == UnaryOperatorType.Not && binaryOp != null) {
  51. bool successful = true;
  52. switch (binaryOp.Operator) {
  53. case BinaryOperatorType.Equality:
  54. binaryOp.Operator = BinaryOperatorType.InEquality;
  55. break;
  56. case BinaryOperatorType.InEquality:
  57. binaryOp.Operator = BinaryOperatorType.Equality;
  58. break;
  59. case BinaryOperatorType.GreaterThan: // TODO: these are invalid for floats (stupid NaN)
  60. binaryOp.Operator = BinaryOperatorType.LessThanOrEqual;
  61. break;
  62. case BinaryOperatorType.GreaterThanOrEqual:
  63. binaryOp.Operator = BinaryOperatorType.LessThan;
  64. break;
  65. case BinaryOperatorType.LessThanOrEqual:
  66. binaryOp.Operator = BinaryOperatorType.GreaterThan;
  67. break;
  68. case BinaryOperatorType.LessThan:
  69. binaryOp.Operator = BinaryOperatorType.GreaterThanOrEqual;
  70. break;
  71. default:
  72. successful = false;
  73. break;
  74. }
  75. if (successful) {
  76. unary.ReplaceWith(binaryOp);
  77. return binaryOp.AcceptVisitor(this, data);
  78. }
  79. successful = true;
  80. switch (binaryOp.Operator) {
  81. case BinaryOperatorType.ConditionalAnd:
  82. binaryOp.Operator = BinaryOperatorType.ConditionalOr;
  83. break;
  84. case BinaryOperatorType.ConditionalOr:
  85. binaryOp.Operator = BinaryOperatorType.ConditionalAnd;
  86. break;
  87. default:
  88. successful = false;
  89. break;
  90. }
  91. if (successful) {
  92. binaryOp.Left.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
  93. binaryOp.Right.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e));
  94. unary.ReplaceWith(binaryOp);
  95. return binaryOp.AcceptVisitor(this, data);
  96. }
  97. }
  98. return base.VisitUnaryOperatorExpression(unary, data);
  99. }
  100. readonly static AstNode asCastIsNullPattern = new BinaryOperatorExpression(
  101. new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")),
  102. BinaryOperatorType.Equality,
  103. new NullReferenceExpression()
  104. );
  105. readonly static AstNode asCastIsNotNullPattern = new BinaryOperatorExpression(
  106. new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")),
  107. BinaryOperatorType.InEquality,
  108. new NullReferenceExpression()
  109. );
  110. public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
  111. {
  112. // lifted operators can't be transformed
  113. if (binaryOperatorExpression.Annotation<LiftedOperator>() != null)
  114. return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
  115. BinaryOperatorType op = binaryOperatorExpression.Operator;
  116. bool? rightOperand = null;
  117. if (binaryOperatorExpression.Right is PrimitiveExpression)
  118. rightOperand = ((PrimitiveExpression)binaryOperatorExpression.Right).Value as bool?;
  119. if (op == BinaryOperatorType.Equality && rightOperand == true || op == BinaryOperatorType.InEquality && rightOperand == false) {
  120. // 'b == true' or 'b != false' is useless
  121. binaryOperatorExpression.Left.AcceptVisitor(this, data);
  122. binaryOperatorExpression.ReplaceWith(binaryOperatorExpression.Left);
  123. return null;
  124. } else if (op == BinaryOperatorType.Equality && rightOperand == false || op == BinaryOperatorType.InEquality && rightOperand == true) {
  125. // 'b == false' or 'b != true' is a negation:
  126. Expression left = binaryOperatorExpression.Left;
  127. left.Remove();
  128. UnaryOperatorExpression uoe = new UnaryOperatorExpression(UnaryOperatorType.Not, left);
  129. binaryOperatorExpression.ReplaceWith(uoe);
  130. return uoe.AcceptVisitor(this, data);
  131. } else {
  132. bool negate = false;
  133. Match m = asCastIsNotNullPattern.Match(binaryOperatorExpression);
  134. if (!m.Success) {
  135. m = asCastIsNullPattern.Match(binaryOperatorExpression);
  136. negate = true;
  137. }
  138. if (m.Success) {
  139. Expression expr = m.Get<Expression>("expr").Single().Detach().IsType(m.Get<AstType>("type").Single().Detach());
  140. if (negate)
  141. expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr);
  142. binaryOperatorExpression.ReplaceWith(expr);
  143. return expr.AcceptVisitor(this, data);
  144. } else {
  145. return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
  146. }
  147. }
  148. }
  149. void IAstTransform.Run(AstNode node)
  150. {
  151. node.AcceptVisitor(this, null);
  152. }
  153. }
  154. }