/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.lang.psi.util;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiMatcher;
import com.intellij.psi.util.PsiMatcherExpression;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class LeafPsiMatcher implements PsiMatcher {
private final boolean reverse;
private PsiElement element;
public LeafPsiMatcher(PsiElement element) {
this(element, false);
}
public LeafPsiMatcher(PsiElement element, boolean reverse) {
this.element = element;
this.reverse = reverse;
}
public PsiMatcher parent(PsiMatcherExpression e) {
element = element.getParent();
if (element == null || (e != null && e.match(element) != Boolean.TRUE)) return NullPsiMatcherImpl.INSTANCE;
return this;
}
public PsiMatcher firstChild(PsiMatcherExpression e) {
final PsiElement[] children = getChildren();
for (PsiElement child : children) {
element = child;
if (e == null || e.match(element) == Boolean.TRUE) {
return this;
}
}
return NullPsiMatcherImpl.INSTANCE;
}
private PsiElement[] getChildren() {
final List<PsiElement> children = new ArrayList<>();
element.acceptChildren(new PsiElementVisitor() {
public void visitElement(PsiElement element) {
children.add(element);
}
});
if (reverse) {
Collections.reverse(children);
}
return children.toArray(PsiElement.EMPTY_ARRAY);
}
public PsiMatcher ancestor(PsiMatcherExpression e) {
while (element != null) {
Boolean res = e == null ? Boolean.TRUE : e.match(element);
if (res == Boolean.TRUE) break;
if (res == null) return NullPsiMatcherImpl.INSTANCE;
element = element.getParent();
}
if (element == null) return NullPsiMatcherImpl.INSTANCE;
return this;
}
public PsiMatcher descendant(PsiMatcherExpression e) {
final PsiElement[] children = getChildren();
for (PsiElement child : children) {
element = child;
final Boolean res = e == null ? Boolean.TRUE : e.match(element);
if (res == Boolean.TRUE) {
return this;
} else if (res == Boolean.FALSE) {
final PsiMatcher grandChild = descendant(e);
if (grandChild != NullPsiMatcherImpl.INSTANCE) return grandChild;
}
}
return NullPsiMatcherImpl.INSTANCE;
}
public PsiMatcher dot(PsiMatcherExpression e) {
return e == null || e.match(element) == Boolean.TRUE ? this : NullPsiMatcherImpl.INSTANCE;
}
public PsiElement getElement() {
return element;
}
private static class NullPsiMatcherImpl implements PsiMatcher {
public PsiMatcher parent(PsiMatcherExpression e) {
return this;
}
public PsiMatcher firstChild(PsiMatcherExpression e) {
return this;
}
public PsiMatcher ancestor(PsiMatcherExpression e) {
return this;
}
public PsiMatcher descendant(PsiMatcherExpression e) {
return this;
}
public PsiMatcher dot(PsiMatcherExpression e) {
return this;
}
public PsiElement getElement() {
return null;
}
private static final NullPsiMatcherImpl INSTANCE = new NullPsiMatcherImpl();
}
}