Skip to content

Commit

Permalink
feature CtScannerListener listens for nodes of EarlyTerminatingScanner
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Mar 8, 2017
1 parent 6433c2c commit 7f2c7e7
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
58 changes: 57 additions & 1 deletion src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,32 @@
package spoon.reflect.visitor;

import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.chain.CtScannerListener;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
* The extension of {@link CtScanner}, which supports early termination of scanning process.
* Is useful when your algorithm is searching for an node after node is found
* future scanning makes no sense.
* Then you can call {@link #terminate()}, which assures that no more AST nodes are visited,
* means no {@link #scan(CtElement)} method is called and the scanning algorithm finishes
* as soon as possible.
*<br>
* There is possible to register an implementation of {@link CtScannerListener},
* whose {@link CtScannerListener#enter(CtElement)}/{@link CtScannerListener#exit(CtElement)}
* methods are called before/after each AST node is visited.<br>
* Note that the {@link CtScannerListener#enter(CtElement)} can influence whether AST node and it's children is visited. See it's documentation for details.
*
* @param <T> the type of the result produced by this scanner.
*/
public class EarlyTerminatingScanner<T> extends CtScanner {

private boolean terminate = false;
private T result;
private CtScannerListener listener;

protected void terminate() {
terminate = true;
Expand All @@ -39,10 +56,29 @@ protected void setResult(T result) {
this.result = result;
}

/**
* @return the result of scanning - the value, which was stored by previous call of {@link #setResult(Object)}
*/
public T getResult() {
return result;
}

/**
* @return null or the implementation of {@link CtScannerListener}, which is registered to listen for enter/exit of nodes during scanning of AST
*/
public CtScannerListener getListener() {
return listener;
}

/**
* @param listener the implementation of {@link CtScannerListener}, which will listen for enter/exit of nodes during scanning of AST
* @return this to support fluent API
*/
public EarlyTerminatingScanner<T> setListener(CtScannerListener listener) {
this.listener = listener;
return this;
}

@Override
public void scan(Collection<? extends CtElement> elements) {
if (isTerminated() || elements == null) {
Expand All @@ -60,9 +96,29 @@ public void scan(Collection<? extends CtElement> elements) {

@Override
public void scan(CtElement element) {
if (isTerminated()) {
if (element == null || isTerminated()) {
return;
}
if (listener == null) {
//the listener is not defined
//visit this element and may be children
doScan(element);
} else {
//the listener is defined, call it's enter method first
if (listener.enter(element)) {
//the listener decided to visit this element and may be children
doScan(element);
//then call exit, only if enter returned true
listener.exit(element);
} //else the listener decided to skip this element and all children. Do not call exit.
}
}

/**
* This method is called ONLY when listener decides that element and children may be visited.
* It is needed to let child classes to override it and to react on that situation
*/
protected void doScan(CtElement element) {
super.scan(element);
}

Expand Down
45 changes: 45 additions & 0 deletions src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor.chain;

import spoon.reflect.declaration.CtElement;

/**
* Listens for entering/exiting of scanning of AST
*/
public interface CtScannerListener {
/**
* Called before scanning process enters an element
* <br>
* The returning false or throwing an exception causes that processing of that element and all it's children is skipped.
* The returning true causes that element is normally processed, and {@link #exit(CtElement)} will be called for that element.
*
* @param element the processed element
* @return true to continue processing this element and it's children,
* false to skip this element and it's children.
*/
boolean enter(CtElement element);

/**
* This method is called after element and all it's children are processed.
* This method is NOT called if the exception was thrown in {@link #enter(CtElement)} or during processing of element or any children children
* This method is NOT called for element whose {@link #enter(CtElement)} returned false
*
* @param element the processed element
*/
void exit(CtElement element);
}

0 comments on commit 7f2c7e7

Please sign in to comment.