private void tryConvertToNumber(Node n) { switch (n.getType()) { case NUMBER: // Nothing to do return; case AND: case OR: case COMMA: tryConvertToNumber(n.getLastChild()); return; case HOOK: tryConvertToNumber(n.getSecondChild()); tryConvertToNumber(n.getLastChild()); return; case NAME: if (!NodeUtil.isUndefined(n)) { return; } break; } Double result = NodeUtil.getNumberValue(n, shouldUseTypes); if (result == null) { return; } double value = result; Node replacement = NodeUtil.numberNode(value, n); if (replacement.isEquivalentTo(n)) { return; } n.getParent().replaceChild(n, replacement); reportCodeChange(); }
/** Try to fold arithmetic binary operators */ private Node performArithmeticOp(Token opType, Node left, Node right) { // Unlike other operations, ADD operands are not always converted // to Number. if (opType == Token.ADD && (NodeUtil.mayBeString(left, shouldUseTypes) || NodeUtil.mayBeString(right, shouldUseTypes))) { return null; } double result; // TODO(johnlenz): Handle NaN with unknown value. BIT ops convert NaN // to zero so this is a little awkward here. Double lValObj = NodeUtil.getNumberValue(left, shouldUseTypes); if (lValObj == null) { return null; } Double rValObj = NodeUtil.getNumberValue(right, shouldUseTypes); if (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 ADD: result = lval + rval; break; case SUB: result = lval - rval; break; case MUL: result = lval * rval; break; case MOD: if (rval == 0) { return null; } result = lval % rval; break; case DIV: if (rval == 0) { return null; } result = lval / rval; break; default: throw new Error("Unexpected arithmetic operator"); } // TODO(johnlenz): consider removing the result length check. // length of the left and right value plus 1 byte for the operator. if ((String.valueOf(result).length() <= String.valueOf(lval).length() + String.valueOf(rval).length() + 1 // Do not try to fold arithmetic for numbers > 2^53. After that // point, fixed-point math starts to break down and become inaccurate. && Math.abs(result) <= MAX_FOLD_NUMBER) || Double.isNaN(result) || result == Double.POSITIVE_INFINITY || result == Double.NEGATIVE_INFINITY) { return NodeUtil.numberNode(result, null); } return null; }