com.intellij.psi.SyntaxTraverser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-api Show documentation
Show all versions of core-api Show documentation
A packaging of the IntelliJ Community Edition core-api library.
This is release number 1 of trunk branch 142.
The newest version!
package com.intellij.psi;
import com.intellij.lang.*;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.Function;
import com.intellij.util.UnmodifiableIterator;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FilteredTraverser;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
/**
* @author gregsh
*/
public abstract class SyntaxTraverser extends FilteredTraverser> implements Iterable {
@NotNull
public static SyntaxTraverser psiTraverser() {
return new PsiTraverser(null);
}
@NotNull
public static SyntaxTraverser revPsiTraverser() {
return new RevPsiTraverser(null);
}
@NotNull
public static SyntaxTraverser astTraverser() {
return new ASTTraverser(null);
}
@NotNull
public static SyntaxTraverser lightTraverser(PsiBuilder builder) {
FlyweightCapableTreeStructure lightTree = builder.getLightTree();
Meta meta = FilteredTraverser.emptyMeta().withRoots(Collections.singletonList(lightTree.getRoot()));
return new LightASTTraverser(meta, builder.getOriginalText(), lightTree);
}
protected SyntaxTraverser(@Nullable Meta meta) {
super(meta);
}
@NotNull
public abstract IElementType nodeType(@NotNull T node);
@NotNull
public abstract TextRange nodeRange(@NotNull T node);
@NotNull
public abstract CharSequence nodeText(@NotNull T node);
@Nullable
public abstract T parent(@NotNull T node);
@NotNull
public SyntaxTraverser expandTypes(@NotNull Condition super IElementType> condition) {
return super.expand(Conditions.compose(NODE_TYPE(), condition));
}
@NotNull
public SyntaxTraverser filterTypes(@NotNull Condition super IElementType> condition) {
return super.filter(Conditions.compose(NODE_TYPE(), condition));
}
@NotNull
public Function NODE_TYPE() {
return new Function() {
@Override
public IElementType fun(T t) {
return nodeType(t);
}
};
}
@Nullable
public T getRawDeepestLast() {
for (T result = getRoot(), last; result != null; result = last) {
JBIterable children = children(result);
if (children.isEmpty()) return result;
//noinspection AssignmentToForLoopParameter
last = children.last();
}
return null;
}
@NotNull
public JBIterable parents(@Nullable final T element) {
return new JBIterable() {
@Override
public Iterator iterator() {
return new Iterator() {
T cur = element;
@Override
public boolean hasNext() {
return cur != null;
}
@Override
public T next() {
T result = cur;
cur = parent(cur);
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
private abstract static class FirstNextTraverser extends SyntaxTraverser {
public FirstNextTraverser(Meta meta) {
super(meta);
}
@Nullable
protected abstract T first(@NotNull T node);
@Nullable
protected abstract T next(@NotNull T node);
@Override
protected final Iterable childrenImpl(@NotNull final T node) {
final T first = first(node);
if (first == null) return JBIterable.empty();
return new JBIterable() {
@Override
public Iterator iterator() {
return new UnmodifiableIterator(null) {
T cur = first;
@Override
public boolean hasNext() {
return cur != null;
}
@Override
public T next() {
T result = cur;
cur = FirstNextTraverser.this.next(cur);
return result;
}
};
}
};
}
}
private static class PsiTraverser extends FirstNextTraverser {
public PsiTraverser(Meta meta) {
super(meta);
}
@Override
protected SyntaxTraverser newInstance(Meta meta) {
return new PsiTraverser(meta);
}
@Nullable
protected PsiElement first(@NotNull PsiElement node) {
return node.getFirstChild();
}
@Nullable
protected PsiElement next(@NotNull PsiElement node) {
return node.getNextSibling();
}
@NotNull
@Override
public IElementType nodeType(@NotNull PsiElement node) {
return node.getNode().getElementType();
}
@NotNull
@Override
public TextRange nodeRange(@NotNull PsiElement node) {
return node.getTextRange();
}
@NotNull
@Override
public CharSequence nodeText(@NotNull PsiElement node) {
return node.getText();
}
@Nullable
@Override
public PsiElement parent(@NotNull PsiElement node) {
PsiElement parent = node.getParent();
return parent instanceof PsiFile ? null : parent;
}
}
private static class RevPsiTraverser extends PsiTraverser {
public RevPsiTraverser(Meta meta) {
super(meta);
}
@Override
protected SyntaxTraverser newInstance(Meta meta) {
return new RevPsiTraverser(meta);
}
@Nullable
@Override
protected PsiElement first(@NotNull PsiElement node) {
return node.getLastChild();
}
@Nullable
@Override
protected PsiElement next(@NotNull PsiElement node) {
return node.getPrevSibling();
}
}
private static class ASTTraverser extends FirstNextTraverser {
public ASTTraverser(Meta meta) {
super(meta);
}
@Override
protected SyntaxTraverser newInstance(Meta meta) {
return new ASTTraverser(meta);
}
@Nullable
@Override
protected ASTNode first(@NotNull ASTNode node) {
return node.getFirstChildNode();
}
@Nullable
@Override
protected ASTNode next(@NotNull ASTNode node) {
return node.getTreeNext();
}
@NotNull
@Override
public IElementType nodeType(@NotNull ASTNode node) {
return node.getElementType();
}
@NotNull
@Override
public TextRange nodeRange(@NotNull ASTNode node) {
return node.getTextRange();
}
@NotNull
@Override
public CharSequence nodeText(@NotNull ASTNode node) {
return node.getText();
}
@Nullable
@Override
public ASTNode parent(@NotNull ASTNode node) {
return node.getTreeParent();
}
}
private abstract static class FlyweightTraverser extends SyntaxTraverser {
final FlyweightCapableTreeStructure myTree;
FlyweightTraverser(@NotNull Meta meta,
@NotNull FlyweightCapableTreeStructure structure) {
super(meta);
myTree = structure;
}
@Nullable
@Override
public T parent(@NotNull T node) {
return myTree.getParent(node);
}
@Override
protected Iterable childrenImpl(@NotNull final T node) {
return new JBIterable() {
@Override
public Iterator iterator() {
Ref ref = Ref.create();
int count = myTree.getChildren(myTree.prepareForGetChildren(node), ref);
if (count == 0) return ContainerUtil.emptyIterator();
T[] array = ref.get();
LinkedList list = ContainerUtil.newLinkedList();
for (int i = 0; i < count; i++) {
T t = array[i];
if (nodeType(t).getLanguage() == Language.ANY) continue; // skip TokenType.* types
array[i] = null; // do not dispose meaningful TokenNodes
list.addLast(t);
}
myTree.disposeChildren(array, count);
return list.iterator();
}
};
}
}
private static class LightASTTraverser extends FlyweightTraverser {
private final CharSequence myText;
public LightASTTraverser(@NotNull Meta meta,
@NotNull CharSequence text,
@NotNull FlyweightCapableTreeStructure structure) {
super(meta, structure);
myText = text;
}
@Override
protected SyntaxTraverser newInstance(Meta meta) {
return new LightASTTraverser(meta, myText, myTree);
}
@NotNull
@Override
public IElementType nodeType(@NotNull LighterASTNode node) {
return node.getTokenType();
}
@NotNull
@Override
public TextRange nodeRange(@NotNull LighterASTNode node) {
return TextRange.create(node.getStartOffset(), node.getEndOffset());
}
@NotNull
@Override
public CharSequence nodeText(@NotNull LighterASTNode node) {
return myText.subSequence(node.getStartOffset(), node.getEndOffset());
}
@Nullable
@Override
public LighterASTNode parent(@NotNull LighterASTNode node) {
return node instanceof LighterASTTokenNode ? null : super.parent(node);
}
}
}