third_party/closure-compiler/src/src/com/google/javascript/jscomp/PeepholeFoldConstants.java
/**
   * Try to fold arithmetic binary operators
   */
Try to fold arithmetic binary operators
Try to fold arithmetic binary operators
private Node performArithmeticOp(Token opType, Node left, Node right) {
    if (opType == Token.ADD
        && (NodeUtil.mayBeString(left, shouldUseTypes)
            || NodeUtil.mayBeString(right, shouldUseTypes))) {
      return null;
    }
    double result;
    Double lValObj = getSideEffectFreeNumberValue(left);
    Double rValObj = getSideEffectFreeNumberValue(right);
    if ((lValObj == null && rValObj == null) || !isNumeric(left) || !isNumeric(right)) {
      return null;
    }
    switch (opType) {
      case ADD:
        if (lValObj != null && rValObj != null) {
          return maybeReplaceBinaryOpWithNumericResult(lValObj + rValObj, lValObj, rValObj);
        }
        if (lValObj != null && lValObj == 0) {
          return right.cloneTree(true);
        } else if (rValObj != null && rValObj == 0) {
          return left.cloneTree(true);
        }
        return null;
      case SUB:
        if (lValObj != null && rValObj != null) {
          return maybeReplaceBinaryOpWithNumericResult(lValObj - rValObj, lValObj, rValObj);
        }
        if (lValObj != null && lValObj == 0) {
          return IR.neg(right.cloneTree(true));
        } else if (rValObj != null && rValObj == 0) {
          return left.cloneTree(true);
        }
        return null;
      case MUL:
        if (lValObj != null && rValObj != null) {
          return maybeReplaceBinaryOpWithNumericResult(lValObj * rValObj, lValObj, rValObj);
        }
        if (lValObj != null) {
          if (lValObj == 1) {
            return right.cloneTree(true);
          }
        } else {
          if (rValObj == 1) {
            return left.cloneTree(true);
          }
        }
        return null;
      case DIV:
        if (lValObj != null && rValObj != null) {
          if (rValObj == 0) {
            return null;
          }
          return maybeReplaceBinaryOpWithNumericResult(lValObj / rValObj, lValObj, rValObj);
        }
        if (rValObj != null) {
          if (rValObj == 1) {
            return left.cloneTree(true);
          }
        }
        return null;
      case EXPONENT:
        if (lValObj != null && rValObj != null) {
          return maybeReplaceBinaryOpWithNumericResult(
              Math.pow(lValObj, rValObj), lValObj, rValObj);
        }
        return null;
      default:
    }
    if (lValObj == null || rValObj == null) {
      return null;
    }
    double lval = lValObj;
    double rval = rValObj;
    switch (opType) {
      case BITAND:
        result = NodeUtil.toInt32(lval) & NodeUtil.toInt32(rval);
        break;
      case BITOR:
        result = NodeUtil.toInt32(lval) | NodeUtil.toInt32(rval);
        break;
      case BITXOR:
        result = NodeUtil.toInt32(lval) ^ NodeUtil.toInt32(rval);
        break;
      case MOD:
        if (rval == 0) {
          return null;
        }
        result = lval % rval;
        break;
      default:
        throw new Error("Unexpected arithmetic operator: " + opType);
    }
    return maybeReplaceBinaryOpWithNumericResult(result, lval, rval);
  }
private Node performArithmeticOp ( Token opType , Node left , Node right ) { if ( opType == Token . ADD && ( NodeUtil . mayBeString ( left , shouldUseTypes ) || NodeUtil . mayBeString ( right , shouldUseTypes ) ) ) { return null ; } double result ; Double lValObj = getSideEffectFreeNumberValue ( left ) ; Double rValObj = getSideEffectFreeNumberValue ( right ) ; if ( ( lValObj == null && rValObj == null ) || ! isNumeric ( left ) || ! isNumeric ( right ) ) { return null ; } switch ( opType ) { case ADD : if ( lValObj != null && rValObj != null ) { return maybeReplaceBinaryOpWithNumericResult ( lValObj + rValObj , lValObj , rValObj ) ; } if ( lValObj != null && lValObj == 0 ) { return right . cloneTree ( true ) ; } else if ( rValObj != null && rValObj == 0 ) { return left . cloneTree ( true ) ; } return null ; case SUB : if ( lValObj != null && rValObj != null ) { return maybeReplaceBinaryOpWithNumericResult ( lValObj - rValObj , lValObj , rValObj ) ; } if ( lValObj != null && lValObj == 0 ) { return IR . neg ( right . cloneTree ( true ) ) ; } else if ( rValObj != null && rValObj == 0 ) { return left . cloneTree ( true ) ; } return null ; case MUL : if ( lValObj != null && rValObj != null ) { return maybeReplaceBinaryOpWithNumericResult ( lValObj * rValObj , lValObj , rValObj ) ; } if ( lValObj != null ) { if ( lValObj == 1 ) { return right . cloneTree ( true ) ; } } else { if ( rValObj == 1 ) { return left . cloneTree ( true ) ; } } return null ; case DIV : if ( lValObj != null && rValObj != null ) { if ( rValObj == 0 ) { return null ; } return maybeReplaceBinaryOpWithNumericResult ( lValObj / rValObj , lValObj , rValObj ) ; } if ( rValObj != null ) { if ( rValObj == 1 ) { return left . cloneTree ( true ) ; } } return null ; case EXPONENT : if ( lValObj != null && rValObj != null ) { return maybeReplaceBinaryOpWithNumericResult ( Math . pow ( lValObj , rValObj ) , lValObj , rValObj ) ; } return null ; default : } if ( lValObj == null || rValObj == null ) { return null ; } double lval = lValObj ; double rval = rValObj ; switch ( opType ) { case BITAND : result = NodeUtil . toInt32 ( lval ) & NodeUtil . toInt32 ( rval ) ; break ; case BITOR : result = NodeUtil . toInt32 ( lval ) | NodeUtil . toInt32 ( rval ) ; break ; case BITXOR : result = NodeUtil . toInt32 ( lval ) ^ NodeUtil . toInt32 ( rval ) ; break ; case MOD : if ( rval == 0 ) { return null ; } result = lval % rval ; break ; default : throw new Error ( "Unexpected arithmetic operator: " + opType ) ; } return maybeReplaceBinaryOpWithNumericResult ( result , lval , rval ) ; }
Try to fold arithmetic binary operators
Try to fold arithmetic binary operators
// Unlike other operations, ADD operands are not always converted // to Number. // TODO(johnlenz): Handle NaN with unknown value. BIT ops convert NaN // to zero so this is a little awkward here. // at least one of the two operands must have a value and both must be numeric // handle the operations that have algebraic identities, since we can simplify the tree without // actually knowing the value statically. // 0 - x -> -x // x - 0 -> x // NOTE: 0*x != 0 for all x, if x==0, then it is NaN.  So we can't take advantage of that // without some kind of non-NaN proof.  So the special cases here only deal with 1*x // NOTE: 0/x != 0 for all x, if x==0, then it is NaN // x/1->x // fall-through