/**
  * Determines if the damage region affects a particular tree node, looking only at those tokens
  * that actually belong to the node and not to its children.
  */
 protected boolean isDamageTreeNode(ISimpleTerm tree, boolean isOriginalTree, int skippedChars) {
   IToken current = findLeftMostLayoutToken(getLeftToken(tree));
   IToken last = findRightMostLayoutToken(getRightToken(tree));
   if (current != null && last != null) {
     if (!isDamagedRange(
         current.getStartOffset(), last.getEndOffset(), isOriginalTree, skippedChars))
       return false;
     Iterator<ISimpleTerm> iterator = tryGetListIterator(tree);
     for (int i = 0, max = tree.getSubtermCount(); i < max; i++) {
       ISimpleTerm child = iterator == null ? tree.getSubterm(i) : iterator.next();
       IToken childLeft = findLeftMostLayoutToken(getLeftToken(child));
       IToken childRight = findRightMostLayoutToken(getRightToken(child));
       if (childLeft != null && childRight != null) {
         if (childLeft.getIndex() > current.getIndex()
             && isDamagedRange(
                 current.getEndOffset() + 1,
                 childLeft.getStartOffset() - 1,
                 isOriginalTree,
                 skippedChars)) {
           return true;
         }
         current = childRight;
       }
     }
     return isDamagedRange(
         current.getEndOffset() + 1, last.getEndOffset(), isOriginalTree, skippedChars);
   } else {
     return false;
   }
 }
  /**
   * Gets all non-list tree nodes from a tree that are in the damage region according to {@link
   * #isDamageTreeNode}. Tries to take the innermost {@link #incrementalSorts} tree node where
   * possible instead of taking an inner non-incremental tree node.
   *
   * @param tree Current tree node
   * @param results Found tree nodes
   * @param isOriginalTree Whether the tree is the input tree of the incremental parser
   * @param skippedChars See {@link IncrementalInputBuilder#getLastSkippedCharsBeforeDamage()}.
   * @param outerIncrementalNode The innermost ancestor of the current tree that is in {@link
   *     #incrementalSorts}.
   * @return the last ancestral tree node added to the list
   */
  private ISimpleTerm getDamageRegionTreeNodes(
      ISimpleTerm tree,
      List<ISimpleTerm> results,
      boolean isOriginalTree,
      int skippedChars,
      ISimpleTerm outerIncrementalNode) {

    if (incrementalSorts.isIncrementalNode(tree)) outerIncrementalNode = tree;

    if (!tree.isList() // prefer adding list children
        && isDamageTreeNode(tree, isOriginalTree, skippedChars))
      return addDamageRegionTreeNode(tree, results, outerIncrementalNode);

    // Recurse
    boolean addedChild = false;
    Iterator<ISimpleTerm> iterator = tryGetListIterator(tree);
    for (int i = 0, max = tree.getSubtermCount(); i < max; i++) {
      ISimpleTerm child = iterator == null ? tree.getSubterm(i) : iterator.next();
      ISimpleTerm addedAncestor =
          getDamageRegionTreeNodes(
              child, results, isOriginalTree, skippedChars, outerIncrementalNode);
      if (addedAncestor != null && addedAncestor == outerIncrementalNode) return addedAncestor;
      addedChild = true;
    }

    if (!addedChild
        && tree.isList() // add list (outerIncrementalNode), if we must
        && isDamageTreeNode(tree, isOriginalTree, skippedChars))
      return addDamageRegionTreeNode(tree, results, outerIncrementalNode);

    return null;
  }
  private void bindAstNode(ISimpleTerm node, int tokenIndex, int endTokenIndex) {
    assert getTokenizer(node) == this;
    int tokenCount = getTokenCount();

    // Set ast node for spaces between children and recursively for children
    Iterator<ISimpleTerm> iterator = SimpleTermVisitor.tryGetListIterator(node);
    for (int i = 0, max = node.getSubtermCount(); i < max; i++) {
      ISimpleTerm child = iterator == null ? node.getSubterm(i) : iterator.next();

      int childStart = getLeftToken(child).getIndex();
      int childEnd = getRightToken(child).getIndex();

      while (tokenIndex < childStart && tokenIndex < tokenCount) {
        Token token = getTokenAt(tokenIndex++);
        token.setAstNode(node);
      }

      bindAstNode(child, childStart, childEnd);
      tokenIndex = childEnd + 1;
    }

    // Set ast node for tokens after children
    while (tokenIndex <= endTokenIndex && tokenIndex < tokenCount) {
      Token token = getTokenAt(tokenIndex++);
      token.setAstNode(node);
    }
  }