package sk.stuba.fiit.perconik.core.java.dom; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.base.Predicate; import org.eclipse.jdt.core.dom.ASTNode; import static com.google.common.base.Preconditions.checkNotNull; public final class NodeTransformers { private NodeTransformers() {} public static <N extends ASTNode> NodeCutter<N> cutterUsingFilter(final Predicate<ASTNode> filter) { return NodeCutter.using(filter); } private enum ToRootFunction implements Function<ASTNode, ASTNode> { INSTANCE; public ASTNode apply(@Nullable final ASTNode node) { return Nodes.root(node); } @Override public String toString() { return "root"; } } private enum ToParentFunction implements Function<ASTNode, ASTNode> { INSTANCE; public ASTNode apply(@Nullable final ASTNode node) { return Nodes.parent(node); } @Override public String toString() { return "parent"; } } private static abstract class InternalFunction<N extends ASTNode> implements Function<N, ASTNode> { final Predicate<ASTNode> predicate; InternalFunction(final Predicate<ASTNode> predicate) { this.predicate = checkNotNull(predicate); } @Override public boolean equals(@Nullable final Object o) { return null != o && this.getClass() == o.getClass() && this.predicate.equals(((InternalFunction<?>) o).predicate); } @Override public int hashCode() { return this.predicate.hashCode(); } } private static final class ToFirstDownToRootFunction<N extends ASTNode> extends InternalFunction<N> { ToFirstDownToRootFunction(final Predicate<ASTNode> predicate) { super(predicate); } public ASTNode apply(final N node) { return Nodes.firstDownToRoot(node, this.predicate); } @Override public String toString() { return "firstDownToRoot"; } } private static final class ToFirstUpToLeavesFunction<N extends ASTNode> extends InternalFunction<N> { ToFirstUpToLeavesFunction(final Predicate<ASTNode> predicate) { super(predicate); } public ASTNode apply(final N node) { return Nodes.firstUpToLeaves(node, this.predicate); } @Override public String toString() { return "firstUpToLeaves"; } } private static final class ToFirstAncestorFunction<N extends ASTNode> extends InternalFunction<N> { ToFirstAncestorFunction(final Predicate<ASTNode> predicate) { super(predicate); } public ASTNode apply(final N node) { return Nodes.firstAncestor(node, this.predicate); } @Override public String toString() { return "firstAncestor"; } } private static final class ToFirstDescendantFunction<N extends ASTNode> extends InternalFunction<N> { ToFirstDescendantFunction(final Predicate<ASTNode> predicate) { super(predicate); } public ASTNode apply(final N node) { return Nodes.firstDescendant(node, this.predicate); } @Override public String toString() { return "firstDescendant"; } } private static <N extends ASTNode, T> Function<N, T> cast(final Function<?, T> transformer) { // only for stateless internal singletons shared across all types @SuppressWarnings("unchecked") Function<N, T> result = (Function<N, T>) transformer; return result; } public static <N extends ASTNode> Function<N, ASTNode> toRoot() { return cast(ToRootFunction.INSTANCE); } public static <N extends ASTNode> Function<N, ASTNode> toParent() { return cast(ToParentFunction.INSTANCE); } public static <N extends ASTNode> Function<N, ASTNode> toFirstDownToRoot(final Predicate<ASTNode> predicate) { return new ToFirstDownToRootFunction<>(predicate); } public static <N extends ASTNode> Function<N, ASTNode> toFirstUpToLeaves(final Predicate<ASTNode> predicate) { return new ToFirstUpToLeavesFunction<>(predicate); } public static <N extends ASTNode> Function<N, ASTNode> toFirstAncestor(final Predicate<ASTNode> predicate) { return new ToFirstAncestorFunction<>(predicate); } public static <N extends ASTNode> Function<N, ASTNode> toFirstDescendant(final Predicate<ASTNode> predicate) { return new ToFirstDescendantFunction<>(predicate); } }