Java Code Examples for com.google.javascript.rhino.Node#isNumber()

The following examples show how to use com.google.javascript.rhino.Node#isNumber() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ClosureOptimizePrimitives.java    From astor with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Returns whether the given call to goog.object.create can be converted to an
 * object literal.
 */
private boolean canOptimizeObjectCreate(Node firstParam) {
  Node curParam = firstParam;
  while (curParam != null) {
    // All keys must be strings or numbers.
    if (!curParam.isString() && !curParam.isNumber()) {
      return false;
    }
    curParam = curParam.getNext();

    // Check for an odd number of parameters.
    if (curParam == null) {
      return false;
    }
    curParam = curParam.getNext();
  }
  return true;
}
 
Example 2
Source File: PeepholeReplaceKnownMethods.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Try to evaluate String.indexOf/lastIndexOf:
 *     "abcdef".indexOf("bc") -> 1
 *     "abcdefbc".indexOf("bc", 3) -> 6
 */
private Node tryFoldStringIndexOf(
    Node n, String functionName, Node lstringNode, Node firstArg) {
  Preconditions.checkArgument(n.isCall());
  Preconditions.checkArgument(lstringNode.isString());

  String lstring = NodeUtil.getStringValue(lstringNode);
  boolean isIndexOf = functionName.equals("indexOf");
  Node secondArg = firstArg.getNext();
  String searchValue = NodeUtil.getStringValue(firstArg);
  // searchValue must be a valid string.
  if (searchValue == null) {
    return n;
  }
  int fromIndex = isIndexOf ? 0 : lstring.length();
  if (secondArg != null) {
    // Third-argument and non-numeric second arg are problematic. Discard.
    if (secondArg.getNext() != null || !secondArg.isNumber()) {
      return n;
    } else {
      fromIndex = (int) secondArg.getDouble();
    }
  }
  int indexVal = isIndexOf ? lstring.indexOf(searchValue, fromIndex)
                           : lstring.lastIndexOf(searchValue, fromIndex);
  Node newNode = IR.number(indexVal);
  n.getParent().replaceChild(n, newNode);

  reportCodeChange();

  return newNode;
}
 
Example 3
Source File: RemoveUnusedVars.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 4
Source File: Closure_23_PeepholeFoldConstants_t.java    From coming with MIT License 5 votes vote down vote up
private Node tryReduceVoid(Node n) {
  Node child = n.getFirstChild();
  if (!child.isNumber() || child.getDouble() != 0.0) {
    if (!mayHaveSideEffects(n)) {
      n.replaceChild(child, IR.number(0));
      reportCodeChange();
    }
  }
  return n;
}
 
Example 5
Source File: Closure_1_RemoveUnusedVars_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 6
Source File: Closure_45_RemoveUnusedVars_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 7
Source File: Closure_45_RemoveUnusedVars_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 8
Source File: Cardumen_00152_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 9
Source File: Cardumen_00152_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 10
Source File: PeepholeReplaceKnownMethods.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Try to fold .charAt() calls on strings
 */
private Node tryFoldStringCharAt(Node n, Node stringNode, Node arg1) {
  Preconditions.checkArgument(n.isCall());
  Preconditions.checkArgument(stringNode.isString());

  int index;
  String stringAsString = stringNode.getString();

  if (arg1 != null && arg1.isNumber()
      && arg1.getNext() == null) {
    index = (int) arg1.getDouble();
  } else {
    return n;
  }

  if (index < 0 || stringAsString.length() <= index) {
    // http://es5.github.com/#x15.5.4.4 says "" is returned when index is
    // out of bounds but we bail.
    return n;
  }

  Node resultNode = IR.string(
      stringAsString.substring(index, index + 1));
  Node parent = n.getParent();
  parent.replaceChild(n, resultNode);
  reportCodeChange();
  return resultNode;
}
 
Example 11
Source File: Cardumen_00203_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 12
Source File: Cardumen_00249_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 13
Source File: Cardumen_00249_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 14
Source File: Cardumen_0021_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 15
Source File: Cardumen_0021_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove all references to a parameter if possible otherwise simplify the
 * side-effect free parameters.
 */
private void tryRemoveArgFromCallSites(
    Node function, int argIndex, boolean canModifyAllSites) {
  Definition definition = getFunctionDefinition(function);

  for (UseSite site : defFinder.getUseSites(definition)) {
    if (isModifiableCallSite(site)) {
      Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
      if (arg != null) {
        Node argParent = arg.getParent();
        // Even if we can't change the signature in general we can always
        // remove an unused value off the end of the parameter list.
        if (canModifyAllSites
            || (arg.getNext() == null
                && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
          toRemove.add(arg);
        } else {
          // replace the node in the arg with 0
          if (!NodeUtil.mayHaveSideEffects(arg, compiler)
              && (!arg.isNumber() || arg.getDouble() != 0)) {
            toReplaceWithZero.add(arg);
          }
        }
      }
    }
  }
}
 
Example 16
Source File: DeclarationGenerator.java    From clutz with MIT License 4 votes vote down vote up
/**
 * Attempt to convert the node to a string enum or numeric enum and return a boolean indicating
 * whether it successfully emitted the enum.
 */
private boolean maybeStringOrNumericEnum(
    EnumType enumType,
    String unqualifiedName,
    Node objectOfAllMembers,
    Map<String, Node> elements) {

  JSType primitiveType = enumType.getEnumeratedTypeOfEnumObject();
  if (!primitiveType.equals(numberType) && !primitiveType.equals(stringType)) {
    return false;
  }

  // Look at all enum members. If any of the Closure string enum's values is not literal don't
  // emit anything and fall back to the safe conversion. Also, if any of the Closure string
  // enum's keys starts with a digit it's invalid in TS. Quoted digits are considered numeric as
  // well so they cannot be used as enum keys either.
  if (primitiveType.equals(stringType)) {
    for (Node c : objectOfAllMembers.children()) {
      if (Character.isDigit(c.getString().charAt(0))) {
        return false;
      }
      if (!c.getFirstChild().isString()) {
        return false;
      }
    }
  }

  maybeEmitJsDoc(enumType.getJSDocInfo(), /* ignoreParams= */ true);
  emit("enum");
  emit(unqualifiedName);
  emit("{");
  emitBreak();
  indent();

  for (String elem : sorted(elements.keySet())) {
    emit(elem);
    @Nullable Node n = elements.get(elem);
    if (n != null) {
      if (n.isNumber()) {
        emit("=");
        emit(String.valueOf(n.getDouble()));
      } else if (n.isString()) {
        emit("=");
        emit("'" + escapeEcmaScript(n.getString()) + "'");
      }
    }
    emit(",");
    emitBreak();
  }
  unindent();
  emit("}");
  emitBreak();
  return true;
}
 
Example 17
Source File: PeepholeFoldConstants.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Try to fold shift operations
 */
private Node tryFoldShift(Node n, Node left, Node right) {
  if (left.isNumber() &&
      right.isNumber()) {

    double result;
    double lval = left.getDouble();
    double rval = right.getDouble();

    // check ranges.  We do not do anything that would clip the double to
    // a 32-bit range, since the user likely does not intend that.
    if (!(lval >= Integer.MIN_VALUE && lval <= Integer.MAX_VALUE)) {
      report(BITWISE_OPERAND_OUT_OF_RANGE, left);
      return n;
    }

    // only the lower 5 bits are used when shifting, so don't do anything
    // if the shift amount is outside [0,32)
    if (!(rval >= 0 && rval < 32)) {
      report(SHIFT_AMOUNT_OUT_OF_BOUNDS, right);
      return n;
    }

    // Convert the numbers to ints
    int lvalInt = (int) lval;
    if (lvalInt != lval) {
      report(FRACTIONAL_BITWISE_OPERAND, left);
      return n;
    }

    int rvalInt = (int) rval;
    if (rvalInt != rval) {
      report(FRACTIONAL_BITWISE_OPERAND, right);
      return n;
    }

    switch (n.getType()) {
      case Token.LSH:
        result = lvalInt << rvalInt;
        break;
      case Token.RSH:
        result = lvalInt >> rvalInt;
        break;
      case Token.URSH:
        // JavaScript handles zero shifts on signed numbers differently than
        // Java as an Java int can not represent the unsigned 32-bit number
        // where JavaScript can so use a long here.
        long lvalLong = lvalInt & 0xffffffffL;
        result = lvalLong >>> rvalInt;
        break;
      default:
        throw new AssertionError("Unknown shift operator: " +
            Token.name(n.getType()));
    }

    Node newNumber = IR.number(result);
    n.getParent().replaceChild(n, newNumber);
    reportCodeChange();

    return newNumber;
  }

  return n;
}
 
Example 18
Source File: PeepholeReplaceKnownMethods.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Try to fold .substr() calls on strings
 */
private Node tryFoldStringSubstr(Node n, Node stringNode, Node arg1) {
  Preconditions.checkArgument(n.isCall());
  Preconditions.checkArgument(stringNode.isString());

  int start, length;
  String stringAsString = stringNode.getString();

  // TODO(nicksantos): We really need a NodeUtil.getNumberValue
  // function.
  if (arg1 != null && arg1.isNumber()) {
    start = (int) arg1.getDouble();
  } else {
    return n;
  }

  Node arg2 = arg1.getNext();
  if (arg2 != null) {
    if (arg2.isNumber()) {
      length = (int) arg2.getDouble();
    } else {
      return n;
    }

    if (arg2.getNext() != null) {
      // If we got more args than we expected, bail out.
      return n;
    }
  } else {
    // parameter 2 not passed
    length = stringAsString.length() - start;
  }

  // Don't handle these cases. The specification actually does
  // specify the behavior in some of these cases, but we haven't
  // done a thorough investigation that it is correctly implemented
  // in all browsers.
  if ((start + length) > stringAsString.length() ||
      (length < 0) ||
      (start < 0)) {
    return n;
  }

  String result = stringAsString.substring(start, start + length);
  Node resultNode = IR.string(result);

  Node parent = n.getParent();
  parent.replaceChild(n, resultNode);
  reportCodeChange();
  return resultNode;
}
 
Example 19
Source File: Closure_23_PeepholeFoldConstants_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * Try to fold shift operations
 */
private Node tryFoldShift(Node n, Node left, Node right) {
  if (left.isNumber() &&
      right.isNumber()) {

    double result;
    double lval = left.getDouble();
    double rval = right.getDouble();

    // check ranges.  We do not do anything that would clip the double to
    // a 32-bit range, since the user likely does not intend that.
    if (!(lval >= Integer.MIN_VALUE && lval <= Integer.MAX_VALUE)) {
      error(BITWISE_OPERAND_OUT_OF_RANGE, left);
      return n;
    }

    // only the lower 5 bits are used when shifting, so don't do anything
    // if the shift amount is outside [0,32)
    if (!(rval >= 0 && rval < 32)) {
      error(SHIFT_AMOUNT_OUT_OF_BOUNDS, right);
      return n;
    }

    // Convert the numbers to ints
    int lvalInt = (int) lval;
    if (lvalInt != lval) {
      error(FRACTIONAL_BITWISE_OPERAND, left);
      return n;
    }

    int rvalInt = (int) rval;
    if (rvalInt != rval) {
      error(FRACTIONAL_BITWISE_OPERAND, right);
      return n;
    }

    switch (n.getType()) {
      case Token.LSH:
        result = lvalInt << rvalInt;
        break;
      case Token.RSH:
        result = lvalInt >> rvalInt;
        break;
      case Token.URSH:
        // JavaScript handles zero shifts on signed numbers differently than
        // Java as an Java int can not represent the unsigned 32-bit number
        // where JavaScript can so use a long here.
        long lvalLong = lvalInt & 0xffffffffL;
        result = lvalLong >>> rvalInt;
        break;
      default:
        throw new AssertionError("Unknown shift operator: " +
            Token.name(n.getType()));
    }

    Node newNumber = IR.number(result);
    n.getParent().replaceChild(n, newNumber);
    reportCodeChange();

    return newNumber;
  }

  return n;
}
 
Example 20
Source File: Closure_23_PeepholeFoldConstants_t.java    From coming with MIT License 4 votes vote down vote up
private Node tryFoldArrayAccess(Node n, Node left, Node right) {
  Node parent = n.getParent();
  // If GETPROP/GETELEM is used as assignment target the array literal is
  // acting as a temporary we can't fold it here:
  //    "[][0] += 1"
  if (isAssignmentTarget(n)) {
    return n;
  }

  if (!right.isNumber()) {
    // Sometimes people like to use complex expressions to index into
    // arrays, or strings to index into array methods.
    return n;
  }

  double index = right.getDouble();
  int intIndex = (int) index;
  if (intIndex != index) {
    error(INVALID_GETELEM_INDEX_ERROR, right);
    return n;
  }

  if (intIndex < 0) {
    error(INDEX_OUT_OF_BOUNDS_ERROR, right);
    return n;
  }

  Node current = left.getFirstChild();
  Node elem = null;
  for (int i = 0; current != null; i++) {
    if (i != intIndex) {
      if (mayHaveSideEffects(current)) {
        return n;
      }
    } else {
      elem = current;
    }

    current = current.getNext();
  }

  if (elem == null) {
    error(INDEX_OUT_OF_BOUNDS_ERROR, right);
    return n;
  }

  if (elem.isEmpty()) {
    elem = NodeUtil.newUndefinedNode(elem);
  } else {
    left.removeChild(elem);
  }

  // Replace the entire GETELEM with the value
  n.getParent().replaceChild(n, elem);
  reportCodeChange();
  return elem;
}