protected List<ILeafNode> findNextHiddenLeafs(final INode node) { ArrayList<ILeafNode> _xblockexpression = null; { final ArrayList<ILeafNode> result = CollectionLiterals.<ILeafNode>newArrayList(); final NodeIterator ni = new NodeIterator(node); while (ni.hasNext()) { { final INode next = ni.next(); if ((next instanceof ILeafNode)) { boolean _isHidden = ((ILeafNode)next).isHidden(); if (_isHidden) { result.add(((ILeafNode)next)); } else { return result; } } } } _xblockexpression = result; } return _xblockexpression; }
protected ILeafNode findPreviousLeaf(final INode node, final Function1<? super ILeafNode, ? extends Boolean> matches) { INode current = node; while ((current instanceof ICompositeNode)) { current = ((ICompositeNode)current).getLastChild(); } if (((current instanceof ILeafNode) && (matches.apply(((ILeafNode) current))).booleanValue())) { return ((ILeafNode) current); } if ((current != null)) { final NodeIterator ni = new NodeIterator(current); while (ni.hasPrevious()) { { final INode previous = ni.previous(); if (((previous instanceof ILeafNode) && (matches.apply(((ILeafNode) previous))).booleanValue())) { return ((ILeafNode) previous); } } } } return null; }
public ILeafNode findNextLeaf(final INode node, final Function1<? super ILeafNode, ? extends Boolean> matches) { Object _xifexpression = null; if ((node != null)) { if (((node instanceof ILeafNode) && (matches.apply(((ILeafNode) node))).booleanValue())) { return ((ILeafNode) node); } final NodeIterator ni = new NodeIterator(node); while (ni.hasNext()) { { final INode next = ni.next(); if (((next instanceof ILeafNode) && (matches.apply(((ILeafNode) next))).booleanValue())) { return ((ILeafNode) next); } } } } return ((ILeafNode)_xifexpression); }
protected Set<INode> getLeadingCommentsIncludingWhitespace(ILeafNode node) { Set<INode> associatedNodes = Sets.newHashSet(); Set<INode> pendingWhitespace = Sets.newHashSet(); INode lastLink = node; NodeIterator ni = new NodeIterator(lastLink); while(ni.hasPrevious()) { INode prev = ni.previous(); if (tokenUtil.isCommentNode(prev)) { if (isLeadingCommentFor(prev, lastLink)) { lastLink = prev; associatedNodes.addAll(pendingWhitespace); associatedNodes.add(prev); } else { break; } } else if (tokenUtil.isWhitespaceNode(prev)) { pendingWhitespace.add(prev); } else if (prev instanceof ILeafNode){ break; } } return associatedNodes; }
protected Set<INode> getTrailingCommentsIncludingWhitespace(ILeafNode node) { Set<INode> associatedNodes = Sets.newHashSet(); Set<INode> pendingWhitespace = Sets.newHashSet(); INode lastLink = node; NodeIterator ni = new NodeIterator(lastLink); while(ni.hasNext()) { INode next = ni.next(); if (tokenUtil.isCommentNode(next)) { if (isTrailingCommentFor(next, lastLink)) { lastLink = next; associatedNodes.addAll(pendingWhitespace); associatedNodes.add(next); } else { break; } } else if (tokenUtil.isWhitespaceNode(next)) { pendingWhitespace.add(next); } else if (next instanceof ILeafNode){ break; } } return associatedNodes; }
protected List<INode> getRemainingHiddenNodesInContainer(INode from, INode root) { if (from == null || root == null) return Collections.emptyList(); List<INode> out = Lists.newArrayList(); NodeIterator ni = new NodeIterator(from); while (ni.hasNext()) { INode next = ni.next(); if (next.getTotalOffset() > root.getTotalEndOffset()) return out; else if (tokenUtil.isWhitespaceOrCommentNode(next)) { out.add(next); } else if (tokenUtil.isToken(next)) return Collections.emptyList(); } return out; }
public EmitterNodeIterator(INode fromNode, INode toNode, boolean passAbsorber, boolean allowHidden) { if (fromNode != null) { this.iterator = new NodeIterator(fromNode); this.passAbsorber = passAbsorber; if (toNode != null) { if (toNode == fromNode) this.end = toNode.getOffset() + toNode.getLength(); else if (toNode.getOffset() < fromNode.getOffset()) this.end = toNode.getOffset() + toNode.getLength(); else this.end = toNode.getOffset(); } else this.end = Integer.MAX_VALUE; this.allowHidden = allowHidden; next(); } }
/** * Helper method that collects all the hidden tokens that follow the given node. * * @param from * starting point in the node model, must not be {@code null} * @param deletedSemanticElements * set of semantic elements that have been deleted from the model, must not be {@code null} * @return list of hidden tokens, never {@code null}, can be empty */ private List<INode> getFollowingHiddenTokens(final INode from, final Set<EObject> deletedSemanticElements) { List<INode> result = Lists.newArrayList(); NodeIterator nodes = new NodeIterator(from); while (nodes.hasNext()) { INode next = nodes.next(); if (next.getTotalOffset() > rootEndOffset || next.equals(lastEmittedNode)) { break; } else if (tokenUtil.isWhitespaceOrCommentNode(next)) { if (!emittedComments.contains(next)) { result.add(next); } } else if (belongsToDeletedElement(next)) { handleDeletedElement(result, deletedSemanticElements, next); nodes.prune(); } else { break; } } return result; }
/** * Helper method that collects all the preceding hidden tokens for the given node. * * @param to * node model element to get the tokens for, must not be {@code null} * @param deletedSemanticElements * set of semantic elements that have been deleted from the model, must not be {@code null} * @return list of hidden tokens, never {@code null}, can be empty */ private List<INode> getPrecedingHiddenTokens(final INode to, final Set<EObject> deletedSemanticElements) { List<INode> result = Lists.newLinkedList(); NodeIterator nodes = new NodeIterator(to); while (nodes.hasPrevious()) { INode previous = nodes.previous(); if (previous.getTotalEndOffset() < rootOffset || previous.equals(lastEmittedNode)) { break; } else if (tokenUtil.isWhitespaceOrCommentNode(previous)) { if (!emittedComments.contains(previous)) { result.add(0, previous); } } else if (belongsToDeletedElement(previous)) { handleDeletedElement(result, deletedSemanticElements, previous); nodes.prune(); } else { break; } } return result; }
/** * Returns trailing comments of the given leaf node. * * @param node * leaf element of the node model to start looking from, must not be {@code null} * @return list of hidden tokens, can be empty, never {@code null} */ private List<INode> getTrailingCommentsIncludingWhitespace(final ILeafNode node) { List<INode> associatedNodes = Lists.newLinkedList(); Set<INode> pendingWhitespace = Sets.newHashSet(); INode lastLink = node; NodeIterator nodes = new NodeIterator(lastLink); while (nodes.hasNext()) { INode next = nodes.next(); if (tokenUtil.isCommentNode(next)) { if (isTrailingCommentFor(next, lastLink)) { lastLink = next; associatedNodes.addAll(pendingWhitespace); pendingWhitespace.clear(); associatedNodes.add(next); } else { break; } } else if (tokenUtil.isWhitespaceNode(next)) { pendingWhitespace.add(next); } else if (next instanceof ILeafNode) { break; } } return associatedNodes; }
/** * Returns the list of nodes that belong to 'root' node and follow the 'from' node. * * @param from * node model element to start from, must not be {@code null} * @param root * top-level node model element, must not be {@code null} * @return list of hiddens nodes, possibly empty, but never {@code null} */ private List<INode> getRemainingHiddenNodesInContainer(final INode from, final INode root) { if (from == null || root == null) { return Collections.emptyList(); } List<INode> out = Lists.newArrayList(); NodeIterator nodes = new NodeIterator(from); while (nodes.hasNext()) { INode next = nodes.next(); if (next.getStartLine() > root.getEndLine()) { return out; } else if (tokenUtil.isWhitespaceOrCommentNode(next)) { out.add(next); } else if (tokenUtil.isToken(next)) { return out; } } return out; }
protected List<ILeafNode> findPreviousHiddenLeafs(final INode node) { List<ILeafNode> _xblockexpression = null; { INode current = node; while ((current instanceof ICompositeNode)) { current = ((ICompositeNode)current).getLastChild(); } final ArrayList<ILeafNode> result = CollectionLiterals.<ILeafNode>newArrayList(); if ((current != null)) { final NodeIterator ni = new NodeIterator(current); while (ni.hasPrevious()) { { final INode previous = ni.previous(); if (((!Objects.equal(previous, current)) && (previous instanceof ILeafNode))) { boolean _isHidden = ((ILeafNode) previous).isHidden(); if (_isHidden) { result.add(((ILeafNode) previous)); } else { return ListExtensions.<ILeafNode>reverse(result); } } } } } _xblockexpression = ListExtensions.<ILeafNode>reverse(result); } return _xblockexpression; }
@Test public void testPruneComposite() throws Exception { NodeIterator nodeIterator = new NodeIterator(nodes[3]); nodeIterator.prune(); assertEquals(nodes[6], nodeIterator.next()); assertEquals(nodes[3], nodeIterator.previous()); assertEquals(nodes[2], nodeIterator.previous()); assertEquals(nodes[1], nodeIterator.previous()); }
@Test public void testPruneLeaf() throws Exception { // pruning a leaf should not have any effect NodeIterator nodeIterator = new NodeIterator(nodes[8]); nodeIterator.prune(); assertEquals(nodes[9], nodeIterator.next()); assertEquals(nodes[8], nodeIterator.previous()); assertEquals(nodes[7], nodeIterator.previous()); assertEquals(nodes[6], nodeIterator.previous()); }
protected void checkAscending(int index) { int i = index; NodeIterator nodeIterator = new NodeIterator(nodes[i]); while (nodeIterator.hasNext()) { assertEquals("Ascending " + i, nodes[++i], nodeIterator.next()); } }
protected void checkDescending(int index) { int i = index; NodeIterator nodeIterator = new NodeIterator(nodes[i]); while (nodeIterator.hasPrevious()) { assertEquals(nodes[--i], nodeIterator.previous()); } }
/** * Collects & emits the set of comments/whitespaces that logically belong to a container of some objects and <b>not</b> to the first child of the container. * * @param container * node model element that represents a container, must not be {@code null} */ private void emitContainerComments(final INode container) { List<INode> containerComments = Lists.newArrayList(); Set<INode> firstElementComments = getHiddenNodesBelongingTo(NodeModelUtils.findActualSemanticObjectFor(container)); NodeIterator nodes = new NodeIterator(container); while (nodes.hasNext()) { INode next = nodes.next(); if (firstElementComments.contains(next) || tokenUtil.isToken(next)) { break; } else if (tokenUtil.isWhitespaceOrCommentNode(next)) { containerComments.add(next); } } emitHiddenTokens(containerComments); }
/** * Returns the leading comments of the given leaf node. * * @param node * leaf element of the node model to look up to, must not be {@code null} * @return list of hidden tokens, can be empty, never {@code null} */ private List<INode> getLeadingCommentsIncludingWhitespace(final ILeafNode node) { List<INode> associatedNodes = Lists.newLinkedList(); Set<INode> pendingWhitespace = Sets.newHashSet(); INode lastLink = node; NodeIterator nodes = new NodeIterator(lastLink); while (nodes.hasPrevious()) { INode prev = nodes.previous(); if (tokenUtil.isCommentNode(prev)) { if (isLeadingCommentFor(prev, lastLink)) { lastLink = prev; associatedNodes.addAll(0, pendingWhitespace); pendingWhitespace.clear(); associatedNodes.add(0, prev); } else { break; } } else if (tokenUtil.isWhitespaceNode(prev)) { pendingWhitespace.add(prev); } else if (prev instanceof ILeafNode) { break; } } associatedNodes.addAll(0, pendingWhitespace); // We want trailing comments to have precedence over leading comments // Therefore all the trailing comments of the previous node must be computed // and deleted from the results, as they have been already output in previous call of 'emitTrailingTokens' method EObject nodeObject = NodeModelUtils.findActualSemanticObjectFor(node); ICompositeNode actualNode = NodeModelUtils.findActualNodeFor(nodeObject); INode previousNode = actualNode.getPreviousSibling(); if (previousNode instanceof ICompositeNode) { associatedNodes.removeAll(getTrailingCommentsIncludingWhitespace(previousNode)); } // Following line is need to insert a new line after the leading comments if it is needed, but wasn't originally present // See also usage in 'emitHiddenTokens' associatedNodes.add(0, new LeadingCommentsMarkerNode()); return associatedNodes; }
/** * Collects all the hidden tokens between two given nodes of the node model. * * @param from * node that serves as a start point, must not be {@code null} * @param to * search end point, must not be {@code null} * @param deletedSemanticElements * set of the deleted semantic elements, must not be {@code null} * @return list of hidden tokens, never {@code null}, but can be empty */ private List<INode> getHiddenTokensBetween(final INode from, final INode to, final Set<EObject> deletedSemanticElements) { EObject fromElement = NodeModelUtils.findActualSemanticObjectFor(from); if (from.equals(NodeModelUtils.getNode(fromElement))) { // If the starting node represents some container, emit the comments that belong to it // This is needed to correctly handle some edge cases like ImportList in AvqScript // Logic for distinguishing between container's comments and the ones of first element is expected to be implemented in 'isLeadingCommentFor' emitContainerComments(from); } List<INode> result = Lists.newArrayList(); boolean handleReordering = from.getTotalOffset() > to.getTotalOffset(); if (!handleReordering) { // Elements are not reordered // Just going through the interval and collecting comments, unless they have already been emitted NodeIterator nodes = new NodeIterator(from); while (nodes.hasNext()) { INode next = nodes.next(); if (tokenUtil.isWhitespaceOrCommentNode(next)) { if (!emittedComments.contains(next)) { result.add(next); } } else if (next.equals(to)) { // We have hit the 'to' node // If it is a composite one, we have to iterate through its children // and collect whitespaces/comments until we encounter first token (keyword, identifier...) if (next instanceof ICompositeNode && (GrammarUtil.isDatatypeRuleCall(next.getGrammarElement()) || GrammarUtil.isEnumRuleCall(next.getGrammarElement()) || next.getGrammarElement() instanceof CrossReference)) { while (nodes.hasNext()) { INode lastNodeChild = nodes.next(); if (tokenUtil.isWhitespaceOrCommentNode(lastNodeChild)) { if (!emittedComments.contains(lastNodeChild)) { result.add(lastNodeChild); } } else if (lastNodeChild instanceof ILeafNode) { break; } } break; } else { // 'to' node is not a composite one, nothing to do here, just exit the loop break; } } else if (belongsToDeletedElement(next)) { handleDeletedElement(result, deletedSemanticElements, next); nodes.prune(); } else if (tokenUtil.isToken(next)) { // We have encountered some token, but not the one we expected // Will be handled by invoking 'getLeadingCommentsIncludingWhitespace' method later handleReordering = true; break; } } } if (handleReordering) { return getLeadingCommentsIncludingWhitespace(to); } return result; }