/*
* xtc - The eXTensible Compiler
* Copyright (C) 2006, 2007 IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.lang;
import xtc.tree.GNode;
import xtc.tree.Node;
import xtc.tree.Visitor;
/**
* A visitor that simplifies Java ASTs. Turns BasicCastExpression into
* CastExpression, and turns ConstructorDeclaration into MethodDeclaration.
* Subsumes Dimensions into the close-by Type wherever possible. The resulting
* AST uses only GNode names that occur in the original grammar.
*
* @author Martin Hirzel
*/
public class JavaAstSimplifier extends Visitor {
private static GNode concatDims(final GNode d1, final GNode d2) {
if (null == d1)
return d2;
if (null == d2)
return d1;
assert false; //TD 04 implement when it gets exercised
return null;
}
/** Copy location from nOld to nNew, then return nNew. */
public static GNode copyLoc(final GNode nOld, final GNode nNew) {
nNew.setLocation(nOld);
return nNew;
}
/** Catch-all visit method, replaces subtrees in-place by dispatched version. */
public Node visit(final Node n) {
for (int i=0; i<n.size(); i++) {
final Object o = n.get(i);
if (o instanceof Node)
n.set(i, dispatch((Node) o));
}
return n;
}
/** Turn BasicCastExpression into general CastExpression. */
public final GNode visitBasicCastExpression(final GNode n) {
final GNode typeName = (GNode) dispatch(n.getGeneric(0));
final GNode dimensions = (GNode) dispatch(n.getGeneric(1));
final GNode expression = (GNode) dispatch(n.getGeneric(2));
final GNode type = copyLoc(n, GNode.create("Type", typeName, dimensions));
return copyLoc(n, GNode.create("CastExpression", type, expression));
}
/** Turn ConstructorDeclaration into general MethodDeclaration. */
public final GNode visitConstructorDeclaration(final GNode n) {
final GNode modifiers = (GNode) dispatch(n.getNode(0));
final GNode formals = (GNode) dispatch(n.getNode(3));
final GNode throwsClause = (GNode) dispatch(n.getNode(4));
final GNode body = (GNode) dispatch(n.getNode(5));
final GNode result = copyLoc(n, GNode.create("MethodDeclaration", modifiers,
null, null, n.getString(2), formals, null, throwsClause, body));
return result;
}
/** Move dimensions from parameter declaration into declared type of the parameter. */
public final GNode visitFormalParameter(final GNode n) {
final GNode modifiers = (GNode) dispatch(n.getGeneric(0));
final GNode oldType = (GNode) dispatch(n.getGeneric(1));
final String name = n.getString(3);
final GNode dim1 = (GNode) dispatch(n.getGeneric(4));
final GNode dim2 = oldType.getGeneric(1);
final GNode newDimensions = concatDims(dim1, dim2);
final GNode newType = copyLoc(oldType, GNode.create("Type", oldType.get(0), newDimensions));
return copyLoc(n, GNode.create("FormalParameter", modifiers, newType, null, name, null));
}
/** Move dimensions from method declaration into the return type. */
public final GNode visitMethodDeclaration(final GNode n) {
final GNode modifiers = (GNode) dispatch(n.getGeneric(0));
final GNode oldResultType = (GNode) dispatch(n.getGeneric(2));
final String name = n.getString(3);
final GNode formals = (GNode) dispatch(n.getGeneric(4));
final GNode dimensions = n.getGeneric(5);
final GNode throwsClause = (GNode) dispatch(n.getGeneric(6));
final GNode body = (GNode) dispatch(n.getGeneric(7));
final GNode newResultType;
if (null == dimensions) {
newResultType = oldResultType;
} else {
assert oldResultType.hasName("Type");
final GNode typeName = oldResultType.getGeneric(0);
final GNode newDimensions = concatDims(n.getGeneric(5), oldResultType.getGeneric(1));
newResultType = copyLoc(oldResultType, GNode.create("Type", typeName, newDimensions));
}
return copyLoc(n, GNode.create("MethodDeclaration", modifiers, null,
newResultType, name, formals, null, throwsClause, body));
}
/** Move unary minus into IntegerLiteral, to simplify checking that the literal is valid in Java. */
public final GNode visitUnaryExpression(final GNode n) {
if ("-".equals(n.getString(0)) && n.getGeneric(1).hasName("IntegerLiteral")) {
final String baseLit = n.getGeneric(1).getString(0);
if ('-' != baseLit.charAt(0))
return copyLoc(n, GNode.create("IntegerLiteral", "-" + baseLit));
}
n.set(1, dispatch(n.getNode(1)));
return n;
}
}