Source Code Cross Referenced for JavaAnalyzer.java in  » Parser » Rats-Parser-Generators » xtc » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Parser » Rats Parser Generators » xtc.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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">&sect;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">&sect;15.9</a>,
0621:             * <a
0622:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448">&sect;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">&sect;10.6</a>).
0634:             * Note: VariableInitializer &gt; 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">&sect;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">&sect;15.22</a>, 
0684:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;15.15</a>,
0694:             * <a
0695:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;15.22</a>, 
0732:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;15.22</a>, 
0741:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;8.6</a>,
0768:             * <a
0769:             * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#39245">&sect;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">&sect;3.10.3</a>,
0822:             * <a
0823:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;15.8.1</a>,
0824:             * <a
0825:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;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">&sect;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">&sect;15.16</a>,
0936:             * <a
0937:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;3.10.4</a>,
0973:             * <a
0974:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;15.8.1</a>,
0975:             * <a
0976:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;8.1.5</a>,
1008:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#236431">&sect;9.1.3</a>,
1009:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">&sect;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">&sect;8.1</a>,
1021:             * <a
1022:             * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#247766">&sect;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">&sect;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">&sect;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">&sect;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">&sect;15.25</a>,
1142:             * <a
1143:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;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">&sect;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 &gt; 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">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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 ("=" / "+=" / "-=" / "*=" / "/=" / "&amp;=" / "|=" / "^=" / "%=" / "&lt;&lt;=" / "&gt;&gt;=" / "&gt;&gt;&gt;=") Expression
1629:             * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5281">&sect;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">&sect;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">&sect;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">&sect;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">&sect;3.10.2</a>,
1731:             * <a
1732:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;15.8.1</a>,
1733:             * <a
1734:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;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">&sect;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">&sect;14.13</a>).
1792:             * Note that ForControl &gt; 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">&sect;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">&sect;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">&sect;3.10.1</a>,
1846:             * <a
1847:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;15.8.1</a>,
1848:             * <a
1849:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;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">&sect;15.22</a>, 
1988:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;15.15</a>,
2015:             * <a
2016:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;15.22</a>, 
2035:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;8.1.1</a>,
2088:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#78091">&sect;8.3.1</a>,
2089:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#78188">&sect;8.4.3</a>,
2090:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#247581">&sect;8.5.1</a>,
2091:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#42018">&sect;8.8.3</a>,
2092:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#235947">&sect;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">&sect;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">&sect;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">&sect;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">&sect;3.10.7</a>,
2251:             * <a
2252:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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 ("&lt;" / "&gt;" / "&lt;=" / "&gt;=") Expression
2327:             * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#40641">&sect;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">&sect;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">&sect;15.11.1</a>,
2448:             * <a
2449:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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 ("&lt;&lt;" / "&gt;&gt;" / "&gt;&gt;&gt;") Expression
2495:             * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5121">&sect;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">&sect;3.10.5</a>,
2572:             * <a
2573:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#224125">&sect;15.8.1</a>,
2574:             * <a
2575:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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">&sect;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">&sect;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">&sect;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">&sect;15.8.3</a>,
2723:             * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251603">&sect;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">&sect;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">&sect;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">&sect;4</a>,
2770:             * <a
2771:             * href="http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#25518">&sect;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">&sect;15.15</a>,
2785:             * <a
2786:             * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5313">&sect;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">&sect;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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.