/*******************************************************************************
* Copyright (c) 2006, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Mike Kucera (IBM Corporation) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.parser.util;
import java.io.PrintStream;
import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTPointer;
import org.eclipse.cdt.core.dom.ast.c.ICArrayType;
import org.eclipse.cdt.core.dom.ast.c.ICPointerType;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
/**
* A utility that prints an AST to the console or any print stream, useful for debugging purposes.
*
* @noextend This interface is not intended to be extended by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@SuppressWarnings("nls")
public class ASTPrinter {
private static boolean PRINT_PARENT_PROPERTIES = false;
private static boolean RESOLVE_BINDINGS = false;
/**
* Prints the AST to the given PrintStream.
*
* @return Always returns false, boolean return type allows this method
* to be called from a conditional breakpoint during debugging.
*/
public static boolean print(IASTNode node, PrintStream out) {
if (node == null) {
out.println("null");
return false;
}
if (node instanceof IASTTranslationUnit) {
IASTPreprocessorStatement[] preStats = ((IASTTranslationUnit)node).getAllPreprocessorStatements();
if (preStats != null) {
for (IASTPreprocessorStatement stat : preStats)
print(out, 0, stat);
}
}
node.accept(new PrintVisitor(out));
if (node instanceof IASTTranslationUnit) {
IASTProblem[] problems = ((IASTTranslationUnit)node).getPreprocessorProblems();
if (problems != null) {
for (IASTProblem problem : problems)
print(out, 0, problem);
}
IASTComment[] comments = ((IASTTranslationUnit)node).getComments();
if (comments != null) {
for (IASTComment comment : comments)
print(out, 0, comment);
}
}
return false;
}
/**
* Prints the AST to stdout.
*
* @return Always returns false, boolean return type allows this method
* to be called from a conditional breakpoint during debugging.
*/
public static boolean print(IASTNode root) {
return print(root, System.out);
}
/**
* Prints problem nodes in the AST to the given printstream.
*
* @return Always returns false, boolean return type allows this method
* to be called from a conditional breakpoint during debugging.
*/
public static boolean printProblems(IASTNode node, PrintStream out) {
if (node == null) {
out.println("null");
return false;
}
node.accept(new PrintProblemsVisitor(out));
if (node instanceof IASTTranslationUnit) {
IASTProblem[] problems = ((IASTTranslationUnit)node).getPreprocessorProblems();
if (problems != null) {
for (IASTProblem problem : problems) {
print(out, 0, problem);
}
}
}
return false;
}
/**
* Prints problem nodes in the AST to stdout.
*
* @return Always returns false, boolean return type allows this method
* to be called from a conditional breakpoint during debugging.
*/
public static boolean printProblems(IASTNode root) {
return printProblems(root, System.out);
}
private static class PrintVisitor extends ASTGenericVisitor {
final PrintStream out;
int indentLevel = 0;
public PrintVisitor(PrintStream out) {
super(true);
this.out = out;
shouldVisitAmbiguousNodes = true;
}
@Override protected int genericVisit(IASTNode node) {
print(out, indentLevel++, node);
return PROCESS_CONTINUE;
}
@Override protected int genericLeave(IASTNode node) {
indentLevel--;
return PROCESS_CONTINUE;
}
@Override public int visit(ASTAmbiguousNode node) {
print(out, indentLevel++, node);
for(IASTNode n : node.getNodes())
n.accept(this);
indentLevel--;
return PROCESS_CONTINUE;
}
}
private static class PrintProblemsVisitor extends PrintVisitor {
public PrintProblemsVisitor(PrintStream out) {
super(out);
}
@Override protected int genericVisit(IASTNode node) {
indentLevel++;
if(node instanceof IASTProblem)
print(out, indentLevel, node);
return PROCESS_CONTINUE;
}
}
private static void print(PrintStream out, int indentLevel, Object n) {
for (int i = 0; i < indentLevel; i++)
out.print(" ");
if (n == null) {
out.println("NULL");
return;
}
out.print(n.getClass().getName());
if (n instanceof ASTNode) {
ASTNode node = (ASTNode) n;
out.print(" (" + node.getOffset() + "," + node.getLength() + ") ");
if (node.getParent() == null && !(node instanceof IASTTranslationUnit)) {
out.print("PARENT IS NULL ");
}
if (PRINT_PARENT_PROPERTIES)
out.print(node.getPropertyInParent());
}
if (n instanceof ICArrayType) {
ICArrayType at = (ICArrayType)n;
if (at.isRestrict()) {
out.print(" restrict");
}
}
if (n instanceof IASTName) {
IASTName name = (IASTName)n;
out.print(" " + ((IASTName)n).toString());
if (RESOLVE_BINDINGS) {
try {
IBinding binding = name.resolveBinding();
print(out, indentLevel, binding);
} catch(Exception e) {
System.out.println("Exception while resolving binding: " + name);
}
}
} else if (n instanceof ICASTPointer) {
ICASTPointer pointer = (ICASTPointer) n;
if (pointer.isConst())
out.print(" const");
if (pointer.isVolatile())
out.print(" volatile");
if (pointer.isRestrict())
out.print(" restrict");
} else if (n instanceof ICPointerType) {
ICPointerType pointer = (ICPointerType)n;
if (pointer.isConst())
out.print(" const");
if (pointer.isVolatile())
out.print(" volatile");
if (pointer.isRestrict())
out.print(" restrict");
out.println();
try {
print(out, indentLevel, ((ITypeContainer)n).getType());
} catch(Exception e) {}
} else if (n instanceof ICASTArrayModifier) {
if (((ICASTArrayModifier)n).isRestrict()) {
out.print(" restrict");
}
} else if (n instanceof IASTComment) {
out.print("'" + new String(((IASTComment)n).getComment()) + "'");
// } else if (n instanceof ICompositeType) {
// try {
// IField[] fields = ((ICompositeType)n).getFields();
// if (fields == null || fields.length == 0) {
// out.print(" no fields");
// }
// for (IField field : fields) {
// out.println();
// print(out, indentLevel + 1, field);
// }
// } catch (DOMException e) {
// e.printStackTrace();
// }
} else if (n instanceof ITypeContainer) {
out.println();
try {
print(out, indentLevel, ((ITypeContainer)n).getType());
} catch(Exception e) {}
} else if (n instanceof IVariable) {
IVariable var = (IVariable) n;
IType t;
t = var.getType();
out.println();
print(out, indentLevel, t);
} else if (n instanceof IProblemBinding) {
IProblemBinding problem = (IProblemBinding)n;
out.print(problem.getMessage());
}
out.println();
}
}