package ru.csu.stan.java.ast.main;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.lang.model.type.TypeKind;
import javax.tools.JavaFileObject;
import ru.csu.stan.java.ast.core.BypassException;
import ru.csu.stan.java.ast.core.ContentAssistant;
import ru.csu.stan.java.ast.core.Messages;
import ru.csu.stan.java.ast.core.TraversalHandler;
import ru.csu.stan.java.ast.core.TreeWalker;
import ru.csu.stan.java.ast.nodes.handlers.JCAnnotationHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCArrayAccessHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCArrayTypeTreeHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCAssertHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCAssignHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCAssignOpHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCBinaryHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCBlockHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCBreakHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCCaseHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCCatchHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCClassDeclHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCCompilationUnitHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCConditionalHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCContinueHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCDoWhileLoopHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCEnhancedForLoopHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCErroneousHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCExpressionStatementHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCFieldAccessHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCForLoopHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCIdentHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCIfHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCImportHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCInstanceOfHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCLabeledStatementHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCLiteralHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCMethodDeclHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCMethodInvocationHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCModifiersHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCNewArrayHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCNewClassHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCParensHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCPrimitiveTypeTreeHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCReturnHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCSkipHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCSwitchHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCSynchronizedHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCThrowHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCTreeHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCTryHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCTypeApplyHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCTypeCastHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCTypeParameterHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCUnaryHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCVariableDeclHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCWhileLoopHandler;
import ru.csu.stan.java.ast.nodes.handlers.JCWildcardHandler;
import ru.csu.stan.java.ast.nodes.handlers.LetExprHandler;
import ru.csu.stan.java.ast.nodes.handlers.TypeBoundKindHandler;
import ru.csu.stan.java.ast.symbols.handlers.SymbolHandler;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCAssert;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCErroneous;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCSkip;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Position.LineMap;
public class TreeWalkerImpl implements TreeWalker, TraversalHandler {
private final LineMap lineMap;
private final JCTree root;
private Collection<TraversalHandler> handlers = new HashSet<TraversalHandler>();
public TreeWalkerImpl(JCTree root, LineMap lineMap) {
if (lineMap == null) {
throw new NullPointerException("Line map is null");
}
if (root == null) {
throw new NullPointerException("Root is null");
}
this.root = root;
this.lineMap = lineMap;
}
public void executeBypass() {
handle(root, root.getClass().getCanonicalName());
}
public void addBypassHandler(TraversalHandler handler) {
handlers.add(handler);
}
public void removeBypassHandler(TraversalHandler handler) {
handlers.remove(handler);
}
@Override
public final void handle(Symbol symbol, String innerName) {
handleSymbol(symbol, getNodeName(innerName));
}
@Override
public final void handle(Type type, String innerName) {
onType(type, getNodeName(innerName));
}
@Override
public final void handle(Name nameElement, String innerName) {
onName(nameElement, getNodeName(innerName));
}
@Override
public final void handle(JCTree node, String innerName) {
onHandleNode(node, getNodeName(innerName), false);
}
@Override
public final void handle(JCTree node, String innerName, boolean separateName) {
onHandleNode(node, getNodeName(innerName), separateName);
}
@Override
public final void handle(List<? extends JCTree> nodesList, String innerName) {
onHandleList(nodesList, getNodeName(innerName));
}
@Override
public final void handleFlags(long flags) {
onFlags(flags);
}
@Override
public final void handlePrimitiveType(TypeKind typeKind) {
onPrimitiveType(typeKind);
}
private void handleSymbol(Symbol symbol, String innerName) {
if (symbol == null) {
} else {
onSymbolStart(symbol, innerName);
try {
SymbolHandler<? extends Symbol> handler = getHandler(symbol);
handler.perform();
} catch (BypassException e) {
onErrorOcured(e);
}
onSymbolEnd(symbol, innerName);
}
}
@Override
public void handleSourceFile(JavaFileObject javaFile) {
onSourceFile(javaFile);
}
protected void onHandleNode(JCTree node, String name, boolean separateName) {
if (node == null) {
onNullNode(name);
} else {
if (separateName)
onEmptyNodeName(name);
Position position = PositionImpl.createPosition(lineMap, node.getPreferredPosition());
onStartNode(node, name, position);
if (JCLiteral.class.isInstance(node)) {
onLiteral(JCLiteral.class.cast(node).getValue(), JCLiteral.class.cast(node).getKind());
} else
if (JCSkip.class.isInstance(node)) {
onEmptyStatement();
} else
if (TypeBoundKind.class.isInstance(node)) {
onBoundKind(TypeBoundKind.class.cast(node).kind);
} else {
try {
JCTreeHandler handler = getHandler(node);
handler.perform(node);
} catch (BypassException e) {
onErrorOcured(e);
}
}
onEndNode(node, name, position);
if (separateName)
onEndNode(null, name, position);
}
}
protected void onHandleList(List<? extends JCTree> nodesList, String name) {
if (nodesList == null || nodesList.size() == 0) {
onNullNodesList(name);
} else {
onStartNodesList(nodesList, name);
int i = 0;
for (JCTree node : nodesList) {
onHandleNode(node, "I" + i++, false);
}
onEndNodesList(nodesList, name);
}
}
@Override
public void onType(Type type, String name) {
for (TraversalHandler handler : handlers) {
handler.onType(type, name);
}
}
@Override
public void onName(Name nameElement, String name) {
for (TraversalHandler handler : handlers) {
handler.onName(nameElement, name);
}
}
@Override
public void onSymbolStart(Symbol symbol, String name) {
for (TraversalHandler handler : handlers) {
handler.onSymbolStart(symbol, name);
}
}
@Override
public void onSymbolEnd(Symbol symbol, String name) {
for (TraversalHandler handler : handlers) {
handler.onSymbolEnd(symbol, name);
}
}
@Override
public void onNullSymbol(String name) {
for (TraversalHandler handler : handlers) {
handler.onNullSymbol(name);
}
}
@Override
public void onStartNode(JCTree node, String name, Position position) {
for (TraversalHandler handler : handlers) {
handler.onStartNode(node, name, position);
}
}
@Override
public void onEndNode(JCTree node, String name, Position position) {
for (TraversalHandler handler : handlers) {
handler.onEndNode(node, name, position);
}
}
@Override
public void onNullNode(String name) {
for (TraversalHandler handler : handlers) {
handler.onNullNode(name);
}
}
@Override
public void onStartNodesList(List<? extends JCTree> nodesList,
String name) {
for (TraversalHandler handler : handlers) {
handler.onStartNodesList(nodesList, name);
}
}
@Override
public void onEndNodesList(List<? extends JCTree> nodesList, String name) {
for (TraversalHandler handler : handlers) {
handler.onEndNodesList(nodesList, name);
}
}
@Override
public void onNullNodesList(String name) {
for (TraversalHandler handler : handlers) {
handler.onNullNodesList(name);
}
}
@Override
public void onLiteral(Object value, Kind valueType) {
for (TraversalHandler handler : handlers) {
handler.onLiteral(value, valueType);
}
}
@Override
public void onEmptyStatement() {
for (TraversalHandler handler : handlers) {
handler.onEmptyStatement();
}
}
@Override
public void onFlags(long flags) {
for (TraversalHandler handler : handlers) {
handler.onFlags(flags);
}
}
@Override
public void onPrimitiveType(TypeKind primitiveType) {
for (TraversalHandler handler : handlers) {
handler.onPrimitiveType(primitiveType);
}
}
@Override
public void onBoundKind(BoundKind boundKind) {
for (TraversalHandler handler : handlers) {
handler.onBoundKind(boundKind);
}
}
@Override
public void onErrorOcured(Exception e) {
for (TraversalHandler handler : handlers) {
handler.onErrorOcured(e);
}
}
@Override
public void onSourceFile(JavaFileObject file) {
for (TraversalHandler handler : handlers) {
handler.onSourceFile(file);
}
}
@Override
public void onEmptyNodeName(String nodeName) {
for (TraversalHandler handler : handlers) {
handler.onEmptyNodeName(nodeName);
}
}
private String getNodeName(String innerName) {
String name = ContentAssistant.getNodeName(innerName);
if (name == null) {
name = innerName;
}
return name;
}
@SuppressWarnings("unchecked")
private <K extends Symbol> SymbolHandler<K> getHandler(K symbol)
throws BypassException {
Class<? extends SymbolHandler<?>> symbolHandlerClass = symbolsHandlers
.get(symbol.getClass());
if (symbolHandlerClass == null) {
throw new BypassException(Messages.MESSAGE_ATB102E, symbol
.getClass().getCanonicalName());
}
try {
Constructor<? extends SymbolHandler<?>> constructor = symbolHandlerClass
.getConstructor(TreeWalker.class, symbol.getClass());
if (constructor == null) {
throw new BypassException(Messages.MESSAGE_ATB103E, symbol
.getClass().getCanonicalName());
}
return (SymbolHandler<K>) constructor.newInstance(this, symbol);
} catch (Exception e) {
throw new BypassException(Messages.MESSAGE_ATB103E, e, symbol
.getClass().getCanonicalName());
}
}
private static final Map<Class<? extends Symbol>, Class<? extends SymbolHandler<?>>> symbolsHandlers = new HashMap<Class<? extends Symbol>, Class<? extends SymbolHandler<?>>>();
static {
}
private JCTreeHandler getHandler(JCTree node) throws BypassException {
Class<? extends JCTreeHandler> handlerClass = nodeHandlers.get(node
.getClass());
if (handlerClass == null) {
throw new BypassException(Messages.MESSAGE_ATB100E, node.getClass()
.getCanonicalName());
}
try {
Constructor<? extends JCTreeHandler> constructor = handlerClass
.getConstructor(TreeWalker.class);
if (constructor == null) {
throw new BypassException(Messages.MESSAGE_ATB101E, node
.getClass().getCanonicalName());
}
return constructor.newInstance(this);
} catch (Exception e) {
throw new BypassException(Messages.MESSAGE_ATB101E, e, node
.getClass().getCanonicalName());
}
}
private static final Map<Class<? extends JCTree>, Class<? extends JCTreeHandler>> nodeHandlers = new HashMap<Class<? extends JCTree>, Class<? extends JCTreeHandler>>();
static {
nodeHandlers.put(JCAnnotation.class, JCAnnotationHandler.class);
nodeHandlers.put(JCArrayAccess.class, JCArrayAccessHandler.class);
nodeHandlers.put(JCArrayTypeTree.class, JCArrayTypeTreeHandler.class);
nodeHandlers.put(JCAssert.class, JCAssertHandler.class);
nodeHandlers.put(JCAssign.class, JCAssignHandler.class);
nodeHandlers.put(JCAssignOp.class, JCAssignOpHandler.class);
nodeHandlers.put(JCBinary.class, JCBinaryHandler.class);
nodeHandlers.put(JCBlock.class, JCBlockHandler.class);
nodeHandlers.put(JCBreak.class, JCBreakHandler.class);
nodeHandlers.put(JCCase.class, JCCaseHandler.class);
nodeHandlers.put(JCCatch.class, JCCatchHandler.class);
nodeHandlers.put(JCClassDecl.class, JCClassDeclHandler.class);
nodeHandlers.put(JCCompilationUnit.class,
JCCompilationUnitHandler.class);
nodeHandlers.put(JCConditional.class, JCConditionalHandler.class);
nodeHandlers.put(JCContinue.class, JCContinueHandler.class);
nodeHandlers.put(JCDoWhileLoop.class, JCDoWhileLoopHandler.class);
nodeHandlers.put(JCEnhancedForLoop.class,
JCEnhancedForLoopHandler.class);
nodeHandlers.put(JCErroneous.class, JCErroneousHandler.class);
nodeHandlers.put(JCExpressionStatement.class,
JCExpressionStatementHandler.class);
nodeHandlers.put(JCFieldAccess.class, JCFieldAccessHandler.class);
nodeHandlers.put(JCForLoop.class, JCForLoopHandler.class);
nodeHandlers.put(JCIdent.class, JCIdentHandler.class);
nodeHandlers.put(JCIf.class, JCIfHandler.class);
nodeHandlers.put(JCImport.class, JCImportHandler.class);
nodeHandlers.put(JCInstanceOf.class, JCInstanceOfHandler.class);
nodeHandlers.put(JCLabeledStatement.class,
JCLabeledStatementHandler.class);
nodeHandlers.put(JCLiteral.class, JCLiteralHandler.class);
nodeHandlers.put(JCMethodDecl.class, JCMethodDeclHandler.class);
nodeHandlers.put(JCMethodInvocation.class,
JCMethodInvocationHandler.class);
nodeHandlers.put(JCModifiers.class, JCModifiersHandler.class);
nodeHandlers.put(JCNewArray.class, JCNewArrayHandler.class);
nodeHandlers.put(JCNewClass.class, JCNewClassHandler.class);
nodeHandlers.put(JCParens.class, JCParensHandler.class);
nodeHandlers.put(JCPrimitiveTypeTree.class,
JCPrimitiveTypeTreeHandler.class);
nodeHandlers.put(JCReturn.class, JCReturnHandler.class);
nodeHandlers.put(JCSkip.class, JCSkipHandler.class);
nodeHandlers.put(JCSwitch.class, JCSwitchHandler.class);
nodeHandlers.put(JCSynchronized.class, JCSynchronizedHandler.class);
nodeHandlers.put(JCThrow.class, JCThrowHandler.class);
nodeHandlers.put(JCTry.class, JCTryHandler.class);
nodeHandlers.put(JCTypeApply.class, JCTypeApplyHandler.class);
nodeHandlers.put(JCTypeCast.class, JCTypeCastHandler.class);
nodeHandlers.put(JCTypeParameter.class, JCTypeParameterHandler.class);
nodeHandlers.put(JCUnary.class, JCUnaryHandler.class);
nodeHandlers.put(JCVariableDecl.class, JCVariableDeclHandler.class);
nodeHandlers.put(JCWhileLoop.class, JCWhileLoopHandler.class);
nodeHandlers.put(JCWildcard.class, JCWildcardHandler.class);
nodeHandlers.put(LetExpr.class, LetExprHandler.class);
nodeHandlers.put(TypeBoundKind.class, TypeBoundKindHandler.class);
}
private static class PositionImpl implements Position {
private final int line;
private final int column;
private PositionImpl(int line, int column) {
this.line = line;
this.column = column;
}
@Override
public int getColumnNumber() {
return column;
}
@Override
public int getLineNumber() {
return line;
}
public static Position createPosition(LineMap lineMap, int position) {
if (position < 0) {
return new PositionImpl(-1, -1);
}
return new PositionImpl(lineMap.getLineNumber(position), lineMap
.getColumnNumber(position));
}
}
}