0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.debugger.jpda.expr;
0043:
0044: import com.sun.jdi.*;
0045:
0046: import java.util.*;
0047: import java.util.logging.Level;
0048: import java.util.logging.Logger;
0049:
0050: import org.netbeans.api.debugger.jpda.InvalidExpressionException;
0051: import org.netbeans.api.debugger.jpda.JPDAClassType;
0052: import org.netbeans.api.debugger.jpda.JPDAThread;
0053: import org.netbeans.modules.debugger.jpda.models.CallStackFrameImpl;
0054: import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
0055: import org.openide.util.NbBundle;
0056:
0057: /**
0058: * Engine that evaluates a Java expression in a context of a running JVM. The
0059: * JVM (or at least the current thread) must be suspended. A single instance of this evaluator may
0060: * only be used from a single thread, no multithreading support is provided.
0061: *
0062: * TODO: the evaluator should check the expression's language version
0063: *
0064: * @author Maros Sandor
0065: */
0066: public class Evaluator implements JavaParserVisitor {
0067:
0068: private static final boolean verbose = System
0069: .getProperty("netbeans.debugger.noInvokeMethods") != null;
0070:
0071: private static final Logger loggerMethod = Logger
0072: .getLogger("org.netbeans.modules.debugger.jpda.invokeMethod"); // NOI18N
0073: private static final Logger loggerValue = Logger
0074: .getLogger("org.netbeans.modules.debugger.jpda.getValue"); // NOI8N
0075:
0076: private Expression expression;
0077: private EvaluationContext evaluationContext;
0078:
0079: private VirtualMachine vm;
0080: private StackFrame frame;
0081: private ThreadReference frameThread;
0082: private int frameIndex;
0083:
0084: private SimpleNode currentNode;
0085: private String currentPackage;
0086: private Operators operators;
0087:
0088: Evaluator(Expression expression, EvaluationContext context) {
0089: this .expression = expression;
0090: this .evaluationContext = context;
0091: }
0092:
0093: /**
0094: * Evaluates the expression for which it was created.
0095: *
0096: * @return the result of evaluating the expression as a JDI Value object.
0097: * It returns null if the result itself is null.
0098: * @throws EvaluationException if the expression cannot be evaluated for whatever reason
0099: * @throws IncompatibleThreadStateException if the context thread is in an
0100: * incompatible state (running, dead)
0101: */
0102: public Value evaluate() throws EvaluationException,
0103: IncompatibleThreadStateException {
0104: frame = evaluationContext.getFrame();
0105: vm = evaluationContext.getFrame().virtualMachine();
0106: frameThread = frame.thread();
0107: frameIndex = indexOf(frameThread.frames(), frame);
0108: if (frameIndex == -1) {
0109: throw new IncompatibleThreadStateException(
0110: "Thread does not contain current frame");
0111: }
0112: currentPackage = evaluationContext.getFrame().location()
0113: .declaringType().name();
0114: int idx = currentPackage.lastIndexOf('.');
0115: currentPackage = (idx > 0) ? currentPackage.substring(0,
0116: idx + 1) : "";
0117: operators = new Operators(vm);
0118: SimpleNode rootNode = expression.getRoot();
0119: return (Value) rootNode.jjtAccept(this , null);
0120: }
0121:
0122: private int indexOf(List frames, StackFrame frame) {
0123: int n = frames.size();
0124: Location loc = frame.location();
0125: for (int i = 0; i < n; i++) {
0126: if (loc.equals(((StackFrame) frames.get(i)).location()))
0127: return i;
0128: }
0129: return -1;
0130: }
0131:
0132: public Object visit(SimpleNode node, Object data)
0133: throws EvaluationException {
0134: currentNode = node;
0135: switch (node.jjtGetID()) {
0136: case JavaParserTreeConstants.JJTRESULTTYPE:
0137: return visitResultType(node, data);
0138:
0139: case JavaParserTreeConstants.JJTARRAYINITIALIZER:
0140: return visitArrayInitializer(node, data);
0141:
0142: case JavaParserTreeConstants.JJTARRAYDIMSANDINITS:
0143: return visitArrayDimsAndInits(node, data);
0144:
0145: case JavaParserTreeConstants.JJTALLOCATIONEXPRESSION:
0146: return visitAllocationExpression(node, data);
0147:
0148: case JavaParserTreeConstants.JJTARGUMENTLIST:
0149: return visitArgumentList(node, data);
0150:
0151: case JavaParserTreeConstants.JJTARGUMENTS:
0152: return visitArguments(node, data);
0153:
0154: case JavaParserTreeConstants.JJTCASTEXPRESSION:
0155: return visitCastExpression(node, data);
0156:
0157: case JavaParserTreeConstants.JJTPOSTFIXEXPRESSION:
0158: return visitPostfixExpression(node, data);
0159:
0160: case JavaParserTreeConstants.JJTPREDECREMENTEXPRESSION:
0161: case JavaParserTreeConstants.JJTPREINCREMENTEXPRESSION:
0162: return visitPrefixExpression(node, data);
0163:
0164: case JavaParserTreeConstants.JJTUNARYEXPRESSION:
0165: case JavaParserTreeConstants.JJTUNARYEXPRESSIONNOTPLUSMINUS:
0166: return visitUnaryExpression(node, data);
0167:
0168: case JavaParserTreeConstants.JJTCLASSORINTERFACETYPE:
0169: return visitClassOrInterfaceType(node, data);
0170:
0171: case JavaParserTreeConstants.JJTIDENTIFIER:
0172: return visitIdentifier(node, data);
0173:
0174: case JavaParserTreeConstants.JJTPRIMITIVETYPE:
0175: return visitPrimitiveType(node, data);
0176:
0177: case JavaParserTreeConstants.JJTREFERENCETYPE:
0178: return visitReferenceType(node, data);
0179:
0180: case JavaParserTreeConstants.JJTNAME:
0181: return visitName(node, data);
0182:
0183: case JavaParserTreeConstants.JJTEXPRESSION:
0184: return visitExpression(node, data);
0185:
0186: case JavaParserTreeConstants.JJTPRIMARYEXPRESSION:
0187: return visitPrimaryExpression(node, data);
0188:
0189: case JavaParserTreeConstants.JJTPRIMARYPREFIX:
0190: return visitPrimaryPrefix(node, data);
0191:
0192: case JavaParserTreeConstants.JJTPRIMARYSUFFIX:
0193: return visitPrimarySuffix(node, data);
0194:
0195: case JavaParserTreeConstants.JJTCONDITIONALEXPRESSION:
0196: return visitConditionalExpression(node, data);
0197:
0198: case JavaParserTreeConstants.JJTCONDITIONALOREXPRESSION:
0199: case JavaParserTreeConstants.JJTCONDITIONALANDEXPRESSION:
0200: return visitConditionalOrAndExpression(node, data);
0201:
0202: case JavaParserTreeConstants.JJTSHIFTEXPRESSION:
0203: case JavaParserTreeConstants.JJTRELATIONALEXPRESSION:
0204: case JavaParserTreeConstants.JJTEQUALITYEXPRESSION:
0205: case JavaParserTreeConstants.JJTINCLUSIVEOREXPRESSION:
0206: case JavaParserTreeConstants.JJTANDEXPRESSION:
0207: case JavaParserTreeConstants.JJTEXCLUSIVEOREXPRESSION:
0208: case JavaParserTreeConstants.JJTADDITIVEEXPRESSION:
0209: case JavaParserTreeConstants.JJTMULTIPLICATIVEEXPRESSION:
0210: return visitBinaryExpression(node, data);
0211:
0212: case JavaParserTreeConstants.JJTINSTANCEOFEXPRESSION:
0213: return visitInstanceOfExpression(node, data);
0214:
0215: case JavaParserTreeConstants.JJTLITERAL:
0216: return visitLiteral(node, data);
0217:
0218: case JavaParserTreeConstants.JJTBOOLEANLITERAL:
0219: return visitBooleanLiteral(node, data);
0220:
0221: case JavaParserTreeConstants.JJTNULLLITERAL:
0222: return null;
0223: }
0224: return Assert.error(node, "unknownNonterminal");
0225: }
0226:
0227: private ObjectReference primitiveClass(String name)
0228: throws IncompatibleThreadStateException {
0229: ReferenceType primType = resolveType("java.lang."
0230: + name.substring(0, 1).toUpperCase()
0231: + name.substring(1));
0232: try {
0233: if (loggerValue.isLoggable(Level.FINE)) {
0234: loggerValue.fine("STARTED : " + primType + ".getValue("
0235: + primType.fieldByName("TYPE") + ")");
0236: }
0237: return (ObjectReference) primType.getValue(primType
0238: .fieldByName("TYPE"));
0239: } finally {
0240: if (loggerValue.isLoggable(Level.FINE)) {
0241: loggerValue.fine("FINISHED: " + primType + ".getValue("
0242: + primType.fieldByName("TYPE") + ")");
0243: }
0244: }
0245: }
0246:
0247: private Object visitResultType(SimpleNode node, Object data) {
0248: try {
0249: if (node.getAttribute("void") != null) {
0250: return primitiveClass("void");
0251: }
0252: Type type = (Type) node.jjtGetChild(0)
0253: .jjtAccept(this , data);
0254: if (type instanceof ReferenceType)
0255: return type;
0256:
0257: return primitiveClass(type.name());
0258: } catch (IncompatibleThreadStateException e) {
0259: return Assert.error(node, "internalErrorResolvingType",
0260: "void");
0261: }
0262: }
0263:
0264: private Object visitArrayInitializer(SimpleNode node, Object data) {
0265: Object[] values = new Object[node.jjtGetNumChildren()];
0266: for (int i = 0; i < values.length; i++) {
0267: values[i] = node.jjtGetChild(i).jjtAccept(this , data);
0268: if (!(values[i] instanceof Value)
0269: && !(values[i] instanceof Object[])) {
0270: Assert
0271: .error(node, "invalidArrayInitializer",
0272: values[i]);
0273: }
0274: }
0275: return values;
0276: }
0277:
0278: private Object visitArrayDimsAndInits(SimpleNode node, Object data) {
0279:
0280: Type arrayType = (Type) data;
0281: int dimensions = ((Integer) node.getAttribute("dimensions"))
0282: .intValue();
0283: ArrayReference arrayRef = null;
0284:
0285: try {
0286: if (node.getAttribute("initializers") != null) {
0287: Object[] initValues = (Object[]) node.jjtGetChild(0)
0288: .jjtAccept(this , data);
0289: return createArray(arrayType, dimensions, initValues);
0290: } else {
0291: int sizeCount = node.jjtGetNumChildren();
0292: int[] sizes = new int[sizeCount];
0293: for (int i = 0; i < sizeCount; i++) {
0294: Object sizeObj = node.jjtGetChild(i).jjtAccept(
0295: this , data);
0296: Assert.assertAssignable(sizeObj,
0297: PrimitiveValue.class, node,
0298: "arraySizeBadType", sizeObj);
0299: Assert.assertNotAssignable(sizeObj,
0300: BooleanValue.class, node,
0301: "arraySizeBadType", sizeObj);
0302: Assert.assertNotAssignable(sizeObj,
0303: FloatValue.class, node, "arraySizeBadType",
0304: sizeObj);
0305: Assert.assertNotAssignable(sizeObj,
0306: DoubleValue.class, node,
0307: "arraySizeBadType", sizeObj);
0308: sizes[i] = ((PrimitiveValue) sizeObj).intValue();
0309: }
0310: return createArray(arrayType, dimensions, sizes, 0);
0311: }
0312: } catch (IncompatibleThreadStateException e) {
0313: Assert.error(node, "arrayCreateError", e);
0314: } catch (ClassNotLoadedException e) {
0315: Assert.error(node, "arrayCreateError", e);
0316: } catch (InvalidTypeException e) {
0317: Assert.error(node, "arrayCreateError", e);
0318: } catch (UnsupportedOperationException uoex) {
0319: return Assert.error(node, "calleeException", uoex);
0320: }
0321:
0322: return arrayRef;
0323: }
0324:
0325: private String brackets = "[[[[[[[[[[[[[[[[[[[";
0326:
0327: private String brackets(int length) {
0328: if (brackets.length() < length) {
0329: char[] bracketsArray = new char[length];
0330: Arrays.fill(bracketsArray, '[');
0331: brackets = new String(bracketsArray);
0332: }
0333: return brackets.substring(0, length);
0334: }
0335:
0336: private ArrayReference createArray(Type baseType, int dimensions,
0337: int[] sizes, int index)
0338: throws IncompatibleThreadStateException,
0339: ClassNotLoadedException, InvalidTypeException {
0340:
0341: ArrayType arrayType = (ArrayType) resolveType(brackets(dimensions)
0342: + baseType.signature());
0343: ArrayReference arrayRef = arrayType.newInstance(sizes[index]);
0344: if (sizes.length > index + 1) {
0345: for (int i = 0; i < sizes[index]; i++) {
0346: arrayRef.setValue(i, createArray(baseType,
0347: dimensions - 1, sizes, index + 1));
0348: }
0349: }
0350: return arrayRef;
0351: }
0352:
0353: private ArrayReference createArray(Type baseType, int dimensions,
0354: Object[] values) throws IncompatibleThreadStateException,
0355: ClassNotLoadedException, InvalidTypeException {
0356:
0357: ArrayType arrayType = (ArrayType) resolveType(brackets(dimensions)
0358: + baseType.signature());
0359: ArrayReference arrayRef = arrayType.newInstance(values.length);
0360: for (int i = 0; i < values.length; i++) {
0361: if (values[i] instanceof Object[]) {
0362: arrayRef.setValue(i, createArray(baseType,
0363: dimensions - 1, (Object[]) values[i]));
0364: } else {
0365: arrayRef.setValue(i, (Value) values[i]);
0366: }
0367: }
0368: return arrayRef;
0369: }
0370:
0371: private Object visitAllocationExpression(SimpleNode node,
0372: Object data) {
0373:
0374: Type arrayType = (Type) node.jjtGetChild(0).jjtAccept(this ,
0375: data);
0376:
0377: // new object creation
0378: if (((SimpleNode) node.jjtGetChild(1)).jjtGetID() == JavaParserTreeConstants.JJTARGUMENTS) {
0379: if (arrayType instanceof ClassType) {
0380: Identifier fvmc = new Identifier(false,
0381: (ReferenceType) arrayType, "<init>");
0382: return node.jjtGetChild(1).jjtAccept(this , fvmc);
0383: }
0384: Assert.assertNotAssignable(arrayType, InterfaceType.class,
0385: node, "instantiateInterface", arrayType.name());
0386: }
0387:
0388: // an array
0389: return node.jjtGetChild(1).jjtAccept(this , arrayType);
0390: }
0391:
0392: private Object visitPrimitiveType(SimpleNode node, Object data) {
0393: //TODO: cache primitive types
0394: Token token = (Token) node.getAttribute("token");
0395: switch (token.kind) {
0396: case JavaParserConstants.BOOLEAN:
0397: return vm.mirrorOf(true).type();
0398: case JavaParserConstants.CHAR:
0399: return vm.mirrorOf('a').type();
0400: case JavaParserConstants.BYTE:
0401: return vm.mirrorOf((byte) 0).type();
0402: case JavaParserConstants.SHORT:
0403: return vm.mirrorOf((short) 0).type();
0404: case JavaParserConstants.INT:
0405: return vm.mirrorOf(0).type();
0406: case JavaParserConstants.LONG:
0407: return vm.mirrorOf(0L).type();
0408: case JavaParserConstants.FLOAT:
0409: return vm.mirrorOf(1.0f).type();
0410: case JavaParserConstants.DOUBLE:
0411: return vm.mirrorOf(1.0).type();
0412: default:
0413: throw new RuntimeException("Unknown primitive type: "
0414: + token.image);
0415: }
0416: }
0417:
0418: private Object visitCastExpression(SimpleNode node, Object data) {
0419: Object value = node.jjtGetChild(1).jjtAccept(this , data);
0420: if (value == null)
0421: return null;
0422: Type castType = (Type) node.jjtGetChild(0)
0423: .jjtAccept(this , data);
0424:
0425: if (value instanceof PrimitiveValue) {
0426: PrimitiveValue primValue = (PrimitiveValue) value;
0427: if (primValue instanceof BooleanValue) {
0428: Assert.assertAssignable(castType, BooleanType.class,
0429: node, "castToBooleanRequired", primValue,
0430: castType);
0431: return primValue;
0432: }
0433: Assert.assertNotAssignable(castType, BooleanType.class,
0434: node, "castFromBooleanRequired", primValue,
0435: castType);
0436: if (castType instanceof ByteType) {
0437: return vm.mirrorOf(primValue.byteValue());
0438: } else if (castType instanceof CharType) {
0439: return vm.mirrorOf(primValue.charValue());
0440: } else if (castType instanceof DoubleType) {
0441: return vm.mirrorOf(primValue.doubleValue());
0442: } else if (castType instanceof FloatType) {
0443: return vm.mirrorOf(primValue.floatValue());
0444: } else if (castType instanceof IntegerType) {
0445: return vm.mirrorOf(primValue.intValue());
0446: } else if (castType instanceof LongType) {
0447: return vm.mirrorOf(primValue.longValue());
0448: } else {
0449: return vm.mirrorOf(primValue.shortValue());
0450: }
0451: }
0452:
0453: // value is an object reference
0454: ObjectReference valueType = (ObjectReference) value;
0455: if (!instanceOf(valueType.type(), castType)) {
0456: Assert.error(node, "castError", valueType.type(), castType);
0457: }
0458: return value;
0459: }
0460:
0461: /**
0462: * Evaluates a postfix expression (i++). This evaluation does NOT modify the variable i as would be
0463: * the case in the real life. It also does not check that the operand is a variable, thus 6++ is also legal.
0464: * These checks are really not necessary here in the evaluator.
0465: *
0466: * @param node
0467: * @param data
0468: * @return
0469: */
0470: private Object visitPostfixExpression(SimpleNode node, Object data) {
0471: Object value = node.jjtGetChild(0).jjtAccept(this , data);
0472: Assert.assertAssignable(value, PrimitiveValue.class, node,
0473: "badOperandForPostfixOperator", value);
0474: Assert.assertNotAssignable(value, BooleanValue.class, node,
0475: "badOperandForPostfixOperator", value);
0476:
0477: Token operator = (Token) node.getAttribute("operator");
0478: try {
0479: return operators.evaluate(operator, (PrimitiveValue) value);
0480: } catch (IllegalArgumentException e) {
0481: return Assert.error(node, "postfixOperatorEvaluationError",
0482: operator, e);
0483: }
0484: }
0485:
0486: /**
0487: * Evaluates a prefix expression (++i). This evaluation does NOT modify the variable i as would be
0488: * the case in the real life. It also does not check that the operand is a variable, thus ++6 is also legal.
0489: * These checks are really not necessary here in the evaluator.
0490: *
0491: * @param node
0492: * @param data
0493: * @return
0494: */
0495: private Object visitPrefixExpression(SimpleNode node, Object data) {
0496: Object value = node.jjtGetChild(0).jjtAccept(this , data);
0497: Assert.assertAssignable(value, PrimitiveValue.class, node,
0498: "badOperandForPrefixOperator", value);
0499: Assert.assertNotAssignable(value, BooleanValue.class, node,
0500: "badOperandForPrefixOperator", value);
0501:
0502: Token operator = (Token) node.getAttribute("operator");
0503: try {
0504: return operators.evaluate(operator, (PrimitiveValue) value);
0505: } catch (IllegalArgumentException e) {
0506: return Assert.error(node, "prefixOperatorEvaluationError",
0507: operator, e);
0508: }
0509: }
0510:
0511: private Object visitUnaryExpression(SimpleNode node, Object data) {
0512:
0513: Object value = node.jjtGetChild(0).jjtAccept(this , data);
0514: // System.out.println("In visitUnaryExpression:");
0515: // System.out.println("value -> " + value);
0516: // System.out.println("value.class -> " + value.getClass());
0517: // System.out.println("PrimitiveValue.class -> " + PrimitiveValue.class);
0518: // System.out.println("BooleanValue.class -> " + BooleanValue.class);
0519: // System.out.println("Assignable ? " + BooleanValue.class.isAssignableFrom(value.getClass()));
0520: Assert.assertAssignable(value, PrimitiveValue.class, node,
0521: "badOperandForUnaryOperator", value);
0522: // Assert on next line is probably a mistake:
0523: //Assert.assertNotAssignable(value, BooleanValue.class, node, "badOperandForUnaryOperator", value);
0524:
0525: Token operator = (Token) node.getAttribute("operator");
0526: try {
0527: return operators.evaluate(operator, (PrimitiveValue) value);
0528: } catch (IllegalArgumentException e) {
0529: return Assert.error(node, "unaryOperatorEvaluationError",
0530: operator, e);
0531: }
0532: }
0533:
0534: private Object visitIdentifier(SimpleNode node, Object data) {
0535: return ((Token) node.getAttribute("token")).image;
0536: }
0537:
0538: private Object visitClassOrInterfaceType(SimpleNode node,
0539: Object data) {
0540:
0541: StringBuffer fullName = new StringBuffer();
0542:
0543: int n = node.jjtGetNumChildren();
0544: for (int i = 0; i < n; i++) {
0545: String namePart = (String) node.jjtGetChild(i).jjtAccept(
0546: this , data);
0547: fullName.append('.');
0548: fullName.append(namePart);
0549:
0550: if (i < n - 1) {
0551: SimpleNode nextNode = (SimpleNode) node
0552: .jjtGetChild(i + 1);
0553: if (nextNode.jjtGetID() == JavaParserTreeConstants.JJTTYPEARGUMENTS) {
0554: i++;
0555: }
0556: }
0557: }
0558:
0559: String name = fullName.substring(1);
0560: try {
0561: return resolveType(name);
0562: } catch (IncompatibleThreadStateException e) {
0563: return Assert.error(node, "internalErrorResolvingType",
0564: name);
0565: }
0566: }
0567:
0568: /**
0569: * Resolving of types is slow.
0570: *
0571: * @param name
0572: * @return
0573: * @throws IncompatibleThreadStateException
0574: */
0575: private ReferenceType resolveType(String name)
0576: throws IncompatibleThreadStateException {
0577: ReferenceType type;
0578:
0579: if (name.charAt(0) == '[') {
0580: if ((type = getClass(name)) != null)
0581: return type;
0582: Assert.error(currentNode, "unknownType", name);
0583: }
0584:
0585: String innerName = frame.location().declaringType().name()
0586: + "$" + name;
0587: if ((type = getClass(innerName)) != null)
0588: return type;
0589:
0590: int idx = name.lastIndexOf('.');
0591: if (idx == -1) {
0592: if ((type = getClass(currentPackage + name)) != null)
0593: return type;
0594: } else {
0595: if ((type = getClass(name)) != null)
0596: return type;
0597: }
0598:
0599: if (idx != -1) {
0600: innerName = name.substring(0, idx) + "$"
0601: + name.substring(idx + 1);
0602: if (innerName.indexOf('.') == -1)
0603: innerName = currentPackage + innerName;
0604: if ((type = getClass(innerName)) != null)
0605: return type;
0606: }
0607:
0608: List imports = evaluationContext.getImports();
0609: for (Iterator i = imports.iterator(); i.hasNext();) {
0610: String importStatement = (String) i.next();
0611: int ix = importStatement.lastIndexOf('.');
0612: String qualifier = importStatement.substring(ix + 1);
0613: if (!qualifier.equals("*") && !qualifier.equals(name))
0614: continue;
0615: String fullName = importStatement.substring(0, ix + 1)
0616: + name;
0617: type = getClass(fullName);
0618: if (type != null)
0619: return type;
0620: }
0621:
0622: Assert.error(currentNode, "unknownType", name);
0623: return null;
0624: }
0625:
0626: private ReferenceType getClass(String typeName)
0627: throws IncompatibleThreadStateException {
0628:
0629: List classes = vm.classesByName(typeName);
0630: if (classes.size() != 0) {
0631: return (ReferenceType) classes.get(0);
0632: }
0633:
0634: // if (forName == null) {
0635: // try {
0636: // ClassObjectReference executingClass = frame.location().declaringType().classObject();
0637: // ClassType currentClass = (ClassType) executingClass.referenceType();
0638: // forName = currentClass.concreteMethodByName("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
0639: // } catch (Exception e) {
0640: // // The should not happen
0641: // }
0642: // }
0643: //
0644: // try {
0645: // ClassLoaderReference executingClassloader = frame.location().declaringType().classLoader();
0646: // ClassObjectReference executingClass = frame.location().declaringType().classObject();
0647: // List args = new ArrayList();
0648: // args.add(vm.mirrorOf(typeName));
0649: // args.add(vm.mirrorOf(true));
0650: // args.add(executingClassloader);
0651: // if (verbose) {
0652: // throw new UnsupportedOperationException (NbBundle.getMessage (
0653: // Evaluator.class,
0654: // "CTL_UnsupportedOperationException"
0655: // ));
0656: // }
0657: // ClassObjectReference cor = (ClassObjectReference) executingClass.
0658: // invokeMethod (frameThread, forName, args, 0);
0659: // return cor.reflectedType();
0660: // } catch (Exception e) {
0661: // // The class cannot be loaded, return null
0662: // } finally {
0663: // // the stack frame may have been invalidated by invoking the forName method
0664: // frame = frameThread.frame(frameIndex);
0665: // }
0666: return null;
0667: }
0668:
0669: private Object visitReferenceType(SimpleNode node, Object data) {
0670: Type baseType = (Type) node.jjtGetChild(0)
0671: .jjtAccept(this , data);
0672: int dimensions = ((Integer) node.getAttribute("arrayCount"))
0673: .intValue();
0674: if (dimensions > 0) {
0675: try {
0676: return resolveType(brackets(dimensions)
0677: + baseType.signature().replace('/', '.'));
0678: } catch (IncompatibleThreadStateException e) {
0679: Assert.error(node, "internalError");
0680: }
0681: }
0682: return baseType;
0683: }
0684:
0685: private Object visitInstanceOfExpression(SimpleNode node,
0686: Object data) {
0687:
0688: Object leftOper = node.jjtGetChild(0).jjtAccept(this , data);
0689: if (leftOper == null)
0690: return vm.mirrorOf(false);
0691: Assert.assertAssignable(leftOper, ObjectReference.class, node,
0692: "instanceOfLeftOperandNotAReference", leftOper);
0693:
0694: ReferenceType left = ((ObjectReference) leftOper)
0695: .referenceType(); // org.netbeans.Sucks
0696: ReferenceType right = (ReferenceType) node.jjtGetChild(1)
0697: .jjtAccept(this , data); // int []
0698:
0699: return vm.mirrorOf(instanceOf(left, right));
0700: }
0701:
0702: private boolean instanceOf(Type left, Type right) {
0703: if (left == null)
0704: return false;
0705: if (left.equals(right))
0706: return true;
0707:
0708: if (right instanceof ArrayType) {
0709: if (!(left instanceof ArrayType)) {
0710: return false;
0711: } else {
0712: ArrayType leftArray = (ArrayType) left;
0713: ArrayType rightArray = (ArrayType) right;
0714: Type leftType;
0715: Type rightType;
0716: try {
0717: leftType = leftArray.componentType();
0718: rightType = rightArray.componentType();
0719: } catch (ClassNotLoadedException e) {
0720: // TODO: load missing classes
0721: return false;
0722: }
0723: return instanceOf(leftType, rightType);
0724: }
0725: }
0726:
0727: if (left instanceof ClassType) {
0728: ClassType classLeft = (ClassType) left;
0729: if (right instanceof InterfaceType) {
0730: List ifaces = classLeft.allInterfaces();
0731: for (Iterator i = ifaces.iterator(); i.hasNext();) {
0732: InterfaceType type = (InterfaceType) i.next();
0733: if (type.equals(right))
0734: return true;
0735: }
0736: return false;
0737: } else { // right instanceof ClassType
0738: for (;;) {
0739: classLeft = classLeft.super class();
0740: if (classLeft == null)
0741: return false;
0742: if (classLeft.equals(right))
0743: return true;
0744: }
0745: }
0746: }
0747:
0748: return false;
0749: }
0750:
0751: private Object visitConditionalOrAndExpression(SimpleNode node,
0752: Object data) {
0753:
0754: Token operator = (Token) node.getAttribute("operator");
0755:
0756: int n = node.jjtGetNumChildren();
0757: for (int i = 0; i < n; i++) {
0758: Object value = node.jjtGetChild(i).jjtAccept(this , data);
0759: Assert.assertAssignable(value, BooleanValue.class, node,
0760: "conditionalOrAndBooleanOperandRequired", value);
0761: boolean val = ((BooleanValue) value).booleanValue();
0762: if (operator.kind == JavaParserConstants.SC_OR && val
0763: || operator.kind == JavaParserConstants.SC_AND
0764: && !val) {
0765: return value;
0766: }
0767: }
0768: return vm.mirrorOf(operator.kind == JavaParserConstants.SC_AND);
0769: }
0770:
0771: private Object visitConditionalExpression(SimpleNode node,
0772: Object data) {
0773:
0774: Object condition = node.jjtGetChild(0).jjtAccept(this , data);
0775: Assert.assertAssignable(condition, BooleanValue.class, node,
0776: "conditionalQuestionMarkBooleanOperandRequired",
0777: condition);
0778:
0779: boolean val = ((BooleanValue) condition).booleanValue();
0780:
0781: if (val) {
0782: return node.jjtGetChild(1).jjtAccept(this , data);
0783: } else {
0784: return node.jjtGetChild(2).jjtAccept(this , data);
0785: }
0786: }
0787:
0788: private Object visitBooleanLiteral(SimpleNode node, Object data) {
0789: Token token = (Token) node.getAttribute("token");
0790: return vm.mirrorOf(token.kind == JavaParserConstants.TRUE);
0791: }
0792:
0793: private Object visitName(SimpleNode node, Object data) {
0794: Object[] tokens = node.getAttributes("token");
0795: StringBuffer name = new StringBuffer();
0796: for (int i = 0; i < tokens.length; i++) {
0797: name.append('.');
0798: name.append(tokens[i]);
0799: }
0800: return name.substring(1);
0801: }
0802:
0803: private Object visitPrimaryPrefix(SimpleNode node, Object data) {
0804:
0805: if (node.jjtGetNumChildren() == 0) {
0806: ObjectReference this Object = frame.this Object();
0807: if (this Object == null) {
0808: Assert.error(node, "thisObjectUnavailable");
0809: }
0810:
0811: if (node.getAttribute("this") != null)
0812: return this Object; // this
0813:
0814: // (X.)*super.X?
0815: String qualifier = (String) node.getAttribute("qualifier");
0816: String identifier = (String) node
0817: .getAttribute("identifier");
0818:
0819: return new Identifier((ObjectReference) this Object,
0820: identifier, qualifier);
0821: }
0822:
0823: SimpleNode first = (SimpleNode) node.jjtGetChild(0);
0824: switch (first.jjtGetID()) {
0825:
0826: case JavaParserTreeConstants.JJTLITERAL:
0827: return visit(first, data);
0828:
0829: case JavaParserTreeConstants.JJTEXPRESSION:
0830: return visit(first, data);
0831:
0832: case JavaParserTreeConstants.JJTNAME: {
0833: String identifier = (String) visit(first, data);
0834: if (identifier.indexOf('.') == -1) {
0835: return new Identifier(true, frame.this Object(), frame
0836: .location().declaringType(), identifier);
0837: }
0838:
0839: // check for variable dereference: var.toString
0840: int idx = identifier.indexOf('.');
0841: String name = identifier.substring(0, idx);
0842:
0843: ObjectReference member = null;
0844: try {
0845: Value variable = evaluateVariable(new Identifier(true,
0846: frame.this Object(), frame.location()
0847: .declaringType(), name));
0848: Assert.assertAssignable(variable,
0849: ObjectReference.class, node,
0850: "objectReferenceRequiredOnDereference",
0851: variable);
0852: member = (ObjectReference) variable;
0853: } catch (EvaluationException e) {
0854: // not a variable
0855: }
0856:
0857: ReferenceType type = null;
0858: if (member == null) {
0859: // type declaration first: System.out, or java.lang.System.out.println
0860: for (;;) {
0861: try {
0862: type = resolveType(name);
0863: break;
0864: } catch (EvaluationException e) {
0865: // unknown type
0866: } catch (IncompatibleThreadStateException e) {
0867: Assert.error(node, "internalError");
0868: }
0869: idx = identifier.indexOf('.', idx + 1);
0870: if (idx == -1)
0871: break;
0872: name = identifier.substring(0, idx);
0873: }
0874: if (type == null)
0875: Assert.error(node, "unknownType", identifier);
0876: }
0877:
0878: // resolve dereferences until the last name component
0879: for (;;) {
0880: int idx2 = identifier.indexOf('.', idx + 1);
0881: int idx22 = idx2;
0882: if (idx2 == -1) {
0883: idx2 = identifier.length();
0884: }
0885: Identifier ident;
0886: if (member != null) {
0887: ident = new Identifier(false, member, identifier
0888: .substring(idx + 1, idx2));
0889: } else {
0890: ident = new Identifier(false, type, identifier
0891: .substring(idx + 1, idx2));
0892: }
0893: if (idx22 == -1)
0894: return ident;
0895: Value variable = evaluateVariable(ident);
0896: Assert.assertAssignable(variable,
0897: ObjectReference.class, node,
0898: "objectReferenceRequiredOnDereference",
0899: variable);
0900: member = (ObjectReference) variable;
0901: idx = idx2;
0902: }
0903: }
0904: case JavaParserTreeConstants.JJTRESULTTYPE:
0905: Object type = first.jjtAccept(this , data);
0906: if (type instanceof ReferenceType) {
0907: return ((ReferenceType) type).classObject();
0908: } else {
0909: return type;
0910: }
0911:
0912: default:
0913: return first.jjtAccept(this , data);
0914: }
0915: }
0916:
0917: private Object visitArgumentList(SimpleNode node, Object data) {
0918: int n = node.jjtGetNumChildren();
0919: Value[] argValues = new Value[n];
0920: for (int i = 0; i < n; i++) {
0921: Object val = node.jjtGetChild(i).jjtAccept(this , data);
0922: if (val != null)
0923: Assert.assertAssignable(val, Value.class, node,
0924: "badArgument", val);
0925: argValues[i] = (Value) val;
0926: }
0927: return argValues;
0928: }
0929:
0930: private class MethodCall {
0931: ReferenceType typeContext;
0932: ObjectReference instanceContext;
0933: Method method;
0934: List<Value> args;
0935:
0936: public MethodCall(ReferenceType typeContext,
0937: ObjectReference instanceContext, Method method,
0938: List<Value> args) {
0939: this .typeContext = typeContext;
0940: this .instanceContext = instanceContext;
0941: this .method = method;
0942: this .args = args;
0943: }
0944: }
0945:
0946: private Object visitArguments(SimpleNode node, Object data) {
0947: Assert.assertAssignable(data, Identifier.class, node,
0948: "argumentsBadSyntax", data);
0949: Identifier ctx = (Identifier) data;
0950:
0951: Value[] args;
0952: if (node.jjtGetNumChildren() > 0) {
0953: args = (Value[]) node.jjtGetChild(0).jjtAccept(this , null);
0954: } else {
0955: args = new Value[0];
0956: }
0957:
0958: MethodCall method;
0959: try {
0960: method = getConcreteMethod(ctx, args);
0961: } catch (UnsupportedOperationException uoex) {
0962: return Assert.error(node, "calleeException", uoex, ctx);
0963: }
0964:
0965: if (method.instanceContext != null) {
0966: try {
0967: if (verbose)
0968: throw new UnsupportedOperationException(
0969: NbBundle
0970: .getMessage(Evaluator.class,
0971: "CTL_UnsupportedOperationException"));
0972: if (!evaluationContext.canInvokeMethods()) {
0973: return Assert.error(node, "calleeException",
0974: new UnsupportedOperationException(), ctx);
0975: }
0976: evaluationContext.methodToBeInvoked();
0977: if (loggerMethod.isLoggable(Level.FINE)) {
0978: loggerMethod.fine("STARTED : "
0979: + method.instanceContext + "."
0980: + method.method + " (" + method.args
0981: + ") in thread " + frameThread);
0982: }
0983: return method.instanceContext.invokeMethod(frameThread,
0984: method.method, method.args,
0985: ObjectReference.INVOKE_SINGLE_THREADED
0986: | ObjectReference.INVOKE_NONVIRTUAL);
0987: } catch (InvalidTypeException e) {
0988: Assert.error(node, "callException", e, ctx);
0989: } catch (ClassNotLoadedException e) {
0990: // TODO: load the class
0991: Assert.error(node, "callException", e, ctx);
0992: } catch (IncompatibleThreadStateException e) {
0993: Assert.error(node, "callException", e, ctx);
0994: } catch (InvocationException e) {
0995: Assert.error(node, "calleeException", e, ctx);
0996: } catch (UnsupportedOperationException e) {
0997: evaluationContext.setCanInvokeMethods(false);
0998: Assert.error(node, "calleeException", e, ctx);
0999: } finally {
1000: if (loggerMethod.isLoggable(Level.FINE)) {
1001: loggerMethod.fine("FINISHED: "
1002: + method.instanceContext + "."
1003: + method.method + " (" + method.args
1004: + ") in thread " + frameThread);
1005: }
1006: try {
1007: evaluationContext.methodInvokeDone();
1008: } catch (IncompatibleThreadStateException itsex) {
1009: InvalidExpressionException ieex = new InvalidExpressionException(
1010: itsex);
1011: ieex.initCause(itsex);
1012: throw new IllegalStateException(ieex);
1013: }
1014: try {
1015: frame = frameThread.frame(frameIndex);
1016: } catch (IncompatibleThreadStateException e) {
1017: Assert.error(node, "callException", e, ctx);
1018: }
1019: }
1020: }
1021:
1022: if (method.typeContext instanceof ClassType) {
1023: ClassType classContext = (ClassType) method.typeContext;
1024: try {
1025: if (method.method.isConstructor()) {
1026: if (verbose)
1027: throw new UnsupportedOperationException(
1028: NbBundle
1029: .getMessage(Evaluator.class,
1030: "CTL_UnsupportedOperationException"));
1031: try {
1032: return classContext.newInstance(frameThread,
1033: method.method, method.args,
1034: ClassType.INVOKE_SINGLE_THREADED);
1035: } catch (UnsupportedOperationException uoex) {
1036: return Assert.error(node, "calleeException",
1037: uoex, ctx);
1038: }
1039: } else {
1040: if (verbose)
1041: throw new UnsupportedOperationException(
1042: NbBundle
1043: .getMessage(Evaluator.class,
1044: "CTL_UnsupportedOperationException"));
1045: if (!evaluationContext.canInvokeMethods()) {
1046: return Assert.error(node, "calleeException",
1047: new UnsupportedOperationException(),
1048: ctx);
1049: }
1050: evaluationContext.methodToBeInvoked();
1051: return classContext.invokeMethod(frameThread,
1052: method.method, method.args,
1053: ClassType.INVOKE_SINGLE_THREADED);
1054: }
1055: } catch (InvalidTypeException e) {
1056: Assert.error(node, "callException", e, ctx);
1057: } catch (ClassNotLoadedException e) {
1058: // TODO: load the class
1059: Assert.error(node, "callException", e, ctx);
1060: } catch (IncompatibleThreadStateException e) {
1061: Assert.error(node, "callException", e, ctx);
1062: } catch (InvocationException e) {
1063: Assert.error(node, "calleeException", e, ctx);
1064: } catch (IllegalArgumentException e) {
1065: Assert.error(node, "callException", e, ctx);
1066: } catch (UnsupportedOperationException e) {
1067: evaluationContext.setCanInvokeMethods(false);
1068: Assert.error(node, "calleeException", e, ctx);
1069: } finally {
1070: try {
1071: evaluationContext.methodInvokeDone();
1072: } catch (IncompatibleThreadStateException itsex) {
1073: InvalidExpressionException ieex = new InvalidExpressionException(
1074: itsex);
1075: ieex.initCause(itsex);
1076: throw new IllegalStateException(ieex);
1077: }
1078: try {
1079: frame = frameThread.frame(frameIndex);
1080: } catch (IncompatibleThreadStateException e) {
1081: Assert.error(node, "callException", e, ctx);
1082: }
1083: }
1084: }
1085:
1086: return Assert.error(node, "noSuchMethod", ctx);
1087: }
1088:
1089: private boolean isAccessible(TypeComponent member) {
1090: if (member.isPublic())
1091: return true;
1092:
1093: ReferenceType callerType = frame.location().declaringType();
1094: ReferenceType calleeType = member.declaringType();
1095:
1096: if (member.isPrivate()) {
1097: if (callerType.equals(calleeType))
1098: return true;
1099: if (isNested(calleeType, callerType)
1100: || isNested(callerType, calleeType))
1101: return true;
1102: return false;
1103: }
1104:
1105: String callerName = callerType.name();
1106: String calleeName = calleeType.name();
1107: int idx1 = callerName.lastIndexOf('.');
1108: int idx2 = calleeName.lastIndexOf('.');
1109:
1110: if (idx1 * idx2 < 0)
1111: return false;
1112: if (idx1 + idx2 == -2)
1113: return true;
1114:
1115: if (callerName.substring(0, idx1).equals(
1116: calleeName.substring(0, idx2)))
1117: return true;
1118: if (member.isProtected()) {
1119: return instanceOf(callerType, calleeType);
1120: }
1121:
1122: return false;
1123: }
1124:
1125: private boolean isNested(ReferenceType outter, ReferenceType inner) {
1126: List nestedTypes = outter.nestedTypes();
1127: for (Iterator i = nestedTypes.iterator(); i.hasNext();) {
1128: ReferenceType type = (ReferenceType) i.next();
1129: if (type.equals(inner) || isNested(type, inner))
1130: return true;
1131: }
1132: return false;
1133: }
1134:
1135: private MethodCall getConcreteMethod(Identifier ctx, Value[] args) {
1136: ReferenceType type = ctx.typeContext;
1137: ObjectReference object = ctx.instanceContext;
1138:
1139: if (ctx.super Qualifier != null) {
1140: if (!(ctx.typeContext instanceof ClassType))
1141: Assert.error(currentNode, "superUsedOnNonClass", ctx);
1142: if (ctx.super Qualifier.length() > 0) {
1143: object = getEnclosingObject(ctx.instanceContext,
1144: ctx.super Qualifier);
1145: Assert.assertNotNull(object, currentNode,
1146: "notEnclosingType", ctx);
1147: }
1148: ClassType cls = (ClassType) object.referenceType();
1149: type = cls.super class();
1150: }
1151:
1152: if (ctx.typeContext == null) {
1153: Assert.error(currentNode, "methodCallOnNull",
1154: ctx.identifier);
1155: }
1156:
1157: List<Method> methods = getMethodsByName(type, ctx.identifier);
1158:
1159: //Try outer classes
1160: ReferenceType origType = type;
1161: ObjectReference origObject = object;
1162:
1163: while (methods.size() == 0) {
1164: Field outerRef = type.fieldByName("this$0");
1165: if (outerRef == null) {
1166: //System.out.println("No outerRef.");
1167: type = origType;
1168: object = origObject;
1169: break; //No outer reference
1170: }
1171: if (loggerValue.isLoggable(Level.FINE)) {
1172: loggerValue.fine("STARTED : " + object + ".getValue("
1173: + outerRef + ")");
1174: }
1175: object = (ObjectReference) object.getValue(outerRef);
1176: if (loggerValue.isLoggable(Level.FINE)) {
1177: loggerValue.fine("FINISHED: getValue(" + outerRef
1178: + ") = " + object);
1179: }
1180: type = object.referenceType();
1181: methods = getMethodsByName(type, ctx.identifier);
1182:
1183: }
1184:
1185: //Static Imports
1186: if (ctx.localContext && methods.size() == 0) {
1187: for (Iterator i = staticImportsIterator(ctx.identifier); i
1188: .hasNext();) {
1189: String typeName = (String) i.next();
1190: try {
1191: ReferenceType importedType = resolveType(typeName);
1192: methods = getMethodsByName(importedType,
1193: ctx.identifier);
1194: if (methods.size() > 0) {
1195: type = importedType;
1196: object = null;
1197: break;
1198: }
1199: } catch (Exception e) {
1200: // no such method
1201: continue;
1202: }
1203: }
1204: }
1205:
1206: List<MethodCall> possibleMethods = new ArrayList<MethodCall>();
1207:
1208: for (Iterator<Method> i = methods.iterator(); i.hasNext();) {
1209: Method method = i.next();
1210: if (!isAccessible(method))
1211: continue;
1212:
1213: List argTypes = null;
1214: try {
1215: argTypes = method.argumentTypes();
1216: } catch (ClassNotLoadedException e) {
1217: // TODO: load class
1218: continue;
1219: } catch (ObjectCollectedException ocex) {
1220: continue;
1221: }
1222:
1223: // TODO: probably incomplete handling of an implicit constructor of a nested type
1224: if (args.length == 0 && "<init>".equals(ctx.identifier)
1225: && argTypes.size() == 1) {
1226: if (frame.this Object() != null
1227: && argTypes.get(0).equals(
1228: frame.location().declaringType())) {
1229: args = new Value[] { frame.this Object() };
1230: }
1231: }
1232:
1233: List<Value> newArgs = prepareArguments(args, argTypes);
1234: if (newArgs == null)
1235: continue;
1236: possibleMethods.add(new MethodCall(type, object, method,
1237: newArgs));
1238: }
1239: Assert.assertNonEmpty(possibleMethods, currentNode,
1240: "noSuchMethod", ctx);
1241: MethodCall call = mostSpecific(possibleMethods, args);
1242: Assert.assertNotNull(call, currentNode, "ambigousMethod", ctx);
1243: call = findConcrete(call);
1244: return call;
1245: }
1246:
1247: private static List<Method> getMethodsByName(ReferenceType type,
1248: String name) {
1249: if (type instanceof ArrayType) { // There are no methods by JDI definition ?!?
1250: type = type.classObject().referenceType();
1251: if ("toString".equals(name)) { // NOI18N
1252: // We have to get the super class' toString() method for some strange reason...
1253: type = ((ClassType) type).super class();
1254: }
1255: }
1256: List<Method> methods = type.methodsByName(name);
1257: return methods;
1258: }
1259:
1260: private MethodCall mostSpecific(List<MethodCall> possibleMethods,
1261: Value[] args) {
1262: if (possibleMethods.size() == 0)
1263: return null;
1264: if (possibleMethods.size() == 1)
1265: return possibleMethods.get(0);
1266:
1267: MethodCall mostSpecific = null;
1268: int conversions = Integer.MAX_VALUE;
1269: for (Iterator<MethodCall> i = possibleMethods.iterator(); i
1270: .hasNext();) {
1271: MethodCall methodCall = i.next();
1272: List methodArguments = null;
1273: try {
1274: methodArguments = methodCall.method.argumentTypes();
1275: } catch (ClassNotLoadedException e) {
1276: continue;
1277: } catch (ObjectCollectedException ocex) {
1278: continue;
1279: }
1280: int cc = conversionsCount(methodArguments, args);
1281: if (cc == 0)
1282: return methodCall;
1283: if (cc == conversions) {
1284: return null;
1285: }
1286: if (cc < conversions) {
1287: conversions = cc;
1288: mostSpecific = methodCall;
1289: }
1290: }
1291: return mostSpecific;
1292: }
1293:
1294: private int conversionsCount(List argumentTypes, Value[] args) {
1295: int idx = 0;
1296: int cc = 0;
1297: for (Iterator i = argumentTypes.iterator(); i.hasNext(); idx++) {
1298: Type argType = (Type) i.next();
1299: if (args[idx] == null)
1300: continue;
1301: if (representSameType(argType, args[idx].type()))
1302: continue;
1303: cc++;
1304: }
1305: return cc;
1306: }
1307:
1308: private boolean representSameType(Type t1, Type t2) {
1309: String t1s = t1.signature();
1310: String t2s = t2.signature();
1311:
1312: if (t1s.equals(t2s))
1313: return true;
1314: if (t1s.length() == 1 && t2s.length() == 1 || t1s.length() > 1
1315: && t2s.length() > 1)
1316: return false;
1317:
1318: String primitiveType = t1s.length() == 1 ? t1s : t2s;
1319: String classType = t1s.length() > 1 ? t1s : t2s;
1320:
1321: return wrapperSignature(primitiveType.charAt(0)).equals(
1322: classType);
1323: }
1324:
1325: private MethodCall findConcrete(MethodCall call) {
1326: if (call.method.isAbstract()) {
1327: ReferenceType type = call.instanceContext.referenceType();
1328: if (type instanceof ClassType) {
1329: Method m = ((ClassType) type).concreteMethodByName(
1330: call.method.name(), call.method.signature());
1331: if (m != null) {
1332: call.method = m;
1333: call.typeContext = type;
1334: }
1335: }
1336: }
1337: return call;
1338: }
1339:
1340: private List<Value> prepareArguments(Value[] args, List argTypes) {
1341:
1342: boolean ellipsis;
1343: try {
1344: ellipsis = argTypes.size() > 0
1345: && argTypes.get(argTypes.size() - 1) instanceof ArrayType
1346: && (args.length == 0
1347: || args[args.length - 1] == null || isConvertible(
1348: ((ArrayType) argTypes
1349: .get(argTypes.size() - 1))
1350: .componentType(),
1351: args[args.length - 1]));
1352: } catch (ClassNotLoadedException e) {
1353: // TODO: load the offending class?
1354: return null;
1355: }
1356: if (ellipsis) {
1357: if (args.length < argTypes.size() - 1)
1358: return null;
1359: } else {
1360: if (args.length != argTypes.size())
1361: return null;
1362: }
1363:
1364: List<Value> newArgs = new ArrayList<Value>();
1365: int idx = 0;
1366: for (Iterator i = argTypes.iterator(); i.hasNext(); idx++) {
1367: Type type = (Type) i.next();
1368: if (ellipsis && !i.hasNext())
1369: continue;
1370: if (!isConvertible(type, args[idx]))
1371: return null;
1372: newArgs.add(boxUnboxIfNeeded(args[idx], type));
1373: }
1374:
1375: if (ellipsis) {
1376: // JDI will handle vararg calls, we just need to check argument types
1377: ArrayType elipsisType = (ArrayType) argTypes.get(argTypes
1378: .size() - 1);
1379: if (args.length == argTypes.size() - 1) {
1380: // nothing to check
1381: } else {
1382: Type componentType = null;
1383: try {
1384: componentType = elipsisType.componentType();
1385: } catch (ClassNotLoadedException e) {
1386: // TODO: load the offending class
1387: return null;
1388: }
1389: if (args.length == argTypes.size()) {
1390: if (args[args.length - 1] != null
1391: && !elipsisType
1392: .equals(args[args.length - 1]
1393: .type())) {
1394: if (!isConvertible(componentType,
1395: args[args.length - 1]))
1396: return null;
1397: }
1398: newArgs.add(boxUnboxIfNeeded(args[args.length - 1],
1399: componentType));
1400: } else if (args.length > argTypes.size()) {
1401: for (int i = argTypes.size() - 1; i < args.length; i++) {
1402: if (!isConvertible(componentType, args[i]))
1403: return null;
1404: newArgs.add(boxUnboxIfNeeded(args[i],
1405: componentType));
1406: }
1407: }
1408: }
1409: }
1410:
1411: return newArgs;
1412: }
1413:
1414: private Value boxUnboxIfNeeded(Value value, Type type) {
1415: if (value instanceof ObjectReference
1416: && type instanceof PrimitiveType) {
1417: return unbox((ObjectReference) value, type);
1418: } else if (value instanceof PrimitiveValue
1419: && type instanceof ClassType) {
1420: return box((PrimitiveValue) value, (ClassType) type);
1421: } else {
1422: return value;
1423: }
1424: }
1425:
1426: /**
1427: * Wraps the passed primitive value to an object of the given type. The class type of the object must be
1428: * wider than the primitive value type. For example, it is not possible to wrap a long value to a Short object.
1429: *
1430: * @param primitiveValue
1431: * @param type
1432: * @return
1433: */
1434: private ObjectReference box(PrimitiveValue primitiveValue,
1435: ClassType type) {
1436: try {
1437: if (type instanceof Object) {
1438: type = wrapperType((PrimitiveType) primitiveValue
1439: .type());
1440: }
1441: return newInstance(type, new Value[] { primitiveValue });
1442: } catch (Exception e) {
1443: // this should never happen, indicates an internal error
1444: throw new RuntimeException(
1445: "Unexpected exception while invoking boxing method",
1446: e);
1447: }
1448: }
1449:
1450: private ClassType wrapperType(PrimitiveType type)
1451: throws IncompatibleThreadStateException {
1452: char sig = type.signature().charAt(0);
1453: return (ClassType) resolveType(wrapperClassname(sig));
1454: }
1455:
1456: private String wrapperSignature(char primitiveSignature) {
1457: switch (primitiveSignature) {
1458: case 'Z':
1459: return "Ljava/lang/Boolean;";
1460: case 'B':
1461: return "Ljava/lang/Byte;";
1462: case 'C':
1463: return "Ljava/lang/Character;";
1464: case 'S':
1465: return "Ljava/lang/Short;";
1466: case 'I':
1467: return "Ljava/lang/Integer;";
1468: case 'J':
1469: return "Ljava/lang/Long;";
1470: case 'F':
1471: return "Ljava/lang/Float;";
1472: case 'D':
1473: return "Ljava/lang/Double;";
1474: }
1475: throw new RuntimeException(); // never happens
1476: }
1477:
1478: private String wrapperClassname(char primitiveSignature) {
1479: switch (primitiveSignature) {
1480: case 'Z':
1481: return "java.lang.Boolean";
1482: case 'B':
1483: return "java.lang.Byte";
1484: case 'C':
1485: return "java.lang.Character";
1486: case 'S':
1487: return "java.lang.Short";
1488: case 'I':
1489: return "java.lang.Integer";
1490: case 'J':
1491: return "java.lang.Long";
1492: case 'F':
1493: return "java.lang.Float";
1494: case 'D':
1495: return "java.lang.Double";
1496: }
1497: throw new RuntimeException(); // never happens
1498: }
1499:
1500: private ObjectReference newInstance(ClassType type,
1501: Value[] constructorArgs) throws InvocationException,
1502: ClassNotLoadedException, IncompatibleThreadStateException,
1503: InvalidTypeException {
1504:
1505: MethodCall method = getConcreteMethod(new Identifier(type,
1506: "<init>"), constructorArgs);
1507: try {
1508: return type
1509: .newInstance(frameThread, method.method,
1510: method.args,
1511: ObjectReference.INVOKE_SINGLE_THREADED);
1512: } finally {
1513: frame = frameThread.frame(frameIndex);
1514: }
1515: }
1516:
1517: private PrimitiveValue unbox(ObjectReference val, Type type) {
1518:
1519: if (type instanceof BooleanType)
1520: return invokeUnboxingMethod(val, "booleanValue");
1521: if (type instanceof ByteType)
1522: return invokeUnboxingMethod(val, "byteValue");
1523: if (type instanceof CharType)
1524: return invokeUnboxingMethod(val, "charValue");
1525: if (type instanceof ShortType)
1526: return invokeUnboxingMethod(val, "shortValue");
1527: if (type instanceof IntegerType)
1528: return invokeUnboxingMethod(val, "intValue");
1529: if (type instanceof LongType)
1530: return invokeUnboxingMethod(val, "longValue");
1531: if (type instanceof FloatType)
1532: return invokeUnboxingMethod(val, "floatValue");
1533: if (type instanceof DoubleType)
1534: return invokeUnboxingMethod(val, "doubleValue");
1535: throw new RuntimeException("Invalid type while unboxing: "
1536: + type.signature()); // never happens
1537: }
1538:
1539: private PrimitiveValue invokeUnboxingMethod(
1540: ObjectReference reference, String methodName) {
1541: Method toCall = (Method) reference.referenceType()
1542: .methodsByName(methodName).get(0);
1543: try {
1544: if (verbose)
1545: throw new UnsupportedOperationException(NbBundle
1546: .getMessage(Evaluator.class,
1547: "CTL_UnsupportedOperationException"));
1548: if (!evaluationContext.canInvokeMethods()) {
1549: throw new UnsupportedOperationException();
1550: }
1551: evaluationContext.methodToBeInvoked();
1552: if (loggerMethod.isLoggable(Level.FINE)) {
1553: loggerMethod.fine("STARTED : " + reference + "."
1554: + toCall + " () in thread " + frameThread);
1555: }
1556: return (PrimitiveValue) reference.invokeMethod(frameThread,
1557: toCall, new ArrayList<Value>(0),
1558: ObjectReference.INVOKE_SINGLE_THREADED);
1559: } catch (UnsupportedOperationException uoex) {
1560: evaluationContext.setCanInvokeMethods(false);
1561: // this can happen on VMs that can not invoke methods...
1562: throw new RuntimeException(
1563: "Unexpected exception while invoking unboxing method",
1564: uoex);
1565: } catch (Exception e) {
1566: // this should never happen, indicates an internal error
1567: throw new RuntimeException(
1568: "Unexpected exception while invoking unboxing method",
1569: e);
1570: } finally {
1571: if (loggerMethod.isLoggable(Level.FINE)) {
1572: loggerMethod.fine("FINISHED: " + reference + "."
1573: + toCall + " () in thread " + frameThread);
1574: }
1575: try {
1576: evaluationContext.methodInvokeDone();
1577: } catch (IncompatibleThreadStateException itsex) {
1578: InvalidExpressionException ieex = new InvalidExpressionException(
1579: itsex);
1580: ieex.initCause(itsex);
1581: throw new IllegalStateException(ieex);
1582: }
1583: try {
1584: frame = frameThread.frame(frameIndex);
1585: } catch (IncompatibleThreadStateException e) {
1586: throw new RuntimeException(
1587: "Unexpected exception while invoking unboxing method",
1588: e);
1589: }
1590: }
1591: }
1592:
1593: private static final String[] typeSignaturesSorted = {
1594: "Ljava/lang/Byte;", "B", "Ljava/lang/Character;", "C",
1595: "Ljava/lang/Short;", "S", "Ljava/lang/Integer;", "I",
1596: "Ljava/lang/Long;", "J", "Ljava/lang/Float;", "F",
1597: "Ljava/lang/Double;", "D" };
1598:
1599: /**
1600: * int short
1601: * double float
1602: * int Integer
1603: * Integer int
1604: * Runnable Thread
1605: * Object Socket
1606: * <OREF> null
1607: *
1608: * @param wideType
1609: * @param value
1610: */
1611: private boolean isConvertible(Type wideType, Value value) {
1612:
1613: if (value == null)
1614: return wideType instanceof ReferenceType;
1615:
1616: String narrow = value.type().signature();
1617: String wide = wideType.signature();
1618: if (wide.equals(narrow))
1619: return true;
1620:
1621: if (wide.length() == 1) {
1622: if (wide.equals("Z"))
1623: return narrow.equals("Ljava/lang/Boolean;");
1624: for (int i = 0; i < typeSignaturesSorted.length; i++) {
1625: if (narrow.equals(typeSignaturesSorted[i]))
1626: return true;
1627: if (wide.equals(typeSignaturesSorted[i]))
1628: return false;
1629: }
1630: return false;
1631: }
1632:
1633: if (wide.equals("Ljava/lang/Object;"))
1634: return true;
1635:
1636: if (narrow.length() == 1) {
1637: if (narrow.equals("Z"))
1638: return wide.equals("Ljava/lang/Boolean;");
1639: for (int i = 0; i < typeSignaturesSorted.length; i++) {
1640: if (narrow.equals(typeSignaturesSorted[i])) {
1641: for (int j = i - 1; j < typeSignaturesSorted.length; j++) {
1642: if (wide.equals(typeSignaturesSorted[j]))
1643: return true;
1644: }
1645: return false;
1646: }
1647: }
1648: }
1649:
1650: return instanceOf(value.type(), wideType);
1651: }
1652:
1653: private Object visitPrimarySuffix(SimpleNode node, Object data) {
1654: Token token = (Token) node.getAttribute("token");
1655: if (token == null) {
1656: // AllocationExpression() | Arguments() | ReferenceTypeList()
1657: return node.jjtGetChild(0).jjtAccept(this , data);
1658: }
1659: switch (token.kind) {
1660: case JavaParserConstants.IDENTIFIER:
1661: data = resolveVariable(data); // data may be an Identifier, object.field.anotherfield
1662: Assert.assertAssignable(data, ObjectReference.class, node,
1663: "identifierNotAReference", data);
1664: return new Identifier(false, (ObjectReference) data,
1665: token.image);
1666:
1667: case JavaParserConstants.LBRACKET: {
1668: data = resolveVariable(data);
1669: Assert.assertAssignable(data, ArrayReference.class, node,
1670: "notarray", data, token);
1671: Object index = node.jjtGetChild(0).jjtAccept(this , data);
1672: Assert.assertAssignable(index, PrimitiveValue.class, node,
1673: "arrayIndexNAN", data, index);
1674: Assert.assertNotAssignable(index, BooleanValue.class, node,
1675: "arrayIndexNAN", data, index);
1676: int idx = ((PrimitiveValue) index).intValue();
1677: ArrayReference array = (ArrayReference) data;
1678: Assert.assertLess(idx, array.length(), node,
1679: "arrayIndexOutOfBounds", array, new Integer(idx));
1680: return array.getValue(idx);
1681: }
1682:
1683: case JavaParserConstants.THIS:
1684: case JavaParserConstants.SUPER: {
1685: Identifier ctx = (Identifier) data;
1686: if (!vm.canGetSyntheticAttribute())
1687: Assert.error(node, "unknownType", ctx.identifier);
1688:
1689: ObjectReference enclosingObject = getEnclosingObject(frame
1690: .this Object(), ctx.identifier);
1691: Assert.assertNotNull(enclosingObject, node, "unknownType",
1692: ctx.identifier);
1693: return enclosingObject;
1694: }
1695: }
1696: return Assert.error(node, "internalError");
1697: }
1698:
1699: private ObjectReference getEnclosingObject(ObjectReference obj,
1700: String typeQualifier) {
1701: boolean done;
1702: do {
1703: done = true;
1704: List fields = obj.referenceType().allFields();
1705: for (Iterator j = fields.iterator(); j.hasNext();) {
1706: Field field = (Field) j.next();
1707: if (field.isSynthetic()
1708: && field.name().startsWith("this$")) {
1709: if (loggerValue.isLoggable(Level.FINE)) {
1710: loggerValue.fine("STARTED : " + obj
1711: + ".getValue(" + field + ")");
1712: }
1713: obj = (ObjectReference) obj.getValue(field);
1714: if (loggerValue.isLoggable(Level.FINE)) {
1715: loggerValue.fine("FINISHED: getValue(" + field
1716: + ") = " + obj);
1717: }
1718: ClassType type = (ClassType) obj.referenceType();
1719: if (type.name().endsWith(typeQualifier)) {
1720: return obj;
1721: }
1722: done = false;
1723: break;
1724: }
1725: }
1726: } while (!done);
1727: return null;
1728: }
1729:
1730: private Value evaluateVariable(Identifier ctx) {
1731:
1732: // local variable
1733: if (ctx.localContext) {
1734: try {
1735: LocalVariable var = frame
1736: .visibleVariableByName(ctx.identifier);
1737: if (var != null)
1738: return frame.getValue(var);
1739: } catch (AbsentInformationException e) {
1740: // Try to get arguments
1741: try {
1742: org.netbeans.api.debugger.jpda.LocalVariable[] lvs;
1743: lvs = new CallStackFrameImpl(frame, 0,
1744: evaluationContext.getDebugger())
1745: .getMethodArguments();
1746: if (lvs != null) {
1747: for (org.netbeans.api.debugger.jpda.LocalVariable lv : lvs) {
1748: if (ctx.identifier.equals(lv.getName())) {
1749: return ((JDIVariable) lv).getJDIValue();
1750: }
1751: }
1752: }
1753: } catch (NativeMethodException nmex) {
1754: // ignore - no arguments available
1755: }
1756: }
1757: }
1758:
1759: // field
1760: if (ctx.instanceContext != null) {
1761: Field field = ctx.typeContext.fieldByName(ctx.identifier);
1762: if (field != null) {
1763: try {
1764: if (loggerValue.isLoggable(Level.FINE)) {
1765: loggerValue.fine("STARTED : "
1766: + ctx.instanceContext + ".getValue("
1767: + field + ")");
1768: }
1769: return ctx.instanceContext.getValue(field);
1770: } finally {
1771: if (loggerValue.isLoggable(Level.FINE)) {
1772: loggerValue.fine("FINISHED : "
1773: + ctx.instanceContext + ".getValue("
1774: + field + ")");
1775: }
1776: }
1777: }
1778: if (ctx.instanceContext instanceof ArrayReference) {
1779: if (ctx.identifier.equals("length")) {
1780: return vm
1781: .mirrorOf(((ArrayReference) ctx.instanceContext)
1782: .length());
1783: }
1784: }
1785: }
1786:
1787: // field from static context
1788: if (ctx.typeContext != null) {
1789: Field field = ctx.typeContext.fieldByName(ctx.identifier);
1790: try {
1791: if (field != null) {
1792: try {
1793: if (loggerValue.isLoggable(Level.FINE)) {
1794: loggerValue.fine("STARTED : "
1795: + ctx.typeContext + ".getValue("
1796: + field + ")");
1797: }
1798: return ctx.typeContext.getValue(field);
1799: } finally {
1800: if (loggerValue.isLoggable(Level.FINE)) {
1801: loggerValue.fine("FINISHED : "
1802: + ctx.typeContext + ".getValue("
1803: + field + ")");
1804: }
1805: }
1806: }
1807: } catch (IllegalArgumentException e) {
1808: Assert.error(currentNode,
1809: "accessInstanceVariableFromStaticContext", ctx);
1810: }
1811: }
1812:
1813: // local variable accessed from innerclass
1814: if (ctx.instanceContext != null) {
1815: Field field = ctx.typeContext.fieldByName("val$"
1816: + ctx.identifier);
1817: if (field != null) {
1818: try {
1819: if (loggerValue.isLoggable(Level.FINE)) {
1820: loggerValue.fine("STARTED : "
1821: + ctx.instanceContext + ".getValue("
1822: + field + ")");
1823: }
1824: return ctx.instanceContext.getValue(field);
1825: } finally {
1826: if (loggerValue.isLoggable(Level.FINE)) {
1827: loggerValue.fine("FINISHED: "
1828: + ctx.instanceContext + ".getValue("
1829: + field + ")");
1830: }
1831: }
1832: }
1833: }
1834:
1835: // outer field accessed from innerclass
1836: if (ctx.instanceContext != null) {
1837: Field helpField = ctx.typeContext.fieldByName("this$0");
1838: if (helpField != null) {
1839: if (loggerValue.isLoggable(Level.FINE)) {
1840: loggerValue.fine("STARTED : " + ctx.instanceContext
1841: + ".getValue(" + helpField + ")");
1842: }
1843: ObjectReference or = (ObjectReference) ctx.instanceContext
1844: .getValue(helpField);
1845: if (loggerValue.isLoggable(Level.FINE)) {
1846: loggerValue.fine("FINISHED: " + ctx.instanceContext
1847: + ".getValue(" + helpField + ") = " + or);
1848: }
1849: if (or != null) {
1850: Field field = or.referenceType().fieldByName(
1851: ctx.identifier);
1852: if (field != null) {
1853: try {
1854: if (loggerValue.isLoggable(Level.FINE)) {
1855: loggerValue.fine("STARTED : " + or
1856: + ".getValue(" + field + ")");
1857: }
1858: return or.getValue(field);
1859: } finally {
1860: if (loggerValue.isLoggable(Level.FINE)) {
1861: loggerValue.fine("FINISHED: " + or
1862: + ".getValue(" + field + ")");
1863: }
1864: }
1865: }
1866: }
1867: }
1868: }
1869:
1870: // static import
1871: for (Iterator i = staticImportsIterator(ctx.identifier); i
1872: .hasNext();) {
1873: String typeName = (String) i.next();
1874: try {
1875: ReferenceType type = resolveType(typeName);
1876: Field field = type.fieldByName(ctx.identifier);
1877: if (field != null) {
1878: try {
1879: if (loggerValue.isLoggable(Level.FINE)) {
1880: loggerValue.fine("STARTED : " + type
1881: + ".getValue(" + field + ")");
1882: }
1883: return type.getValue(field);
1884: } finally {
1885: if (loggerValue.isLoggable(Level.FINE)) {
1886: loggerValue.fine("FINISHED: " + type
1887: + ".getValue(" + field + ")");
1888: }
1889: }
1890: }
1891: } catch (Exception e) {
1892: // no such type or field
1893: }
1894: }
1895:
1896: // class special variable
1897: if (expression.classReplaced().equals(ctx.identifier)) {
1898: ReferenceType refType = frame.location().declaringType();
1899: JPDAClassType classType = evaluationContext.getDebugger()
1900: .getClassType(refType);
1901: return ((JDIVariable) classType.classObject())
1902: .getJDIValue();
1903: }
1904:
1905: // return special variable
1906: if (expression.returnReplaced().equals(ctx.identifier)) {
1907: ThreadReference tr = frame.thread();
1908: JPDAThreadImpl thread = (JPDAThreadImpl) evaluationContext
1909: .getDebugger().getThread(tr);
1910: JDIVariable returnVar = (JDIVariable) thread
1911: .getReturnVariable();
1912: if (returnVar != null) {
1913: return returnVar.getJDIValue();
1914: } else {
1915: return null;
1916: }
1917: }
1918:
1919: return (Value) Assert
1920: .error(currentNode, "unknownVariable", ctx);
1921: }
1922:
1923: private Iterator<String> staticImportsIterator(String identifier) {
1924: return iterator(evaluationContext.getStaticImports(),
1925: identifier);
1926: }
1927:
1928: private Iterator<String> iterator(List<String> imports,
1929: String identifier) {
1930: List<String> filteredList = new ArrayList<String>();
1931: for (Iterator<String> i = imports.iterator(); i.hasNext();) {
1932: String statement = i.next();
1933: int idx = statement.lastIndexOf('.');
1934: String qualifier = statement.substring(idx + 1);
1935: if (qualifier.equals("*") || qualifier.equals(identifier)) {
1936: filteredList.add(statement.substring(0, idx));
1937: }
1938: }
1939: return filteredList.iterator();
1940: }
1941:
1942: private Value resolveVariable(Object data) {
1943: if (data == null || data instanceof Value)
1944: return (Value) data;
1945:
1946: Identifier name = (Identifier) data;
1947: return evaluateVariable(name);
1948: }
1949:
1950: private Object visitPrimaryExpression(SimpleNode node, Object data) {
1951:
1952: int n = node.jjtGetNumChildren();
1953:
1954: Object value = node.jjtGetChild(0).jjtAccept(this , data);
1955: for (int i = 1; i < n; i++) {
1956: value = node.jjtGetChild(i).jjtAccept(this , value);
1957: }
1958:
1959: if (value instanceof Identifier) {
1960: Identifier ctx = (Identifier) value;
1961: return evaluateVariable(ctx);
1962: }
1963:
1964: return value;
1965: }
1966:
1967: private Object visitExpression(SimpleNode node, Object data) {
1968: int n = node.jjtGetNumChildren();
1969: if (n == 1) {
1970: // conditionalExpression
1971: return node.jjtGetChild(0).jjtAccept(this , data);
1972: } else {
1973: // assignmentoperator conditionalExpression
1974: return node.jjtGetChild(2).jjtAccept(this , data);
1975: }
1976: }
1977:
1978: private Object visitLiteral(SimpleNode node, Object data) {
1979: Token token = (Token) node.getAttribute("token");
1980: if (token == null)
1981: return node.jjtGetChild(0).jjtAccept(this , data);
1982:
1983: try {
1984: switch (token.kind) {
1985:
1986: case JavaParser.INTEGER_LITERAL:
1987: // XXX might be simpler to use Long.decode()
1988: String name = token.image.toLowerCase();
1989: boolean isLong = name.endsWith("l");
1990: long value;
1991:
1992: if (isLong) {
1993: name = name.substring(0, name.length() - 1);
1994: }
1995:
1996: if (name.startsWith("0x")) {
1997: value = Long.parseLong(name.substring(2), 16);
1998: } else if (name.length() > 1 && name.charAt(0) == '0') {
1999: value = Long.parseLong(name.substring(1), 8);
2000: } else {
2001: value = Long.parseLong(name);
2002: }
2003:
2004: if (isLong) {
2005: return vm.mirrorOf(value);
2006: } else {
2007: if (value > Integer.MAX_VALUE
2008: || value < Integer.MIN_VALUE) {
2009: Assert
2010: .error(node, "integerLiteralTooBig",
2011: name);
2012: } else {
2013: return vm.mirrorOf((int) value);
2014: }
2015: }
2016:
2017: case JavaParser.FLOATING_POINT_LITERAL:
2018: char spec = token.image
2019: .charAt(token.image.length() - 1);
2020: if (spec == 'f' || spec == 'F') {
2021: return vm.mirrorOf(Float.parseFloat(token.image));
2022: } else {
2023: return vm.mirrorOf(Double.parseDouble(token.image));
2024: }
2025:
2026: case JavaParser.STRING_LITERAL:
2027: return vm.mirrorOf(resolveString(token.image.substring(
2028: 1, token.image.length() - 1)));
2029:
2030: case JavaParser.CHARACTER_LITERAL:
2031: return vm.mirrorOf(resolveString(
2032: token.image.substring(1,
2033: token.image.length() - 1)).charAt(0));
2034:
2035: default:
2036: return Assert.error(node, "unknownLiteralType",
2037: token.image);
2038: }
2039: } catch (NumberFormatException e) {
2040: return Assert.error(node, "badFormatOfIntegerLiteral",
2041: token.image);
2042: }
2043: }
2044:
2045: private String resolveString(String input) {
2046: String result = "";
2047: int index = 0;
2048: while (index < input.length()) {
2049: if (input.charAt(index) != '\\')
2050: result = result + input.charAt(index);
2051: else { // resolve an escape sequence
2052: index++;
2053: char c;
2054: switch (input.charAt(index)) {
2055: case 'b':
2056: c = '\b';
2057: break;
2058: case 't':
2059: c = '\t';
2060: break;
2061: case 'n':
2062: c = '\n';
2063: break;
2064: case 'f':
2065: c = '\f';
2066: break;
2067: case 'r':
2068: c = '\r';
2069: break;
2070: case '\"':
2071: c = '\"';
2072: break;
2073: case '\'':
2074: c = '\'';
2075: break;
2076: case '\\':
2077: c = '\\';
2078: break;
2079:
2080: default:
2081: // resolve octal value
2082: c = 0;
2083: while ((index < input.length())
2084: && (input.charAt(index) >= '0')
2085: && (input.charAt(index) <= '7')
2086: && (c * 8 + input.charAt(index) - '0' < 256)) {
2087: c = (char) (c * 8 + (input.charAt(index) - '0'));
2088: index++;
2089: } // while
2090: index--;
2091: } // switch
2092: result = result + c;
2093: } // else
2094: index++;
2095: } // while
2096: return result;
2097: }
2098:
2099: private Object visitBinaryExpression(SimpleNode node, Object data) {
2100: Object[] operators = node.getAttributes("operator");
2101: int n = node.jjtGetNumChildren();
2102:
2103: Value value = (Value) node.jjtGetChild(0).jjtAccept(this , data);
2104: for (int i = 1; i < n; i++) {
2105: Value next = (Value) node.jjtGetChild(i).jjtAccept(this ,
2106: data);
2107: try {
2108: value = this .operators.evaluate(value,
2109: (Token) operators[i - 1], next);
2110: } catch (IllegalArgumentException e) {
2111: return Assert.error(node, "evaluateError", value,
2112: ((Token) operators[i - 1]).image, next);
2113: }
2114: }
2115: return value;
2116: }
2117:
2118: public static Value invokeVirtual(ObjectReference objectReference,
2119: Method method, ThreadReference evaluationThread,
2120: List<Value> args) throws InvalidExpressionException {
2121:
2122: if (verbose)
2123: throw new UnsupportedOperationException(NbBundle
2124: .getMessage(Evaluator.class,
2125: "CTL_UnsupportedOperationException"));
2126: try {
2127: if (loggerMethod.isLoggable(Level.FINE)) {
2128: loggerMethod.fine("STARTED : " + objectReference + "."
2129: + method + " (" + args + ") in thread "
2130: + evaluationThread);
2131: }
2132: Value value = objectReference.invokeMethod(
2133: evaluationThread, method, args,
2134: ObjectReference.INVOKE_SINGLE_THREADED);
2135: if (loggerMethod.isLoggable(Level.FINE)) {
2136: loggerMethod.fine(" return = " + value);
2137: }
2138: return value;
2139: } catch (InvalidTypeException itex) {
2140: throw new InvalidExpressionException(itex);
2141: } catch (ClassNotLoadedException cnlex) {
2142: throw new InvalidExpressionException(cnlex);
2143: } catch (IncompatibleThreadStateException itsex) {
2144: InvalidExpressionException ieex = new InvalidExpressionException(
2145: itsex);
2146: ieex.initCause(itsex);
2147: throw ieex;
2148: } catch (InvocationException iex) {
2149: InvalidExpressionException ieex = new InvalidExpressionException(
2150: iex);
2151: ieex.initCause(iex);
2152: throw ieex;
2153: } catch (UnsupportedOperationException uoex) {
2154: InvalidExpressionException ieex = new InvalidExpressionException(
2155: uoex);
2156: ieex.initCause(uoex);
2157: throw ieex;
2158: } catch (ObjectCollectedException ocex) {
2159: throw new InvalidExpressionException(NbBundle.getMessage(
2160: Evaluator.class, "CTL_EvalError_collected"));
2161: } finally {
2162: if (loggerMethod.isLoggable(Level.FINE)) {
2163: loggerMethod.fine("FINISHED: " + objectReference + "."
2164: + method + " (" + args + ") in thread "
2165: + evaluationThread);
2166: }
2167: }
2168: }
2169: }
|