0001: /*
0002: * Copyright 2007 Google Inc.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005: * use this file except in compliance with the License. You may obtain a copy of
0006: * the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013: * License for the specific language governing permissions and limitations under
0014: * the License.
0015: */
0016: package com.google.gwt.dev.jjs.impl;
0017:
0018: import com.google.gwt.dev.jjs.ast.CanBeAbstract;
0019: import com.google.gwt.dev.jjs.ast.CanBeFinal;
0020: import com.google.gwt.dev.jjs.ast.CanBeNative;
0021: import com.google.gwt.dev.jjs.ast.CanBeStatic;
0022: import com.google.gwt.dev.jjs.ast.Context;
0023: import com.google.gwt.dev.jjs.ast.HasName;
0024: import com.google.gwt.dev.jjs.ast.HasType;
0025: import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
0026: import com.google.gwt.dev.jjs.ast.JArrayRef;
0027: import com.google.gwt.dev.jjs.ast.JArrayType;
0028: import com.google.gwt.dev.jjs.ast.JAssertStatement;
0029: import com.google.gwt.dev.jjs.ast.JBinaryOperation;
0030: import com.google.gwt.dev.jjs.ast.JBlock;
0031: import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
0032: import com.google.gwt.dev.jjs.ast.JBreakStatement;
0033: import com.google.gwt.dev.jjs.ast.JCaseStatement;
0034: import com.google.gwt.dev.jjs.ast.JCastOperation;
0035: import com.google.gwt.dev.jjs.ast.JCharLiteral;
0036: import com.google.gwt.dev.jjs.ast.JClassLiteral;
0037: import com.google.gwt.dev.jjs.ast.JClassType;
0038: import com.google.gwt.dev.jjs.ast.JConditional;
0039: import com.google.gwt.dev.jjs.ast.JContinueStatement;
0040: import com.google.gwt.dev.jjs.ast.JDoStatement;
0041: import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
0042: import com.google.gwt.dev.jjs.ast.JExpression;
0043: import com.google.gwt.dev.jjs.ast.JExpressionStatement;
0044: import com.google.gwt.dev.jjs.ast.JField;
0045: import com.google.gwt.dev.jjs.ast.JFieldRef;
0046: import com.google.gwt.dev.jjs.ast.JFloatLiteral;
0047: import com.google.gwt.dev.jjs.ast.JForStatement;
0048: import com.google.gwt.dev.jjs.ast.JIfStatement;
0049: import com.google.gwt.dev.jjs.ast.JInstanceOf;
0050: import com.google.gwt.dev.jjs.ast.JIntLiteral;
0051: import com.google.gwt.dev.jjs.ast.JInterfaceType;
0052: import com.google.gwt.dev.jjs.ast.JLabel;
0053: import com.google.gwt.dev.jjs.ast.JLabeledStatement;
0054: import com.google.gwt.dev.jjs.ast.JLocal;
0055: import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
0056: import com.google.gwt.dev.jjs.ast.JLocalRef;
0057: import com.google.gwt.dev.jjs.ast.JLongLiteral;
0058: import com.google.gwt.dev.jjs.ast.JMethod;
0059: import com.google.gwt.dev.jjs.ast.JMethodCall;
0060: import com.google.gwt.dev.jjs.ast.JNewArray;
0061: import com.google.gwt.dev.jjs.ast.JNewInstance;
0062: import com.google.gwt.dev.jjs.ast.JNode;
0063: import com.google.gwt.dev.jjs.ast.JNullLiteral;
0064: import com.google.gwt.dev.jjs.ast.JNullType;
0065: import com.google.gwt.dev.jjs.ast.JParameter;
0066: import com.google.gwt.dev.jjs.ast.JParameterRef;
0067: import com.google.gwt.dev.jjs.ast.JPostfixOperation;
0068: import com.google.gwt.dev.jjs.ast.JPrefixOperation;
0069: import com.google.gwt.dev.jjs.ast.JPrimitiveType;
0070: import com.google.gwt.dev.jjs.ast.JProgram;
0071: import com.google.gwt.dev.jjs.ast.JReferenceType;
0072: import com.google.gwt.dev.jjs.ast.JReturnStatement;
0073: import com.google.gwt.dev.jjs.ast.JStatement;
0074: import com.google.gwt.dev.jjs.ast.JStringLiteral;
0075: import com.google.gwt.dev.jjs.ast.JSwitchStatement;
0076: import com.google.gwt.dev.jjs.ast.JThisRef;
0077: import com.google.gwt.dev.jjs.ast.JThrowStatement;
0078: import com.google.gwt.dev.jjs.ast.JTryStatement;
0079: import com.google.gwt.dev.jjs.ast.JType;
0080: import com.google.gwt.dev.jjs.ast.JWhileStatement;
0081: import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
0082: import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
0083: import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
0084: import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
0085: import com.google.gwt.dev.jjs.ast.js.JsonArray;
0086: import com.google.gwt.dev.jjs.ast.js.JsonObject;
0087: import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
0088: import com.google.gwt.dev.util.TextOutput;
0089:
0090: import java.util.Iterator;
0091:
0092: /**
0093: * Implements a reasonable toString() for all JNodes. The goal is to print a
0094: * recognizable declaration for large constructs (classes, methods) for easy use
0095: * in a debugger. Expressions and Statements should look like Java code
0096: * fragments.
0097: */
0098: public class ToStringGenerationVisitor extends TextOutputVisitor {
0099:
0100: protected static final char[] CHARS_ABSTRACT = "abstract "
0101: .toCharArray();
0102: protected static final char[] CHARS_ASSERT = "assert "
0103: .toCharArray();
0104: protected static final char[] CHARS_BREAK = "break".toCharArray();
0105: protected static final char[] CHARS_CASE = "case ".toCharArray();
0106: protected static final char[] CHARS_CATCH = " catch ".toCharArray();
0107: protected static final char[] CHARS_CLASS = "class ".toCharArray();
0108: protected static final char[] CHARS_COMMA = ", ".toCharArray();
0109: protected static final char[] CHARS_CONTINUE = "continue"
0110: .toCharArray();
0111: protected static final char[] CHARS_DEFAULT = "default"
0112: .toCharArray();
0113: protected static final char[] CHARS_DO = "do".toCharArray();
0114: protected static final char[] CHARS_DOTCLASS = ".class"
0115: .toCharArray();
0116: protected static final char[] CHARS_ELSE = "else".toCharArray();
0117: protected static final char[] CHARS_EMPTYDIMS = "[]".toCharArray();
0118: protected static final char[] CHARS_EXTENDS = "extends "
0119: .toCharArray();
0120: protected static final char[] CHARS_FALSE = "false".toCharArray();
0121: protected static final char[] CHARS_FINAL = "final ".toCharArray();
0122: protected static final char[] CHARS_FINALLY = " finally "
0123: .toCharArray();
0124: protected static final char[] CHARS_FOR = "for ".toCharArray();
0125: protected static final char[] CHARS_IF = "if ".toCharArray();
0126: protected static final char[] CHARS_IMPLEMENTS = "implements "
0127: .toCharArray();
0128: protected static final char[] CHARS_INSTANCEOF = " instanceof "
0129: .toCharArray();
0130: protected static final char[] CHARS_INTERFACE = "interface "
0131: .toCharArray();
0132: protected static final char[] CHARS_NATIVE = "native "
0133: .toCharArray();
0134: protected static final char[] CHARS_NEW = "new ".toCharArray();
0135: protected static final char[] CHARS_NULL = "null".toCharArray();
0136: protected static final char[] CHARS_PRIVATE = "private "
0137: .toCharArray();
0138: protected static final char[] CHARS_PROTECTED = "protected "
0139: .toCharArray();
0140: protected static final char[] CHARS_PUBLIC = "public "
0141: .toCharArray();
0142: protected static final char[] CHARS_RETURN = "return".toCharArray();
0143: protected static final char[] CHARS_SLASHSTAR = "/*".toCharArray();
0144: protected static final char[] CHARS_STARSLASH = "*/".toCharArray();
0145: protected static final char[] CHARS_STATIC = "static "
0146: .toCharArray();
0147: protected static final char[] CHARS_SUPER = "super".toCharArray();
0148: protected static final char[] CHARS_SWITCH = "switch "
0149: .toCharArray();
0150: protected static final char[] CHARS_THIS = "this".toCharArray();
0151: protected static final char[] CHARS_THROW = "throw".toCharArray();
0152: protected static final char[] CHARS_THROWS = " throws "
0153: .toCharArray();
0154: protected static final char[] CHARS_TRUE = "true".toCharArray();
0155: protected static final char[] CHARS_TRY = "try ".toCharArray();
0156: protected static final char[] CHARS_WHILE = "while ".toCharArray();
0157:
0158: protected static boolean isInitializer(JMethod x) {
0159: return x.getName().equals("$clinit")
0160: || x.getName().equals("$init");
0161: }
0162:
0163: private boolean needSemi = true;
0164:
0165: private boolean suppressType = false;
0166:
0167: public ToStringGenerationVisitor(TextOutput textOutput) {
0168: super (textOutput);
0169: }
0170:
0171: @Override
0172: public boolean visit(JAbsentArrayDimension x, Context ctx) {
0173: // nothing to print, parent prints []
0174: return false;
0175: }
0176:
0177: @Override
0178: public boolean visit(JArrayRef x, Context ctx) {
0179: JExpression instance = x.getInstance();
0180: parenPush(x, instance);
0181: accept(instance);
0182: parenPop(x, instance);
0183: print('[');
0184: accept(x.getIndexExpr());
0185: print(']');
0186: return false;
0187: }
0188:
0189: @Override
0190: public boolean visit(JArrayType x, Context ctx) {
0191: accept(x.getLeafType());
0192: for (int i = 0, c = x.getDims(); i < c; ++i) {
0193: print("[]");
0194: }
0195: return false;
0196: }
0197:
0198: @Override
0199: public boolean visit(JAssertStatement x, Context ctx) {
0200: print(CHARS_ASSERT);
0201: accept(x.getTestExpr());
0202: if (x.getArg() != null) {
0203: print(" : ");
0204: accept(x.getArg());
0205: }
0206: return false;
0207: }
0208:
0209: @Override
0210: public boolean visit(JBinaryOperation x, Context ctx) {
0211: // TODO(later): associativity
0212: JExpression arg1 = x.getLhs();
0213: parenPush(x, arg1);
0214: accept(arg1);
0215: parenPop(x, arg1);
0216:
0217: space();
0218: print(x.getOp().getSymbol());
0219: space();
0220:
0221: JExpression arg2 = x.getRhs();
0222: parenPush(x, arg2);
0223: accept(arg2);
0224: parenPop(x, arg2);
0225:
0226: return false;
0227: }
0228:
0229: @Override
0230: public boolean visit(JBlock x, Context ctx) {
0231: openBlock();
0232: for (int i = 0; i < x.statements.size(); ++i) {
0233: JStatement statement = x.statements.get(i);
0234: needSemi = true;
0235: accept(statement);
0236: if (needSemi) {
0237: semi();
0238: }
0239: newline();
0240: }
0241: closeBlock();
0242: needSemi = false;
0243: return false;
0244: }
0245:
0246: @Override
0247: public boolean visit(JBooleanLiteral x, Context ctx) {
0248: printBooleanLiteral(x.getValue());
0249: return false;
0250: }
0251:
0252: @Override
0253: public boolean visit(JBreakStatement x, Context ctx) {
0254: print(CHARS_BREAK);
0255: if (x.getLabel() != null) {
0256: space();
0257: accept(x.getLabel());
0258: }
0259: return false;
0260: }
0261:
0262: @Override
0263: public boolean visit(JCaseStatement x, Context ctx) {
0264: if (x.getExpr() != null) {
0265: print(CHARS_CASE);
0266: accept(x.getExpr());
0267: } else {
0268: print(CHARS_DEFAULT);
0269: }
0270: print(':');
0271: space();
0272: needSemi = false;
0273: return false;
0274: }
0275:
0276: @Override
0277: public boolean visit(JCastOperation x, Context ctx) {
0278: lparen();
0279: printType(x);
0280: rparen();
0281: space();
0282:
0283: JExpression expr = x.getExpr();
0284: parenPush(x, expr);
0285: accept(expr);
0286: parenPop(x, expr);
0287: return false;
0288: }
0289:
0290: @Override
0291: public boolean visit(JCharLiteral x, Context ctx) {
0292: printCharLiteral(x.getValue());
0293: return false;
0294: }
0295:
0296: @Override
0297: public boolean visit(JClassLiteral x, Context ctx) {
0298: printTypeName(x.getRefType());
0299: print(CHARS_DOTCLASS);
0300: return false;
0301: }
0302:
0303: @Override
0304: public boolean visit(JClassType x, Context ctx) {
0305: printAbstractFlag(x);
0306: printFinalFlag(x);
0307: print(CHARS_CLASS);
0308: printTypeName(x);
0309: space();
0310: if (x.extnds != null) {
0311: print(CHARS_EXTENDS);
0312: printTypeName(x.extnds);
0313: space();
0314: }
0315:
0316: if (x.implments.size() > 0) {
0317: print(CHARS_IMPLEMENTS);
0318: for (int i = 0, c = x.implments.size(); i < c; ++i) {
0319: if (i > 0) {
0320: print(CHARS_COMMA);
0321: }
0322: printTypeName(x.implments.get(i));
0323: }
0324: space();
0325: }
0326:
0327: return false;
0328: }
0329:
0330: @Override
0331: public boolean visit(JConditional x, Context ctx) {
0332: // TODO(later): associativity
0333: JExpression ifTest = x.getIfTest();
0334: parenPush(x, ifTest);
0335: accept(ifTest);
0336: parenPop(x, ifTest);
0337:
0338: print(" ? ");
0339:
0340: JExpression thenExpr = x.getThenExpr();
0341: parenPush(x, thenExpr);
0342: accept(thenExpr);
0343: parenPop(x, thenExpr);
0344:
0345: print(" : ");
0346:
0347: JExpression elseExpr = x.getElseExpr();
0348: parenPush(x, elseExpr);
0349: accept(elseExpr);
0350: parenPop(x, elseExpr);
0351:
0352: return false;
0353: }
0354:
0355: @Override
0356: public boolean visit(JContinueStatement x, Context ctx) {
0357: print(CHARS_CONTINUE);
0358: if (x.getLabel() != null) {
0359: space();
0360: accept(x.getLabel());
0361: }
0362: return false;
0363: }
0364:
0365: @Override
0366: public boolean visit(JDoStatement x, Context ctx) {
0367: print(CHARS_DO);
0368: if (x.getBody() != null) {
0369: nestedStatementPush(x.getBody());
0370: accept(x.getBody());
0371: nestedStatementPop(x.getBody());
0372: }
0373: if (needSemi) {
0374: semi();
0375: newline();
0376: } else {
0377: space();
0378: needSemi = true;
0379: }
0380: print(CHARS_WHILE);
0381: lparen();
0382: accept(x.getTestExpr());
0383: rparen();
0384: return false;
0385: }
0386:
0387: @Override
0388: public boolean visit(JDoubleLiteral x, Context ctx) {
0389: printDoubleLiteral(x.getValue());
0390: return false;
0391: }
0392:
0393: @Override
0394: public boolean visit(JExpressionStatement x, Context ctx) {
0395: accept(x.getExpr());
0396: return false;
0397: }
0398:
0399: @Override
0400: public boolean visit(JField x, Context ctx) {
0401: // Due to our wacky construction model, only constant fields may be final
0402: // when generating source
0403: if (x.constInitializer != null) {
0404: printFinalFlag(x);
0405: } else {
0406: printMemberFinalFlag(x);
0407: }
0408:
0409: printStaticFlag(x);
0410: printType(x);
0411: space();
0412: printUniqueName(x);
0413: return false;
0414: }
0415:
0416: @Override
0417: public boolean visit(JFieldRef x, Context ctx) {
0418: JExpression instance = x.getInstance();
0419: if (instance != null) {
0420: parenPush(x, instance);
0421: accept(instance);
0422: parenPop(x, instance);
0423: } else {
0424: printTypeName(x.getField().getEnclosingType());
0425: }
0426: print('.');
0427: printUniqueName(x.getField());
0428: return false;
0429: }
0430:
0431: @Override
0432: public boolean visit(JFloatLiteral x, Context ctx) {
0433: printFloatLiteral(x.getValue());
0434: return false;
0435: }
0436:
0437: @Override
0438: public boolean visit(JForStatement x, Context ctx) {
0439: print(CHARS_FOR);
0440: lparen();
0441:
0442: Iterator<JStatement> iter = x.getInitializers().iterator();
0443: if (iter.hasNext()) {
0444: JStatement stmt = iter.next();
0445: accept(stmt);
0446: }
0447: suppressType = true;
0448: while (iter.hasNext()) {
0449: print(CHARS_COMMA);
0450: JStatement stmt = iter.next();
0451: accept(stmt);
0452: }
0453: suppressType = false;
0454:
0455: semi();
0456: space();
0457: if (x.getTestExpr() != null) {
0458: accept(x.getTestExpr());
0459: }
0460:
0461: semi();
0462: space();
0463: visitCollectionWithCommas(x.getIncrements().iterator());
0464: rparen();
0465:
0466: if (x.getBody() != null) {
0467: nestedStatementPush(x.getBody());
0468: accept(x.getBody());
0469: nestedStatementPop(x.getBody());
0470: }
0471: return false;
0472: }
0473:
0474: @Override
0475: public boolean visit(JIfStatement x, Context ctx) {
0476: print(CHARS_IF);
0477: lparen();
0478: accept(x.getIfExpr());
0479: rparen();
0480:
0481: if (x.getThenStmt() != null) {
0482: nestedStatementPush(x.getThenStmt());
0483: accept(x.getThenStmt());
0484: nestedStatementPop(x.getThenStmt());
0485: }
0486:
0487: if (x.getElseStmt() != null) {
0488: if (needSemi) {
0489: semi();
0490: newline();
0491: } else {
0492: space();
0493: needSemi = true;
0494: }
0495: print(CHARS_ELSE);
0496: boolean elseIf = x.getElseStmt() instanceof JIfStatement;
0497: if (!elseIf) {
0498: nestedStatementPush(x.getElseStmt());
0499: } else {
0500: space();
0501: }
0502: accept(x.getElseStmt());
0503: if (!elseIf) {
0504: nestedStatementPop(x.getElseStmt());
0505: }
0506: }
0507:
0508: return false;
0509: }
0510:
0511: @Override
0512: public boolean visit(JInstanceOf x, Context ctx) {
0513: JExpression expr = x.getExpr();
0514: parenPush(x, expr);
0515: accept(expr);
0516: parenPop(x, expr);
0517: print(CHARS_INSTANCEOF);
0518: printTypeName(x.getTestType());
0519: return false;
0520: }
0521:
0522: @Override
0523: public boolean visit(JInterfaceType x, Context ctx) {
0524: print(CHARS_INTERFACE);
0525: printTypeName(x);
0526: space();
0527:
0528: if (x.implments.size() > 0) {
0529: print(CHARS_EXTENDS);
0530: for (int i = 0, c = x.implments.size(); i < c; ++i) {
0531: if (i > 0) {
0532: print(CHARS_COMMA);
0533: }
0534: printTypeName(x.implments.get(i));
0535: }
0536: space();
0537: }
0538:
0539: return false;
0540: }
0541:
0542: @Override
0543: public boolean visit(JIntLiteral x, Context ctx) {
0544: print(Integer.toString(x.getValue()).toCharArray());
0545: return false;
0546: }
0547:
0548: @Override
0549: public boolean visit(JLabel x, Context ctx) {
0550: printName(x);
0551: return false;
0552: }
0553:
0554: @Override
0555: public boolean visit(JLabeledStatement x, Context ctx) {
0556: accept(x.getLabel());
0557: print(" : ");
0558: accept(x.getBody());
0559: return false;
0560: }
0561:
0562: @Override
0563: public boolean visit(JLocal x, Context ctx) {
0564: printFinalFlag(x);
0565: printType(x);
0566: space();
0567: printName(x);
0568: return false;
0569: }
0570:
0571: @Override
0572: public boolean visit(JLocalDeclarationStatement x, Context ctx) {
0573: if (!suppressType) {
0574: accept(x.getLocalRef().getTarget());
0575: } else {
0576: accept(x.getLocalRef());
0577: }
0578: JExpression initializer = x.getInitializer();
0579: if (initializer != null) {
0580: print(" = ");
0581: accept(initializer);
0582: }
0583: return false;
0584: }
0585:
0586: @Override
0587: public boolean visit(JLocalRef x, Context ctx) {
0588: printName(x.getLocal());
0589: return false;
0590: }
0591:
0592: @Override
0593: public boolean visit(JLongLiteral x, Context ctx) {
0594: printLongLiteral(x.getValue());
0595: return false;
0596: }
0597:
0598: @Override
0599: public boolean visit(JMethod x, Context ctx) {
0600: // special: transcribe clinit and init as if they were initializer blocks
0601: if (isInitializer(x)) {
0602: if (x.isStatic()) {
0603: print(CHARS_STATIC);
0604: }
0605: if (shouldPrintMethodBody()) {
0606: accept(x.getBody());
0607: } else {
0608: print("{ ... }");
0609: newlineOpt();
0610: }
0611: } else {
0612: printMethodHeader(x);
0613: if (shouldPrintMethodBody() && !x.isAbstract()) {
0614: space();
0615: accept(x.getBody());
0616: } else {
0617: semi();
0618: newlineOpt();
0619: }
0620: }
0621:
0622: return false;
0623: }
0624:
0625: @Override
0626: public boolean visit(JMethodCall x, Context ctx) {
0627: JExpression instance = x.getInstance();
0628: JMethod target = x.getTarget();
0629: if (instance != null) {
0630: parenPush(x, instance);
0631: accept(instance);
0632: parenPop(x, instance);
0633: } else {
0634: printTypeName(target.getEnclosingType());
0635: }
0636: print('.');
0637: if (target.isStatic()) {
0638: printUniqueName(target);
0639: } else {
0640: printName(target);
0641: }
0642: lparen();
0643: visitCollectionWithCommas(x.getArgs().iterator());
0644: rparen();
0645: return false;
0646: }
0647:
0648: @Override
0649: public boolean visit(JMultiExpression x, Context ctx) {
0650: lparen();
0651: visitCollectionWithCommas(x.exprs.iterator());
0652: rparen();
0653: return false;
0654: }
0655:
0656: @Override
0657: public boolean visit(JNewArray x, Context ctx) {
0658: print(CHARS_NEW);
0659: printTypeName(x.getArrayType().getLeafType());
0660: if (x.initializers != null) {
0661: print('{');
0662: visitCollectionWithCommas(x.initializers.iterator());
0663: print('}');
0664: } else {
0665: for (int i = 0; i < x.dims.size(); ++i) {
0666: JExpression expr = x.dims.get(i);
0667: print('[');
0668: accept(expr);
0669: print(']');
0670: }
0671: }
0672: return false;
0673: }
0674:
0675: @Override
0676: public boolean visit(JNewInstance x, Context ctx) {
0677: print(CHARS_NEW);
0678: printType(x);
0679: lparen();
0680: rparen();
0681: return false;
0682: }
0683:
0684: @Override
0685: public boolean visit(JNullLiteral x, Context ctx) {
0686: print(CHARS_NULL);
0687: return false;
0688: }
0689:
0690: @Override
0691: public boolean visit(JNullType x, Context ctx) {
0692: printTypeName(x);
0693: return false;
0694: }
0695:
0696: @Override
0697: public boolean visit(JParameter x, Context ctx) {
0698: printType(x);
0699: space();
0700: printName(x);
0701: return false;
0702: }
0703:
0704: @Override
0705: public boolean visit(JParameterRef x, Context ctx) {
0706: printName(x.getTarget());
0707: return false;
0708: }
0709:
0710: @Override
0711: public boolean visit(JPostfixOperation x, Context ctx) {
0712: // TODO(later): associativity
0713: JExpression arg = x.getArg();
0714: parenPush(x, arg);
0715: accept(arg);
0716: parenPop(x, arg);
0717: print(x.getOp().getSymbol());
0718: return false;
0719: }
0720:
0721: @Override
0722: public boolean visit(JPrefixOperation x, Context ctx) {
0723: // TODO(later): associativity
0724: print(x.getOp().getSymbol());
0725: JExpression arg = x.getArg();
0726: parenPush(x, arg);
0727: accept(arg);
0728: parenPop(x, arg);
0729: return false;
0730: }
0731:
0732: @Override
0733: public boolean visit(JPrimitiveType x, Context ctx) {
0734: printTypeName(x);
0735: return false;
0736: }
0737:
0738: @Override
0739: public boolean visit(JProgram x, Context ctx) {
0740: print("<JProgram>");
0741: return false;
0742: }
0743:
0744: @Override
0745: public boolean visit(JReturnStatement x, Context ctx) {
0746: print(CHARS_RETURN);
0747: if (x.getExpr() != null) {
0748: space();
0749: accept(x.getExpr());
0750: }
0751: return false;
0752: }
0753:
0754: @Override
0755: public boolean visit(JsniFieldRef x, Context ctx) {
0756: return visit(x.getField(), ctx);
0757: }
0758:
0759: @Override
0760: public boolean visit(JsniMethodBody x, Context ctx) {
0761: print("/*-{");
0762: // don't visit my block
0763: newline();
0764: print("}-*/");
0765: semi();
0766: return false;
0767: }
0768:
0769: @Override
0770: public boolean visit(JsniMethodRef x, Context ctx) {
0771: printMethodHeader(x.getTarget());
0772: return false;
0773: }
0774:
0775: @Override
0776: public boolean visit(JsonArray x, Context ctx) {
0777: print('[');
0778: visitCollectionWithCommas(x.exprs.iterator());
0779: print(']');
0780: return false;
0781: }
0782:
0783: @Override
0784: public boolean visit(JsonObject x, Context ctx) {
0785: print('{');
0786: visitCollectionWithCommas(x.propInits.iterator());
0787: print('}');
0788: return false;
0789: }
0790:
0791: @Override
0792: public boolean visit(JsonPropInit x, Context ctx) {
0793: accept(x.labelExpr);
0794: print(':');
0795: accept(x.valueExpr);
0796: return false;
0797: }
0798:
0799: @Override
0800: public boolean visit(JStringLiteral x, Context ctx) {
0801: printStringLiteral(x.getValue());
0802: return false;
0803: }
0804:
0805: @Override
0806: public boolean visit(JSwitchStatement x, Context ctx) {
0807: print(CHARS_SWITCH);
0808: lparen();
0809: accept(x.getExpr());
0810: rparen();
0811: space();
0812: nestedStatementPush(x.getBody());
0813: accept(x.getBody());
0814: nestedStatementPop(x.getBody());
0815: return false;
0816: }
0817:
0818: @Override
0819: public boolean visit(JThisRef x, Context ctx) {
0820: print(CHARS_THIS);
0821: return false;
0822: }
0823:
0824: @Override
0825: public boolean visit(JThrowStatement x, Context ctx) {
0826: print(CHARS_THROW);
0827: if (x.getExpr() != null) {
0828: space();
0829: accept(x.getExpr());
0830: }
0831: return false;
0832: }
0833:
0834: @Override
0835: public boolean visit(JTryStatement x, Context ctx) {
0836: print(CHARS_TRY);
0837: accept(x.getTryBlock());
0838: for (int i = 0, c = x.getCatchArgs().size(); i < c; ++i) {
0839: print(CHARS_CATCH);
0840: lparen();
0841: JLocalRef localRef = x.getCatchArgs().get(i);
0842: accept(localRef.getTarget());
0843: rparen();
0844: space();
0845: JBlock block = x.getCatchBlocks().get(i);
0846: accept(block);
0847: }
0848: if (x.getFinallyBlock() != null) {
0849: print(CHARS_FINALLY);
0850: accept(x.getFinallyBlock());
0851: }
0852: return false;
0853: }
0854:
0855: @Override
0856: public boolean visit(JWhileStatement x, Context ctx) {
0857: print(CHARS_WHILE);
0858: lparen();
0859: accept(x.getTestExpr());
0860: rparen();
0861: if (x.getBody() != null) {
0862: nestedStatementPush(x.getBody());
0863: accept(x.getBody());
0864: nestedStatementPop(x.getBody());
0865: }
0866: return false;
0867: }
0868:
0869: protected void closeBlock() {
0870: indentOut();
0871: print('}');
0872: }
0873:
0874: protected void lparen() {
0875: print('(');
0876: }
0877:
0878: protected boolean nestedStatementPop(JStatement statement) {
0879: boolean pop = !(statement instanceof JBlock);
0880: if (pop) {
0881: indentOut();
0882: }
0883: return pop;
0884: }
0885:
0886: protected boolean nestedStatementPush(JStatement statement) {
0887: boolean push = !(statement instanceof JBlock);
0888: if (push) {
0889: indentIn();
0890: newline();
0891: } else {
0892: space();
0893: }
0894: return push;
0895: }
0896:
0897: protected void openBlock() {
0898: print('{');
0899: indentIn();
0900: newline();
0901: }
0902:
0903: protected boolean parenPop(int parentPrec, JExpression child) {
0904: int childPrec = JavaPrecedenceVisitor.exec(child);
0905: if (parentPrec < childPrec) {
0906: rparen();
0907: return true;
0908: } else {
0909: return false;
0910: }
0911: }
0912:
0913: protected boolean parenPop(JExpression parent, JExpression child) {
0914: return parenPop(JavaPrecedenceVisitor.exec(parent), child);
0915: }
0916:
0917: protected boolean parenPush(int parentPrec, JExpression child) {
0918: int childPrec = JavaPrecedenceVisitor.exec(child);
0919: if (parentPrec < childPrec) {
0920: lparen();
0921: return true;
0922: } else {
0923: return false;
0924: }
0925: }
0926:
0927: protected boolean parenPush(JExpression parent, JExpression child) {
0928: return parenPush(JavaPrecedenceVisitor.exec(parent), child);
0929: }
0930:
0931: protected void printAbstractFlag(CanBeAbstract x) {
0932: if (x.isAbstract()) {
0933: print(CHARS_ABSTRACT);
0934: }
0935: }
0936:
0937: protected void printBooleanLiteral(boolean value) {
0938: print(value ? CHARS_TRUE : CHARS_FALSE);
0939: }
0940:
0941: protected void printChar(char c) {
0942: switch (c) {
0943: case '\b':
0944: print("\\b");
0945: break;
0946: case '\t':
0947: print("\\t");
0948: break;
0949: case '\n':
0950: print("\\n");
0951: break;
0952: case '\f':
0953: print("\\f");
0954: break;
0955: case '\r':
0956: print("\\r");
0957: break;
0958: case '\"':
0959: print("\\\"");
0960: break;
0961: case '\'':
0962: print("\\'");
0963: break;
0964: case '\\':
0965: print("\\\\");
0966: break;
0967: default:
0968: if (Character.isISOControl(c)) {
0969: print("\\u");
0970: if (c < 0x1000) {
0971: print('0');
0972: }
0973:
0974: if (c < 0x100) {
0975: print('0');
0976: }
0977:
0978: if (c < 0x10) {
0979: print('0');
0980: }
0981: print(Integer.toHexString(c));
0982: } else {
0983: print(c);
0984: }
0985: }
0986: }
0987:
0988: protected void printCharLiteral(char value) {
0989: print('\'');
0990: printChar(value);
0991: print('\'');
0992: }
0993:
0994: protected void printDoubleLiteral(double value) {
0995: print(Double.toString(value));
0996: }
0997:
0998: protected void printFinalFlag(CanBeFinal x) {
0999: if (x.isFinal()) {
1000: print(CHARS_FINAL);
1001: }
1002: }
1003:
1004: protected void printFloatLiteral(float value) {
1005: print(Float.toString(value));
1006: print('f');
1007: }
1008:
1009: protected void printLongLiteral(long value) {
1010: print(Long.toString(value));
1011: print('L');
1012: }
1013:
1014: protected void printMemberFinalFlag(CanBeFinal x) {
1015: if (x.isFinal()) {
1016: print(CHARS_FINAL);
1017: }
1018: }
1019:
1020: protected void printMethodHeader(JMethod x) {
1021: // Modifiers
1022: if (x.isPrivate()) {
1023: print(CHARS_PRIVATE);
1024: } else {
1025: print(CHARS_PUBLIC);
1026: }
1027: printStaticFlag(x);
1028: printAbstractFlag(x);
1029: printNativeFlag(x);
1030: printMemberFinalFlag(x);
1031: printType(x);
1032: space();
1033: if (x.isStatic()) {
1034: printUniqueName(x);
1035: } else {
1036: printName(x);
1037: }
1038:
1039: // Parameters
1040: printParameterList(x);
1041:
1042: if (x.thrownExceptions.size() > 0) {
1043: print(CHARS_THROWS);
1044: Iterator<JClassType> iter = x.thrownExceptions.iterator();
1045: if (iter.hasNext()) {
1046: printTypeName(iter.next());
1047: }
1048: while (iter.hasNext()) {
1049: print(CHARS_COMMA);
1050: printTypeName(iter.next());
1051: }
1052: }
1053: }
1054:
1055: protected void printName(HasName x) {
1056: print(x.getName());
1057: }
1058:
1059: protected void printNativeFlag(CanBeNative x) {
1060: if (x.isNative()) {
1061: print(CHARS_NATIVE);
1062: }
1063: }
1064:
1065: protected void printParameterList(JMethod x) {
1066: lparen();
1067: visitCollectionWithCommas(x.params.iterator());
1068: rparen();
1069: }
1070:
1071: protected void printStaticFlag(CanBeStatic x) {
1072: if (x.isStatic()) {
1073: print(CHARS_STATIC);
1074: }
1075: }
1076:
1077: protected void printStringLiteral(String string) {
1078: char[] s = string.toCharArray();
1079: print('\"');
1080: for (int i = 0; i < s.length; ++i) {
1081: printChar(s[i]);
1082: }
1083: print('\"');
1084: }
1085:
1086: protected void printType(HasType hasType) {
1087: printTypeName(hasType.getType());
1088: }
1089:
1090: protected void printTypeName(JType type) {
1091: if (type instanceof JReferenceType) {
1092: print(((JReferenceType) type).getShortName());
1093: } else {
1094: print(type.getName());
1095: }
1096: }
1097:
1098: protected void rparen() {
1099: print(')');
1100: }
1101:
1102: protected void semi() {
1103: print(';');
1104: }
1105:
1106: protected boolean shouldPrintMethodBody() {
1107: return false;
1108: }
1109:
1110: protected void space() {
1111: print(' ');
1112: }
1113:
1114: protected void visitCollectionWithCommas(
1115: Iterator<? extends JNode> iter) {
1116: if (iter.hasNext()) {
1117: accept(iter.next());
1118: }
1119: while (iter.hasNext()) {
1120: print(CHARS_COMMA);
1121: accept(iter.next());
1122: }
1123: }
1124:
1125: private void printUniqueName(HasName x) {
1126: print(x.getName());
1127: }
1128:
1129: }
|