0001: /*
0002: * Copyright 1998-2003 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package com.sun.tools.example.debug.expr;
0027:
0028: import com.sun.jdi.*;
0029: import java.util.*;
0030:
0031: abstract class LValue {
0032:
0033: // The JDI Value object for this LValue. Once we have this Value,
0034: // we have to remember it since after we return the LValue object
0035: // to the ExpressionParser, it might decide that it needs
0036: // the 'toString' value for the LValue in which case it will
0037: // call getMassagedValue to get this toString value. At that
0038: // point, we don't want to call JDI a 2nd time to get the Value
0039: // for the LValue. This is especially wrong when the LValue
0040: // represents a member function. We would end up calling it
0041: // a 2nd time.
0042: //
0043: // Unfortunately, there are several levels of calls to
0044: // get/set values in this file. To minimize confusion,
0045: // jdiValue is set/tested at the lowest level - right
0046: // next to the actual calls to JDI methods to get/set the
0047: // value in the debuggee.
0048: protected Value jdiValue;
0049:
0050: abstract Value getValue() throws InvocationException,
0051: IncompatibleThreadStateException, InvalidTypeException,
0052: ClassNotLoadedException, ParseException;
0053:
0054: abstract void setValue0(Value value) throws ParseException,
0055: InvalidTypeException, ClassNotLoadedException;
0056:
0057: abstract void invokeWith(List<Value> arguments)
0058: throws ParseException;
0059:
0060: void setValue(Value value) throws ParseException {
0061: try {
0062: setValue0(value);
0063: } catch (InvalidTypeException exc) {
0064: throw new ParseException(
0065: "Attempt to set value of incorrect type" + exc);
0066: } catch (ClassNotLoadedException exc) {
0067: throw new ParseException("Attempt to set value before "
0068: + exc.className() + " was loaded" + exc);
0069: }
0070: }
0071:
0072: void setValue(LValue lval) throws ParseException {
0073: setValue(lval.interiorGetValue());
0074: }
0075:
0076: LValue memberLValue(ExpressionParser.GetFrame frameGetter,
0077: String fieldName) throws ParseException {
0078: try {
0079: return memberLValue(fieldName, frameGetter.get().thread());
0080: } catch (IncompatibleThreadStateException exc) {
0081: throw new ParseException("Thread not suspended");
0082: }
0083: }
0084:
0085: LValue memberLValue(String fieldName, ThreadReference thread)
0086: throws ParseException {
0087:
0088: Value val = interiorGetValue();
0089: if ((val instanceof ArrayReference)
0090: && "length".equals(fieldName)) {
0091: return new LValueArrayLength((ArrayReference) val);
0092: }
0093: return new LValueInstanceMember(val, fieldName, thread);
0094: }
0095:
0096: // Return the Value for this LValue that would be used to concatenate
0097: // to a String. IE, if it is an Object, call toString in the debuggee.
0098: Value getMassagedValue(ExpressionParser.GetFrame frameGetter)
0099: throws ParseException {
0100: Value vv = interiorGetValue();
0101:
0102: // If vv is an ObjectReference, then we have to
0103: // do the implicit call to toString().
0104: if (vv instanceof ObjectReference
0105: && !(vv instanceof StringReference)
0106: && !(vv instanceof ArrayReference)) {
0107: StackFrame frame;
0108: try {
0109: frame = frameGetter.get();
0110: } catch (IncompatibleThreadStateException exc) {
0111: throw new ParseException("Thread not suspended");
0112: }
0113:
0114: ThreadReference thread = frame.thread();
0115: LValue toStringMember = memberLValue("toString", thread);
0116: toStringMember.invokeWith(new ArrayList<Value>());
0117: return toStringMember.interiorGetValue();
0118: }
0119: return vv;
0120: }
0121:
0122: Value interiorGetValue() throws ParseException {
0123: Value value;
0124: try {
0125: value = getValue();
0126: } catch (InvocationException e) {
0127: throw new ParseException(
0128: "Unable to complete expression. Exception "
0129: + e.exception() + " thrown");
0130: } catch (IncompatibleThreadStateException itse) {
0131: throw new ParseException(
0132: "Unable to complete expression. Thread "
0133: + "not suspended for method invoke");
0134: } catch (InvalidTypeException ite) {
0135: throw new ParseException(
0136: "Unable to complete expression. Method "
0137: + "argument type mismatch");
0138: } catch (ClassNotLoadedException tnle) {
0139: throw new ParseException(
0140: "Unable to complete expression. Method "
0141: + "argument type " + tnle.className()
0142: + " not yet loaded");
0143: }
0144: return value;
0145: }
0146:
0147: LValue arrayElementLValue(LValue lval) throws ParseException {
0148: Value indexValue = lval.interiorGetValue();
0149: int index;
0150: if ((indexValue instanceof IntegerValue)
0151: || (indexValue instanceof ShortValue)
0152: || (indexValue instanceof ByteValue)
0153: || (indexValue instanceof CharValue)) {
0154: index = ((PrimitiveValue) indexValue).intValue();
0155: } else {
0156: throw new ParseException(
0157: "Array index must be a integer type");
0158: }
0159: return new LValueArrayElement(interiorGetValue(), index);
0160: }
0161:
0162: public String toString() {
0163: try {
0164: return interiorGetValue().toString();
0165: } catch (ParseException e) {
0166: return "<Parse Exception>";
0167: }
0168: }
0169:
0170: static final int STATIC = 0;
0171: static final int INSTANCE = 1;
0172:
0173: static Field fieldByName(ReferenceType refType, String name,
0174: int kind) {
0175: /*
0176: * TO DO: Note that this currently fails to find superclass
0177: * or implemented interface fields. This is due to a temporary
0178: * limititation of RefType.fieldByName. Once that method is
0179: * fixed, superclass fields will be found.
0180: */
0181: Field field = refType.fieldByName(name);
0182: if (field != null) {
0183: boolean isStatic = field.isStatic();
0184: if (((kind == STATIC) && !isStatic)
0185: || ((kind == INSTANCE) && isStatic)) {
0186: field = null;
0187: }
0188: }
0189: /***
0190: System.err.println("fieldByName: " + refType.name() + " " +
0191: name + " " +
0192: kind + " " +
0193: (field != null));
0194: ***/
0195: return field;
0196: }
0197:
0198: static List methodsByName(ReferenceType refType, String name,
0199: int kind) {
0200: List list = refType.methodsByName(name);
0201: Iterator iter = list.iterator();
0202: while (iter.hasNext()) {
0203: Method method = (Method) iter.next();
0204: boolean isStatic = method.isStatic();
0205: if (((kind == STATIC) && !isStatic)
0206: || ((kind == INSTANCE) && isStatic)) {
0207: iter.remove();
0208: }
0209: }
0210: return list;
0211: }
0212:
0213: static List<String> primitiveTypeNames = new ArrayList<String>();
0214: static {
0215: primitiveTypeNames.add("boolean");
0216: primitiveTypeNames.add("byte");
0217: primitiveTypeNames.add("char");
0218: primitiveTypeNames.add("short");
0219: primitiveTypeNames.add("int");
0220: primitiveTypeNames.add("long");
0221: primitiveTypeNames.add("float");
0222: primitiveTypeNames.add("double");
0223: }
0224:
0225: static final int SAME = 0;
0226: static final int ASSIGNABLE = 1;
0227: static final int DIFFERENT = 2;
0228:
0229: /*
0230: * Return SAME, DIFFERENT or ASSIGNABLE.
0231: * SAME means each arg type is the same as type of the corr. arg.
0232: * ASSIGNABLE means that not all the pairs are the same, but
0233: * for those that aren't, at least the argType is assignable
0234: * from the type of the argument value.
0235: * DIFFERENT means that in at least one pair, the
0236: * argType is not assignable from the type of the argument value.
0237: * IE, one is an Apple and the other is an Orange.
0238: */
0239: static int argumentsMatch(List argTypes, List arguments) {
0240: if (argTypes.size() != arguments.size()) {
0241: return DIFFERENT;
0242: }
0243:
0244: Iterator typeIter = argTypes.iterator();
0245: Iterator valIter = arguments.iterator();
0246: int result = SAME;
0247:
0248: // If any pair aren't the same, change the
0249: // result to ASSIGNABLE. If any pair aren't
0250: // assignable, return DIFFERENT
0251: while (typeIter.hasNext()) {
0252: Type argType = (Type) typeIter.next();
0253: Value value = (Value) valIter.next();
0254: if (value == null) {
0255: // Null values can be passed to any non-primitive argument
0256: if (primitiveTypeNames.contains(argType.name())) {
0257: return DIFFERENT;
0258: }
0259: // Else, we will assume that a null value
0260: // exactly matches an object type.
0261: }
0262: if (!value.type().equals(argType)) {
0263: if (isAssignableTo(value.type(), argType)) {
0264: result = ASSIGNABLE;
0265: } else {
0266: return DIFFERENT;
0267: }
0268: }
0269: }
0270: return result;
0271: }
0272:
0273: // These is...AssignableTo methods are based on similar code in the JDI
0274: // implementations of ClassType, ArrayType, and InterfaceType
0275:
0276: static boolean isComponentAssignable(Type fromType, Type toType) {
0277: if (fromType instanceof PrimitiveType) {
0278: // Assignment of primitive arrays requires identical
0279: // component types.
0280: return fromType.equals(toType);
0281: }
0282: if (toType instanceof PrimitiveType) {
0283: return false;
0284: }
0285: // Assignment of object arrays requires availability
0286: // of widening conversion of component types
0287: return isAssignableTo(fromType, toType);
0288: }
0289:
0290: static boolean isArrayAssignableTo(ArrayType fromType, Type toType) {
0291: if (toType instanceof ArrayType) {
0292: try {
0293: Type toComponentType = ((ArrayType) toType)
0294: .componentType();
0295: return isComponentAssignable(fromType.componentType(),
0296: toComponentType);
0297: } catch (ClassNotLoadedException e) {
0298: // One or both component types has not yet been
0299: // loaded => can't assign
0300: return false;
0301: }
0302: }
0303: if (toType instanceof InterfaceType) {
0304: // Only valid InterfaceType assignee is Cloneable
0305: return toType.name().equals("java.lang.Cloneable");
0306: }
0307: // Only valid ClassType assignee is Object
0308: return toType.name().equals("java.lang.Object");
0309: }
0310:
0311: static boolean isAssignableTo(Type fromType, Type toType) {
0312: if (fromType.equals(toType)) {
0313: return true;
0314: }
0315:
0316: // If one is boolean, so must be the other.
0317: if (fromType instanceof BooleanType) {
0318: if (toType instanceof BooleanType) {
0319: return true;
0320: }
0321: return false;
0322: }
0323: if (toType instanceof BooleanType) {
0324: return false;
0325: }
0326:
0327: // Other primitive types are intermixable only with each other.
0328: if (fromType instanceof PrimitiveType) {
0329: if (toType instanceof PrimitiveType) {
0330: return true;
0331: }
0332: return false;
0333: }
0334: if (toType instanceof PrimitiveType) {
0335: return false;
0336: }
0337:
0338: // neither one is primitive.
0339: if (fromType instanceof ArrayType) {
0340: return isArrayAssignableTo((ArrayType) fromType, toType);
0341: }
0342: List interfaces;
0343: if (fromType instanceof ClassType) {
0344: ClassType super clazz = ((ClassType) fromType).super class();
0345: if ((super clazz != null)
0346: && isAssignableTo(super clazz, toType)) {
0347: return true;
0348: }
0349: interfaces = ((ClassType) fromType).interfaces();
0350: } else {
0351: // fromType must be an InterfaceType
0352: interfaces = ((InterfaceType) fromType).super interfaces();
0353: }
0354: Iterator iter = interfaces.iterator();
0355: while (iter.hasNext()) {
0356: InterfaceType interfaze = (InterfaceType) iter.next();
0357: if (isAssignableTo(interfaze, toType)) {
0358: return true;
0359: }
0360: }
0361: return false;
0362: }
0363:
0364: static Method resolveOverload(List overloads, List arguments)
0365: throws ParseException {
0366:
0367: // If there is only one method to call, we'll just choose
0368: // that without looking at the args. If they aren't right
0369: // the invoke will return a better error message than we
0370: // could generate here.
0371: if (overloads.size() == 1) {
0372: return (Method) overloads.get(0);
0373: }
0374:
0375: // Resolving overloads is beyond the scope of this exercise.
0376: // So, we will look for a method that matches exactly the
0377: // types of the arguments. If we can't find one, then
0378: // if there is exactly one method whose param types are assignable
0379: // from the arg types, we will use that. Otherwise,
0380: // it is an error. We won't guess which of multiple possible
0381: // methods to call. And, since casts aren't implemented,
0382: // the user can't use them to pick a particular overload to call.
0383: // IE, the user is out of luck in this case.
0384: Iterator iter = overloads.iterator();
0385: Method retVal = null;
0386: int assignableCount = 0;
0387: while (iter.hasNext()) {
0388: Method mm = (Method) iter.next();
0389: List argTypes;
0390: try {
0391: argTypes = mm.argumentTypes();
0392: } catch (ClassNotLoadedException ee) {
0393: // This probably won't happen for the
0394: // method that we are really supposed to
0395: // call.
0396: continue;
0397: }
0398: int compare = argumentsMatch(argTypes, arguments);
0399: if (compare == SAME) {
0400: return mm;
0401: }
0402: if (compare == DIFFERENT) {
0403: continue;
0404: }
0405: // Else, it is assignable. Remember it.
0406: retVal = mm;
0407: assignableCount++;
0408: }
0409:
0410: // At this point, we didn't find an exact match,
0411: // but we found one for which the args are assignable.
0412: //
0413: if (retVal != null) {
0414: if (assignableCount == 1) {
0415: return retVal;
0416: }
0417: throw new ParseException("Arguments match multiple methods");
0418: }
0419: throw new ParseException("Arguments match no method");
0420: }
0421:
0422: private static class LValueLocal extends LValue {
0423: final StackFrame frame;
0424: final LocalVariable var;
0425:
0426: LValueLocal(StackFrame frame, LocalVariable var) {
0427: this .frame = frame;
0428: this .var = var;
0429: }
0430:
0431: Value getValue() {
0432: if (jdiValue == null) {
0433: jdiValue = frame.getValue(var);
0434: }
0435: return jdiValue;
0436: }
0437:
0438: void setValue0(Value val) throws InvalidTypeException,
0439: ClassNotLoadedException {
0440: frame.setValue(var, val);
0441: jdiValue = val;
0442: }
0443:
0444: void invokeWith(List<Value> arguments) throws ParseException {
0445: throw new ParseException(var.name() + " is not a method");
0446: }
0447: }
0448:
0449: private static class LValueInstanceMember extends LValue {
0450: final ObjectReference obj;
0451: final ThreadReference thread;
0452: final Field matchingField;
0453: final List overloads;
0454: Method matchingMethod = null;
0455: List<Value> methodArguments = null;
0456:
0457: LValueInstanceMember(Value value, String memberName,
0458: ThreadReference thread) throws ParseException {
0459: if (!(value instanceof ObjectReference)) {
0460: throw new ParseException(
0461: "Cannot access field of primitive type: "
0462: + value);
0463: }
0464: this .obj = (ObjectReference) value;
0465: this .thread = thread;
0466: ReferenceType refType = obj.referenceType();
0467: /*
0468: * Can't tell yet whether this LValue will be accessed as a
0469: * field or method, so we keep track of all the possibilities
0470: */
0471: matchingField = LValue.fieldByName(refType, memberName,
0472: LValue.INSTANCE);
0473: overloads = LValue.methodsByName(refType, memberName,
0474: LValue.INSTANCE);
0475: if ((matchingField == null) && overloads.size() == 0) {
0476: throw new ParseException(
0477: "No instance field or method with the name "
0478: + memberName + " in " + refType.name());
0479: }
0480: }
0481:
0482: Value getValue() throws InvocationException,
0483: InvalidTypeException, ClassNotLoadedException,
0484: IncompatibleThreadStateException, ParseException {
0485: if (jdiValue != null) {
0486: return jdiValue;
0487: }
0488: if (matchingMethod == null) {
0489: if (matchingField == null) {
0490: throw new ParseException("No such field in "
0491: + obj.referenceType().name());
0492: }
0493: return jdiValue = obj.getValue(matchingField);
0494: } else {
0495: return jdiValue = obj.invokeMethod(thread,
0496: matchingMethod, methodArguments, 0);
0497: }
0498: }
0499:
0500: void setValue0(Value val) throws ParseException,
0501: InvalidTypeException, ClassNotLoadedException {
0502: if (matchingMethod != null) {
0503: throw new ParseException(
0504: "Cannot assign to a method invocation");
0505: }
0506: obj.setValue(matchingField, val);
0507: jdiValue = val;
0508: }
0509:
0510: void invokeWith(List<Value> arguments) throws ParseException {
0511: if (matchingMethod != null) {
0512: throw new ParseException(
0513: "Invalid consecutive invocations");
0514: }
0515: methodArguments = arguments;
0516: matchingMethod = LValue.resolveOverload(overloads,
0517: arguments);
0518: }
0519: }
0520:
0521: private static class LValueStaticMember extends LValue {
0522: final ReferenceType refType;
0523: final ThreadReference thread;
0524: final Field matchingField;
0525: final List overloads;
0526: Method matchingMethod = null;
0527: List<Value> methodArguments = null;
0528:
0529: LValueStaticMember(ReferenceType refType, String memberName,
0530: ThreadReference thread) throws ParseException {
0531: this .refType = refType;
0532: this .thread = thread;
0533: /*
0534: * Can't tell yet whether this LValue will be accessed as a
0535: * field or method, so we keep track of all the possibilities
0536: */
0537: matchingField = LValue.fieldByName(refType, memberName,
0538: LValue.STATIC);
0539: overloads = LValue.methodsByName(refType, memberName,
0540: LValue.STATIC);
0541: if ((matchingField == null) && overloads.size() == 0) {
0542: throw new ParseException(
0543: "No static field or method with the name "
0544: + memberName + " in " + refType.name());
0545: }
0546: }
0547:
0548: Value getValue() throws InvocationException,
0549: InvalidTypeException, ClassNotLoadedException,
0550: IncompatibleThreadStateException, ParseException {
0551: if (jdiValue != null) {
0552: return jdiValue;
0553: }
0554: if (matchingMethod == null) {
0555: return jdiValue = refType.getValue(matchingField);
0556: } else if (refType instanceof ClassType) {
0557: ClassType clazz = (ClassType) refType;
0558: return jdiValue = clazz.invokeMethod(thread,
0559: matchingMethod, methodArguments, 0);
0560: } else {
0561: throw new InvalidTypeException(
0562: "Cannot invoke static method on "
0563: + refType.name());
0564: }
0565: }
0566:
0567: void setValue0(Value val) throws ParseException,
0568: InvalidTypeException, ClassNotLoadedException {
0569: if (matchingMethod != null) {
0570: throw new ParseException(
0571: "Cannot assign to a method invocation");
0572: }
0573: if (!(refType instanceof ClassType)) {
0574: throw new ParseException("Cannot set interface field: "
0575: + refType);
0576: }
0577: ((ClassType) refType).setValue(matchingField, val);
0578: jdiValue = val;
0579: }
0580:
0581: void invokeWith(List<Value> arguments) throws ParseException {
0582: if (matchingMethod != null) {
0583: throw new ParseException(
0584: "Invalid consecutive invocations");
0585: }
0586: methodArguments = arguments;
0587: matchingMethod = LValue.resolveOverload(overloads,
0588: arguments);
0589: }
0590: }
0591:
0592: private static class LValueArrayLength extends LValue {
0593: /*
0594: * Since one can code "int myLen = myArray.length;",
0595: * one might expect that these JDI calls would get a Value
0596: * object for the length of an array in the debugee:
0597: * Field xxx = ArrayType.fieldByName("length")
0598: * Value lenVal= ArrayReference.getValue(xxx)
0599: *
0600: * However, this doesn't work because the array length isn't
0601: * really stored as a field, and can't be accessed as such
0602: * via JDI. Instead, the arrayRef.length() method has to be
0603: * used.
0604: */
0605: final ArrayReference arrayRef;
0606:
0607: LValueArrayLength(ArrayReference value) {
0608: this .arrayRef = value;
0609: }
0610:
0611: Value getValue() {
0612: if (jdiValue == null) {
0613: jdiValue = arrayRef.virtualMachine().mirrorOf(
0614: arrayRef.length());
0615: }
0616: return jdiValue;
0617: }
0618:
0619: void setValue0(Value value) throws ParseException {
0620: throw new ParseException("Cannot set constant: " + value);
0621: }
0622:
0623: void invokeWith(List<Value> arguments) throws ParseException {
0624: throw new ParseException("Array element is not a method");
0625: }
0626: }
0627:
0628: private static class LValueArrayElement extends LValue {
0629: final ArrayReference array;
0630: final int index;
0631:
0632: LValueArrayElement(Value value, int index)
0633: throws ParseException {
0634: if (!(value instanceof ArrayReference)) {
0635: throw new ParseException("Must be array type: " + value);
0636: }
0637: this .array = (ArrayReference) value;
0638: this .index = index;
0639: }
0640:
0641: Value getValue() {
0642: if (jdiValue == null) {
0643: jdiValue = array.getValue(index);
0644: }
0645: return jdiValue;
0646: }
0647:
0648: void setValue0(Value val) throws InvalidTypeException,
0649: ClassNotLoadedException {
0650: array.setValue(index, val);
0651: jdiValue = val;
0652: }
0653:
0654: void invokeWith(List<Value> arguments) throws ParseException {
0655: throw new ParseException("Array element is not a method");
0656: }
0657: }
0658:
0659: private static class LValueConstant extends LValue {
0660: final Value value;
0661:
0662: LValueConstant(Value value) {
0663: this .value = value;
0664: }
0665:
0666: Value getValue() {
0667: if (jdiValue == null) {
0668: jdiValue = value;
0669: }
0670: return jdiValue;
0671: }
0672:
0673: void setValue0(Value val) throws ParseException {
0674: throw new ParseException("Cannot set constant: " + value);
0675: }
0676:
0677: void invokeWith(List<Value> arguments) throws ParseException {
0678: throw new ParseException("Constant is not a method");
0679: }
0680: }
0681:
0682: static LValue make(VirtualMachine vm, boolean val) {
0683: return new LValueConstant(vm.mirrorOf(val));
0684: }
0685:
0686: static LValue make(VirtualMachine vm, byte val) {
0687: return new LValueConstant(vm.mirrorOf(val));
0688: }
0689:
0690: static LValue make(VirtualMachine vm, char val) {
0691: return new LValueConstant(vm.mirrorOf(val));
0692: }
0693:
0694: static LValue make(VirtualMachine vm, short val) {
0695: return new LValueConstant(vm.mirrorOf(val));
0696: }
0697:
0698: static LValue make(VirtualMachine vm, int val) {
0699: return new LValueConstant(vm.mirrorOf(val));
0700: }
0701:
0702: static LValue make(VirtualMachine vm, long val) {
0703: return new LValueConstant(vm.mirrorOf(val));
0704: }
0705:
0706: static LValue make(VirtualMachine vm, float val) {
0707: return new LValueConstant(vm.mirrorOf(val));
0708: }
0709:
0710: static LValue make(VirtualMachine vm, double val) {
0711: return new LValueConstant(vm.mirrorOf(val));
0712: }
0713:
0714: static LValue make(VirtualMachine vm, String val)
0715: throws ParseException {
0716: return new LValueConstant(vm.mirrorOf(val));
0717: }
0718:
0719: static LValue makeBoolean(VirtualMachine vm, Token token) {
0720: return make(vm, token.image.charAt(0) == 't');
0721: }
0722:
0723: static LValue makeCharacter(VirtualMachine vm, Token token) {
0724: return make(vm, token.image.charAt(1));
0725: }
0726:
0727: static LValue makeFloat(VirtualMachine vm, Token token) {
0728: return make(vm, Float.valueOf(token.image).floatValue());
0729: }
0730:
0731: static LValue makeDouble(VirtualMachine vm, Token token) {
0732: return make(vm, Double.valueOf(token.image).doubleValue());
0733: }
0734:
0735: static LValue makeInteger(VirtualMachine vm, Token token) {
0736: return make(vm, Integer.parseInt(token.image));
0737: }
0738:
0739: static LValue makeShort(VirtualMachine vm, Token token) {
0740: return make(vm, Short.parseShort(token.image));
0741: }
0742:
0743: static LValue makeLong(VirtualMachine vm, Token token) {
0744: return make(vm, Long.parseLong(token.image));
0745: }
0746:
0747: static LValue makeByte(VirtualMachine vm, Token token) {
0748: return make(vm, Byte.parseByte(token.image));
0749: }
0750:
0751: static LValue makeString(VirtualMachine vm, Token token)
0752: throws ParseException {
0753: int len = token.image.length();
0754: return make(vm, token.image.substring(1, len - 1));
0755: }
0756:
0757: static LValue makeNull(VirtualMachine vm, Token token)
0758: throws ParseException {
0759: return new LValueConstant(null);
0760: }
0761:
0762: static LValue makeThisObject(VirtualMachine vm,
0763: ExpressionParser.GetFrame frameGetter, Token token)
0764: throws ParseException {
0765: if (frameGetter == null) {
0766: throw new ParseException("No current thread");
0767: } else {
0768: try {
0769: StackFrame frame = frameGetter.get();
0770: ObjectReference this Object = frame.this Object();
0771:
0772: if (this Object == null) {
0773: throw new ParseException(
0774: "No 'this'. In native or static method");
0775: } else {
0776: return new LValueConstant(this Object);
0777: }
0778: } catch (IncompatibleThreadStateException exc) {
0779: throw new ParseException("Thread not suspended");
0780: }
0781: }
0782: }
0783:
0784: static LValue makeNewObject(VirtualMachine vm,
0785: ExpressionParser.GetFrame frameGetter, String className,
0786: List<Value> arguments) throws ParseException {
0787: List classes = vm.classesByName(className);
0788: if (classes.size() == 0) {
0789: throw new ParseException("No class named: " + className);
0790: }
0791:
0792: if (classes.size() > 1) {
0793: throw new ParseException("More than one class named: "
0794: + className);
0795: }
0796: ReferenceType refType = (ReferenceType) classes.get(0);
0797:
0798: if (!(refType instanceof ClassType)) {
0799: throw new ParseException(
0800: "Cannot create instance of interface " + className);
0801: }
0802:
0803: ClassType classType = (ClassType) refType;
0804: List<Method> methods = new ArrayList<Method>(classType
0805: .methods()); // writable
0806: Iterator iter = methods.iterator();
0807: while (iter.hasNext()) {
0808: Method method = (Method) iter.next();
0809: if (!method.isConstructor()) {
0810: iter.remove();
0811: }
0812: }
0813: Method constructor = LValue.resolveOverload(methods, arguments);
0814:
0815: ObjectReference newObject;
0816: try {
0817: ThreadReference thread = frameGetter.get().thread();
0818: newObject = classType.newInstance(thread, constructor,
0819: arguments, 0);
0820: } catch (InvocationException ie) {
0821: throw new ParseException("Exception in " + className
0822: + " constructor: "
0823: + ie.exception().referenceType().name());
0824: } catch (IncompatibleThreadStateException exc) {
0825: throw new ParseException("Thread not suspended");
0826: } catch (Exception e) {
0827: /*
0828: * TO DO: Better error handling
0829: */
0830: throw new ParseException("Unable to create " + className
0831: + " instance");
0832: }
0833: return new LValueConstant(newObject);
0834: }
0835:
0836: private static LValue nFields(LValue lval, StringTokenizer izer,
0837: ThreadReference thread) throws ParseException {
0838: if (!izer.hasMoreTokens()) {
0839: return lval;
0840: } else {
0841: return nFields(lval.memberLValue(izer.nextToken(), thread),
0842: izer, thread);
0843: }
0844: }
0845:
0846: static LValue makeName(VirtualMachine vm,
0847: ExpressionParser.GetFrame frameGetter, String name)
0848: throws ParseException {
0849: StringTokenizer izer = new StringTokenizer(name, ".");
0850: String first = izer.nextToken();
0851: // check local variables
0852: if (frameGetter != null) {
0853: try {
0854: StackFrame frame = frameGetter.get();
0855: ThreadReference thread = frame.thread();
0856: LocalVariable var;
0857: try {
0858: var = frame.visibleVariableByName(first);
0859: } catch (AbsentInformationException e) {
0860: var = null;
0861: }
0862: if (var != null) {
0863: return nFields(new LValueLocal(frame, var), izer,
0864: thread);
0865: } else {
0866: ObjectReference this Object = frame.this Object();
0867: if (this Object != null) {
0868: // check if it is a field of 'this'
0869: LValue this LValue = new LValueConstant(
0870: this Object);
0871: LValue fv;
0872: try {
0873: fv = this LValue.memberLValue(first, thread);
0874: } catch (ParseException exc) {
0875: fv = null;
0876: }
0877: if (fv != null) {
0878: return nFields(fv, izer, thread);
0879: }
0880: }
0881: }
0882: // check for class name
0883: while (izer.hasMoreTokens()) {
0884: List classes = vm.classesByName(first);
0885: if (classes.size() > 0) {
0886: if (classes.size() > 1) {
0887: throw new ParseException(
0888: "More than one class named: "
0889: + first);
0890: } else {
0891: ReferenceType refType = (ReferenceType) classes
0892: .get(0);
0893: LValue lval = new LValueStaticMember(
0894: refType, izer.nextToken(), thread);
0895: return nFields(lval, izer, thread);
0896: }
0897: }
0898: first = first + '.' + izer.nextToken();
0899: }
0900: } catch (IncompatibleThreadStateException exc) {
0901: throw new ParseException("Thread not suspended");
0902: }
0903: }
0904: throw new ParseException("Name unknown: " + name);
0905: }
0906:
0907: static String stringValue(LValue lval,
0908: ExpressionParser.GetFrame frameGetter)
0909: throws ParseException {
0910: Value val = lval.getMassagedValue(frameGetter);
0911: if (val == null) {
0912: return "null";
0913: }
0914: if (val instanceof StringReference) {
0915: return ((StringReference) val).value();
0916: }
0917: return val.toString(); // is this correct in all cases?
0918: }
0919:
0920: static LValue booleanOperation(VirtualMachine vm, Token token,
0921: LValue rightL, LValue leftL) throws ParseException {
0922: String op = token.image;
0923: Value right = rightL.interiorGetValue();
0924: Value left = leftL.interiorGetValue();
0925: if (!(right instanceof PrimitiveValue)
0926: || !(left instanceof PrimitiveValue)) {
0927: if (op.equals("==")) {
0928: return make(vm, right.equals(left));
0929: } else if (op.equals("!=")) {
0930: return make(vm, !right.equals(left));
0931: } else {
0932: throw new ParseException("Operands or '" + op
0933: + "' must be primitive");
0934: }
0935: }
0936: // can compare any numeric doubles
0937: double rr = ((PrimitiveValue) right).doubleValue();
0938: double ll = ((PrimitiveValue) left).doubleValue();
0939: boolean res;
0940: if (op.equals("<")) {
0941: res = rr < ll;
0942: } else if (op.equals(">")) {
0943: res = rr > ll;
0944: } else if (op.equals("<=")) {
0945: res = rr <= ll;
0946: } else if (op.equals(">=")) {
0947: res = rr >= ll;
0948: } else if (op.equals("==")) {
0949: res = rr == ll;
0950: } else if (op.equals("!=")) {
0951: res = rr != ll;
0952: } else {
0953: throw new ParseException("Unknown operation: " + op);
0954: }
0955: return make(vm, res);
0956: }
0957:
0958: static LValue operation(VirtualMachine vm, Token token,
0959: LValue rightL, LValue leftL,
0960: ExpressionParser.GetFrame frameGetter)
0961: throws ParseException {
0962: String op = token.image;
0963: Value right = rightL.interiorGetValue();
0964: Value left = leftL.interiorGetValue();
0965: if ((right instanceof StringReference)
0966: || (left instanceof StringReference)) {
0967: if (op.equals("+")) {
0968: // If one is an ObjectRef, we will need to invoke
0969: // toString on it, so we need the thread.
0970: return make(vm, stringValue(rightL, frameGetter)
0971: + stringValue(leftL, frameGetter));
0972: }
0973: }
0974: if ((right instanceof ObjectReference)
0975: || (left instanceof ObjectReference)) {
0976: if (op.equals("==")) {
0977: return make(vm, right.equals(left));
0978: } else if (op.equals("!=")) {
0979: return make(vm, !right.equals(left));
0980: } else {
0981: throw new ParseException("Invalid operation '" + op
0982: + "' on an Object");
0983: }
0984: }
0985: if ((right instanceof BooleanValue)
0986: || (left instanceof BooleanValue)) {
0987: throw new ParseException("Invalid operation '" + op
0988: + "' on a Boolean");
0989: }
0990: // from here on, we know it is a integer kind of type
0991: PrimitiveValue primRight = (PrimitiveValue) right;
0992: PrimitiveValue primLeft = (PrimitiveValue) left;
0993: if ((primRight instanceof DoubleValue)
0994: || (primLeft instanceof DoubleValue)) {
0995: double rr = primRight.doubleValue();
0996: double ll = primLeft.doubleValue();
0997: double res;
0998: if (op.equals("+")) {
0999: res = rr + ll;
1000: } else if (op.equals("-")) {
1001: res = rr - ll;
1002: } else if (op.equals("*")) {
1003: res = rr * ll;
1004: } else if (op.equals("/")) {
1005: res = rr / ll;
1006: } else {
1007: throw new ParseException("Unknown operation: " + op);
1008: }
1009: return make(vm, res);
1010: }
1011: if ((primRight instanceof FloatValue)
1012: || (primLeft instanceof FloatValue)) {
1013: float rr = primRight.floatValue();
1014: float ll = primLeft.floatValue();
1015: float res;
1016: if (op.equals("+")) {
1017: res = rr + ll;
1018: } else if (op.equals("-")) {
1019: res = rr - ll;
1020: } else if (op.equals("*")) {
1021: res = rr * ll;
1022: } else if (op.equals("/")) {
1023: res = rr / ll;
1024: } else {
1025: throw new ParseException("Unknown operation: " + op);
1026: }
1027: return make(vm, res);
1028: }
1029: if ((primRight instanceof LongValue)
1030: || (primLeft instanceof LongValue)) {
1031: long rr = primRight.longValue();
1032: long ll = primLeft.longValue();
1033: long res;
1034: if (op.equals("+")) {
1035: res = rr + ll;
1036: } else if (op.equals("-")) {
1037: res = rr - ll;
1038: } else if (op.equals("*")) {
1039: res = rr * ll;
1040: } else if (op.equals("/")) {
1041: res = rr / ll;
1042: } else {
1043: throw new ParseException("Unknown operation: " + op);
1044: }
1045: return make(vm, res);
1046: } else {
1047: int rr = primRight.intValue();
1048: int ll = primLeft.intValue();
1049: int res;
1050: if (op.equals("+")) {
1051: res = rr + ll;
1052: } else if (op.equals("-")) {
1053: res = rr - ll;
1054: } else if (op.equals("*")) {
1055: res = rr * ll;
1056: } else if (op.equals("/")) {
1057: res = rr / ll;
1058: } else {
1059: throw new ParseException("Unknown operation: " + op);
1060: }
1061: return make(vm, res);
1062: }
1063: }
1064: }
|