/* * Get the index of comment which contains given position. If there's no * matching comment, then return depends on exact parameter: = 0: return -1 * < 0: return index of the comment before the given position > 0: return * index of the comment after the given position */ private int getCommentIndex(int start, int position, int exact) { if (position == 0) { if (this.comments.length > 0 && this.comments[0].getStart() == 0) { return 0; } return -1; } int bottom = start, top = this.comments.length - 1; int i = 0, index = -1; Comment comment = null; while (bottom <= top) { i = bottom + (top - bottom) / 2; comment = this.comments[i]; int commentStart = comment.getStart(); if (position < commentStart) { top = i - 1; } else if (position >= (commentStart + comment.getLength())) { bottom = i + 1; } else { index = i; break; } } if (index < 0 && exact != 0) { comment = this.comments[i]; if (position < comment.getStart()) { return exact < 0 ? i - 1 : i; } else { return exact < 0 ? i : i + 1; } } return index; }
/** * Search and store node trailing comments. Comments are searched in position range from node end * position to specified next start. If one or several comment are found, returns last comment end * position, otherwise returns node end position. * * <p>Starts to search for first comment after node end position and return if none was found... * * <p>When first comment is found after node, goes down in comment list until one of following * conditions becomes true: * * <ol> * <li>comment start is after next start * <li>there's other than white characters between current node and comment * <li>TODO there's more than 1 line between current node and comment * </ol> * * If at least potential comments have been found, then all of them has to be separated from * following node. So, remove all comments which do not verify this assumption. Note that this * verification is not applicable on last node. * * <p>If finally there's still trailing comments, then stores indexes of the first and last one in * trailing comments table. */ int storeTrailingComments(ASTNode node, int nextStart, boolean lastChild, int[] parentLineRange) { // Init extended position int nodeEnd = node.getEnd() - 1; if (nodeEnd == nextStart) { // special case for last child of its parent if (++this.trailingPtr == 0) { this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; this.trailingIndexes = new long[STORAGE_INCREMENT]; this.lastTrailingPtr = -1; } else if (this.trailingPtr == this.trailingNodes.length) { int newLength = (this.trailingPtr * 3 / 2) + STORAGE_INCREMENT; System.arraycopy( this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); System.arraycopy( this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); } this.trailingNodes[this.trailingPtr] = node; this.trailingIndexes[this.trailingPtr] = -1; return nodeEnd; } int extended = nodeEnd; // Get line number int nodeEndLine = getLineNumber(nodeEnd, parentLineRange); // Find comments range index int idx = getCommentIndex(0, nodeEnd, 1); if (idx == -1) { return nodeEnd; } // Look after potential comments int startIdx = idx; int endIdx = -1; int length = this.comments.length; int commentStart = extended + 1; int previousEnd = nodeEnd + 1; int sameLineIdx = -1; while (idx < length && commentStart < nextStart) { // get comment and leave if next starting position has been reached Comment comment = this.comments[idx]; commentStart = comment.getStart(); // verify that there's nothing else than white spaces between // node/comments if (commentStart >= nextStart) { // stop search on condition 1) break; } else if (previousEnd < commentStart) { try { resetTo(previousEnd, commentStart); this.scanner.next_token(); String token = this.scanner.yytext(); if (token != null && token.trim().length() > 0) { // stop search on condition 2) // if first index fails, then there's no extended // position in fact... if (idx == startIdx) { return nodeEnd; } // otherwise we get the last index of trailing comment // => break break; } } catch (Exception e) { // Should not happen, but return no extended position... assert false; return nodeEnd; } } // Store index if we're on the same line than node end int commentLine = getLineNumber(commentStart, parentLineRange); if (commentLine == nodeEndLine) { sameLineIdx = idx; } // Store previous infos previousEnd = commentStart + comment.getLength(); endIdx = idx++; } if (endIdx != -1) { // Verify that following node start is separated if (!lastChild) { int nextLine = getLineNumber(nextStart, parentLineRange); int previousLine = getLineNumber(previousEnd, parentLineRange); if ((nextLine - previousLine) <= 1) { if (sameLineIdx == -1) return nodeEnd; endIdx = sameLineIdx; } } // Store trailing comments indexes if (++this.trailingPtr == 0) { this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; this.trailingIndexes = new long[STORAGE_INCREMENT]; this.lastTrailingPtr = -1; } else if (this.trailingPtr == this.trailingNodes.length) { int newLength = (this.trailingPtr * 3 / 2) + STORAGE_INCREMENT; System.arraycopy( this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); System.arraycopy( this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); } this.trailingNodes[this.trailingPtr] = node; long nodeRange = (((long) startIdx) << 32) + endIdx; this.trailingIndexes[this.trailingPtr] = nodeRange; // Compute new extended end extended = this.comments[endIdx].getEnd() - 1; // Look for children unresolved extended end ASTNode previousNode = node; int ptr = this.trailingPtr - 1; // children extended end were stored // before while (ptr >= 0) { long range = this.trailingIndexes[ptr]; if (range != -1) break; // there's no more unresolved nodes ASTNode unresolved = this.trailingNodes[ptr]; if (previousNode != unresolved.getParent()) break; // we're no longer in node ancestor hierarchy this.trailingIndexes[ptr] = nodeRange; previousNode = unresolved; ptr--; // get previous node } // Remove remaining unresolved nodes if (ptr > this.lastTrailingPtr) { int offset = ptr - this.lastTrailingPtr; for (int i = ptr + 1; i <= this.trailingPtr; i++) { this.trailingNodes[i - offset] = this.trailingNodes[i]; this.trailingIndexes[i - offset] = this.trailingIndexes[i]; } this.trailingPtr -= offset; } this.lastTrailingPtr = this.trailingPtr; } return extended; }
/** * Search and store node leading comments. Comments are searched in position range from previous * extended position to node start position. If one or several comment are found, returns first * comment start position, otherwise returns node start position. * * <p>Starts to search for first comment before node start position and return if none was * found... * * <p>When first comment is found before node, goes up in comment list until one of following * conditions becomes true: * * <ol> * <li>comment end is before previous end * <li>comment start and previous end is on the same line but not on same line of node start * <li>there's other than white characters between current node and comment * <li>TODO : there's more than 1 line between current node and comment * </ol> * * If some comment have been found, then no token should be on on the same line before, so remove * all comments which do not verify this assumption. * * <p>If finally there's leading still comments, then stores indexes of the first and last one in * leading comments table. */ int storeLeadingComments(ASTNode node, int previousEnd, int[] parentLineRange) { // Init extended position int nodeStart = node.getStart(); int extended = nodeStart; // Get line of node start position int previousEndLine = getLineNumber(previousEnd, parentLineRange); int nodeStartLine = getLineNumber(nodeStart, parentLineRange); // Find first comment index int idx = getCommentIndex(0, nodeStart, -1); if (idx == -1) { return nodeStart; } // Look after potential comments int startIdx = -1; int endIdx = idx; int previousStart = nodeStart; while (idx >= 0 && previousStart >= previousEnd) { // Verify for each comment that there's only white spaces between // end and start of {following comment|node} Comment comment = this.comments[idx]; int commentStart = comment.getStart(); int end = commentStart + comment.getLength() - 1; int commentLine = getLineNumber(commentStart, parentLineRange); if (end <= previousEnd || (commentLine == previousEndLine && commentLine != nodeStartLine)) { // stop search on condition 1) and 2) break; } else if ((end + 1) < previousStart) { // may be equals => then no // scan is necessary try { resetTo(end + 1, previousStart); this.scanner.next_token(); String token = this.scanner.yytext(); if (token != null && token.trim().length() > 0) { // stop search on condition 3) // if first comment fails, then there's no extended // position in fact if (idx == endIdx) { return nodeStart; } break; } } catch (Exception e) { // Should not happen, but return no extended position... assert false; return nodeStart; } } // Store previous infos previousStart = commentStart; startIdx = idx--; } if (startIdx != -1) { // Store leading comments indexes if (startIdx <= endIdx) { if (++this.leadingPtr == 0) { this.leadingNodes = new ASTNode[STORAGE_INCREMENT]; this.leadingIndexes = new long[STORAGE_INCREMENT]; } else if (this.leadingPtr == this.leadingNodes.length) { int newLength = (this.leadingPtr * 3 / 2) + STORAGE_INCREMENT; System.arraycopy( this.leadingNodes, 0, this.leadingNodes = new ASTNode[newLength], 0, this.leadingPtr); System.arraycopy( this.leadingIndexes, 0, this.leadingIndexes = new long[newLength], 0, this.leadingPtr); } this.leadingNodes[this.leadingPtr] = node; this.leadingIndexes[this.leadingPtr] = (((long) startIdx) << 32) + endIdx; extended = this.comments[endIdx].getStart(); } } return extended; }