0001: /*
0002: * xtc - The eXTensible Compiler
0003: * Copyright (C) 2006-2007 IBM Corp.
0004: *
0005: * This program is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU General Public License
0007: * version 2 as published by the Free Software Foundation.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017: * USA.
0018: */
0019: package xtc.lang;
0020:
0021: import java.io.File;
0022: import java.math.BigInteger;
0023: import java.util.ArrayList;
0024: import java.util.HashSet;
0025: import java.util.List;
0026: import java.util.Set;
0027:
0028: import xtc.Constants;
0029: import xtc.tree.Attribute;
0030: import xtc.tree.GNode;
0031: import xtc.tree.Node;
0032: import xtc.tree.Visitor;
0033: import xtc.type.AliasT;
0034: import xtc.type.AnnotatedT;
0035: import xtc.type.ArrayT;
0036: import xtc.type.ClassOrInterfaceT;
0037: import xtc.type.ClassT;
0038: import xtc.type.ErrorT;
0039: import xtc.type.IntegerT;
0040: import xtc.type.InterfaceT;
0041: import xtc.type.LabelT;
0042: import xtc.type.MethodT;
0043: import xtc.type.NumberT;
0044: import xtc.type.PackageT;
0045: import xtc.type.Type;
0046: import xtc.type.VoidT;
0047: import xtc.type.WrappedT;
0048: import xtc.util.Runtime;
0049: import xtc.util.SymbolTable;
0050:
0051: /**
0052: * A visitor that constructs a symbol table for a Java compilation unit. Assumes
0053: * that the AST has been simplified with JavaAstSimplifier. So far, the visitor
0054: * doesn't check for errors properly, it only populates the symbol table and
0055: * annotates AST nodes with their type.
0056: *
0057: * <h4>Jacks regression tests</h4>
0058: *
0059: * You can use JavaDriver to run the "jacks" compiler regression
0060: * testing suite for this type checker.
0061: * Download jacks by doing<ul>
0062: * <li>cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/mauve co jacks</ul>
0063: * Make sure it works by setting JAVAC in setup_javac, then doing<ul>
0064: * <li>./jacks javac "3.2-valid-1 3.2-invalid-1"</ul>
0065: * That should report something like<ul>
0066: * <li>javac: Total 5011 Passed 2 Skipped 5009 Failed 0</ul>
0067: * Create an xtc_setup file: copy javac_setup, then change:<ul>
0068: * <li>set JAVA_HOME ""
0069: * <li>set JAVAC /usr/bin/java
0070: * <li>set JAVAC_FLAGS "-cp /Users/hirzel/jeannie/java/classes:/Users/hirzel/jeannie/java/bin/antlr.jar xtc.lang.JavaDriver -ast -simplifyAST -analyze"
0071: set JAVA "this_variable_intentionally_nonsensical"
0072: * <li>set JAVA "this_variable_intentionally_nonsensical"</ul>
0073: * or whatever is appropriate for your paths. Yes, we intentionally set JAVAC "java",
0074: * since xtc.lang.JavaAnalyzer will run on a Java virtual machine.<br>
0075: * Now, try that it works by doing<ul>
0076: * <li>./jacks xtc "3.2-valid-1 3.2-invalid-1"</ul>
0077: * That should report something like<ul>
0078: * <li>xtc: Total 5011 Passed 2 Skipped 5009 Failed 0</ul>
0079: * To run the remaining 5009 tests, omit the last command line argument, and be
0080: * very patient.
0081: *
0082: * @author Martin Hirzel
0083: */
0084: public class JavaAnalyzer extends Visitor {
0085: public static final class JavaContext {
0086: /** Handled by enclosing try/catch, or declared as thrown by enclosing method. */
0087: public List<Type> _handledExceptions = new ArrayList<Type>();
0088:
0089: /** False if scope should also include parameters of method, catch, or for. */
0090: public boolean _hasScope = true;
0091:
0092: /** Current expression or array initializer is expected to initialize variable of target type. */
0093: Type _initializing = null;
0094:
0095: /** Can do "break" or "continue" for enclosing while/do/for loop. */
0096: public boolean _loop = false;
0097:
0098: /** Can not use "this" or instance member. */
0099: public boolean _static = false;
0100:
0101: /** Can do "break" for enclosing switch statement. */
0102: public boolean _switch = false;
0103:
0104: public final void restore(final JavaContext other) {
0105: _handledExceptions = other._handledExceptions;
0106: _hasScope = other._hasScope;
0107: _initializing = other._initializing;
0108: _loop = other._loop;
0109: _static = other._static;
0110: _switch = other._switch;
0111: }
0112:
0113: public final JavaContext save() {
0114: final JavaContext result = new JavaContext();
0115: result.restore(this );
0116: return result;
0117: }
0118: }
0119:
0120: public static Type getRValueNoError(final Type type) {
0121: assert null != type;
0122: if (type.isVoid())
0123: return type;
0124: if (JavaEntities.isExpressionT(type)) {
0125: final boolean isL = JavaEntities.isGeneralLValueT(type);
0126: final Type result = isL ? JavaEntities.dereference(type)
0127: : type;
0128: assert JavaEntities.isGeneralRValueT(result);
0129: return result;
0130: }
0131: return null;
0132: }
0133:
0134: protected static boolean hasModifier(final Type t, final String m) {
0135: return JavaEntities.hasModifier(t, m);
0136: }
0137:
0138: public static Type setType(final Node n, final Type result) {
0139: if (result.isMethod())
0140: assert n.hasName("Arguments")
0141: || n.hasName("MethodDeclaration")
0142: || n.hasName("DeconstructorDeclaration");
0143: n.setProperty(Constants.TYPE, result);
0144: return result;
0145: }
0146:
0147: protected final JavaExternalAnalyzer _externalAnalyzer;
0148: public final JavaContext _context;
0149: protected final Runtime _runtime;
0150:
0151: protected final SymbolTable _table;
0152:
0153: public JavaAnalyzer(final Runtime runtime, final SymbolTable table) {
0154: _context = new JavaContext();
0155: _externalAnalyzer = newExternalAnalyzer(runtime, table);
0156: _runtime = runtime;
0157: _table = table;
0158: JavaEntities.addBaseTypes(_table);
0159: }
0160:
0161: public JavaExternalAnalyzer newExternalAnalyzer(
0162: final Runtime runtime, final SymbolTable table) {
0163: return new JavaExternalAnalyzer(runtime, table);
0164: }
0165:
0166: /** Use this for asserting that the input is typed correctly. */
0167: protected boolean assrt(final Node n, final boolean cond,
0168: final String msgFormat, final Object... msgArgs) {
0169: return JavaEntities.runtimeAssrt(_runtime, n, cond, msgFormat,
0170: msgArgs);
0171: }
0172:
0173: protected void assrtLegalHandledExceptions(final GNode n) {
0174: assert null == n || n.hasName("ThrowsClause") : n.getName();
0175: final Type tThrowable = JavaEntities.tThrowable(_table);
0176: final List<Type> legal = new ArrayList<Type>();
0177: for (int i = 0; i < _context._handledExceptions.size(); i++) {
0178: final Type e = resolveIfAlias(_context._handledExceptions
0179: .get(i), n.getNode(i));
0180: final boolean ok = e.isError()
0181: || JavaTypeConverter.isAssignable(_table,
0182: classpath(), tThrowable, e);
0183: if (assrt(n.getNode(i), ok, "throwable expected"))
0184: legal.add(e);
0185: }
0186: _context._handledExceptions = legal;
0187: }
0188:
0189: protected void assrtLegalIdentifier(final GNode n, final String id) {
0190: assrt(n, !"true".equals(id), "illegal identifier");
0191: assrt(n, !"false".equals(id), "illegal identifier");
0192: assrt(n, !"null".equals(id), "illegal identifier");
0193: }
0194:
0195: protected void assrtLegalMethod(final GNode n, final MethodT method) {
0196: final ClassOrInterfaceT base = JavaEntities.declaringType(
0197: _table, method);
0198: for (final MethodT m : JavaEntities.methodsOwn(base))
0199: assrt(n, m == method
0200: || !JavaEntities.sameMethodSignature(method, m),
0201: "duplicate method");
0202: if (!JavaEntities.isConstructor(JavaEntities
0203: .resolveToRawClassOrInterfaceT(base), method)) {
0204: final List<MethodT> methodsInherited = JavaEntities
0205: .methodsInherited(_table, classpath(), base, true);
0206: for (final MethodT sup : methodsInherited)
0207: if (JavaEntities.isSuperMethod(_table, classpath(),
0208: sup, method))
0209: assrtLegalOverride(n, sup, method);
0210: }
0211: }
0212:
0213: protected void assrtLegalMethodBody(final GNode n, final Type method) {
0214: if (null == n.get(7))
0215: assrt(n, hasModifier(method, "abstract")
0216: || hasModifier(method, "native"),
0217: "missing method body");
0218: else
0219: assrt(n, !hasModifier(method, "abstract")
0220: && !hasModifier(method, "native"),
0221: "unexpected method body");
0222: }
0223:
0224: private void assrtLegalOverride(final GNode n, final MethodT sup,
0225: final MethodT sub) {
0226: assrt(n, !hasModifier(sup, "final"),
0227: "cannot override final method");
0228: if (hasModifier(sup, "static"))
0229: assrt(n, hasModifier(sub, "static"),
0230: "instance method cannot override static method");
0231: else if (JavaEntities.sameMethodSignature(sup, sub))
0232: assrt(n, !hasModifier(sub, "static"),
0233: "static method cannot hide instance method");
0234: if (hasModifier(sup, "public"))
0235: assrt(n, hasModifier(sub, "public"),
0236: "cannot reduce visibility");
0237: else if (hasModifier(sup, "protected"))
0238: assrt(n, hasModifier(sub, "public")
0239: || hasModifier(sub, "protected"),
0240: "cannot reduce visibility");
0241: else
0242: assrt(n, !hasModifier(sub, "private"),
0243: "cannot reduce visibility");
0244: resolveIfAlias(sup.getResult());
0245: assrt(n, JavaEntities.sameMethodReturnType(sup, sub),
0246: "incompatible return type");
0247: for (final Type e1 : sub.getExceptions()) {
0248: boolean declared = false;
0249: for (final Type e2 : sup.getExceptions())
0250: if (JavaEntities.isSuperClass(_table, classpath(), e2,
0251: e1)) {
0252: declared = true;
0253: break;
0254: }
0255: assrt(n, declared,
0256: "incompatible throws clause in overriding method");
0257: }
0258: }
0259:
0260: public final List<File> classpath() {
0261: return JavaEntities.classpath(_runtime);
0262: }
0263:
0264: public Type dispatchRValue(final GNode n) {
0265: final Type type = (Type) dispatch(n);
0266: if (null == type || type.isPackage()) {
0267: _runtime.error("unknown or ambiguous name", n);
0268: return JavaEntities.nameToBaseType("int");
0269: }
0270: return getRValue(type, n);
0271: }
0272:
0273: private static char escapeSequenceChar(final String s,
0274: final int start) {
0275: // gosling_et_al_2000 3.3 and 3.10.6
0276: final int len = s.length();
0277: assert start + 1 <= len && '\\' == s.charAt(start);
0278: switch (s.charAt(start + 1)) {
0279: case 'b':
0280: return '\b';
0281: case 't':
0282: return '\t';
0283: case 'n':
0284: return '\n';
0285: case 'f':
0286: return '\f';
0287: case 'r':
0288: return '\r';
0289: case '"':
0290: return '"';
0291: case '\'':
0292: return '\'';
0293: case '\\':
0294: return '\\';
0295: }
0296: int c = 0, i = start + 1;
0297: while (i < len && '0' <= s.charAt(i) && s.charAt(i) < '8') {
0298: c = 8 * c + s.charAt(i) - '0';
0299: i++;
0300: }
0301: assert i != start + 1;
0302: return (char) c;
0303: }
0304:
0305: private final int escapeSequenceEnd(final String s, final int start) {
0306: // gosling_et_al_2000 3.3 and 3.10.6
0307: final int len = s.length();
0308: assert start + 1 <= len && '\\' == s.charAt(start);
0309: switch (s.charAt(start + 1)) {
0310: case 'b':
0311: case 't':
0312: case 'n':
0313: case 'f':
0314: case 'r':
0315: case '"':
0316: case '\'':
0317: case '\\':
0318: return start + 2;
0319: }
0320: int c = 0, i = start + 1;
0321: while (i < len && '0' <= s.charAt(i) && s.charAt(i) < '8') {
0322: c = 8 * c + s.charAt(i) - '0';
0323: i++;
0324: }
0325: return i;
0326: }
0327:
0328: private Type getRValue(final Type type, final GNode n) {
0329: final Type result = getRValueNoError(type);
0330: if (null == result) {
0331: _runtime.error("unknown or ambiguous name", n);
0332: return ErrorT.TYPE;
0333: }
0334: return result;
0335: }
0336:
0337: private final boolean isAssignable(final int src, final Type tgt) {
0338: // gosling_et_al_2000 5.2
0339: if (JavaEntities.nameToBaseType("byte") == tgt)
0340: return (byte) src == src;
0341: if (JavaEntities.nameToBaseType("char") == tgt)
0342: return (char) src == src;
0343: if (JavaEntities.nameToBaseType("short") == tgt)
0344: return (short) src == src;
0345: return true;
0346: }
0347:
0348: public boolean isHandled(final Type tThrown) {
0349: final List<File> classpath = classpath();
0350: for (final Type tCaught : _context._handledExceptions)
0351: if (JavaTypeConverter.isAssignable(_table, classpath,
0352: tCaught, tThrown))
0353: return true;
0354: return false;
0355: }
0356:
0357: private boolean isStringConstant(final Type x) {
0358: return x.hasConstant()
0359: && JavaEntities.isReferenceT(x)
0360: && JavaTypeConverter.isIdentical(x, JavaEntities
0361: .tString(_table));
0362: }
0363:
0364: private Type processBitwiseBinaryExpression(final GNode n,
0365: final String operator) {
0366: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
0367: final Type x = getRValue(xLvalue, n.getGeneric(0));
0368: final Type y = dispatchRValue(n.getGeneric(1));
0369: if (x.isError() || y.isError())
0370: return setType(n, ErrorT.TYPE);
0371: final Type result;
0372: Type tBool = JavaEntities.nameToBaseType("boolean");
0373: final boolean xIsBool = JavaTypeConverter.isIdentical(x, tBool), yIsBool = JavaTypeConverter
0374: .isIdentical(y, tBool);
0375: assert "&".equals(operator) || "|".equals(operator)
0376: || "^".equals(operator);
0377: if (xIsBool || yIsBool) {
0378: if (!assrt(n, xIsBool && yIsBool, "operator type mismatch"))
0379: return setType(n, ErrorT.TYPE);
0380: if (x.hasConstant() && y.hasConstant()) {
0381: final boolean valX = x.getConstant().isTrue();
0382: final boolean valY = y.getConstant().isTrue();
0383: if ("&".equals(operator))
0384: result = tBool.annotate().constant(valX & valY);
0385: else if ("|".equals(operator))
0386: result = tBool.annotate().constant(valX | valY);
0387: else
0388: result = tBool.annotate().constant(valX ^ valY);
0389: } else {
0390: result = tBool;
0391: }
0392: } else {
0393: final Type promX = JavaTypeConverter.promoteBinaryNumeric(
0394: y, x);
0395: final Type promY = JavaTypeConverter.promoteBinaryNumeric(
0396: x, y);
0397: if (null == promX
0398: || !JavaEntities.resolveToRawRValue(promX)
0399: .isInteger()) {
0400: _runtime.error("integral operator expected", n
0401: .getNode(0));
0402: result = x;
0403: } else if (null == promY
0404: || !JavaEntities.resolveToRawRValue(promY)
0405: .isInteger()) {
0406: _runtime.error("integral operator expected", n
0407: .getNode(2));
0408: result = x;
0409: } else if (!x.hasConstant() || !y.hasConstant()) {
0410: result = promX;
0411: } else {
0412: final NumberT typNum = (NumberT) JavaEntities
0413: .resolveToRawRValue(promX);
0414: final Number valNumX = (Number) promX.getConstant()
0415: .getValue();
0416: final Number valNumY = (Number) promY.getConstant()
0417: .getValue();
0418: switch (typNum.getKind()) {
0419: case INT: {
0420: final int valX = valNumX.intValue(), valY = valNumY
0421: .intValue();
0422: if ("&".equals(operator))
0423: result = typNum.annotate().constant(
0424: new Integer(valX & valY));
0425: else if ("|".equals(operator))
0426: result = typNum.annotate().constant(
0427: new Integer(valX | valY));
0428: else
0429: result = typNum.annotate().constant(
0430: new Integer(valX ^ valY));
0431: break;
0432: }
0433: case LONG: {
0434: final long valX = valNumX.longValue(), valY = valNumY
0435: .longValue();
0436: if ("&".equals(operator))
0437: result = typNum.annotate().constant(
0438: new Long(valX & valY));
0439: else if ("|".equals(operator))
0440: result = typNum.annotate().constant(
0441: new Long(valX | valY));
0442: else
0443: result = typNum.annotate().constant(
0444: new Long(valX ^ valY));
0445: break;
0446: }
0447: default:
0448: throw new Error();
0449: }
0450: }
0451: }
0452: return setType(n, result);
0453: }
0454:
0455: private Type processTypeName(final GNode n) {
0456: if (n.hasName("PrimitiveType"))
0457: return (Type) dispatch(n);
0458: assert n.hasName("QualifiedIdentifier");
0459: final String typeName = (String) dispatch(n);
0460: final ClassOrInterfaceT result = JavaEntities
0461: .qualifiedNameToType(_table, classpath(), _table
0462: .current().getQualifiedName(), typeName);
0463: return result;
0464: }
0465:
0466: protected final Type resolveIfAlias(final Type type) {
0467: return resolveIfAlias(type, null);
0468: }
0469:
0470: protected final Type resolveIfAlias(final Type type, final Node n) {
0471: final Type resolved = JavaEntities.resolveIfAlias(_table,
0472: classpath(), _table.current().getQualifiedName(), type);
0473: if (null == resolved || resolved.isAlias()
0474: && null == resolved.toAlias().getType()) {
0475: if (null != n)
0476: _runtime.error("unknown class or interface "
0477: + type.toAlias().getName(), n);
0478: return ErrorT.TYPE;
0479: }
0480: return resolved;
0481: }
0482:
0483: /**
0484: * Visit an AdditiveExpression = Expression ("+" / "-") Expression
0485: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#15746">§15.18</a>).
0486: */
0487: public final Type visitAdditiveExpression(final GNode n) {
0488: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
0489: final Type x = getRValue(xLvalue, n.getGeneric(0));
0490: final Type y = dispatchRValue(n.getGeneric(2));
0491: if (x.isError() || y.isError())
0492: return setType(n, ErrorT.TYPE);
0493: final Type result;
0494: if ("+".equals(n.getString(1))) {
0495: final Type tString = JavaEntities.tString(_table);
0496: if (JavaTypeConverter.isIdentical(tString, x)
0497: || JavaTypeConverter.isIdentical(tString, y)) {
0498: if (x.hasConstant() && y.hasConstant()) {
0499: final Type convX = JavaTypeConverter.convertString(
0500: _table, x);
0501: final Type convY = JavaTypeConverter.convertString(
0502: _table, y);
0503: final String valX = (String) convX.getConstant()
0504: .getValue();
0505: final String valY = (String) convY.getConstant()
0506: .getValue();
0507: result = tString.annotate().constant(valX + valY);
0508: } else {
0509: result = tString;
0510: }
0511: } else {
0512: final Type promX = JavaTypeConverter
0513: .promoteBinaryNumeric(y, x);
0514: final Type promY = JavaTypeConverter
0515: .promoteBinaryNumeric(x, y);
0516: if (null == promX || null == promY) {
0517: _runtime.error(
0518: "String or numeric operands expected", n);
0519: result = JavaEntities.nameToBaseType("double");
0520: } else if (!promX.hasConstant() || !promY.hasConstant()) {
0521: result = JavaEntities.resolveToRawRValue(promX);
0522: } else {
0523: final NumberT typNum = (NumberT) JavaEntities
0524: .resolveToRawRValue(promX);
0525: final Number valNumX = (Number) promX.getConstant()
0526: .getValue();
0527: final Number valNumY = (Number) promY.getConstant()
0528: .getValue();
0529: switch (typNum.getKind()) {
0530: case INT: {
0531: final int valX = valNumX.intValue(), valY = valNumY
0532: .intValue();
0533: result = typNum.annotate().constant(
0534: new Integer(valX + valY));
0535: break;
0536: }
0537: case LONG: {
0538: final long valX = valNumX.longValue(), valY = valNumY
0539: .longValue();
0540: result = typNum.annotate().constant(
0541: new Long(valX + valY));
0542: break;
0543: }
0544: case FLOAT: {
0545: final float valX = valNumX.floatValue(), valY = valNumY
0546: .floatValue();
0547: result = typNum.annotate().constant(
0548: new Float(valX + valY));
0549: break;
0550: }
0551: case DOUBLE: {
0552: final double valX = valNumX.doubleValue(), valY = valNumY
0553: .doubleValue();
0554: result = typNum.annotate().constant(
0555: new Double(valX + valY));
0556: break;
0557: }
0558: default:
0559: throw new Error();
0560: }
0561: }
0562: }
0563: } else {
0564: assert "-".equals(n.getString(1));
0565: final Type promX = JavaTypeConverter.promoteBinaryNumeric(
0566: y, x);
0567: final Type promY = JavaTypeConverter.promoteBinaryNumeric(
0568: x, y);
0569: if (null == promX || null == promY) {
0570: _runtime.error("numeric operands expected", n);
0571: result = JavaEntities.nameToBaseType("double");
0572: } else if (!promX.hasConstant() || !promY.hasConstant()) {
0573: result = JavaEntities.resolveToRawRValue(promX);
0574: } else {
0575: final NumberT typNum = (NumberT) JavaEntities
0576: .resolveToRawRValue(promX);
0577: final Number valNumX = (Number) promX.getConstant()
0578: .getValue();
0579: final Number valNumY = (Number) promY.getConstant()
0580: .getValue();
0581: switch (typNum.getKind()) {
0582: case INT: {
0583: final int valX = valNumX.intValue(), valY = valNumY
0584: .intValue();
0585: result = typNum.annotate().constant(
0586: new Integer(valX - valY));
0587: break;
0588: }
0589: case LONG: {
0590: final long valX = valNumX.longValue(), valY = valNumY
0591: .longValue();
0592: result = typNum.annotate().constant(
0593: new Long(valX - valY));
0594: break;
0595: }
0596: case FLOAT: {
0597: final float valX = valNumX.floatValue(), valY = valNumY
0598: .floatValue();
0599: result = typNum.annotate().constant(
0600: new Float(valX - valY));
0601: break;
0602: }
0603: case DOUBLE: {
0604: final double valX = valNumX.doubleValue(), valY = valNumY
0605: .doubleValue();
0606: result = typNum.annotate().constant(
0607: new Double(valX - valY));
0608: break;
0609: }
0610: default:
0611: throw new Error();
0612: }
0613: }
0614: }
0615: return setType(n, result);
0616: }
0617:
0618: /**
0619: * Visit Arguments = Expression* (gosling_et_al_2000 <a
0620: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">§15.9</a>,
0621: * <a
0622: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448">§15.12</a>).
0623: */
0624: public final List<Type> visitArguments(final GNode n) {
0625: final List<Type> result = new ArrayList<Type>(n.size());
0626: for (int i = 0; i < n.size(); i++)
0627: result.add(dispatchRValue(n.getGeneric(i)));
0628: return result;
0629: }
0630:
0631: /**
0632: * Visit an ArrayInitializer = VariableInitializer* (gosling_et_al_2000 <a
0633: * href="http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#11358">§10.6</a>).
0634: * Note: VariableInitializer > ArrayInitializer, Expression.
0635: */
0636: public final Type visitArrayInitializer(final GNode n) {
0637: if (assrt(n, _context._initializing.isArray(),
0638: "array initializer type mismatch")) {
0639: final JavaContext savedContext = _context.save();
0640: _context._initializing = JavaEntities
0641: .arrayElementType(_context._initializing.toArray());
0642: for (int i = 0; i < n.size(); i++) {
0643: final Type src = dispatchRValue(n.getGeneric(i));
0644: assrt(n.getGeneric(i), JavaTypeConverter.isAssignable(
0645: _table, classpath(), _context._initializing,
0646: src), "array initializer type mismatch");
0647: }
0648: _context.restore(savedContext);
0649: }
0650: return setType(n, _context._initializing);
0651: }
0652:
0653: public final void visitBasicCastExpression(final GNode n) {
0654: assert false : "must run JavaAstSimplifier first";
0655: }
0656:
0657: /** Visit a BasicForControl = VariableModifiers Type Declarators [Expression] [ExpressionList]
0658: * / null null [ExpressionList] [Expression] [ExpressionList]
0659: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24588">§14.13</a>).
0660: */
0661: public final void visitBasicForControl(final GNode n) {
0662: if (null == n.get(1)) {
0663: assert null == n.get(0);
0664: } else {
0665: @SuppressWarnings("unchecked")
0666: final List<Attribute> modifiers = (List<Attribute>) dispatch(n
0667: .getNode(0));
0668: final Type type = (Type) dispatch(n.getGeneric(1));
0669: _externalAnalyzer.processDeclarators(modifiers, type, n
0670: .getGeneric(2));
0671: }
0672: dispatch(n.getGeneric(2));
0673: if (null != n.get(3)) {
0674: final Type condition = (Type) dispatch(n.getGeneric(3));
0675: assrt(n.getGeneric(3), JavaEntities.resolveToRawRValue(
0676: condition).isBoolean(), "condition must be boolean");
0677: }
0678: dispatch(n.getGeneric(4));
0679: }
0680:
0681: /**
0682: * Visit a BitwiseAndExpression = Expression Expression
0683: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228">§15.22</a>,
0684: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0685: */
0686: public final Type visitBitwiseAndExpression(final GNode n) {
0687: return processBitwiseBinaryExpression(n, "&");
0688: }
0689:
0690: /**
0691: * Visit a BitwiseNegationExpression = Expression
0692: * (gosling_et_al_2000 <a
0693: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4990">§15.15</a>,
0694: * <a
0695: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0696: */
0697: public final Type visitBitwiseNegationExpression(final GNode n) {
0698: final Type type = (Type) dispatch(n.getGeneric(0));
0699: if (type.isError())
0700: return setType(n, type);
0701: final Type promoted = JavaTypeConverter
0702: .promoteUnaryNumeric(getRValue(type, n.getGeneric(0)));
0703: if (!assrt(n, null != promoted, "operand must be numeric"))
0704: return setType(n, ErrorT.TYPE);
0705: if (promoted.hasConstant()) {
0706: final NumberT typNum = (NumberT) JavaEntities
0707: .resolveToRawRValue(promoted);
0708: final Number valNum = (Number) promoted.getConstant()
0709: .getValue();
0710: switch (typNum.getKind()) {
0711: case INT: {
0712: final int valInt = valNum.intValue();
0713: return typNum.annotate().constant(new Integer(~valInt));
0714: }
0715: case LONG: {
0716: final long valLong = valNum.longValue();
0717: return typNum.annotate().constant(new Long(~valLong));
0718: }
0719: default: {
0720: assrt(n, false, "operand must be an integral type");
0721: return setType(n, ErrorT.TYPE);
0722: }
0723: }
0724: } else {
0725: return setType(n, promoted);
0726: }
0727: }
0728:
0729: /**
0730: * Visit a BitwiseOrExpression = Expression Expression
0731: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228">§15.22</a>,
0732: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0733: */
0734: public final Type visitBitwiseOrExpression(final GNode n) {
0735: return processBitwiseBinaryExpression(n, "|");
0736: }
0737:
0738: /**
0739: * Visit a BitwiseXorExpression = Expression Expression
0740: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228">§15.22</a>,
0741: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0742: */
0743: public final Type visitBitwiseXorExpression(final GNode n) {
0744: return processBitwiseBinaryExpression(n, "^");
0745: }
0746:
0747: /**
0748: * Visit a Block = DeclarationOrStatement* (gosling_et_al_2000 <a
0749: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#246838">§14.2</a>).
0750: */
0751: public final Type visitBlock(final GNode n) {
0752: final JavaContext savedContext = _context.save();
0753: _context._hasScope = true;
0754: if (savedContext._hasScope) {
0755: _table.enter(_table.freshName("block"));
0756: _table.mark(n);
0757: }
0758: for (int i = 0; i < n.size(); i++)
0759: dispatch(n.getNode(i));
0760: if (savedContext._hasScope)
0761: _table.exit();
0762: _context.restore(savedContext);
0763: return JavaEntities.nameToBaseType("void");
0764: }
0765:
0766: /** Visit a BlockDeclaration = ["static"] Block (gosling_et_al_2000 <a
0767: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#246032">§8.6</a>,
0768: * <a
0769: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#39245">§8.7</a>). */
0770: public final void visitBlockDeclaration(final GNode n) {
0771: final JavaContext savedContext = _context.save();
0772: assert JavaEntities.isScopeForMember(_table.current()
0773: .getQualifiedName());
0774: final ClassOrInterfaceT enclosingType = JavaEntities
0775: .currentType(_table);
0776: assert JavaEntities.isWrappedClassT(enclosingType);
0777: _context._static = null != n.get(0);
0778: if (JavaEntities.isTypeInner(enclosingType))
0779: assrt(n, !_context._static,
0780: "inner classes may not declare static initializers");
0781: _context._handledExceptions = new ArrayList<Type>();
0782: final ClassT clazz = (ClassT) JavaEntities
0783: .resolveToRawRValue(enclosingType);
0784: final boolean isAnonymous = JavaEntities.isTypeAnonymous(clazz);
0785: if (isAnonymous) {
0786: _context._handledExceptions.add(JavaEntities
0787: .tThrowable(_table));
0788: } else if (_context._static) {
0789: // no checked exceptions allowed in static initializer
0790: } else {
0791: boolean firstConstructor = true;
0792: for (final Type m : clazz.getMethods()) {
0793: final MethodT method = m.toMethod();
0794: if (JavaEntities.isConstructor(clazz, method)) {
0795: final List<Type> nuw = method.getExceptions();
0796: if (firstConstructor) {
0797: _context._handledExceptions.addAll(nuw);
0798: firstConstructor = false;
0799: } else {
0800: final Set<String> old = new HashSet<String>();
0801: for (final Type t : _context._handledExceptions)
0802: old.add(((ClassT) JavaEntities
0803: .resolveToRawRValue(t)).getQName());
0804: _context._handledExceptions.clear();
0805: for (final Type t : nuw) {
0806: final String q = ((ClassT) JavaEntities
0807: .resolveToRawRValue(t)).getQName();
0808: if (old.contains(q))
0809: _context._handledExceptions.add(t);
0810: }
0811: }
0812: }
0813: }
0814: }
0815: dispatch(n.getGeneric(1));
0816: _context.restore(savedContext);
0817: }
0818:
0819: /**
0820: * Visit a BooleanLiteral (gosling_et_al_2000 <a
0821: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#49652">§3.10.3</a>,
0822: * <a
0823: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>,
0824: * <a
0825: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0826: */
0827: public final Type visitBooleanLiteral(final GNode n) {
0828: final Type tBool = JavaEntities.nameToBaseType("boolean");
0829: final boolean isTrue = "true".equals(n.getString(0));
0830: return setType(n, tBool.annotate().constant(isTrue));
0831: }
0832:
0833: /**
0834: * Visit a BreakStatement = [Identifier] (gosling_et_al_2000 <a
0835: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6842">§14.14</a>).
0836: */
0837: public final void visitBreakStatement(final GNode n) {
0838: if (null == n.get(0)) {
0839: assrt(n, _context._loop || _context._switch,
0840: "break without label can only be used in loop or switch");
0841: } else {
0842: final String simpleName = n.getString(0);
0843: final String symbol = SymbolTable.toLabelName(simpleName);
0844: final LabelT label = (LabelT) _table.current().lookup(
0845: symbol);
0846: assrt(n, null != label, "the label " + simpleName
0847: + " is missing");
0848: }
0849: }
0850:
0851: /**
0852: * Visit a CallExpression = [Expression] null MethodName Arguments
0853: * (gosling_et_al_2000 <a
0854: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448">§15.12</a>).
0855: */
0856: public final Type visitCallExpression(final GNode n) {
0857: // TD 21 (15.12) CallExpression = [Expression] MethodName Arguments
0858: final Type typeToSearch;
0859: final boolean inStaticContext;
0860: String identifier = n.getString(2);
0861: if ("super".equals(identifier) && n.get(0) == null) {
0862: // TD 08 (8.8.5.1) allow explicit constructor invocations via this() and super()
0863: typeToSearch = JavaEntities.currentType(_table).toClass()
0864: .getParent();
0865: identifier = resolveIfAlias(typeToSearch).toClass()
0866: .getName();
0867: inStaticContext = false;
0868: } else if (n.get(0) == null) {
0869: final SymbolTable.Scope oldScope = _table.current();
0870: outer: while (true) {
0871: final ClassOrInterfaceT t = JavaEntities
0872: .currentType(_table);
0873: JavaEntities.enterScopeByQualifiedName(_table,
0874: JavaEntities.typeToScopeName(t));
0875: for (final MethodT m : JavaEntities
0876: .methodsOwnAndInherited(_table, classpath(), t))
0877: if (m.getName().equals(identifier)) {
0878: typeToSearch = t;
0879: break outer;
0880: }
0881: if (JavaEntities.isTypeTopLevel(t)) {
0882: typeToSearch = t;
0883: break outer;
0884: }
0885: _table.exit();
0886: }
0887: _table.setScope(oldScope);
0888: inStaticContext = _context._static;
0889: } else {
0890: final Type t1 = (Type) dispatch(n.getGeneric(0));
0891: if (!assrt(n.getGeneric(0), !t1.isPackage(),
0892: "unknown idenfifier"))
0893: return setType(n, ErrorT.TYPE);
0894: inStaticContext = JavaEntities.isNotAValueT(t1);
0895: final Type t2 = inStaticContext ? JavaEntities
0896: .resolveToValue(t1.toAnnotated()) : t1;
0897: final Type t3 = getRValue(t2, n.getGeneric(0));
0898: final Type t4 = JavaEntities.isConstantT(t3) ? ((AnnotatedT) t3)
0899: .getType()
0900: : t3;
0901: typeToSearch = resolveIfAlias(t4);
0902: }
0903: final List<Type> actuals = JavaEntities
0904: .typeList((List) dispatch(n.getNode(3)));
0905: for (final Type actual : actuals)
0906: if (actual.isError())
0907: return setType(n, ErrorT.TYPE);
0908: final MethodT method = JavaEntities.typeDotMethod(_table,
0909: classpath(), typeToSearch, true, identifier, actuals);
0910: if (!assrt(n, null != method && method.isMethod(),
0911: "no such method"))
0912: return setType(n, ErrorT.TYPE);
0913: assrt(n, hasModifier(method, "static") || !inStaticContext,
0914: "static call to non-static method");
0915: JavaEntities.resolveIfAliasMethod(_table, classpath(), method);
0916: for (final Type tThrown : method.getExceptions())
0917: if (JavaEntities.isCheckedException(_table, classpath(),
0918: tThrown))
0919: assrt(n, isHandled(tThrown), "uncaught exception");
0920: setType(n.getGeneric(3), method);
0921: return setType(n, method.getResult());
0922: }
0923:
0924: /** Visit a CaseClause = Expression DeclarationOrStatement* (gosling_et_al_2000 <a
0925: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#35518">§14.10</a>). */
0926: public final Type visitCaseClause(final GNode n) {
0927: final Type key = (Type) dispatch(n.getGeneric(0));
0928: for (int i = 1; i < n.size(); i++)
0929: dispatch(n.getGeneric(i));
0930: return key;
0931: }
0932:
0933: /**
0934: * Visit a CastExpression = Type Expression (gosling_et_al_2000 <a
0935: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#238146">§15.16</a>,
0936: * <a
0937: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0938: */
0939: public final Type visitCastExpression(final GNode n) {
0940: final Type tgt = (Type) dispatch(n.getGeneric(0));
0941: if (tgt.isError())
0942: return setType(n, ErrorT.TYPE);
0943: final Type src = dispatchRValue(n.getGeneric(1));
0944: final Type result = JavaTypeConverter.convertCasting(_table,
0945: classpath(), tgt, src);
0946: if (!assrt(n, null != result, "illegal cast"))
0947: return setType(n, ErrorT.TYPE);
0948: return setType(n, result);
0949: }
0950:
0951: /** Visit a CatchClause = FormalParameter Block (gosling_et_al_2000 <a
0952: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#79311">§14.19</a>). */
0953: public final Type visitCatchClause(final GNode n) {
0954: final JavaContext savedContext = _context.save();
0955: _context._hasScope = false;
0956: _table.enter(_table.freshName("catchClause"));
0957: _table.mark(n);
0958: final GNode pNode = n.getGeneric(0);
0959: final Type tParameter = dispatchRValue(pNode);
0960: final Type tThrowable = JavaEntities.tThrowable(_table);
0961: assrt(pNode, JavaEntities.isSuperClass(_table, classpath(),
0962: tThrowable, tParameter),
0963: "illegal type for exception parameter");
0964: dispatch(n.getGeneric(1));
0965: _table.exit();
0966: _context.restore(savedContext);
0967: return setType(n, tParameter);
0968: }
0969:
0970: /**
0971: * Visit a CharacterLiteral (gosling_et_al_2000 <a
0972: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#100960">§3.10.4</a>,
0973: * <a
0974: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>,
0975: * <a
0976: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
0977: */
0978: public final Type visitCharacterLiteral(final GNode n) {
0979: final String s = n.getString(0);
0980: final int len = s.length();
0981: assert 2 < len && '\'' == s.charAt(0)
0982: && '\'' == s.charAt(len - 1);
0983: Character value = null;
0984: if (3 == len) {
0985: value = new Character(s.charAt(1));
0986: } else {
0987: try {
0988: value = new Character(escapeSequenceChar(s, 1));
0989: if (!assrt(n, len == 1 + escapeSequenceEnd(s, 1),
0990: "illegal escape sequence"))
0991: return setType(n, ErrorT.TYPE);
0992: } catch (final IllegalArgumentException e) {
0993: _runtime.error("illegal escape sequence", n);
0994: return setType(n, ErrorT.TYPE);
0995: }
0996: }
0997: if (!assrt(n, 3 < len || '\r' != value.charValue()
0998: && '\n' != value.charValue(),
0999: "single character must not be line terminator"))
1000: return setType(n, ErrorT.TYPE);
1001: final Type tChar = JavaEntities.nameToBaseType("char");
1002: return setType(n, tChar.annotate().constant(value));
1003: }
1004:
1005: /**
1006: * Visit a ClassBody = Declaration* (gosling_et_al_2000
1007: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#18988">§8.1.5</a>,
1008: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#236431">§9.1.3</a>,
1009: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">§15.9</a>).
1010: */
1011: public final void visitClassBody(final GNode n) {
1012: //TD 07 (8.1.5, 9.1.3, 15.9) ClassBody = Declaration*
1013: for (int i = 0; i < n.size(); i++)
1014: dispatch(n.getNode(i));
1015: }
1016:
1017: /**
1018: * Visit a ClassDeclaration = Modifiers Identifier null [Extension]
1019: * [Implementation] ClassBody (gosling_et_al_2000 <a
1020: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#15372">§8.1</a>,
1021: * <a
1022: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#247766">§14.3</a>).
1023: */
1024: public final void visitClassDeclaration(final GNode n) {
1025: final JavaContext savedContext = _context.save();
1026: _context._handledExceptions = new ArrayList<Type>();
1027: _context._hasScope = true;
1028: _context._switch = false;
1029: _context._loop = false;
1030: final String simpleName = n.getString(1);
1031: assrtLegalIdentifier(n, simpleName);
1032: ClassT base = (ClassT) _table.current().lookupLocally(
1033: SymbolTable.toTagName(simpleName));
1034: if (null == base)
1035: base = _externalAnalyzer.visitClassDeclaration(n);
1036: else
1037: assrt(n, !JavaEntities.isScopeLocal(_table.current()
1038: .getQualifiedName()), "conflicting classes");
1039: {
1040: final Type parent = base.getParent();
1041: if (parent.isAlias()) {
1042: final AliasT alias = parent.toAlias();
1043: resolveIfAlias(alias, n.getGeneric(3));
1044: if (null == alias.getType())
1045: alias.setType(JavaEntities.tObject(_table));
1046: }
1047: assrt(n.getGeneric(3),
1048: JavaEntities.isWrappedClassT(parent),
1049: "class expected");
1050: assrt(n.getGeneric(3), !hasModifier(parent, "final"),
1051: "can't subclass final class");
1052: assrt(n.getGeneric(3), JavaEntities.isAccessible(_table,
1053: classpath(), parent), "inner class not visible");
1054: }
1055: final Set<String> seenInterfaces = new HashSet<String>();
1056: for (int i = 0; i < base.getInterfaces().size(); i++) {
1057: // gosling_et_al_2000 08.1.4
1058: final Type t = resolveIfAlias(base.getInterfaces().get(i),
1059: n.getGeneric(4).getNode(i));
1060: if (!t.isError()
1061: && assrt(n.getGeneric(4), t.isInterface(),
1062: "interface expected")) {
1063: final String qname = t.toInterface().getQName();
1064: assrt(n.getGeneric(4), !seenInterfaces.contains(qname),
1065: "duplicate superinterfaces");
1066: seenInterfaces.add(qname);
1067: assrt(n.getGeneric(4), JavaEntities.isAccessible(
1068: _table, classpath(), t),
1069: "superinterface not accessible");
1070: }
1071: }
1072: final boolean isAbstract = hasModifier(base, "abstract");
1073: if (JavaEntities.hasAbstractMethods(_table, classpath(), base))
1074: assrt(n, isAbstract, "must be abstract");
1075: assrt(n, !JavaEntities.hasCircularDependency(_table,
1076: classpath(), base), "circular class");
1077: _table.enter(simpleName);
1078: _table.mark(n.getNode(5));
1079: dispatch(n.getNode(5));
1080: _table.exit();
1081: if (isAbstract)
1082: assrt(n, JavaEntities.couldCreateConcreteSubclass(_table,
1083: classpath(), base), "conflicting abstract methods");
1084: _context.restore(savedContext);
1085: }
1086:
1087: /**
1088: * Visit a ClassLiteralExpression = Type (gosling_et_al_2000 <a
1089: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251530">§15.8.2</a>).
1090: */
1091: public final Type visitClassLiteralExpression(final GNode n) {
1092: final Type t = (Type) dispatch(n.getNode(0));
1093: assert t.isError() || JavaEntities.isWrappedClassT(t)
1094: || JavaEntities.isWrappedInterfaceT(t) || t.isArray()
1095: || JavaEntities.isPrimitiveT(t);
1096: return setType(n, JavaEntities.tClass(_table));
1097: }
1098:
1099: /**
1100: * Visit a CompilationUnit = [PackageDeclaration] ImportDeclaration*
1101: * Declaration* (gosling_et_al_2000
1102: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#40031">§7.3</a>).
1103: */
1104: public void visitCompilationUnit(final GNode n) {
1105: _externalAnalyzer.dispatch(n);
1106: if (null == n.get(0))
1107: visitPackageDeclaration(null);
1108: else
1109: dispatch(n.getNode(0));
1110: _table.enter(JavaEntities
1111: .fileNameToScopeName(n.getLocation().file));
1112: _table.mark(n);
1113: for (int i = 1; i < n.size(); i++)
1114: dispatch(n.getNode(i));
1115: _table.setScope(_table.root());
1116: }
1117:
1118: /**
1119: * Visit a ConcreteDimensions = Expression+ (gosling_et_al_2000 <a
1120: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#46168">§15.10</a>).
1121: */
1122: public final List<Type> visitConcreteDimensions(final GNode n) {
1123: final List<Type> result = new ArrayList<Type>();
1124: for (int i = 0; i < n.size(); i++) {
1125: final Type r = dispatchRValue(n.getGeneric(i));
1126: result.add(r);
1127: final Type pr = null == r ? null : JavaTypeConverter
1128: .promoteUnaryNumeric(r);
1129: final Type rpr = null == pr ? null : JavaEntities
1130: .resolveToRawRValue(pr);
1131: assrt(n, null != rpr && rpr instanceof IntegerT
1132: && NumberT.Kind.INT == ((IntegerT) rpr).getKind(),
1133: "dimension must be integer");
1134: }
1135: return result;
1136: }
1137:
1138: /**
1139: * Visit a ConditionalExpression = Expression Expression Expression
1140: * (gosling_et_al_2000 <a
1141: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#290293">§15.25</a>,
1142: * <a
1143: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
1144: */
1145: public final Type visitConditionalExpression(final GNode n) {
1146: final Type typCond = dispatchRValue(n.getGeneric(0));
1147: final Type rawCond = JavaEntities.resolveToRawRValue(typCond);
1148: final BigInteger valCond;
1149: if (rawCond.isBoolean()) {
1150: if (typCond.hasConstant())
1151: valCond = typCond.getConstant().bigIntValue();
1152: else
1153: valCond = null;
1154: } else {
1155: assrt(n, rawCond.isError(), "condition must be boolean");
1156: valCond = null;
1157: }
1158: final Type typX = dispatchRValue(n.getGeneric(1));
1159: final Type rawX = JavaEntities.resolveToRawRValue(typX);
1160: final Object valX = typX.hasConstant() ? typX.getConstant()
1161: .getValue() : null;
1162: final Type typY = dispatchRValue(n.getGeneric(2));
1163: final Type rawY = JavaEntities.resolveToRawRValue(typY);
1164: final Object valY = typY.hasConstant() ? typY.getConstant()
1165: .getValue() : null;
1166: final Type result;
1167: if (JavaTypeConverter.isIdentical(typX, typY)) {
1168: if (null == valCond)
1169: result = rawX;
1170: else
1171: result = BigInteger.ONE == valCond ? typX : typY;
1172: } else if (rawX.isNumber() && rawY.isNumber()) {
1173: final NumberT tByte = (NumberT) JavaEntities
1174: .nameToBaseType("byte");
1175: final NumberT tShort = (NumberT) JavaEntities
1176: .nameToBaseType("short");
1177: final NumberT tChar = (NumberT) JavaEntities
1178: .nameToBaseType("char");
1179: final NumberT tInt = (NumberT) JavaEntities
1180: .nameToBaseType("int");
1181: final NumberT rawResult;
1182: if (tByte == rawX && tShort == rawY || tShort == rawX
1183: && tByte == rawY) {
1184: rawResult = tShort;
1185: } else if (tByte == rawX
1186: && tInt == rawY
1187: && null != valY
1188: && (byte) ((Integer) valY).intValue() == ((Integer) valY)
1189: .intValue()) {
1190: rawResult = tByte;
1191: } else if (tShort == rawX
1192: && tInt == rawY
1193: && null != valY
1194: && (short) ((Integer) valY).intValue() == ((Integer) valY)
1195: .intValue()) {
1196: rawResult = tShort;
1197: } else if (tChar == rawX
1198: && tInt == rawY
1199: && null != valY
1200: && (char) ((Integer) valY).intValue() == ((Integer) valY)
1201: .intValue()) {
1202: rawResult = tChar;
1203: } else if (tByte == rawY
1204: && tInt == rawX
1205: && null != valX
1206: && (byte) ((Integer) valX).intValue() == ((Integer) valX)
1207: .intValue()) {
1208: rawResult = tByte;
1209: } else if (tShort == rawY
1210: && tInt == rawX
1211: && null != valX
1212: && (short) ((Integer) valX).intValue() == ((Integer) valX)
1213: .intValue()) {
1214: rawResult = tShort;
1215: } else if (tChar == rawY
1216: && tInt == rawX
1217: && null != valX
1218: && (char) ((Integer) valX).intValue() == ((Integer) valX)
1219: .intValue()) {
1220: rawResult = tChar;
1221: } else {
1222: final NumberT x = (NumberT) JavaTypeConverter
1223: .promoteBinaryNumeric(rawY, rawX);
1224: final NumberT y = (NumberT) JavaTypeConverter
1225: .promoteBinaryNumeric(rawX, rawY);
1226: if (!assrt(n, null != x && null != y, "type mismatch"))
1227: return setType(n, ErrorT.TYPE);
1228: rawResult = x;
1229: }
1230: if (BigInteger.ONE == valCond && null != valX) {
1231: final Object valResult;
1232: if (valX instanceof Number) {
1233: final Number numX = (Number) valX;
1234: switch (rawResult.getKind()) {
1235: case BYTE:
1236: valResult = new Byte(numX.byteValue());
1237: break;
1238: case SHORT:
1239: valResult = new Short(numX.shortValue());
1240: break;
1241: case CHAR:
1242: valResult = new Character((char) numX
1243: .intValue());
1244: break;
1245: case INT:
1246: valResult = new Integer(numX.intValue());
1247: break;
1248: case LONG:
1249: valResult = new Long(numX.longValue());
1250: break;
1251: case FLOAT:
1252: valResult = new Float(numX.floatValue());
1253: break;
1254: case DOUBLE:
1255: valResult = new Double(numX.doubleValue());
1256: break;
1257: default:
1258: throw new Error();
1259: }
1260: } else {
1261: final char charX = ((Character) valX).charValue();
1262: switch (rawResult.getKind()) {
1263: case BYTE:
1264: valResult = new Byte((byte) charX);
1265: break;
1266: case SHORT:
1267: valResult = new Short((short) charX);
1268: break;
1269: case CHAR:
1270: valResult = new Character(charX);
1271: break;
1272: case INT:
1273: valResult = new Integer(charX);
1274: break;
1275: case LONG:
1276: valResult = new Long(charX);
1277: break;
1278: case FLOAT:
1279: valResult = new Float(charX);
1280: break;
1281: case DOUBLE:
1282: valResult = new Double(charX);
1283: break;
1284: default:
1285: throw new Error();
1286: }
1287: }
1288: result = rawResult.annotate().constant(valResult);
1289: } else if (BigInteger.ONE == valCond && null != valY) {
1290: final Number numY = (Number) valY;
1291: final Object valResult;
1292: switch (rawResult.getKind()) {
1293: case BYTE:
1294: valResult = new Byte(numY.byteValue());
1295: break;
1296: case SHORT:
1297: valResult = new Short(numY.shortValue());
1298: break;
1299: case CHAR:
1300: valResult = new Character((char) numY.intValue());
1301: break;
1302: case INT:
1303: valResult = new Integer(numY.intValue());
1304: break;
1305: case LONG:
1306: valResult = new Long(numY.longValue());
1307: break;
1308: case FLOAT:
1309: valResult = new Float(numY.floatValue());
1310: break;
1311: case DOUBLE:
1312: valResult = new Double(numY.doubleValue());
1313: break;
1314: default:
1315: throw new Error();
1316: }
1317: result = rawResult.annotate().constant(valResult);
1318: } else {
1319: result = rawResult;
1320: }
1321: } else if (!JavaEntities.isPrimitiveT(rawX)
1322: && !JavaEntities.isPrimitiveT(rawY)) {
1323: if (JavaEntities.isNullT(rawX)) {
1324: result = BigInteger.ZERO == valCond ? typY : rawY;
1325: } else if (JavaEntities.isNullT(rawY)) {
1326: result = BigInteger.ONE == valCond ? typY : rawY;
1327: } else {
1328: final Type convX = JavaTypeConverter.convertAssigning(
1329: _table, classpath(), rawY, rawX);
1330: final Type convY = JavaTypeConverter.convertAssigning(
1331: _table, classpath(), rawX, rawY);
1332: if (!assrt(n, null != convX || null != convY,
1333: "mismatched types"))
1334: return setType(n, ErrorT.TYPE);
1335: result = null != convX ? convX : convY;
1336: }
1337: } else {
1338: throw new Error();
1339: }
1340: return setType(n, result);
1341: }
1342:
1343: /**
1344: * Visit a ConditionalStatement = Expression Statement [Statement]
1345: * (gosling_et_al_2000 <a
1346: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5991">§14.9</a>).
1347: */
1348: public final void visitConditionalStatement(final GNode n) {
1349: final Type condition = dispatchRValue(n.getGeneric(0));
1350: if (!JavaEntities.resolveToRawRValue(condition).isBoolean())
1351: _runtime
1352: .error("condition must be boolean", n.getGeneric(0));
1353: dispatch(n.getNode(1));
1354: dispatch(n.getNode(2));
1355: }
1356:
1357: public final void visitConstructorDeclaration(final GNode n) {
1358: assert false : "must run JavaAstSimplifier first";
1359: }
1360:
1361: /**
1362: * Visit a ContinueStatement = [Identifier] (gosling_et_al_2000 <a
1363: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6122">§14.15</a>).
1364: */
1365: public final void visitContinueStatement(final GNode n) {
1366: if (null == n.get(0)) {
1367: assrt(n, _context._loop,
1368: "continue cannot be used outside of a loop");
1369: } else {
1370: final String simpleName = n.getString(0);
1371: final String symbol = SymbolTable.toLabelName(simpleName);
1372: final LabelT label = (LabelT) _table.current().lookup(
1373: symbol);
1374: if (null == label)
1375: _runtime.error("the label " + simpleName
1376: + " is missing", n);
1377: else
1378: assrt(n, label.hasAttribute(Constants.ATT_LOOP),
1379: "%s is not a loop label", label.getName());
1380: }
1381: }
1382:
1383: /**
1384: * Visit Declarator = Identifier [Dimensions] [VariableInitializer].
1385: * (gosling_et_al_2000 <a
1386: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5920">§14.4</a>).
1387: * Note: used by FieldDeclaration and ForInit,
1388: * who are responsible for calling the ExternalAnalyzer first, so
1389: * that the TYPE attribute is already set.
1390: * Note: VariableInitializer > ArrayInitializer, * Expression.
1391: */
1392: public final Type visitDeclarator(final GNode n) {
1393: final JavaContext savedContext = _context.save();
1394: final Type result = resolveIfAlias((Type) n
1395: .getProperty(Constants.TYPE), n);
1396: _context._static = hasModifier(result, "static");
1397: {
1398: final Type wrappedRValue = JavaEntities.dereference(result);
1399: final Type rValue = JavaEntities.isConstantT(wrappedRValue) ? ((AnnotatedT) wrappedRValue)
1400: .getType()
1401: : wrappedRValue;
1402: if (rValue.isAlias()) {
1403: final AliasT alias = (AliasT) rValue;
1404: if (null == alias.getType()) {
1405: _runtime
1406: .error("unknown type " + alias.getName(), n);
1407: alias.setType(JavaEntities.tObject(_table));
1408: return result;
1409: }
1410: }
1411: }
1412: final String id = n.getString(0);
1413: assrtLegalIdentifier(n, id);
1414: if (JavaEntities.isParameterT(result)) {
1415: _runtime.error("duplicate parameter declaration " + id, n);
1416: } else {
1417: assert JavaEntities.isFieldT(result)
1418: || JavaEntities.isLocalT(result);
1419: if (JavaEntities.isScopeLocal(_table.current()
1420: .getQualifiedName()))
1421: if (!SymbolTable.isInNameSpace(_table.current()
1422: .getName(), "method")) {
1423: final Type shadowed = (Type) _table.current()
1424: .getParent().lookup(id);
1425: assrt(n, null == shadowed
1426: || !JavaEntities.isParameterT(shadowed),
1427: "duplicate variable declaration " + id);
1428: }
1429: }
1430: if (null != n.get(2)) {
1431: _context._initializing = getRValue(result, n);
1432: final Type src = dispatchRValue((GNode) n.getNode(2));
1433: if (!src.isError()) {
1434: assert JavaEntities.isGeneralRValueT(src);
1435: assrt(n, JavaTypeConverter.isAssignable(_table,
1436: classpath(), _context._initializing, src),
1437: "initializer type mismatch");
1438: if (src.hasConstant() && !JavaEntities.isNullT(src)
1439: && hasModifier(result, "final")) {
1440: final WrappedT t = JavaEntities
1441: .resolveToRawLValue(result);
1442: t.setType(src);
1443: }
1444: }
1445: }
1446: if (_context._static && JavaEntities.isFieldT(result))
1447: if (JavaEntities.isTypeInner(JavaEntities
1448: .currentType(_table)))
1449: assrt(n, hasModifier(result, "final"),
1450: "static variables of inner classes must be compile-time constants");
1451: _context.restore(savedContext);
1452: return result;
1453: }
1454:
1455: /**
1456: * Visit Declarators = Declarator+
1457: * (gosling_et_al_2000 <a
1458: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5920">§14.4</a>).
1459: * Note: used by FieldDeclaration and ForInit,
1460: * who are responsible for calling the ExternalAnalyzer first, so
1461: * that the TYPE attribute is already set.
1462: */
1463: public final List<Type> visitDeclarators(final GNode n) {
1464: final List<Type> result = new ArrayList<Type>();
1465: for (final Object nDecl : n)
1466: result.add((Type) dispatch((GNode) nDecl));
1467: return result;
1468: }
1469:
1470: /**
1471: * Visit a DefaultClause = DeclarationOrStatement* (gosling_et_al_2000 <a
1472: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#35518">§14.10</a>).
1473: */
1474: public final void visitDefaultClause(final GNode n) {
1475: for (int i = 0; i < n.size(); i++)
1476: dispatch(n.getGeneric(i));
1477: }
1478:
1479: /**
1480: * Visit a DoWhileStatement = Statement Expression (gosling_et_al_2000 <a
1481: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6045">§14.12</a>).
1482: */
1483: public final void visitDoWhileStatement(final GNode n) {
1484: final JavaContext savedContext = _context.save();
1485: _context._loop = true;
1486: dispatch(n.getNode(0));
1487: final Type condition = dispatchRValue(n.getGeneric(1));
1488: if (!JavaEntities.resolveToRawRValue(condition).isBoolean())
1489: _runtime
1490: .error("condition must be boolean", n.getGeneric(0));
1491: _context.restore(savedContext);
1492: }
1493:
1494: /**
1495: * Visit a EmptyDeclaration = (no children) (gosling_et_al_2000 <a
1496: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5970">§14.6</a>).
1497: */
1498: public final void visitEmptyDeclaration(final GNode n) {
1499: assert 0 == n.size();
1500: }
1501:
1502: /**
1503: * Visit a EmptyStatement = (no children) (gosling_et_al_2000 <a
1504: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5970">§14.6</a>).
1505: */
1506: public final void visitEmptyStatement(final GNode n) {
1507: assert 0 == n.size();
1508: }
1509:
1510: /**
1511: * Visit a EqualityExpression = Expression ("==" / "!=") Expression
1512: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5192">§15.21</a>).
1513: */
1514: public final Type visitEqualityExpression(final GNode n) {
1515: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
1516: final Type x = getRValue(xLvalue, n.getGeneric(0));
1517: final Type y = dispatchRValue(n.getGeneric(2));
1518: if (x.isError() || y.isError())
1519: return setType(n, ErrorT.TYPE);
1520: final String o = n.getString(1);
1521: final Type result;
1522: Type tBool = JavaEntities.nameToBaseType("boolean");
1523: final boolean xIsBool = JavaTypeConverter.isIdentical(x, tBool), yIsBool = JavaTypeConverter
1524: .isIdentical(y, tBool);
1525: assert "==".equals(o) || "!=".equals(o);
1526: final Type promX = JavaTypeConverter.promoteBinaryNumeric(y, x);
1527: final Type promY = JavaTypeConverter.promoteBinaryNumeric(x, y);
1528: if (null == promX || null == promY) {
1529: if (xIsBool) {
1530: if (yIsBool) {
1531: if (x.hasConstant() && y.hasConstant()) {
1532: final boolean valX = x.getConstant().isTrue();
1533: final boolean valY = y.getConstant().isTrue();
1534: if ("==".equals(o))
1535: result = tBool.annotate().constant(
1536: valX == valY);
1537: else
1538: result = tBool.annotate().constant(
1539: valX != valY);
1540: } else {
1541: result = tBool;
1542: }
1543: } else {
1544: _runtime.error("boolean expected", n.getNode(n
1545: .size() - 1));
1546: result = tBool;
1547: }
1548: } else {
1549: if (JavaEntities.isNullT(x) || JavaEntities.isNullT(y)) {
1550: assrt(
1551: n,
1552: (JavaEntities.isReferenceT(x) || JavaEntities
1553: .isNullT(x))
1554: && (JavaEntities.isReferenceT(y) || JavaEntities
1555: .isNullT(y)),
1556: "incompatible types");
1557: result = tBool;
1558: } else if (isStringConstant(x) && isStringConstant(y)) {
1559: final String sx = (String) x.getConstant()
1560: .getValue(), sy = (String) y.getConstant()
1561: .getValue();
1562: result = tBool.annotate().constant(
1563: "==".equals(o) ? sx.equals(sy) : !sx
1564: .equals(sy));
1565: } else {
1566: final boolean yx = JavaTypeConverter.isCastable(
1567: _table, classpath(), y, x);
1568: final boolean xy = JavaTypeConverter.isCastable(
1569: _table, classpath(), x, y);
1570: assrt(n, yx || xy, "incompatible types");
1571: result = tBool;
1572: }
1573: }
1574: } else if (!promX.hasConstant() || !promY.hasConstant()) {
1575: result = tBool;
1576: } else {
1577: final NumberT typNum = (NumberT) JavaEntities
1578: .resolveToRawRValue(promX);
1579: final Number valNumX = (Number) promX.getConstant()
1580: .getValue();
1581: final Number valNumY = (Number) promY.getConstant()
1582: .getValue();
1583: switch (typNum.getKind()) {
1584: case INT: {
1585: final int valX = valNumX.intValue(), valY = valNumY
1586: .intValue();
1587: if ("==".equals(o))
1588: result = tBool.annotate().constant(valX == valY);
1589: else
1590: result = tBool.annotate().constant(valX != valY);
1591: break;
1592: }
1593: case LONG: {
1594: final long valX = valNumX.longValue(), valY = valNumY
1595: .longValue();
1596: if ("==".equals(o))
1597: result = tBool.annotate().constant(valX == valY);
1598: else
1599: result = tBool.annotate().constant(valX != valY);
1600: break;
1601: }
1602: case FLOAT: {
1603: final float valX = valNumX.floatValue(), valY = valNumY
1604: .floatValue();
1605: if ("==".equals(o))
1606: result = tBool.annotate().constant(valX == valY);
1607: else
1608: result = tBool.annotate().constant(valX != valY);
1609: break;
1610: }
1611: case DOUBLE: {
1612: final double valX = valNumX.doubleValue(), valY = valNumY
1613: .doubleValue();
1614: if ("==".equals(o))
1615: result = tBool.annotate().constant(valX == valY);
1616: else
1617: result = tBool.annotate().constant(valX != valY);
1618: break;
1619: }
1620: default:
1621: throw new Error();
1622: }
1623: }
1624: return setType(n, result);
1625: }
1626:
1627: /**
1628: * Visit a Expression = Expression ("=" / "+=" / "-=" / "*=" / "/=" / "&=" / "|=" / "^=" / "%=" / "<<=" / ">>=" / ">>>=") Expression
1629: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5281">§15.26</a>).
1630: */
1631: public final Type visitExpression(final GNode n) {
1632: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
1633: final Type x = getRValue(xLvalue, n.getGeneric(0));
1634: final Type y = dispatchRValue(n.getGeneric(2));
1635: if (x.isError() || y.isError())
1636: return setType(n, ErrorT.TYPE);
1637: final String o = n.getString(1);
1638: assert "=".equals(o) || "+=".equals(o) || "-=".equals(o)
1639: || "*=".equals(o) || "/=".equals(o) || "%=".equals(o)
1640: || "&=".equals(o) || "|=".equals(o) || "^=".equals(o)
1641: || "<<=".equals(o) || ">>=".equals(o)
1642: || ">>>=".equals(o);
1643: if (!JavaEntities.isGeneralLValueT(xLvalue)) {
1644: _runtime.error("left operand of assignment not l-value", n);
1645: } else if (hasModifier(xLvalue, "final")) {
1646: _runtime.error("left operand of assignment is final", n);
1647: // TD 30 (15.26) should allow assignments to "blank final" variables, but that
1648: // would require flow-sensitive analysis, which is quite complicated
1649: // for final parameters, assignment should definitely be forbidden
1650: } else if ("=".equals(o)) {
1651: // gosling_et_al_2000 15.26.1 Simple Assignment Operator =
1652: assrt(n.getGeneric(2), JavaTypeConverter.isAssignable(
1653: _table, classpath(), x, y), "illegal assignment");
1654: } else {
1655: // gosling_et_al_2000 15.26.2 Compound Assignment Operators
1656: final char op = o.charAt(0);
1657: final boolean string;
1658: if ('+' == op) {
1659: final Type tString = JavaEntities.tString(_table);
1660: string = JavaTypeConverter.isIdentical(x, tString);
1661: } else {
1662: string = false;
1663: }
1664: if (!string) {
1665: final Type rawX = JavaEntities.resolveToRawRValue(x);
1666: final Type rawY = JavaEntities.resolveToRawRValue(y);
1667: switch (op) {
1668: case '+':
1669: case '-':
1670: case '*':
1671: case '/':
1672: case '%':
1673: assrt(n, rawX.isNumber() && rawY.isNumber(),
1674: "illegal assignment");
1675: break;
1676: case '&':
1677: case '|':
1678: case '^':
1679: assrt(n, rawX.isBoolean() && rawY.isBoolean()
1680: || rawX.isInteger() && rawY.isInteger(),
1681: "illegal assignment");
1682: break;
1683: case '<':
1684: case '>':
1685: assrt(n, rawX.isInteger() && rawY.isInteger(),
1686: "illegal assignment");
1687: break;
1688: default:
1689: assert false;
1690: }
1691: }
1692: }
1693: return setType(n, x);
1694: }
1695:
1696: /**
1697: * Visit an ExpressionList = Expression* (gosling_et_al_2000 <a
1698: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24588">§14.13</a>).
1699: */
1700: public final List<Type> visitExpressionList(final GNode n) {
1701: final List<Type> result = new ArrayList<Type>();
1702: for (int i = 0; i < n.size(); i++)
1703: result.add(dispatchRValue(n.getGeneric(i)));
1704: return result;
1705: }
1706:
1707: /**
1708: * Visit an ExpressionStatement = Expression (gosling_et_al_2000 <a
1709: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5984">§14.8</a>).
1710: */
1711: public final void visitExpressionStatement(final GNode n) {
1712: dispatch(n.getNode(0));
1713: }
1714:
1715: /**
1716: * Visit a FieldDeclaration = Modifiers Type Declarators (gosling_et_al_2000
1717: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40898">§8.3</a>).
1718: */
1719: public final List<Type> visitFieldDeclaration(final GNode n) {
1720: //TD 42 don't treat static initializer like local variable
1721: // if (JavaEntities.isScopeLocal(_table.current().getQualifiedName()))
1722: if (null == n.getGeneric(2).getGeneric(0).getProperty(
1723: Constants.TYPE))
1724: _externalAnalyzer.dispatch(n);
1725: return JavaEntities.typeList((List) dispatch(n.getNode(2)));
1726: }
1727:
1728: /**
1729: * Visit a FloatingPointLiteral (gosling_et_al <a
1730: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#230798">§3.10.2</a>,
1731: * <a
1732: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>,
1733: * <a
1734: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
1735: */
1736: public final Type visitFloatingPointLiteral(final GNode n) {
1737: final String s = n.getString(0);
1738: final boolean isFloat = 'f' == Character.toLowerCase(s.charAt(s
1739: .length() - 1));
1740: final Number value = isFloat ? (Number) new Float(s)
1741: : new Double(s);
1742: if (!assrt(n, isFloat ? !((Float) value).isInfinite()
1743: : !((Double) value).isInfinite(),
1744: "literal out of range")
1745: || !assrt(n,
1746: (0.0 == value.doubleValue()) == JavaEntities
1747: .zeroLiteral(s), "literal out of range"))
1748: return setType(n, ErrorT.TYPE);
1749: final Type type = JavaEntities.nameToBaseType(isFloat ? "float"
1750: : "double");
1751: return setType(n, type.annotate().constant(value));
1752: }
1753:
1754: /**
1755: * Visit a FormalParameter = [Modifier] Type null Identifier [Dimensions] (gosling_et_al_2000 <a
1756: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#38698">§8.4.1</a>,
1757: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#29488">8.8.1</a>,
1758: * <a
1759: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#79311">§14.19</a>).
1760: */
1761: public final Type visitFormalParameter(final GNode n) {
1762: final boolean isInCatch = SymbolTable.isInNameSpace(_table
1763: .current().getName(), "catchClause");
1764: final String id = n.getString(3);
1765: final Type result;
1766: final Type t = (Type) _table.lookup(id);
1767: if (isInCatch) {
1768: assrt(n, null == t, "duplicate parameter " + id);
1769: result = null == t ? (Type) _externalAnalyzer
1770: .visitFormalParameter(n) : t;
1771: } else {
1772: result = t;
1773: }
1774: resolveIfAlias(JavaEntities.dereference(result), n.getNode(1));
1775: return setType(n, result);
1776: }
1777:
1778: /** Visit FormalParameters = FormalParameter* (gosling_et_al_2000 <a
1779: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#38698">§8.4.1</a>,
1780: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#29488">8.8.1</a>. */
1781: public final List<Type> visitFormalParameters(final GNode n) {
1782: final List<Type> result = new ArrayList<Type>(n.size());
1783: for (int i = 0; i < n.size(); i++)
1784: result.add((Type) dispatch(n.getNode(i)));
1785: return result;
1786: }
1787:
1788: /**
1789: * Visit a ForStatement = ForControl Statement
1790: * (gosling_et_al_2000 <a
1791: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24588">§14.13</a>).
1792: * Note that ForControl > BasicForControl.
1793: */
1794: public final void visitForStatement(final GNode n) {
1795: final JavaContext savedContext = _context.save();
1796: _context._loop = true;
1797: _context._hasScope = false;
1798: _table.enter(_table.freshName("forStatement"));
1799: _table.mark(n);
1800: dispatch(n.getGeneric(0));
1801: dispatch(n.getGeneric(1));
1802: _table.exit();
1803: _context.restore(savedContext);
1804: }
1805:
1806: /**
1807: * Visit a ImportDeclaration = QualifiedIdentifier ["*"] (gosling_et_al_2000
1808: * <a
1809: * href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#70209">§7.5</a>).
1810: */
1811: public final void visitImportDeclaration(final GNode n) {
1812: _externalAnalyzer.visitImportDeclaration(n);
1813: }
1814:
1815: /**
1816: * Visit an InstanceOfExpression = Expression Type (gosling_et_al_2000 <a
1817: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#40641">§15.20</a>).
1818: */
1819: public final Type visitInstanceOfExpression(final GNode n) {
1820: final GNode nExpression = n.getGeneric(0);
1821: final Type tExpression = dispatchRValue(nExpression);
1822: if (!tExpression.isError()) {
1823: if (JavaEntities.isReferenceT(tExpression)
1824: || JavaEntities.isNullT(tExpression)) {
1825: final GNode nType = n.getGeneric(1);
1826: final Type tType = (Type) dispatch(nType);
1827: if (!tType.isError()) {
1828: if (JavaEntities.isReferenceT(tType))
1829: assrt(n, JavaTypeConverter.isCastable(_table,
1830: classpath(), tType, tExpression),
1831: "not castable");
1832: else
1833: _runtime
1834: .error("reference type expected", nType);
1835: }
1836: } else {
1837: _runtime.error("reference type expected", nExpression);
1838: }
1839: }
1840: return setType(n, JavaEntities.nameToBaseType("boolean"));
1841: }
1842:
1843: /**
1844: * Visit an IntegerLiteral (gosling_et_al_2000 <a
1845: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#48282">§3.10.1</a>,
1846: * <a
1847: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>,
1848: * <a
1849: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
1850: */
1851: public final Type visitIntegerLiteral(final GNode n) {
1852: final String s = n.getString(0);
1853: final int len = s.length(), radix, digitsStart;
1854: final boolean isNeg = '-' == s.charAt(0);
1855: final boolean isLong = 'L' == Character.toUpperCase(s
1856: .charAt(len - 1));
1857: final int digitsEnd = isLong ? len - 1 : len;
1858: if (s.startsWith("0x") || s.startsWith("0X")) {
1859: radix = 16;
1860: digitsStart = isNeg ? 3 : 2;
1861: } else if (1 < digitsEnd && '0' == s.charAt(0)) {
1862: radix = 8;
1863: digitsStart = isNeg ? 2 : 1;
1864: } else {
1865: radix = 10;
1866: digitsStart = isNeg ? 1 : 0;
1867: }
1868: final String digits = s.substring(digitsStart, digitsEnd);
1869: BigInteger bigInt = new BigInteger(digits, radix);
1870: assert bigInt.compareTo(BigInteger.ZERO) >= 0;
1871: final BigInteger halfLong = new BigInteger("8000000000000000",
1872: 16);
1873: final BigInteger halfInt = new BigInteger("80000000", 16);
1874: final BigInteger fullLong = halfLong.add(halfLong), fullInt = halfInt
1875: .add(halfInt);
1876: final BigInteger max;
1877: if (10 == radix)
1878: if (isLong)
1879: max = isNeg ? halfLong : halfLong
1880: .subtract(BigInteger.ONE);
1881: else
1882: max = isNeg ? halfInt : halfInt
1883: .subtract(BigInteger.ONE);
1884: else
1885: max = (isLong ? fullLong : fullInt)
1886: .subtract(BigInteger.ONE);
1887: if (!assrt(n, bigInt.compareTo(max) <= 0,
1888: "literal out of range"))
1889: return setType(n, ErrorT.TYPE);
1890: if (10 != radix && isLong && bigInt.compareTo(halfLong) >= 0)
1891: bigInt = bigInt.subtract(fullLong);
1892: if (10 != radix && !isLong && bigInt.compareTo(halfInt) >= 0)
1893: bigInt = bigInt.subtract(fullInt);
1894: if (isNeg)
1895: bigInt = BigInteger.ZERO.subtract(bigInt);
1896: final Type type = JavaEntities.nameToBaseType(isLong ? "long"
1897: : "int");
1898: final Number value = isLong ? (Number) new Long(bigInt
1899: .longValue()) : new Integer(bigInt.intValue());
1900: if (!assrt(n, bigInt.equals(BigInteger.valueOf(value
1901: .longValue())), "literal out of range"))
1902: return setType(n, ErrorT.TYPE);
1903: return setType(n, type.annotate().constant(value));
1904: }
1905:
1906: /**
1907: * Visit a InterfaceDeclaration = Modifiers Identifier null [Extension] ClassBody
1908: * (gosling_et_al_2000 <a
1909: * href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#35470">§9.1</a>).
1910: */
1911: public final void visitInterfaceDeclaration(final GNode n) {
1912: if (JavaEntities.isScopeLocal(_table.current()
1913: .getQualifiedName())) {
1914: _runtime.error("interface cannot be local", n);
1915: return;
1916: }
1917: final JavaContext savedContext = _context.save();
1918: _context._handledExceptions = new ArrayList<Type>();
1919: _context._hasScope = true;
1920: _context._switch = false;
1921: _context._loop = false;
1922: final String simpleName = n.getString(1);
1923: assrtLegalIdentifier(n, simpleName);
1924: InterfaceT base = (InterfaceT) _table.current().lookupLocally(
1925: SymbolTable.toTagName(simpleName));
1926: if (null == base)
1927: base = _externalAnalyzer.visitInterfaceDeclaration(n);
1928: final Set<String> seenInterfaces = new HashSet<String>();
1929: for (int i = 0; i < base.getInterfaces().size(); i++) {
1930: // gosling_et_al_2000 9.1.2
1931: final Type t = resolveIfAlias(base.getInterfaces().get(i),
1932: n.getGeneric(3).getNode(i));
1933: if (!t.isError()
1934: && assrt(n.getGeneric(3), t.isInterface(),
1935: "interface expected")) {
1936: final String qname = t.toInterface().getQName();
1937: assrt(n.getGeneric(3), !seenInterfaces.contains(qname),
1938: "duplicate superinterfaces");
1939: seenInterfaces.add(qname);
1940: assrt(n.getGeneric(3), JavaEntities.isAccessible(
1941: _table, classpath(), t),
1942: "superinterface not accessible");
1943: }
1944: }
1945: assrt(n, !JavaEntities.hasCircularDependency(_table,
1946: classpath(), base), "circular class");
1947: _table.enter(simpleName);
1948: _table.mark(n.getNode(4));
1949: dispatch(n.getNode(4));
1950: _table.exit();
1951: _context.restore(savedContext);
1952: }
1953:
1954: /**
1955: * Visit a LabeledStatement = Identifier Statement (gosling_et_al_2000 <a
1956: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#78993">§14.7</a>).
1957: */
1958: public final void visitLabeledStatement(final GNode n) {
1959: _table.enter(_table.freshName("labeledStatement"));
1960: _table.mark(n);
1961: final String simpleName = n.getString(0);
1962: final String symbol = SymbolTable.toLabelName(simpleName);
1963: final SymbolTable.Scope scope = _table.current();
1964: SymbolTable.Scope s = scope;
1965: while (true) {
1966: final String q = s.getQualifiedName();
1967: if (JavaEntities.isScopeTopLevel(q)
1968: || JavaEntities.isScopeForMember(q))
1969: break;
1970: assrt(n, null == s.lookupLocally(symbol),
1971: "duplicate label " + simpleName);
1972: s = s.getParent();
1973: }
1974: final LabelT label = new LabelT(simpleName);
1975: scope.define(symbol, label);
1976: final String kind = n.getNode(1).getName();
1977: if ("ForStatement".equals(kind)
1978: || "WhileStatement".equals(kind)
1979: || "DoWhileStatement".equals(kind))
1980: label.addAttribute(Constants.ATT_LOOP);
1981: dispatch(n.getNode(1));
1982: _table.exit();
1983: }
1984:
1985: /**
1986: * Visit a LogicalAndExpression = Expression Expression
1987: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228">§15.22</a>,
1988: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
1989: */
1990: public final Type visitLogicalAndExpression(final GNode n) {
1991: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
1992: final Type x = getRValue(xLvalue, n.getGeneric(0));
1993: final Type y = dispatchRValue(n.getGeneric(1));
1994: if (x.isError() || y.isError())
1995: return setType(n, ErrorT.TYPE);
1996: final Type result;
1997: final Type tBool = JavaEntities.nameToBaseType("boolean");
1998: final boolean xIsBool = JavaTypeConverter.isIdentical(x, tBool), yIsBool = JavaTypeConverter
1999: .isIdentical(y, tBool);
2000: assrt(n.getGeneric(0), xIsBool, "operand must be boolean");
2001: assrt(n.getGeneric(1), yIsBool, "operand must be boolean");
2002: if (xIsBool && x.hasConstant() && yIsBool && y.hasConstant())
2003: result = tBool.annotate().constant(
2004: x.getConstant().isTrue()
2005: && y.getConstant().isTrue());
2006: else
2007: result = tBool;
2008: return setType(n, result);
2009: }
2010:
2011: /**
2012: * Visit a LogicalNegationExpression = Expression
2013: * (gosling_et_al_2000 <a
2014: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4990">§15.15</a>,
2015: * <a
2016: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
2017: */
2018: public final Type visitLogicalNegationExpression(final GNode n) {
2019: final Type type = (Type) dispatch(n.getGeneric(0));
2020: if (type.isError())
2021: return setType(n, type);
2022: final Type tBool = JavaEntities.nameToBaseType("boolean");
2023: if (!assrt(n, JavaTypeConverter.isIdentical(getRValue(type, n),
2024: tBool), "operand must be boolean"))
2025: return setType(n, ErrorT.TYPE);
2026: if (type.hasConstant())
2027: return setType(n, tBool.annotate().constant(
2028: !type.getConstant().isTrue()));
2029: return setType(n, type);
2030: }
2031:
2032: /**
2033: * Visit a LogicalOrExpression = Expression Expression
2034: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228">§15.22</a>,
2035: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
2036: */
2037: public final Type visitLogicalOrExpression(final GNode n) {
2038: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
2039: final Type x = getRValue(xLvalue, n.getGeneric(0));
2040: final Type y = dispatchRValue(n.getGeneric(1));
2041: if (x.isError() || y.isError())
2042: return setType(n, ErrorT.TYPE);
2043: final Type result;
2044: final Type tBool = JavaEntities.nameToBaseType("boolean");
2045: final boolean xIsBool = JavaTypeConverter.isIdentical(x, tBool), yIsBool = JavaTypeConverter
2046: .isIdentical(y, tBool);
2047: assrt(n.getGeneric(0), xIsBool, "operand must be boolean");
2048: assrt(n.getGeneric(1), yIsBool, "operand must be boolean");
2049: if (xIsBool && x.hasConstant() && yIsBool && y.hasConstant())
2050: result = tBool.annotate().constant(
2051: x.getConstant().isTrue()
2052: || y.getConstant().isTrue());
2053: else
2054: result = tBool;
2055: return setType(n, result);
2056: }
2057:
2058: /**
2059: * Visit a MethodDeclaration = Modifiers null Type Identifier FormalParameters [Dimensions]
2060: * [ThrowsClause] [Block] (gosling_et_al_2000 <a
2061: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40420">§8.4</a>,
2062: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#41652">8.8</a>,
2063: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#78651">9.4</a>).
2064: */
2065: public Type visitMethodDeclaration(final GNode n) {
2066: assrtLegalIdentifier(n, n.getString(3));
2067: _table.enter(JavaEntities.methodSymbolFromAst(n));
2068: _table.mark(n);
2069: final JavaContext savedContext = _context.save();
2070: _context._hasScope = false;
2071: final MethodT result = JavaEntities.currentMethod(_table);
2072: _context._static = hasModifier(result, "static");
2073: resolveIfAlias(result.getResult(), n.getNode(2));
2074: _context._handledExceptions = null == n.get(6) ? new ArrayList<Type>()
2075: : result.getExceptions();
2076: assrtLegalHandledExceptions(n.getGeneric(6));
2077: assrtLegalMethodBody(n, result);
2078: assrtLegalMethod(n, result);
2079: dispatch(n.getNode(4));
2080: dispatch(n.getNode(7));
2081: _context.restore(savedContext);
2082: _table.exit();
2083: return setType(n, result);
2084: }
2085:
2086: /** Visit a Modifiers = Modifier* (gosling_et_al_2000
2087: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#21613">§8.1.1</a>,
2088: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#78091">§8.3.1</a>,
2089: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#78188">§8.4.3</a>,
2090: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#247581">§8.5.1</a>,
2091: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#42018">§8.8.3</a>,
2092: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#235947">§9.1.1</a>). */
2093: public final List<Attribute> visitModifiers(final GNode n) {
2094: return _externalAnalyzer.visitModifiers(n);
2095: }
2096:
2097: /**
2098: * Visit a MultiplicativeExpression = Expression ("*" / "/" / "%") Expression
2099: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#239829">§15.17</a>).
2100: */
2101: public final Type visitMultiplicativeExpression(final GNode n) {
2102: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
2103: final Type x = getRValue(xLvalue, n.getGeneric(0));
2104: final Type y = dispatchRValue(n.getGeneric(2));
2105: if (x.isError() || y.isError())
2106: return setType(n, ErrorT.TYPE);
2107: final String o = n.getString(1);
2108: assert "*".equals(o) || "/".equals(o) || "%".equals(o);
2109: final Type result;
2110: final Type promX = JavaTypeConverter.promoteBinaryNumeric(y, x);
2111: final Type promY = JavaTypeConverter.promoteBinaryNumeric(x, y);
2112: if (null == promX || null == promY) {
2113: _runtime.error("numeric operands expected", n);
2114: result = JavaEntities.nameToBaseType("double");
2115: } else if (!promX.hasConstant() || !promY.hasConstant()) {
2116: result = JavaEntities.resolveToRawRValue(promX);
2117: } else {
2118: final NumberT typNum = (NumberT) JavaEntities
2119: .resolveToRawRValue(promX);
2120: final Number valNumX = (Number) promX.getConstant()
2121: .getValue();
2122: final Number valNumY = (Number) promY.getConstant()
2123: .getValue();
2124: switch (typNum.getKind()) {
2125: case INT: {
2126: final int valX = valNumX.intValue(), valY = valNumY
2127: .intValue();
2128: if ("*".equals(o))
2129: result = typNum.annotate().constant(
2130: new Integer(valX * valY));
2131: else if (0 == valY)
2132: result = typNum;
2133: else if ("/".equals(o))
2134: result = typNum.annotate().constant(
2135: new Integer(valX / valY));
2136: else
2137: result = typNum.annotate().constant(
2138: new Integer(valX % valY));
2139: break;
2140: }
2141: case LONG: {
2142: final long valX = valNumX.longValue(), valY = valNumY
2143: .longValue();
2144: if ("*".equals(o))
2145: result = typNum.annotate().constant(
2146: new Long(valX * valY));
2147: else if (0 == valY)
2148: result = typNum;
2149: else if ("/".equals(o))
2150: result = typNum.annotate().constant(
2151: new Long(valX / valY));
2152: else
2153: result = typNum.annotate().constant(
2154: new Long(valX % valY));
2155: break;
2156: }
2157: case FLOAT: {
2158: final float valX = valNumX.floatValue(), valY = valNumY
2159: .floatValue();
2160: if ("*".equals(o))
2161: result = typNum.annotate().constant(
2162: new Float(valX * valY));
2163: else if ("/".equals(o))
2164: result = typNum.annotate().constant(
2165: new Float(valX / valY));
2166: else
2167: result = typNum.annotate().constant(
2168: new Float(valX % valY));
2169: break;
2170: }
2171: case DOUBLE: {
2172: final double valX = valNumX.doubleValue(), valY = valNumY
2173: .doubleValue();
2174: if ("*".equals(o))
2175: result = typNum.annotate().constant(
2176: new Double(valX * valY));
2177: else if ("/".equals(o))
2178: result = typNum.annotate().constant(
2179: new Double(valX / valY));
2180: else
2181: result = typNum.annotate().constant(
2182: new Double(valX % valY));
2183: break;
2184: }
2185: default:
2186: throw new Error();
2187: }
2188: }
2189: return setType(n, result);
2190: }
2191:
2192: /** Visit a NewArrayExpression = TypeName ConcreteDimensions [Dimensions] null / TypeName null [Dimensions] ArrayInitializer.
2193: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#46168">§15.10</a>). */
2194: public final Type visitNewArrayExpression(final GNode n) {
2195: final Type component = processTypeName(n.getGeneric(0));
2196: if (component.isError())
2197: return setType(n, ErrorT.TYPE);
2198: dispatch(n.getNode(1));
2199: final int abstractDim = JavaExternalAnalyzer.countDimensions(n
2200: .getGeneric(2));
2201: final int dim = abstractDim
2202: + (null == n.get(1) ? 0 : n.getGeneric(1).size());
2203: final Type result = JavaEntities.typeWithDimensions(component,
2204: dim);
2205: if (null != n.get(3)) {
2206: final JavaContext savedContext = _context.save();
2207: _context._initializing = getRValue(result, n.getGeneric(0));
2208: final Type src = dispatchRValue(n.getGeneric(3));
2209: if (!result.isError() && !src.isError())
2210: assrt(n, JavaTypeConverter.isAssignable(_table,
2211: classpath(), _context._initializing, src),
2212: "initializer type mismatch");
2213: _context.restore(savedContext);
2214: }
2215: return setType(n, result);
2216: }
2217:
2218: /**
2219: * Visit a NewClassExpression = [Expression] Type TypeName Arguments [ClassBody]
2220: * (gosling_et_al_2000 <a
2221: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">§15.9</a>).
2222: */
2223: public final Type visitNewClassExpression(final GNode n) {
2224: assrt(n, null == n.get(4),
2225: "anonymous classes not yet implemented");
2226: dispatch(n.getNode(0));
2227: final Type result = processTypeName(n.getGeneric(2));
2228: if (result.isError()
2229: || !assrt(n.getGeneric(2), result.isClass(),
2230: "can only instantiate class types")
2231: || !assrt(n.getGeneric(2), !hasModifier(result,
2232: "abstract"), "cannot instantiate abstract type"))
2233: return setType(n, ErrorT.TYPE);
2234: final List<Type> actuals = JavaEntities
2235: .typeList((List) dispatch(n.getNode(3)));
2236: final Type constructor = JavaEntities.typeDotMethod(_table,
2237: classpath(), result, false, JavaEntities
2238: .typeToSimpleName(result), actuals);
2239: if (null == constructor) {
2240: _runtime.error("could not find constructor", n);
2241: setType(n.getGeneric(3), ErrorT.TYPE);
2242: } else {
2243: setType(n.getGeneric(3), constructor);
2244: }
2245: return setType(n, result);
2246: }
2247:
2248: /**
2249: * Visit a NullLiteral (gosling_et_al_2000 <a
2250: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#230717">§3.10.7</a>,
2251: * <a
2252: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>).
2253: */
2254: public final Type visitNullLiteral(final GNode n) {
2255: return setType(n, JavaEntities.nameToBaseType("null"));
2256: }
2257:
2258: /**
2259: * Visit a PackageDeclaration = QualifiedIdentifier (gosling_et_al_2000 <a
2260: * href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#26619">§7.4</a>).
2261: */
2262: public final void visitPackageDeclaration(final GNode n) {
2263: _externalAnalyzer.visitPackageDeclaration(n);
2264: }
2265:
2266: /**
2267: * Visit a PostfixExpression = Expression ("++" / "--")
2268: * (gosling_et_al_2000 <a
2269: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#36254">§15.14</a>).
2270: */
2271: public final Type visitPostfixExpression(final GNode n) {
2272: final Type lValue = (Type) dispatch(n.getGeneric(0));
2273: if (lValue.isError())
2274: return setType(n, ErrorT.TYPE);
2275: if (!assrt(n, JavaEntities.isGeneralLValueT(lValue),
2276: "operand of %s must be variable", n.getString(1)))
2277: return setType(n, lValue);
2278: assrt(n, !hasModifier(lValue, "final"),
2279: "operand of %s must not be final", n.getString(1));
2280: final Type result = JavaEntities.dereference(lValue);
2281: final Type raw = JavaEntities.resolveToRawRValue(result);
2282: assrt(n, raw.isNumber(), "operand of %s must be number", n
2283: .getString(1));
2284: return setType(n, result);
2285: }
2286:
2287: /**
2288: * Visit a PrimaryIdentifier = Identifier (gosling_et_al_2000 <a
2289: * href="http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#106941">§6.5</a>).
2290: */
2291: public Type visitPrimaryIdentifier(final GNode n) {
2292: // TD 02 (6.5.2, 15.11.1) PrimaryIdentifier = Identifier
2293: final String id = n.getString(0);
2294: final Type t = JavaEntities
2295: .simpleNameToPackageOrTypeOrExpression(_table,
2296: classpath(), _table.current()
2297: .getQualifiedName(), id);
2298: assert t.isPackage() || JavaEntities.isWrappedClassT(t)
2299: || JavaEntities.isWrappedInterfaceT(t)
2300: || JavaEntities.isLocalT(t) || JavaEntities.isFieldT(t)
2301: || JavaEntities.isParameterT(t);
2302: if (JavaEntities.isFieldT(t))
2303: assrt(n, hasModifier(t, "static") || !_context._static,
2304: "static use of instance field");
2305: final Type result = JavaEntities.notAValueIfClassOrInterface(t);
2306: return setType(n, result);
2307: }
2308:
2309: /**
2310: * Visit a PrimitiveType = ("byte" / "short" / "char" / "int" / "long" / "float" / "double" / "boolean")
2311: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#85587">§4.2</a>).
2312: */
2313: public final Type visitPrimitiveType(final GNode n) {
2314: return JavaEntities.nameToBaseType(n.getString(0));
2315: }
2316:
2317: /**
2318: * Visit a QualifiedIdentifier = Identifier+ (gosling_et_al_2000 <a
2319: * href="http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#106941">§6.5</a>).
2320: */
2321: public final String visitQualifiedIdentifier(final GNode n) {
2322: return _externalAnalyzer.visitQualifiedIdentifier(n);
2323: }
2324:
2325: /**
2326: * Visit a RelationalExpression = Expression ("<" / ">" / "<=" / ">=") Expression
2327: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#40641">§15.20</a>).
2328: */
2329: public final Type visitRelationalExpression(final GNode n) {
2330: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
2331: final Type x = getRValue(xLvalue, n.getGeneric(0));
2332: final Type y = dispatchRValue(n.getGeneric(2));
2333: if (x.isError() || y.isError())
2334: return setType(n, ErrorT.TYPE);
2335: final String o = n.getString(1);
2336: final Type result;
2337: Type tBool = JavaEntities.nameToBaseType("boolean");
2338: assert "<".equals(o) || ">".equals(o) || "<=".equals(o)
2339: || ">=".equals(o);
2340: final Type promX = JavaTypeConverter.promoteBinaryNumeric(y, x);
2341: final Type promY = JavaTypeConverter.promoteBinaryNumeric(x, y);
2342: if (null == promX || null == promY) {
2343: _runtime.error("numeric operands expected", n);
2344: result = tBool;
2345: } else if (!promX.hasConstant() || !promY.hasConstant()) {
2346: result = tBool;
2347: } else {
2348: final NumberT typNum = (NumberT) JavaEntities
2349: .resolveToRawRValue(promX);
2350: final Number valNumX = (Number) promX.getConstant()
2351: .getValue();
2352: final Number valNumY = (Number) promY.getConstant()
2353: .getValue();
2354: switch (typNum.getKind()) {
2355: case INT: {
2356: final int valX = valNumX.intValue(), valY = valNumY
2357: .intValue();
2358: if ("<".equals(o))
2359: result = tBool.annotate().constant(valX < valY);
2360: else if ("<=".equals(o))
2361: result = tBool.annotate().constant(valX <= valY);
2362: else if (">".equals(o))
2363: result = tBool.annotate().constant(valX > valY);
2364: else
2365: result = tBool.annotate().constant(valX >= valY);
2366: break;
2367: }
2368: case LONG: {
2369: final long valX = valNumX.longValue(), valY = valNumY
2370: .longValue();
2371: if ("<".equals(o))
2372: result = tBool.annotate().constant(valX < valY);
2373: else if ("<=".equals(o))
2374: result = tBool.annotate().constant(valX <= valY);
2375: else if (">".equals(o))
2376: result = tBool.annotate().constant(valX > valY);
2377: else
2378: result = tBool.annotate().constant(valX >= valY);
2379: break;
2380: }
2381: case FLOAT: {
2382: final float valX = valNumX.floatValue(), valY = valNumY
2383: .floatValue();
2384: if ("<".equals(o))
2385: result = tBool.annotate().constant(valX < valY);
2386: else if ("<=".equals(o))
2387: result = tBool.annotate().constant(valX <= valY);
2388: else if (">".equals(o))
2389: result = tBool.annotate().constant(valX > valY);
2390: else
2391: result = tBool.annotate().constant(valX >= valY);
2392: break;
2393: }
2394: case DOUBLE: {
2395: final double valX = valNumX.doubleValue(), valY = valNumY
2396: .doubleValue();
2397: if ("<".equals(o))
2398: result = tBool.annotate().constant(valX < valY);
2399: else if ("<=".equals(o))
2400: result = tBool.annotate().constant(valX <= valY);
2401: else if (">".equals(o))
2402: result = tBool.annotate().constant(valX > valY);
2403: else
2404: result = tBool.annotate().constant(valX >= valY);
2405: break;
2406: }
2407: default:
2408: throw new Error();
2409: }
2410: }
2411: return setType(n, result);
2412: }
2413:
2414: /**
2415: * Visit a ReturnStatement = [Expression] (gosling_et_al_2000 <a
2416: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6767">§14.16</a>).
2417: */
2418: public void visitReturnStatement(final GNode n) {
2419: final MethodT method = JavaEntities.currentMethod(_table);
2420: if (null == method) {
2421: _runtime.error("return statement outside method", n);
2422: return;
2423: }
2424: final Type t1 = null == n.get(0) ? VoidT.TYPE
2425: : dispatchRValue(n.getGeneric(0));
2426: final Type result = method.getResult();
2427: if (t1.isError() || result.isError())
2428: return;
2429: if (result.isVoid()) {
2430: assrt(n, t1.isVoid(),
2431: "'return' with a value, in method returning void");
2432: } else {
2433: if (t1.isVoid())
2434: _runtime
2435: .error(
2436: "'return' with no value, in method returning non-void",
2437: n);
2438: else
2439: assrt(n, JavaTypeConverter.isAssignable(_table,
2440: classpath(), result, t1),
2441: "return type mismatch");
2442: }
2443: }
2444:
2445: /**
2446: * Visit a SelectionExpression = Expression Identifier (gosling_et_al_2000 <a
2447: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#37055">§15.11.1</a>,
2448: * <a
2449: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
2450: */
2451: public final Type visitSelectionExpression(final GNode n) {
2452: //TD 19 (15.11.1, 15.28) SelectionExpression = Expression Identifier
2453: final Type basePackageOrTypeOrField = (Type) dispatch(n
2454: .getGeneric(0));
2455: final Type baseExpressionType = getRValueNoError(basePackageOrTypeOrField);
2456: final String selector = n.getString(1);
2457: final Type t;
2458: if (null != baseExpressionType) {
2459: t = JavaEntities.typeDotTypeOrField(_table, classpath(),
2460: baseExpressionType, true, selector);
2461: } else if (basePackageOrTypeOrField.isPackage()) {
2462: t = JavaEntities.packageDotPackageOrType(_table,
2463: classpath(), (PackageT) basePackageOrTypeOrField,
2464: selector);
2465: } else if (JavaEntities.isNotAValueT(basePackageOrTypeOrField)) {
2466: final Type baseType = JavaEntities
2467: .resolveToValue(basePackageOrTypeOrField
2468: .toAnnotated());
2469: t = JavaEntities.typeDotTypeOrField(_table, classpath(),
2470: baseType, true, selector);
2471: if (!assrt(n, null != t,
2472: "unknown or ambiguous type or field %s", selector)
2473: || !assrt(n, null == t
2474: || JavaEntities.hasModifier(t, "static"),
2475: "static access to non-static field"))
2476: return setType(n, ErrorT.TYPE);
2477: } else if (JavaEntities
2478: .isWrappedClassT(basePackageOrTypeOrField)
2479: || JavaEntities
2480: .isWrappedInterfaceT(basePackageOrTypeOrField)) {
2481: t = JavaEntities.typeDotTypeOrField(_table, classpath(),
2482: basePackageOrTypeOrField, true, selector);
2483: } else {
2484: throw new Error(basePackageOrTypeOrField.getClass()
2485: .getName());
2486: }
2487: if (null == t)
2488: return setType(n, ErrorT.TYPE);
2489: final Type result = JavaEntities.notAValueIfClassOrInterface(t);
2490: return setType(n, result);
2491: }
2492:
2493: /**
2494: * Visit a ShiftExpression = Expression ("<<" / ">>" / ">>>") Expression
2495: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5121">§15.19</a>).
2496: */
2497: public final Type visitShiftExpression(final GNode n) {
2498: final Type xLvalue = (Type) dispatch(n.getGeneric(0));
2499: final Type x = getRValue(xLvalue, n.getGeneric(0));
2500: final Type y = dispatchRValue(n.getGeneric(2));
2501: if (x.isError() || y.isError())
2502: return setType(n, ErrorT.TYPE);
2503: final String o = n.getString(1);
2504: final Type result;
2505: assert "<<".equals(o) || ">>".equals(o) || ">>>".equals(o);
2506: final Type promX = JavaTypeConverter.promoteUnaryNumeric(x);
2507: final Type promY = JavaTypeConverter.promoteUnaryNumeric(y);
2508: if (null == promX) {
2509: _runtime.error("integral operand expected", n.getNode(0));
2510: result = JavaEntities.nameToBaseType("long");
2511: } else if (null == promY) {
2512: _runtime.error("integral operand expected", n.getNode(2));
2513: result = promX;
2514: } else {
2515: final NumberT typNumX = (NumberT) JavaEntities
2516: .resolveToRawRValue(promX);
2517: final NumberT typNumY = (NumberT) JavaEntities
2518: .resolveToRawRValue(promY);
2519: if (!typNumX.isInteger()) {
2520: _runtime.error("integral operand expected", n
2521: .getNode(0));
2522: result = JavaEntities.nameToBaseType("int");
2523: } else if (!typNumY.isInteger()) {
2524: _runtime.error("integral operand expected", n
2525: .getNode(2));
2526: result = promX;
2527: } else if (!promX.hasConstant() || !promY.hasConstant()) {
2528: result = promX;
2529: } else {
2530: final Number valNumX = (Number) promX.getConstant()
2531: .getValue();
2532: final Number valNumY = (Number) promY.getConstant()
2533: .getValue();
2534: final long valY = valNumY.longValue();
2535: switch (typNumX.getKind()) {
2536: case INT: {
2537: final int valX = valNumX.intValue();
2538: if ("<<".equals(o))
2539: result = typNumX.annotate().constant(
2540: new Integer(valX << valY));
2541: else if (">>".equals(o))
2542: result = typNumX.annotate().constant(
2543: new Integer(valX >> valY));
2544: else
2545: result = typNumX.annotate().constant(
2546: new Integer(valX >>> valY));
2547: break;
2548: }
2549: case LONG: {
2550: final long valX = valNumX.longValue();
2551: if ("<<".equals(o))
2552: result = typNumX.annotate().constant(
2553: new Long(valX << valY));
2554: else if (">>".equals(o))
2555: result = typNumX.annotate().constant(
2556: new Long(valX >> valY));
2557: else
2558: result = typNumX.annotate().constant(
2559: new Long(valX >>> valY));
2560: break;
2561: }
2562: default:
2563: throw new Error();
2564: }
2565: }
2566: }
2567: return setType(n, result);
2568: }
2569:
2570: /** Visit a StringLiteral (gosling_et_al_2000 <a
2571: * href="http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#101083">§3.10.5</a>,
2572: * <a
2573: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">§15.8.1</a>,
2574: * <a
2575: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>). */
2576: public final Type visitStringLiteral(final GNode n) {
2577: final Type tString = JavaEntities.tString(_table);
2578: final String s = n.getString(0);
2579: final StringBuffer result = new StringBuffer();
2580: final int len = s.length() - 1;
2581: int i = 1;
2582: try {
2583: while (i < len) {
2584: final char c = s.charAt(i);
2585: if (c == '\\') {
2586: result.append(escapeSequenceChar(s, i));
2587: i = escapeSequenceEnd(s, i);
2588: } else {
2589: if (!assrt(n, '\r' != c && '\n' != c,
2590: "string must not contain line terminator"))
2591: return setType(n, ErrorT.TYPE);
2592: result.append(c);
2593: i++;
2594: }
2595: }
2596: } catch (final IllegalArgumentException e) {
2597: _runtime.error("illegal escape sequence", n);
2598: return setType(n, ErrorT.TYPE);
2599: }
2600: return setType(n, tString.annotate()
2601: .constant(result.toString()));
2602: }
2603:
2604: /**
2605: * Visit a SubscriptExpression = Expression Expression (gosling_et_al_2000 <a
2606: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#239587">§15.13</a>).
2607: */
2608: public final Type visitSubscriptExpression(final GNode n) {
2609: final Type arrayT = dispatchRValue(n.getGeneric(0));
2610: if (!assrt(n, arrayT.isArray(),
2611: "array reference expression expected"))
2612: return setType(n, ErrorT.TYPE);
2613: final Type indexT = dispatchRValue(n.getGeneric(1));
2614: assrt(n, JavaEntities.isInt(indexT),
2615: "integer expression expected");
2616: final AnnotatedT result = (AnnotatedT) ((ArrayT) arrayT)
2617: .getType();
2618: resolveIfAlias(JavaEntities.dereference(result));
2619: return setType(n, result);
2620: }
2621:
2622: /**
2623: * Visit a SuperExpression = [Type] (gosling_et_al_2000 <a
2624: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20860">§15.11.2</a>).
2625: */
2626: public final Type visitSuperExpression(final GNode n) {
2627: // TD 20 (15.11.2) SuperExpression = [Type]
2628: assrt(n, !_context._static, "static use of super");
2629: final Type subType = JavaEntities.currentType(_table);
2630: final ClassT rawSubType = (ClassT) JavaEntities
2631: .resolveToRawClassOrInterfaceT(subType);
2632: final Type result = JavaEntities.resolveIfAlias(_table,
2633: classpath(), JavaEntities.typeToScopeName(subType),
2634: rawSubType.getParent());
2635: return setType(n, result);
2636: }
2637:
2638: /**
2639: * Visit a SwitchStatement = Expression SwitchClause* (gosling_et_al_2000 <a
2640: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#35518">§14.10</a>).
2641: */
2642: public final void visitSwitchStatement(final GNode n) {
2643: final JavaContext savedContext = _context.save();
2644: _context._switch = true;
2645: final Type expression = (Type) dispatch(n.getGeneric(0));
2646: final Type eRaw;
2647: {
2648: final Type r = JavaEntities.isGeneralLValueT(expression) ? JavaEntities
2649: .dereference(expression)
2650: : expression;
2651: eRaw = JavaEntities.resolveToRawRValue(r);
2652: }
2653: assrt(n.getGeneric(0),
2654: JavaEntities.nameToBaseType("char") == eRaw
2655: || JavaEntities.nameToBaseType("byte") == eRaw
2656: || JavaEntities.nameToBaseType("short") == eRaw
2657: || JavaEntities.nameToBaseType("int") == eRaw,
2658: "switch expression must be char, byte, short, or int");
2659: boolean sawDefault = false;
2660: final Set<Integer> seenValues = new HashSet<Integer>();
2661: for (int iClause = 1; iClause < n.size(); iClause++) {
2662: final GNode clauseNode = n.getGeneric(iClause);
2663: if (clauseNode.hasName("DefaultClause")) {
2664: dispatch(clauseNode);
2665: if (sawDefault)
2666: _runtime.error("duplicate default clause",
2667: clauseNode);
2668: sawDefault = true;
2669: } else {
2670: //final Type clauseType = dispatchRValue(clauseNode);
2671: final Type clauseTypeL = (Type) dispatch(clauseNode);
2672: final Type clauseType = getRValue(clauseTypeL,
2673: clauseNode);
2674: if (JavaTypeConverter.isAssignable(_table, classpath(),
2675: eRaw, clauseType)) {
2676: if (null == clauseType)
2677: throw new Error();
2678: if (JavaEntities.isConstantT(clauseType)) {
2679: final Object clauseValue = clauseType
2680: .getConstant().getValue();
2681: if (null == clauseValue)
2682: throw new Error();
2683: final int i = clauseValue instanceof Character ? ((Character) clauseValue)
2684: .charValue()
2685: : ((Number) clauseValue).intValue();
2686: if (seenValues.contains(new Integer(i)))
2687: _runtime.error("duplicate case clause",
2688: clauseNode);
2689: else
2690: seenValues.add(new Integer(i));
2691: assrt(clauseNode, isAssignable(i, eRaw),
2692: "invalid case clause");
2693: } else {
2694: assrt(n, JavaEntities
2695: .isGeneralLValueT(clauseTypeL)
2696: && hasModifier(clauseTypeL, "final"),
2697: "case expression must be constant");
2698: }
2699: } else {
2700: _runtime.error("invalid case clause", clauseNode);
2701: }
2702: }
2703: }
2704: _context.restore(savedContext);
2705: }
2706:
2707: /**
2708: * Visit a SynchronizedStatement = Expression Block (gosling_et_al_2000 <a
2709: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#255769">§14.18</a>).
2710: */
2711: public final void visitSynchronizedStatement(final GNode n) {
2712: final GNode nMonitor = n.getGeneric(0);
2713: final Type tMonitor = dispatchRValue(nMonitor);
2714: assrt(nMonitor, !JavaEntities.isNullT(tMonitor)
2715: && JavaEntities.isReferenceT(tMonitor),
2716: "invalid type for synchronized statement");
2717: dispatch(n.getNode(1));
2718: }
2719:
2720: /**
2721: * Visit a ThisExpression = [Expression] (gosling_et_al_2000
2722: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251519">§15.8.3</a>,
2723: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251603">§15.8.4</a>).
2724: */
2725: public final Type visitThisExpression(final GNode n) {
2726: // TD 25 (15.8.3, 15.8.4) ThisExpression = [Expression]
2727: assrt(n, !_context._static, "static use of this");
2728: return setType(n, JavaEntities.currentType(_table));
2729: }
2730:
2731: /**
2732: * Visit a ThrowStatement = Expression (gosling_et_al_2000 <a
2733: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#237350">§14.17</a>).
2734: */
2735: public final void visitThrowStatement(final GNode n) {
2736: final Type tThrown = dispatchRValue(n.getGeneric(0));
2737: final Type tThrowable = JavaEntities.tThrowable(_table);
2738: if (!JavaTypeConverter.isAssignable(_table, classpath(),
2739: tThrowable, tThrown))
2740: _runtime.error("exception must be throwable", n.getNode(0));
2741: else if (JavaEntities.isCheckedException(_table, classpath(),
2742: tThrown))
2743: assrt(n, isHandled(tThrown), "uncaught exception");
2744: }
2745:
2746: /**
2747: * Visit a TryCatchFinallyStatement = Block CatchClause* [Block]
2748: * (gosling_et_al_2000 <a
2749: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#79311">§14.19</a>).
2750: */
2751: public final List<Type> visitTryCatchFinallyStatement(final GNode n) {
2752: final List<Type> result = new ArrayList<Type>();
2753: for (int i = 1; i < n.size() - 1; i++)
2754: result.add((Type) dispatch(n.getNode(i)));
2755: final JavaContext savedContext = _context.save();
2756: _context._handledExceptions = new ArrayList<Type>();
2757: _context._handledExceptions
2758: .addAll(savedContext._handledExceptions);
2759: _context._handledExceptions.addAll(result);
2760: dispatch(n.getNode(0));
2761: _context.restore(savedContext);
2762: dispatch(n.getNode(n.size() - 1));
2763: return result;
2764: }
2765:
2766: /**
2767: * Visit a Type = TypeName Dimensions
2768: * (gosling_et_al_2000 <a
2769: * href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#48440">§4</a>,
2770: * <a
2771: * href="http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#25518">§10.1</a>).
2772: * Note that TypeName is either PrimitiveType or ClassType, i.e., QualifiedIdentifier.
2773: */
2774: public final Type visitType(final GNode n) {
2775: //TD 01 (4, 10.1) Type = TypeName Dimensions
2776: final Type t = _externalAnalyzer.visitType(n);
2777: final Type result = resolveIfAlias(t, n);
2778: return setType(n, result);
2779: }
2780:
2781: /**
2782: * Visit a UnaryExpression = ("+" / "-" / "++" / "--") Expression
2783: * (gosling_et_al_2000 <a
2784: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4990">§15.15</a>,
2785: * <a
2786: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">§15.28</a>).
2787: */
2788: public final Type visitUnaryExpression(final GNode n) {
2789: final Type type = (Type) dispatch(n.getGeneric(1));
2790: if (type.isError())
2791: return setType(n, type);
2792: String operator = n.getString(0);
2793: if ("++".equals(operator) || "--".equals(operator)) {
2794: if (JavaEntities.isGeneralLValueT(type)) {
2795: assrt(n, !hasModifier(type, "final"),
2796: "operand of %s must not be final", operator);
2797: final Type rValue = JavaEntities.dereference(type);
2798: final Type raw = JavaEntities
2799: .resolveToRawRValue(rValue);
2800: if (!assrt(n, raw.isNumber(),
2801: "operand of %s must be number", operator))
2802: return setType(n, ErrorT.TYPE);
2803: return setType(n, rValue);
2804: }
2805: _runtime.error("operand of " + operator
2806: + " must be variable", n);
2807: return setType(n, type);
2808: } else {
2809: assert "+".equals(operator) || "-".equals(operator);
2810: final Type promoted = JavaTypeConverter
2811: .promoteUnaryNumeric(getRValue(type, n
2812: .getGeneric(1)));
2813: if (!assrt(n, null != promoted, "operand must be numeric"))
2814: return setType(n, ErrorT.TYPE);
2815: if (promoted.hasConstant()) {
2816: if ("+".equals(operator))
2817: return setType(n, promoted);
2818: final NumberT typNum = (NumberT) JavaEntities
2819: .resolveToRawRValue(promoted);
2820: final Number valNum = (Number) promoted.getConstant()
2821: .getValue();
2822: switch (typNum.getKind()) {
2823: case INT: {
2824: final int valInt = valNum.intValue();
2825: return typNum.annotate().constant(
2826: new Integer("-".equals(operator) ? -valInt
2827: : ~valInt));
2828: }
2829: case LONG: {
2830: final long valLong = valNum.longValue();
2831: return typNum.annotate().constant(
2832: new Long("-".equals(operator) ? -valLong
2833: : ~valLong));
2834: }
2835: case FLOAT: {
2836: if (!assrt(n, "-".equals(operator),
2837: "operand must be an integral type"))
2838: return setType(n, ErrorT.TYPE);
2839: return typNum.annotate().constant(
2840: new Float(-valNum.floatValue()));
2841: }
2842: case DOUBLE: {
2843: if (!assrt(n, "-".equals(operator),
2844: "operand must be an integral type"))
2845: return setType(n, ErrorT.TYPE);
2846: return typNum.annotate().constant(
2847: new Double(-valNum.doubleValue()));
2848: }
2849: default:
2850: throw new Error();
2851: }
2852: } else {
2853: return setType(n, promoted);
2854: }
2855: }
2856: }
2857:
2858: /**
2859: * Visit a WhileStatement = Expression Statement (gosling_et_al_2000 <a
2860: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#237277">§14.11</a>).
2861: */
2862: public final void visitWhileStatement(final GNode n) {
2863: final JavaContext savedContext = _context.save();
2864: _context._loop = true;
2865: final Type condition = dispatchRValue(n.getGeneric(0));
2866: if (!JavaEntities.resolveToRawRValue(condition).isBoolean())
2867: _runtime
2868: .error("condition must be boolean", n.getGeneric(0));
2869: dispatch(n.getNode(1));
2870: _context.restore(savedContext);
2871: }
2872: }
|