All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.psi.SyntaxTraverser Maven / Gradle / Ivy

Go to download

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 condition) {
    return super.expand(Conditions.compose(NODE_TYPE(), condition));
  }

  @NotNull
  public SyntaxTraverser filterTypes(@NotNull Condition 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);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy