KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > example > debug > expr > LValue


1 /*
2  * @(#)LValue.java 1.29 05/11/17
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 /*
8  * Copyright (c) 1997-1999 by Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
11  * modify and redistribute this software in source and binary code form,
12  * provided that i) this copyright notice and license appear on all copies of
13  * the software; and ii) Licensee does not utilize the software in a manner
14  * which is disparaging to Sun.
15  *
16  * This software is provided "AS IS," without a warranty of any kind. ALL
17  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
18  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
19  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
20  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
21  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
22  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
23  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
24  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
25  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGES.
27  *
28  * This software is not designed or intended for use in on-line control of
29  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
30  * the design, construction, operation or maintenance of any nuclear
31  * facility. Licensee represents and warrants that it will not use or
32  * redistribute the Software for such purposes.
33  */

34
35 package com.sun.tools.example.debug.expr;
36
37 import com.sun.jdi.*;
38 import java.util.*;
39
40 abstract class LValue {
41
42     // The JDI Value object for this LValue. Once we have this Value,
43
// we have to remember it since after we return the LValue object
44
// to the ExpressionParser, it might decide that it needs
45
// the 'toString' value for the LValue in which case it will
46
// call getMassagedValue to get this toString value. At that
47
// point, we don't want to call JDI a 2nd time to get the Value
48
// for the LValue. This is especially wrong when the LValue
49
// represents a member function. We would end up calling it
50
// a 2nd time.
51
//
52
// Unfortunately, there are several levels of calls to
53
// get/set values in this file. To minimize confusion,
54
// jdiValue is set/tested at the lowest level - right
55
// next to the actual calls to JDI methods to get/set the
56
// value in the debuggee.
57
protected Value jdiValue;
58
59     abstract Value getValue() throws InvocationException,
60                                      IncompatibleThreadStateException,
61                                      InvalidTypeException,
62                                      ClassNotLoadedException,
63                                      ParseException;
64
65     abstract void setValue0(Value value)
66                    throws ParseException, InvalidTypeException,
67                           ClassNotLoadedException;
68
69     abstract void invokeWith(List arguments) throws ParseException;
70
71     void setValue(Value value) throws ParseException {
72         try {
73             setValue0(value);
74         } catch (InvalidTypeException exc) {
75             throw new ParseException(
76                 "Attempt to set value of incorrect type" +
77                 exc);
78         } catch (ClassNotLoadedException exc) {
79             throw new ParseException(
80                 "Attempt to set value before " + exc.className() + " was loaded" +
81                 exc);
82         }
83     }
84
85     void setValue(LValue lval) throws ParseException {
86         setValue(lval.interiorGetValue());
87     }
88
89     LValue memberLValue(ExpressionParser.GetFrame frameGetter,
90                         String JavaDoc fieldName) throws ParseException {
91         try {
92             return memberLValue(fieldName, frameGetter.get().thread());
93         } catch (IncompatibleThreadStateException exc) {
94             throw new ParseException("Thread not suspended");
95         }
96     }
97
98     LValue memberLValue(String JavaDoc fieldName, ThreadReference thread) throws ParseException {
99         
100         Value val = interiorGetValue();
101         if ((val instanceof ArrayReference) &&
102             "length".equals(fieldName)){
103             return new LValueArrayLength((ArrayReference)val);
104         }
105         return new LValueInstanceMember(val, fieldName, thread);
106     }
107
108     // Return the Value for this LValue that would be used to concatenate
109
// to a String. IE, if it is an Object, call toString in the debuggee.
110
Value getMassagedValue(ExpressionParser.GetFrame frameGetter) throws ParseException {
111         Value vv = interiorGetValue();
112
113         // If vv is an ObjectReference, then we have to
114
// do the implicit call to toString().
115
if (vv instanceof ObjectReference &&
116             !(vv instanceof StringReference) &&
117             !(vv instanceof ArrayReference)) {
118             StackFrame frame;
119             try {
120                 frame = frameGetter.get();
121             } catch (IncompatibleThreadStateException exc) {
122                 throw new ParseException("Thread not suspended");
123             }
124
125             ThreadReference thread = frame.thread();
126             LValue toStringMember = memberLValue("toString", thread);
127             toStringMember.invokeWith(new ArrayList());
128             return toStringMember.interiorGetValue();
129         }
130         return vv;
131     }
132
133     Value interiorGetValue() throws ParseException {
134         Value value;
135         try {
136             value = getValue();
137         } catch (InvocationException e) {
138             throw new ParseException("Unable to complete expression. Exception " +
139                                      e.exception() + " thrown");
140         } catch (IncompatibleThreadStateException itse) {
141             throw new ParseException("Unable to complete expression. Thread " +
142                                      "not suspended for method invoke");
143         } catch (InvalidTypeException ite) {
144             throw new ParseException("Unable to complete expression. Method " +
145                                      "argument type mismatch");
146         } catch (ClassNotLoadedException tnle) {
147             throw new ParseException("Unable to complete expression. Method " +
148                                      "argument type " + tnle.className() +
149                                      " not yet loaded");
150         }
151         return value;
152     }
153
154     LValue arrayElementLValue(LValue lval) throws ParseException {
155         Value indexValue = lval.interiorGetValue();
156         int index;
157         if ( (indexValue instanceof IntegerValue) ||
158              (indexValue instanceof ShortValue) ||
159              (indexValue instanceof ByteValue) ||
160              (indexValue instanceof CharValue) ) {
161             index = ((PrimitiveValue)indexValue).intValue();
162         } else {
163             throw new ParseException("Array index must be a integer type");
164         }
165         return new LValueArrayElement(interiorGetValue(), index);
166     }
167
168     public String JavaDoc toString() {
169         try {
170             return interiorGetValue().toString();
171         } catch (ParseException e) {
172             return "<Parse Exception>";
173         }
174     }
175
176     static final int STATIC = 0;
177     static final int INSTANCE = 1;
178
179     static Field fieldByName(ReferenceType refType, String JavaDoc name, int kind) {
180         /*
181          * TO DO: Note that this currently fails to find superclass
182          * or implemented interface fields. This is due to a temporary
183          * limititation of RefType.fieldByName. Once that method is
184          * fixed, superclass fields will be found.
185          */

186         Field field = refType.fieldByName(name);
187         if (field != null) {
188             boolean isStatic = field.isStatic();
189             if (((kind == STATIC) && !isStatic) ||
190                 ((kind == INSTANCE) && isStatic)) {
191                 field = null;
192             }
193         }
194 /***
195         System.err.println("fieldByName: " + refType.name() + " " +
196                                              name + " " +
197                                              kind + " " +
198                                              (field != null));
199 ***/

200         return field;
201     }
202
203     static List methodsByName(ReferenceType refType, String JavaDoc name, int kind) {
204         List list = refType.methodsByName(name);
205         Iterator iter = list.iterator();
206         while (iter.hasNext()) {
207             Method method = (Method)iter.next();
208             boolean isStatic = method.isStatic();
209             if (((kind == STATIC) && !isStatic) ||
210                 ((kind == INSTANCE) && isStatic)) {
211                 iter.remove();
212             }
213         }
214         return list;
215     }
216
217     static List primitiveTypeNames = new ArrayList();
218     static {
219         primitiveTypeNames.add("boolean");
220         primitiveTypeNames.add("byte");
221         primitiveTypeNames.add("char");
222         primitiveTypeNames.add("short");
223         primitiveTypeNames.add("int");
224         primitiveTypeNames.add("long");
225         primitiveTypeNames.add("float");
226         primitiveTypeNames.add("double");
227     }
228
229
230     static final int SAME = 0;
231     static final int ASSIGNABLE = 1;
232     static final int DIFFERENT = 2;
233     /*
234      * Return SAME, DIFFERENT or ASSIGNABLE.
235      * SAME means each arg type is the same as type of the corr. arg.
236      * ASSIGNABLE means that not all the pairs are the same, but
237      * for those that aren't, at least the argType is assignable
238      * from the type of the argument value.
239      * DIFFERENT means that in at least one pair, the
240      * argType is not assignable from the type of the argument value.
241      * IE, one is an Apple and the other is an Orange.
242      */

243     static int argumentsMatch(List argTypes, List arguments) {
244         if (argTypes.size() != arguments.size()) {
245             return DIFFERENT;
246         }
247
248         Iterator typeIter = argTypes.iterator();
249         Iterator valIter = arguments.iterator();
250         int result = SAME;
251
252         // If any pair aren't the same, change the
253
// result to ASSIGNABLE. If any pair aren't
254
// assignable, return DIFFERENT
255
while (typeIter.hasNext()) {
256             Type argType = (Type)typeIter.next();
257             Value value = (Value)valIter.next();
258             if (value == null) {
259                 // Null values can be passed to any non-primitive argument
260
if (primitiveTypeNames.contains(argType.name())) {
261                     return DIFFERENT;
262                 }
263                 // Else, we will assume that a null value
264
// exactly matches an object type.
265
}
266             if (!value.type().equals(argType)) {
267                 if (isAssignableTo(value.type(), argType)) {
268                     result = ASSIGNABLE;
269                 } else {
270                     return DIFFERENT;
271                 }
272             }
273         }
274         return result;
275     }
276
277
278     // These is...AssignableTo methods are based on similar code in the JDI
279
// implementations of ClassType, ArrayType, and InterfaceType
280

281     static boolean isComponentAssignable(Type fromType, Type toType) {
282         if (fromType instanceof PrimitiveType) {
283             // Assignment of primitive arrays requires identical
284
// component types.
285
return fromType.equals(toType);
286         }
287         if (toType instanceof PrimitiveType) {
288             return false;
289         }
290         // Assignment of object arrays requires availability
291
// of widening conversion of component types
292
return isAssignableTo(fromType, toType);
293     }
294
295     static boolean isArrayAssignableTo(ArrayType fromType, Type toType) {
296         if (toType instanceof ArrayType) {
297             try {
298                 Type toComponentType = ((ArrayType)toType).componentType();
299                 return isComponentAssignable(fromType.componentType(), toComponentType);
300             } catch (ClassNotLoadedException e) {
301                 // One or both component types has not yet been
302
// loaded => can't assign
303
return false;
304             }
305         }
306         if (toType instanceof InterfaceType) {
307             // Only valid InterfaceType assignee is Cloneable
308
return toType.name().equals("java.lang.Cloneable");
309         }
310         // Only valid ClassType assignee is Object
311
return toType.name().equals("java.lang.Object");
312     }
313
314     static boolean isAssignableTo(Type fromType, Type toType) {
315         if (fromType.equals(toType)) {
316             return true;
317         }
318
319         // If one is boolean, so must be the other.
320
if (fromType instanceof BooleanType) {
321             if (toType instanceof BooleanType) {
322                 return true;
323             }
324             return false;
325         }
326         if (toType instanceof BooleanType) {
327             return false;
328         }
329
330         // Other primitive types are intermixable only with each other.
331
if (fromType instanceof PrimitiveType) {
332             if (toType instanceof PrimitiveType) {
333                 return true;
334             }
335             return false;
336         }
337         if (toType instanceof PrimitiveType) {
338             return false;
339         }
340
341         // neither one is primitive.
342
if (fromType instanceof ArrayType) {
343             return isArrayAssignableTo((ArrayType)fromType, toType);
344         }
345         List interfaces;
346         if (fromType instanceof ClassType) {
347             ClassType superclazz = ((ClassType)fromType).superclass();
348             if ((superclazz != null) && isAssignableTo(superclazz, toType)) {
349                 return true;
350             }
351             interfaces = ((ClassType)fromType).interfaces();
352         } else {
353             // fromType must be an InterfaceType
354
interfaces = ((InterfaceType)fromType).superinterfaces();
355         }
356         Iterator iter = interfaces.iterator();
357         while (iter.hasNext()) {
358             InterfaceType interfaze = (InterfaceType)iter.next();
359             if (isAssignableTo(interfaze, toType)) {
360                 return true;
361             }
362         }
363         return false;
364     }
365
366     static Method resolveOverload(List overloads, List arguments)
367                                        throws ParseException {
368
369         // If there is only one method to call, we'll just choose
370
// that without looking at the args. If they aren't right
371
// the invoke will return a better error message than we
372
// could generate here.
373
if (overloads.size() == 1) {
374             return (Method)overloads.get(0);
375         }
376
377         // Resolving overloads is beyond the scope of this exercise.
378
// So, we will look for a method that matches exactly the
379
// types of the arguments. If we can't find one, then
380
// if there is exactly one method whose param types are assignable
381
// from the arg types, we will use that. Otherwise,
382
// it is an error. We won't guess which of multiple possible
383
// methods to call. And, since casts aren't implemented,
384
// the user can't use them to pick a particular overload to call.
385
// IE, the user is out of luck in this case.
386
Iterator iter = overloads.iterator();
387         Method retVal = null;
388         int assignableCount = 0;
389         while (iter.hasNext()) {
390             Method mm = (Method)iter.next();
391             List argTypes;
392             try {
393                 argTypes = mm.argumentTypes();
394             } catch (ClassNotLoadedException ee) {
395                 // This probably won't happen for the
396
// method that we are really supposed to
397
// call.
398
continue;
399             }
400             int compare = argumentsMatch(argTypes, arguments);
401             if (compare == SAME) {
402                 return mm;
403             }
404             if (compare == DIFFERENT) {
405                 continue;
406             }
407             // Else, it is assignable. Remember it.
408
retVal = mm;
409             assignableCount++;
410         }
411
412         // At this point, we didn't find an exact match,
413
// but we found one for which the args are assignable.
414
//
415
if (retVal != null) {
416             if (assignableCount == 1) {
417                 return retVal;
418             }
419             throw new ParseException("Arguments match multiple methods");
420         }
421         throw new ParseException("Arguments match no method");
422     }
423
424     private static class LValueLocal extends LValue {
425         final StackFrame frame;
426         final LocalVariable var;
427
428         LValueLocal(StackFrame frame, LocalVariable var) {
429             this.frame = frame;
430             this.var = var;
431         }
432         
433         Value getValue() {
434             if (jdiValue == null) {
435                 jdiValue = frame.getValue(var);
436             }
437             return jdiValue;
438         }
439
440         void setValue0(Value val) throws InvalidTypeException,
441                                          ClassNotLoadedException {
442             frame.setValue(var, val);
443             jdiValue = val;
444         }
445
446         void invokeWith(List arguments) throws ParseException {
447             throw new ParseException(var.name() + " is not a method");
448         }
449     }
450
451     private static class LValueInstanceMember extends LValue {
452         final ObjectReference obj;
453         final ThreadReference thread;
454         final Field matchingField;
455         final List overloads;
456         Method matchingMethod = null;
457         List methodArguments = null;
458
459         LValueInstanceMember(Value value,
460                             String JavaDoc memberName,
461                             ThreadReference thread) throws ParseException {
462             if (!(value instanceof ObjectReference)) {
463                 throw new ParseException(
464                        "Cannot access field of primitive type: " + value);
465             }
466             this.obj = (ObjectReference)value;
467             this.thread = thread;
468             ReferenceType refType = obj.referenceType();
469             /*
470              * Can't tell yet whether this LValue will be accessed as a
471              * field or method, so we keep track of all the possibilities
472              */

473             matchingField = LValue.fieldByName(refType, memberName,
474                                                LValue.INSTANCE);
475             overloads = LValue.methodsByName(refType, memberName,
476                                               LValue.INSTANCE);
477             if ((matchingField == null) && overloads.size() == 0) {
478                 throw new ParseException("No instance field or method with the name "
479                                + memberName + " in " + refType.name());
480             }
481         }
482         
483         Value getValue() throws InvocationException, InvalidTypeException,
484                                 ClassNotLoadedException, IncompatibleThreadStateException,
485                                 ParseException {
486             if (jdiValue != null) {
487                 return jdiValue;
488             }
489             if (matchingMethod == null) {
490                 if (matchingField == null) {
491                     throw new ParseException("No such field in " + obj.referenceType().name());
492                 }
493                 return jdiValue = obj.getValue(matchingField);
494             } else {
495                 return jdiValue = obj.invokeMethod(thread, matchingMethod, methodArguments, 0);
496             }
497         }
498
499         void setValue0(Value val) throws ParseException,
500                                          InvalidTypeException,
501                                         ClassNotLoadedException {
502             if (matchingMethod != null) {
503                 throw new ParseException("Cannot assign to a method invocation");
504             }
505             obj.setValue(matchingField, val);
506             jdiValue = val;
507         }
508
509         void invokeWith(List arguments) throws ParseException {
510             if (matchingMethod != null) {
511                 throw new ParseException("Invalid consecutive invocations");
512             }
513             methodArguments = arguments;
514             matchingMethod = LValue.resolveOverload(overloads, arguments);
515         }
516     }
517
518     private static class LValueStaticMember extends LValue {
519         final ReferenceType refType;
520         final ThreadReference thread;
521         final Field matchingField;
522         final List overloads;
523         Method matchingMethod = null;
524         List methodArguments = null;
525
526         LValueStaticMember(ReferenceType refType,
527                           String JavaDoc memberName,
528                           ThreadReference thread) throws ParseException {
529             this.refType = refType;
530             this.thread = thread;
531             /*
532              * Can't tell yet whether this LValue will be accessed as a
533              * field or method, so we keep track of all the possibilities
534              */

535             matchingField = LValue.fieldByName(refType, memberName,
536                                                LValue.STATIC);
537             overloads = LValue.methodsByName(refType, memberName,
538                                               LValue.STATIC);
539             if ((matchingField == null) && overloads.size() == 0) {
540                 throw new ParseException("No static field or method with the name "
541                                + memberName + " in " + refType.name());
542             }
543         }
544         
545         Value getValue() throws InvocationException, InvalidTypeException,
546                                 ClassNotLoadedException, IncompatibleThreadStateException,
547                                 ParseException {
548             if (jdiValue != null) {
549                 return jdiValue;
550             }
551             if (matchingMethod == null) {
552                 return jdiValue = refType.getValue(matchingField);
553             } else if (refType instanceof ClassType) {
554                 ClassType clazz = (ClassType)refType;
555                 return jdiValue = clazz.invokeMethod(thread, matchingMethod, methodArguments, 0);
556             } else {
557                 throw new InvalidTypeException("Cannot invoke static method on " +
558                                          refType.name());
559             }
560         }
561
562         void setValue0(Value val)
563                            throws ParseException, InvalidTypeException,
564                                   ClassNotLoadedException {
565             if (matchingMethod != null) {
566                 throw new ParseException("Cannot assign to a method invocation");
567             }
568             if (!(refType instanceof ClassType)) {
569                 throw new ParseException(
570                        "Cannot set interface field: " + refType);
571             }
572             ((ClassType)refType).setValue(matchingField, val);
573             jdiValue = val;
574         }
575
576         void invokeWith(List arguments) throws ParseException {
577             if (matchingMethod != null) {
578                 throw new ParseException("Invalid consecutive invocations");
579             }
580             methodArguments = arguments;
581             matchingMethod = LValue.resolveOverload(overloads, arguments);
582         }
583     }
584
585     private static class LValueArrayLength extends LValue {
586         /*
587          * Since one can code "int myLen = myArray.length;",
588          * one might expect that these JDI calls would get a Value
589          * object for the length of an array in the debugee:
590          * Field xxx = ArrayType.fieldByName("length")
591          * Value lenVal= ArrayReference.getValue(xxx)
592          *
593          * However, this doesn't work because the array length isn't
594          * really stored as a field, and can't be accessed as such
595          * via JDI. Instead, the arrayRef.length() method has to be
596          * used.
597          */

598         final ArrayReference arrayRef;
599         LValueArrayLength (ArrayReference value) {
600             this.arrayRef = value;
601         }
602
603         Value getValue() {
604             if (jdiValue == null) {
605                 jdiValue = arrayRef.virtualMachine().mirrorOf(arrayRef.length());
606             }
607             return jdiValue;
608         }
609
610         void setValue0(Value value) throws ParseException {
611             throw new ParseException("Cannot set constant: " + value);
612         }
613
614         void invokeWith(List arguments) throws ParseException {
615             throw new ParseException("Array element is not a method");
616         }
617     }
618
619     private static class LValueArrayElement extends LValue {
620         final ArrayReference array;
621         final int index;
622
623         LValueArrayElement(Value value, int index) throws ParseException {
624             if (!(value instanceof ArrayReference)) {
625                 throw new ParseException(
626                        "Must be array type: " + value);
627             }
628             this.array = (ArrayReference)value;
629             this.index = index;
630         }
631         
632         Value getValue() {
633             if (jdiValue == null) {
634                 jdiValue = array.getValue(index);
635             }
636             return jdiValue;
637         }
638
639         void setValue0(Value val) throws InvalidTypeException,
640                                          ClassNotLoadedException {
641             array.setValue(index, val);
642             jdiValue = val;
643         }
644
645         void invokeWith(List arguments) throws ParseException {
646             throw new ParseException("Array element is not a method");
647         }
648     }
649
650     private static class LValueConstant extends LValue {
651         final Value value;
652
653         LValueConstant(Value value) {
654             this.value = value;
655         }
656         
657         Value getValue() {
658             if (jdiValue == null) {
659                 jdiValue = value;
660             }
661             return jdiValue;
662         }
663
664         void setValue0(Value val) throws ParseException {
665             throw new ParseException("Cannot set constant: " + value);
666         }
667
668         void invokeWith(List arguments) throws ParseException {
669             throw new ParseException("Constant is not a method");
670         }
671     }
672
673     static LValue make(VirtualMachine vm, boolean val) {
674         return new LValueConstant(vm.mirrorOf(val));
675     }
676
677     static LValue make(VirtualMachine vm, byte val) {
678         return new LValueConstant(vm.mirrorOf(val));
679     }
680
681     static LValue make(VirtualMachine vm, char val) {
682         return new LValueConstant(vm.mirrorOf(val));
683     }
684
685     static LValue make(VirtualMachine vm, short val) {
686         return new LValueConstant(vm.mirrorOf(val));
687     }
688
689     static LValue make(VirtualMachine vm, int val) {
690         return new LValueConstant(vm.mirrorOf(val));
691     }
692
693     static LValue make(VirtualMachine vm, long val) {
694         return new LValueConstant(vm.mirrorOf(val));
695     }
696
697     static LValue make(VirtualMachine vm, float val) {
698         return new LValueConstant(vm.mirrorOf(val));
699     }
700
701     static LValue make(VirtualMachine vm, double val) {
702         return new LValueConstant(vm.mirrorOf(val));
703     }
704
705     static LValue make(VirtualMachine vm, String JavaDoc val) throws ParseException {
706         return new LValueConstant(vm.mirrorOf(val));
707     }
708
709     static LValue makeBoolean(VirtualMachine vm, Token token) {
710         return make(vm, token.image.charAt(0) == 't');
711     }
712
713     static LValue makeCharacter(VirtualMachine vm, Token token) {
714         return make(vm, token.image.charAt(1));
715     }
716
717     static LValue makeFloat(VirtualMachine vm, Token token) {
718         return make(vm, Float.valueOf(token.image).floatValue());
719     }
720
721     static LValue makeDouble(VirtualMachine vm, Token token) {
722         return make(vm, Double.valueOf(token.image).doubleValue());
723     }
724
725     static LValue makeInteger(VirtualMachine vm, Token token) {
726         return make(vm, Integer.parseInt(token.image));
727     }
728
729     static LValue makeShort(VirtualMachine vm, Token token) {
730         return make(vm, Short.parseShort(token.image));
731     }
732
733     static LValue makeLong(VirtualMachine vm, Token token) {
734         return make(vm, Long.parseLong(token.image));
735     }
736
737     static LValue makeByte(VirtualMachine vm, Token token) {
738         return make(vm, Byte.parseByte(token.image));
739     }
740
741     static LValue makeString(VirtualMachine vm,
742                              Token token) throws ParseException {
743         int len = token.image.length();
744         return make(vm, token.image.substring(1,len-1));
745     }
746
747     static LValue makeNull(VirtualMachine vm,
748                            Token token) throws ParseException {
749         return new LValueConstant(null);
750     }
751
752     static LValue makeThisObject(VirtualMachine vm,
753                                  ExpressionParser.GetFrame frameGetter,
754                                  Token token) throws ParseException {
755         if (frameGetter == null) {
756             throw new ParseException("No current thread");
757         } else {
758             try {
759                 StackFrame frame = frameGetter.get();
760                 ObjectReference thisObject = frame.thisObject();
761                 
762         if (thisObject==null) {
763                 throw new ParseException(
764                             "No 'this'. In native or static method");
765         } else {
766             return new LValueConstant(thisObject);
767                 }
768             } catch (IncompatibleThreadStateException exc) {
769                 throw new ParseException("Thread not suspended");
770             }
771         }
772     }
773
774     static LValue makeNewObject(VirtualMachine vm,
775                                  ExpressionParser.GetFrame frameGetter,
776                                 String JavaDoc className, List arguments) throws ParseException {
777         List classes = vm.classesByName(className);
778         if (classes.size() == 0) {
779             throw new ParseException("No class named: " + className);
780         }
781
782         if (classes.size() > 1) {
783             throw new ParseException("More than one class named: " +
784                                      className);
785         }
786         ReferenceType refType = (ReferenceType)classes.get(0);
787
788
789         if (!(refType instanceof ClassType)) {
790             throw new ParseException("Cannot create instance of interface " +
791                                      className);
792         }
793
794         ClassType classType = (ClassType)refType;
795         List methods = new ArrayList(classType.methods()); // writable
796
Iterator iter = methods.iterator();
797         while (iter.hasNext()) {
798             Method method = (Method)iter.next();
799             if (!method.isConstructor()) {
800                 iter.remove();
801             }
802         }
803         Method constructor = LValue.resolveOverload(methods, arguments);
804
805         ObjectReference newObject;
806         try {
807             ThreadReference thread = frameGetter.get().thread();
808             newObject = classType.newInstance(thread, constructor, arguments, 0);
809         } catch (InvocationException ie) {
810             throw new ParseException("Exception in " + className + " constructor: " +
811                                      ie.exception().referenceType().name());
812         } catch (IncompatibleThreadStateException exc) {
813             throw new ParseException("Thread not suspended");
814         } catch (Exception JavaDoc e) {
815             /*
816              * TO DO: Better error handling
817              */

818             throw new ParseException("Unable to create " + className + " instance");
819         }
820     return new LValueConstant(newObject);
821     }
822
823     private static LValue nFields(LValue lval,
824                                   StringTokenizer izer,
825                                   ThreadReference thread)
826                                           throws ParseException {
827         if (!izer.hasMoreTokens()) {
828             return lval;
829         } else {
830             return nFields(lval.memberLValue(izer.nextToken(), thread), izer, thread);
831         }
832     }
833
834     static LValue makeName(VirtualMachine vm,
835                            ExpressionParser.GetFrame frameGetter,
836                            String JavaDoc name) throws ParseException {
837         StringTokenizer izer = new StringTokenizer(name, ".");
838         String JavaDoc first = izer.nextToken();
839         // check local variables
840
if (frameGetter != null) {
841             try {
842                 StackFrame frame = frameGetter.get();
843                 ThreadReference thread = frame.thread();
844                 LocalVariable var;
845                 try {
846                     var = frame.visibleVariableByName(first);
847                 } catch (AbsentInformationException e) {
848                     var = null;
849                 }
850                 if (var != null) {
851                     return nFields(new LValueLocal(frame, var), izer, thread);
852                 } else {
853                     ObjectReference thisObject = frame.thisObject();
854                     if (thisObject != null) {
855                         // check if it is a field of 'this'
856
LValue thisLValue = new LValueConstant(thisObject);
857                         LValue fv;
858                         try {
859                             fv = thisLValue.memberLValue(first, thread);
860                         } catch (ParseException exc) {
861                             fv = null;
862                         }
863                         if (fv != null) {
864                             return nFields(fv, izer, thread);
865                         }
866                     }
867                 }
868                 // check for class name
869
while (izer.hasMoreTokens()) {
870                     List classes = vm.classesByName(first);
871                     if (classes.size() > 0) {
872                         if (classes.size() > 1) {
873                             throw new ParseException("More than one class named: " +
874                                                      first);
875                         } else {
876                             ReferenceType refType = (ReferenceType)classes.get(0);
877                             LValue lval = new LValueStaticMember(refType,
878                                                             izer.nextToken(), thread);
879                             return nFields(lval, izer, thread);
880                         }
881                     }
882                     first = first + '.' + izer.nextToken();
883                 }
884             } catch (IncompatibleThreadStateException exc) {
885                 throw new ParseException("Thread not suspended");
886             }
887         }
888         throw new ParseException("Name unknown: " + name);
889     }
890
891     static String JavaDoc stringValue(LValue lval, ExpressionParser.GetFrame frameGetter
892                               ) throws ParseException {
893         Value val = lval.getMassagedValue(frameGetter);
894         if (val == null) {
895             return "null";
896         }
897         if (val instanceof StringReference) {
898             return ((StringReference)val).value();
899         }
900         return val.toString(); // is this correct in all cases?
901
}
902
903     static LValue booleanOperation(VirtualMachine vm, Token token,
904                             LValue rightL,
905                             LValue leftL) throws ParseException {
906         String JavaDoc op = token.image;
907         Value right = rightL.interiorGetValue();
908         Value left = leftL.interiorGetValue();
909         if ( !(right instanceof PrimitiveValue) ||
910              !(left instanceof PrimitiveValue) ) {
911             if (op.equals("==")) {
912                 return make(vm, right.equals(left));
913             } else if (op.equals("!=")) {
914                 return make(vm, !right.equals(left));
915             } else {
916                 throw new ParseException("Operands or '" + op +
917                                      "' must be primitive");
918             }
919         }
920         // can compare any numeric doubles
921
double rr = ((PrimitiveValue)right).doubleValue();
922         double ll = ((PrimitiveValue)left).doubleValue();
923         boolean res;
924         if (op.equals("<")) {
925             res = rr < ll;
926         } else if (op.equals(">")) {
927             res = rr > ll;
928         } else if (op.equals("<=")) {
929             res = rr <= ll;
930         } else if (op.equals(">=")) {
931             res = rr >= ll;
932         } else if (op.equals("==")) {
933             res = rr == ll;
934         } else if (op.equals("!=")) {
935             res = rr != ll;
936         } else {
937             throw new ParseException("Unknown operation: " + op);
938         }
939         return make(vm, res);
940     }
941
942     static LValue operation(VirtualMachine vm, Token token,
943                             LValue rightL, LValue leftL,
944                             ExpressionParser.GetFrame frameGetter
945                             ) throws ParseException {
946         String JavaDoc op = token.image;
947         Value right = rightL.interiorGetValue();
948         Value left = leftL.interiorGetValue();
949         if ((right instanceof StringReference) ||
950                               (left instanceof StringReference)) {
951             if (op.equals("+")) {
952                 // If one is an ObjectRef, we will need to invoke
953
// toString on it, so we need the thread.
954
return make(vm, stringValue(rightL, frameGetter) +
955                             stringValue(leftL, frameGetter));
956             }
957         }
958         if ((right instanceof ObjectReference) ||
959                               (left instanceof ObjectReference)) {
960             if (op.equals("==")) {
961                 return make(vm, right.equals(left));
962             } else if (op.equals("!=")) {
963                 return make(vm, !right.equals(left));
964             } else {
965                 throw new ParseException("Invalid operation '" +
966                                          op + "' on an Object");
967             }
968         }
969         if ((right instanceof BooleanValue) ||
970                               (left instanceof BooleanValue)) {
971             throw new ParseException("Invalid operation '" +
972                                      op + "' on a Boolean");
973         }
974         // from here on, we know it is a integer kind of type
975
PrimitiveValue primRight = (PrimitiveValue)right;
976         PrimitiveValue primLeft = (PrimitiveValue)left;
977         if ((primRight instanceof DoubleValue) ||
978                               (primLeft instanceof DoubleValue)) {
979             double rr = primRight.doubleValue();
980             double ll = primLeft.doubleValue();
981             double res;
982             if (op.equals("+")) {
983                 res = rr + ll;
984             } else if (op.equals("-")) {
985                 res = rr - ll;
986             } else if (op.equals("*")) {
987                 res = rr * ll;
988             } else if (op.equals("/")) {
989                 res = rr / ll;
990             } else {
991                 throw new ParseException("Unknown operation: " + op);
992             }
993             return make(vm, res);
994         }
995         if ((primRight instanceof FloatValue) ||
996                               (primLeft instanceof FloatValue)) {
997             float rr = primRight.floatValue();
998             float ll = primLeft.floatValue();
999             float res;
1000            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 if (op.equals("/")) {
1007                res = rr / ll;
1008            } else {
1009                throw new ParseException("Unknown operation: " + op);
1010            }
1011            return make(vm, res);
1012        }
1013        if ((primRight instanceof LongValue) ||
1014                              (primLeft instanceof LongValue)) {
1015            long rr = primRight.longValue();
1016            long ll = primLeft.longValue();
1017            long res;
1018            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 if (op.equals("/")) {
1025                res = rr / ll;
1026            } else {
1027                throw new ParseException("Unknown operation: " + op);
1028            }
1029            return make(vm, res);
1030        } else {
1031            int rr = primRight.intValue();
1032            int ll = primLeft.intValue();
1033            int 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        }
1047    }
1048}
1049
Popular Tags