001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2006, 2007 IBM Corp.
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.lang;
020:
021: import xtc.tree.GNode;
022: import xtc.tree.Node;
023: import xtc.tree.Visitor;
024:
025: /**
026: * A visitor that simplifies Java ASTs. Turns BasicCastExpression into
027: * CastExpression, and turns ConstructorDeclaration into MethodDeclaration.
028: * Subsumes Dimensions into the close-by Type wherever possible. The resulting
029: * AST uses only GNode names that occur in the original grammar.
030: *
031: * @author Martin Hirzel
032: */
033: public class JavaAstSimplifier extends Visitor {
034: private static GNode concatDims(final GNode d1, final GNode d2) {
035: if (null == d1)
036: return d2;
037: if (null == d2)
038: return d1;
039: assert false; //TD 04 implement when it gets exercised
040: return null;
041: }
042:
043: /** Copy location from nOld to nNew, then return nNew. */
044: public static GNode copyLoc(final GNode nOld, final GNode nNew) {
045: nNew.setLocation(nOld);
046: return nNew;
047: }
048:
049: /** Catch-all visit method, replaces subtrees in-place by dispatched version. */
050: public Node visit(final Node n) {
051: for (int i = 0; i < n.size(); i++) {
052: final Object o = n.get(i);
053: if (o instanceof Node)
054: n.set(i, dispatch((Node) o));
055: }
056: return n;
057: }
058:
059: /** Turn BasicCastExpression into general CastExpression. */
060: public final GNode visitBasicCastExpression(final GNode n) {
061: final GNode typeName = (GNode) dispatch(n.getGeneric(0));
062: final GNode dimensions = (GNode) dispatch(n.getGeneric(1));
063: final GNode expression = (GNode) dispatch(n.getGeneric(2));
064: final GNode type = copyLoc(n, GNode.create("Type", typeName,
065: dimensions));
066: return copyLoc(n, GNode.create("CastExpression", type,
067: expression));
068: }
069:
070: /** Turn ConstructorDeclaration into general MethodDeclaration. */
071: public final GNode visitConstructorDeclaration(final GNode n) {
072: final GNode modifiers = (GNode) dispatch(n.getNode(0));
073: final GNode formals = (GNode) dispatch(n.getNode(3));
074: final GNode throwsClause = (GNode) dispatch(n.getNode(4));
075: final GNode body = (GNode) dispatch(n.getNode(5));
076: final GNode result = copyLoc(n, GNode.create(
077: "MethodDeclaration", modifiers, null, null, n
078: .getString(2), formals, null, throwsClause,
079: body));
080: return result;
081: }
082:
083: /** Move dimensions from parameter declaration into declared type of the parameter. */
084: public final GNode visitFormalParameter(final GNode n) {
085: final GNode modifiers = (GNode) dispatch(n.getGeneric(0));
086: final GNode oldType = (GNode) dispatch(n.getGeneric(1));
087: final String name = n.getString(3);
088: final GNode dim1 = (GNode) dispatch(n.getGeneric(4));
089: final GNode dim2 = oldType.getGeneric(1);
090: final GNode newDimensions = concatDims(dim1, dim2);
091: final GNode newType = copyLoc(oldType, GNode.create("Type",
092: oldType.get(0), newDimensions));
093: return copyLoc(n, GNode.create("FormalParameter", modifiers,
094: newType, null, name, null));
095: }
096:
097: /** Move dimensions from method declaration into the return type. */
098: public final GNode visitMethodDeclaration(final GNode n) {
099: final GNode modifiers = (GNode) dispatch(n.getGeneric(0));
100: final GNode oldResultType = (GNode) dispatch(n.getGeneric(2));
101: final String name = n.getString(3);
102: final GNode formals = (GNode) dispatch(n.getGeneric(4));
103: final GNode dimensions = n.getGeneric(5);
104: final GNode throwsClause = (GNode) dispatch(n.getGeneric(6));
105: final GNode body = (GNode) dispatch(n.getGeneric(7));
106: final GNode newResultType;
107: if (null == dimensions) {
108: newResultType = oldResultType;
109: } else {
110: assert oldResultType.hasName("Type");
111: final GNode typeName = oldResultType.getGeneric(0);
112: final GNode newDimensions = concatDims(n.getGeneric(5),
113: oldResultType.getGeneric(1));
114: newResultType = copyLoc(oldResultType, GNode.create("Type",
115: typeName, newDimensions));
116: }
117: return copyLoc(n, GNode.create("MethodDeclaration", modifiers,
118: null, newResultType, name, formals, null, throwsClause,
119: body));
120: }
121:
122: /** Move unary minus into IntegerLiteral, to simplify checking that the literal is valid in Java. */
123: public final GNode visitUnaryExpression(final GNode n) {
124: if ("-".equals(n.getString(0))
125: && n.getGeneric(1).hasName("IntegerLiteral")) {
126: final String baseLit = n.getGeneric(1).getString(0);
127: if ('-' != baseLit.charAt(0))
128: return copyLoc(n, GNode.create("IntegerLiteral", "-"
129: + baseLit));
130: }
131: n.set(1, dispatch(n.getNode(1)));
132: return n;
133: }
134: }
|