History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/expr/LValue.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/expr/LValue.java+1056−0
@@ -0,0 +1,1056 @@
1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.example.debug.expr;
27
28import com.sun.jdi.*;
29import java.util.*;
30
31abstract class LValue {
32
33 // The JDI Value object for this LValue. Once we have this Value,
34 // we have to remember it since after we return the LValue object
35 // to the ExpressionParser, it might decide that it needs
36 // the 'toString' value for the LValue in which case it will
37 // call getMassagedValue to get this toString value. At that
38 // point, we don't want to call JDI a 2nd time to get the Value
39 // for the LValue. This is especially wrong when the LValue
40 // represents a member function. We would end up calling it
41 // a 2nd time.
42 //
43 // Unfortunately, there are several levels of calls to
44 // get/set values in this file. To minimize confusion,
45 // jdiValue is set/tested at the lowest level - right
46 // next to the actual calls to JDI methods to get/set the
47 // value in the debuggee.
48 protected Value jdiValue;
49
50 abstract Value getValue() throws InvocationException,
51 IncompatibleThreadStateException,
52 InvalidTypeException,
53 ClassNotLoadedException,
54 ParseException;
55
56 abstract void setValue0(Value value)
57 throws ParseException, InvalidTypeException,
58 ClassNotLoadedException;
59
60 abstract void invokeWith(List<Value> arguments) throws ParseException;
61
62 void setValue(Value value) throws ParseException {
63 try {
64 setValue0(value);
65 } catch (InvalidTypeException exc) {
66 throw new ParseException(
67 "Attempt to set value of incorrect type" +
68 exc);
69 } catch (ClassNotLoadedException exc) {
70 throw new ParseException(
71 "Attempt to set value before " + exc.className() + " was loaded" +
72 exc);
73 }
74 }
75
76 void setValue(LValue lval) throws ParseException {
77 setValue(lval.interiorGetValue());
78 }
79
80 LValue memberLValue(ExpressionParser.GetFrame frameGetter,
81 String fieldName) throws ParseException {
82 try {
83 return memberLValue(fieldName, frameGetter.get().thread());
84 } catch (IncompatibleThreadStateException exc) {
85 throw new ParseException("Thread not suspended");
86 }
87 }
88
89 LValue memberLValue(String fieldName, ThreadReference thread) throws ParseException {
90
91 Value val = interiorGetValue();
92 if ((val instanceof ArrayReference) &&
93 "length".equals(fieldName)){
94 return new LValueArrayLength((ArrayReference)val);
95 }
96 return new LValueInstanceMember(val, fieldName, thread);
97 }
98
99 // Return the Value for this LValue that would be used to concatenate
100 // to a String. IE, if it is an Object, call toString in the debuggee.
101 Value getMassagedValue(ExpressionParser.GetFrame frameGetter) throws ParseException {
102 Value vv = interiorGetValue();
103
104 // If vv is an ObjectReference, then we have to
105 // do the implicit call to toString().
106 if (vv instanceof ObjectReference &&
107 !(vv instanceof StringReference) &&
108 !(vv instanceof ArrayReference)) {
109 StackFrame frame;
110 try {
111 frame = frameGetter.get();
112 } catch (IncompatibleThreadStateException exc) {
113 throw new ParseException("Thread not suspended");
114 }
115
116 ThreadReference thread = frame.thread();
117 LValue toStringMember = memberLValue("toString", thread);
118 toStringMember.invokeWith(new ArrayList<Value>());
119 return toStringMember.interiorGetValue();
120 }
121 return vv;
122 }
123
124 Value interiorGetValue() throws ParseException {
125 Value value;
126 try {
127 value = getValue();
128 } catch (InvocationException e) {
129 throw new ParseException("Unable to complete expression. Exception " +
130 e.exception() + " thrown");
131 } catch (IncompatibleThreadStateException itse) {
132 throw new ParseException("Unable to complete expression. Thread " +
133 "not suspended for method invoke");
134 } catch (InvalidTypeException ite) {
135 throw new ParseException("Unable to complete expression. Method " +
136 "argument type mismatch");
137 } catch (ClassNotLoadedException tnle) {
138 throw new ParseException("Unable to complete expression. Method " +
139 "argument type " + tnle.className() +
140 " not yet loaded");
141 }
142 return value;
143 }
144
145 LValue arrayElementLValue(LValue lval) throws ParseException {
146 Value indexValue = lval.interiorGetValue();
147 int index;
148 if ( (indexValue instanceof IntegerValue) ||
149 (indexValue instanceof ShortValue) ||
150 (indexValue instanceof ByteValue) ||
151 (indexValue instanceof CharValue) ) {
152 index = ((PrimitiveValue)indexValue).intValue();
153 } else {
154 throw new ParseException("Array index must be a integer type");
155 }
156 return new LValueArrayElement(interiorGetValue(), index);
157 }
158
159 @Override
160 public String toString() {
161 try {
162 return interiorGetValue().toString();
163 } catch (ParseException e) {
164 return "<Parse Exception>";
165 }
166 }
167
168 static final int STATIC = 0;
169 static final int INSTANCE = 1;
170
171 static Field fieldByName(ReferenceType refType, String name, int kind) {
172 /*
173 * TO DO: Note that this currently fails to find superclass
174 * or implemented interface fields. This is due to a temporary
175 * limititation of RefType.fieldByName. Once that method is
176 * fixed, superclass fields will be found.
177 */
178 Field field = refType.fieldByName(name);
179 if (field != null) {
180 boolean isStatic = field.isStatic();
181 if (((kind == STATIC) && !isStatic) ||
182 ((kind == INSTANCE) && isStatic)) {
183 field = null;
184 }
185 }
186/***
187 System.err.println("fieldByName: " + refType.name() + " " +
188 name + " " +
189 kind + " " +
190 (field != null));
191***/
192 return field;
193 }
194
195 static List<Method> methodsByName(ReferenceType refType,
196 String name, int kind) {
197 List<Method> list = refType.methodsByName(name);
198 Iterator<Method> iter = list.iterator();
199 while (iter.hasNext()) {
200 Method method = iter.next();
201 boolean isStatic = method.isStatic();
202 if (((kind == STATIC) && !isStatic) ||
203 ((kind == INSTANCE) && isStatic)) {
204 iter.remove();
205 }
206 }
207 return list;
208 }
209
210 static List<String> primitiveTypeNames = new ArrayList<String>();
211 static {
212 primitiveTypeNames.add("boolean");
213 primitiveTypeNames.add("byte");
214 primitiveTypeNames.add("char");
215 primitiveTypeNames.add("short");
216 primitiveTypeNames.add("int");
217 primitiveTypeNames.add("long");
218 primitiveTypeNames.add("float");
219 primitiveTypeNames.add("double");
220 }
221
222
223 static final int SAME = 0;
224 static final int ASSIGNABLE = 1;
225 static final int DIFFERENT = 2;
226 /*
227 * Return SAME, DIFFERENT or ASSIGNABLE.
228 * SAME means each arg type is the same as type of the corr. arg.
229 * ASSIGNABLE means that not all the pairs are the same, but
230 * for those that aren't, at least the argType is assignable
231 * from the type of the argument value.
232 * DIFFERENT means that in at least one pair, the
233 * argType is not assignable from the type of the argument value.
234 * IE, one is an Apple and the other is an Orange.
235 */
236 static int argumentsMatch(List<Type> argTypes, List<Value> arguments) {
237 if (argTypes.size() != arguments.size()) {
238 return DIFFERENT;
239 }
240
241 Iterator<Type> typeIter = argTypes.iterator();
242 Iterator<Value> valIter = arguments.iterator();
243 int result = SAME;
244
245 // If any pair aren't the same, change the
246 // result to ASSIGNABLE. If any pair aren't
247 // assignable, return DIFFERENT
248 while (typeIter.hasNext()) {
249 Type argType = typeIter.next();
250 Value value = valIter.next();
251 if (value == null) {
252 // Null values can be passed to any non-primitive argument
253 if (primitiveTypeNames.contains(argType.name())) {
254 return DIFFERENT;
255 }
256 // Else, we will assume that a null value
257 // exactly matches an object type.
258 }
259 if (!value.type().equals(argType)) {
260 if (isAssignableTo(value.type(), argType)) {
261 result = ASSIGNABLE;
262 } else {
263 return DIFFERENT;
264 }
265 }
266 }
267 return result;
268 }
269
270
271 // These is...AssignableTo methods are based on similar code in the JDI
272 // implementations of ClassType, ArrayType, and InterfaceType
273
274 static boolean isComponentAssignable(Type fromType, Type toType) {
275 if (fromType instanceof PrimitiveType) {
276 // Assignment of primitive arrays requires identical
277 // component types.
278 return fromType.equals(toType);
279 }
280 if (toType instanceof PrimitiveType) {
281 return false;
282 }
283 // Assignment of object arrays requires availability
284 // of widening conversion of component types
285 return isAssignableTo(fromType, toType);
286 }
287
288 static boolean isArrayAssignableTo(ArrayType fromType, Type toType) {
289 if (toType instanceof ArrayType) {
290 try {
291 Type toComponentType = ((ArrayType)toType).componentType();
292 return isComponentAssignable(fromType.componentType(), toComponentType);
293 } catch (ClassNotLoadedException e) {
294 // One or both component types has not yet been
295 // loaded => can't assign
296 return false;
297 }
298 }
299 if (toType instanceof InterfaceType) {
300 // Only valid InterfaceType assignee is Cloneable
301 return toType.name().equals("java.lang.Cloneable");
302 }
303 // Only valid ClassType assignee is Object
304 return toType.name().equals("java.lang.Object");
305 }
306
307 static boolean isAssignableTo(Type fromType, Type toType) {
308 if (fromType.equals(toType)) {
309 return true;
310 }
311
312 // If one is boolean, so must be the other.
313 if (fromType instanceof BooleanType) {
314 if (toType instanceof BooleanType) {
315 return true;
316 }
317 return false;
318 }
319 if (toType instanceof BooleanType) {
320 return false;
321 }
322
323 // Other primitive types are intermixable only with each other.
324 if (fromType instanceof PrimitiveType) {
325 if (toType instanceof PrimitiveType) {
326 return true;
327 }
328 return false;
329 }
330 if (toType instanceof PrimitiveType) {
331 return false;
332 }
333
334 // neither one is primitive.
335 if (fromType instanceof ArrayType) {
336 return isArrayAssignableTo((ArrayType)fromType, toType);
337 }
338 List<InterfaceType> interfaces;
339 if (fromType instanceof ClassType) {
340 ClassType superclazz = ((ClassType)fromType).superclass();
341 if ((superclazz != null) && isAssignableTo(superclazz, toType)) {
342 return true;
343 }
344 interfaces = ((ClassType)fromType).interfaces();
345 } else {
346 // fromType must be an InterfaceType
347 interfaces = ((InterfaceType)fromType).superinterfaces();
348 }
349 for (InterfaceType interfaze : interfaces) {
350 if (isAssignableTo(interfaze, toType)) {
351 return true;
352 }
353 }
354 return false;
355 }
356
357 static Method resolveOverload(List<Method> overloads,
358 List<Value> arguments)
359 throws ParseException {
360
361 // If there is only one method to call, we'll just choose
362 // that without looking at the args. If they aren't right
363 // the invoke will return a better error message than we
364 // could generate here.
365 if (overloads.size() == 1) {
366 return overloads.get(0);
367 }
368
369 // Resolving overloads is beyond the scope of this exercise.
370 // So, we will look for a method that matches exactly the
371 // types of the arguments. If we can't find one, then
372 // if there is exactly one method whose param types are assignable
373 // from the arg types, we will use that. Otherwise,
374 // it is an error. We won't guess which of multiple possible
375 // methods to call. And, since casts aren't implemented,
376 // the user can't use them to pick a particular overload to call.
377 // IE, the user is out of luck in this case.
378 Method retVal = null;
379 int assignableCount = 0;
380 for (Method mm : overloads) {
381 List<Type> argTypes;
382 try {
383 argTypes = mm.argumentTypes();
384 } catch (ClassNotLoadedException ee) {
385 // This probably won't happen for the
386 // method that we are really supposed to
387 // call.
388 continue;
389 }
390 int compare = argumentsMatch(argTypes, arguments);
391 if (compare == SAME) {
392 return mm;
393 }
394 if (compare == DIFFERENT) {
395 continue;
396 }
397 // Else, it is assignable. Remember it.
398 retVal = mm;
399 assignableCount++;
400 }
401
402 // At this point, we didn't find an exact match,
403 // but we found one for which the args are assignable.
404 //
405 if (retVal != null) {
406 if (assignableCount == 1) {
407 return retVal;
408 }
409 throw new ParseException("Arguments match multiple methods");
410 }
411 throw new ParseException("Arguments match no method");
412 }
413
414 private static class LValueLocal extends LValue {
415 final StackFrame frame;
416 final LocalVariable var;
417
418 LValueLocal(StackFrame frame, LocalVariable var) {
419 this.frame = frame;
420 this.var = var;
421 }
422
423 @Override
424 Value getValue() {
425 if (jdiValue == null) {
426 jdiValue = frame.getValue(var);
427 }
428 return jdiValue;
429 }
430
431 @Override
432 void setValue0(Value val) throws InvalidTypeException,
433 ClassNotLoadedException {
434 frame.setValue(var, val);
435 jdiValue = val;
436 }
437
438 @Override
439 void invokeWith(List<Value> arguments) throws ParseException {
440 throw new ParseException(var.name() + " is not a method");
441 }
442 }
443
444 private static class LValueInstanceMember extends LValue {
445 final ObjectReference obj;
446 final ThreadReference thread;
447 final Field matchingField;
448 final List<Method> overloads;
449 Method matchingMethod = null;
450 List<Value> methodArguments = null;
451
452 LValueInstanceMember(Value value,
453 String memberName,
454 ThreadReference thread) throws ParseException {
455 if (!(value instanceof ObjectReference)) {
456 throw new ParseException(
457 "Cannot access field of primitive type: " + value);
458 }
459 this.obj = (ObjectReference)value;
460 this.thread = thread;
461 ReferenceType refType = obj.referenceType();
462 /*
463 * Can't tell yet whether this LValue will be accessed as a
464 * field or method, so we keep track of all the possibilities
465 */
466 matchingField = LValue.fieldByName(refType, memberName,
467 LValue.INSTANCE);
468 overloads = LValue.methodsByName(refType, memberName,
469 LValue.INSTANCE);
470 if ((matchingField == null) && overloads.size() == 0) {
471 throw new ParseException("No instance field or method with the name "
472 + memberName + " in " + refType.name());
473 }
474 }
475
476 @Override
477 Value getValue() throws InvocationException, InvalidTypeException,
478 ClassNotLoadedException, IncompatibleThreadStateException,
479 ParseException {
480 if (jdiValue != null) {
481 return jdiValue;
482 }
483 if (matchingMethod == null) {
484 if (matchingField == null) {
485 throw new ParseException("No such field in " + obj.referenceType().name());
486 }
487 return jdiValue = obj.getValue(matchingField);
488 } else {
489 return jdiValue = obj.invokeMethod(thread, matchingMethod, methodArguments, 0);
490 }
491 }
492
493 @Override
494 void setValue0(Value val) throws ParseException,
495 InvalidTypeException,
496 ClassNotLoadedException {
497 if (matchingMethod != null) {
498 throw new ParseException("Cannot assign to a method invocation");
499 }
500 obj.setValue(matchingField, val);
501 jdiValue = val;
502 }
503
504 @Override
505 void invokeWith(List<Value> arguments) throws ParseException {
506 if (matchingMethod != null) {
507 throw new ParseException("Invalid consecutive invocations");
508 }
509 methodArguments = arguments;
510 matchingMethod = LValue.resolveOverload(overloads, arguments);
511 }
512 }
513
514 private static class LValueStaticMember extends LValue {
515 final ReferenceType refType;
516 final ThreadReference thread;
517 final Field matchingField;
518 final List<Method> overloads;
519 Method matchingMethod = null;
520 List<Value> methodArguments = null;
521
522 LValueStaticMember(ReferenceType refType,
523 String memberName,
524 ThreadReference thread) throws ParseException {
525 this.refType = refType;
526 this.thread = thread;
527 /*
528 * Can't tell yet whether this LValue will be accessed as a
529 * field or method, so we keep track of all the possibilities
530 */
531 matchingField = LValue.fieldByName(refType, memberName,
532 LValue.STATIC);
533 overloads = LValue.methodsByName(refType, memberName,
534 LValue.STATIC);
535 if ((matchingField == null) && overloads.size() == 0) {
536 throw new ParseException("No static field or method with the name "
537 + memberName + " in " + refType.name());
538 }
539 }
540
541 @Override
542 Value getValue() throws InvocationException, InvalidTypeException,
543 ClassNotLoadedException, IncompatibleThreadStateException,
544 ParseException {
545 if (jdiValue != null) {
546 return jdiValue;
547 }
548 if (matchingMethod == null) {
549 return jdiValue = refType.getValue(matchingField);
550 } else if (refType instanceof ClassType) {
551 ClassType clazz = (ClassType)refType;
552 return jdiValue = clazz.invokeMethod(thread, matchingMethod, methodArguments, 0);
553 } else {
554 throw new InvalidTypeException("Cannot invoke static method on " +
555 refType.name());
556 }
557 }
558
559 @Override
560 void setValue0(Value val)
561 throws ParseException, InvalidTypeException,
562 ClassNotLoadedException {
563 if (matchingMethod != null) {
564 throw new ParseException("Cannot assign to a method invocation");
565 }
566 if (!(refType instanceof ClassType)) {
567 throw new ParseException(
568 "Cannot set interface field: " + refType);
569 }
570 ((ClassType)refType).setValue(matchingField, val);
571 jdiValue = val;
572 }
573
574 @Override
575 void invokeWith(List<Value> arguments) throws ParseException {
576 if (matchingMethod != null) {
577 throw new ParseException("Invalid consecutive invocations");
578 }
579 methodArguments = arguments;
580 matchingMethod = LValue.resolveOverload(overloads, arguments);
581 }
582 }
583
584 private static class LValueArrayLength extends LValue {
585 /*
586 * Since one can code "int myLen = myArray.length;",
587 * one might expect that these JDI calls would get a Value
588 * object for the length of an array in the debugee:
589 * Field xxx = ArrayType.fieldByName("length")
590 * Value lenVal= ArrayReference.getValue(xxx)
591 *
592 * However, this doesn't work because the array length isn't
593 * really stored as a field, and can't be accessed as such
594 * via JDI. Instead, the arrayRef.length() method has to be
595 * used.
596 */
597 final ArrayReference arrayRef;
598 LValueArrayLength (ArrayReference value) {
599 this.arrayRef = value;
600 }
601
602 @Override
603 Value getValue() {
604 if (jdiValue == null) {
605 jdiValue = arrayRef.virtualMachine().mirrorOf(arrayRef.length());
606 }
607 return jdiValue;
608 }
609
610 @Override
611 void setValue0(Value value) throws ParseException {
612 throw new ParseException("Cannot set constant: " + value);
613 }
614
615 @Override
616 void invokeWith(List<Value> arguments) throws ParseException {
617 throw new ParseException("Array element is not a method");
618 }
619 }
620
621 private static class LValueArrayElement extends LValue {
622 final ArrayReference array;
623 final int index;
624
625 LValueArrayElement(Value value, int index) throws ParseException {
626 if (!(value instanceof ArrayReference)) {
627 throw new ParseException(
628 "Must be array type: " + value);
629 }
630 this.array = (ArrayReference)value;
631 this.index = index;
632 }
633
634 @Override
635 Value getValue() {
636 if (jdiValue == null) {
637 jdiValue = array.getValue(index);
638 }
639 return jdiValue;
640 }
641
642 @Override
643 void setValue0(Value val) throws InvalidTypeException,
644 ClassNotLoadedException {
645 array.setValue(index, val);
646 jdiValue = val;
647 }
648
649 @Override
650 void invokeWith(List<Value> arguments) throws ParseException {
651 throw new ParseException("Array element is not a method");
652 }
653 }
654
655 private static class LValueConstant extends LValue {
656 final Value value;
657
658 LValueConstant(Value value) {
659 this.value = value;
660 }
661
662 @Override
663 Value getValue() {
664 if (jdiValue == null) {
665 jdiValue = value;
666 }
667 return jdiValue;
668 }
669
670 @Override
671 void setValue0(Value val) throws ParseException {
672 throw new ParseException("Cannot set constant: " + value);
673 }
674
675 @Override
676 void invokeWith(List<Value> arguments) throws ParseException {
677 throw new ParseException("Constant is not a method");
678 }
679 }
680
681 static LValue make(VirtualMachine vm, boolean val) {
682 return new LValueConstant(vm.mirrorOf(val));
683 }
684
685 static LValue make(VirtualMachine vm, byte val) {
686 return new LValueConstant(vm.mirrorOf(val));
687 }
688
689 static LValue make(VirtualMachine vm, char val) {
690 return new LValueConstant(vm.mirrorOf(val));
691 }
692
693 static LValue make(VirtualMachine vm, short val) {
694 return new LValueConstant(vm.mirrorOf(val));
695 }
696
697 static LValue make(VirtualMachine vm, int val) {
698 return new LValueConstant(vm.mirrorOf(val));
699 }
700
701 static LValue make(VirtualMachine vm, long val) {
702 return new LValueConstant(vm.mirrorOf(val));
703 }
704
705 static LValue make(VirtualMachine vm, float val) {
706 return new LValueConstant(vm.mirrorOf(val));
707 }
708
709 static LValue make(VirtualMachine vm, double val) {
710 return new LValueConstant(vm.mirrorOf(val));
711 }
712
713 static LValue make(VirtualMachine vm, String val) throws ParseException {
714 return new LValueConstant(vm.mirrorOf(val));
715 }
716
717 static LValue makeBoolean(VirtualMachine vm, Token token) {
718 return make(vm, token.image.charAt(0) == 't');
719 }
720
721 static LValue makeCharacter(VirtualMachine vm, Token token) {
722 return make(vm, token.image.charAt(1));
723 }
724
725 static LValue makeFloat(VirtualMachine vm, Token token) {
726 return make(vm, Float.valueOf(token.image).floatValue());
727 }
728
729 static LValue makeDouble(VirtualMachine vm, Token token) {
730 return make(vm, Double.valueOf(token.image).doubleValue());
731 }
732
733 static LValue makeInteger(VirtualMachine vm, Token token) {
734 return make(vm, Integer.parseInt(token.image));
735 }
736
737 static LValue makeShort(VirtualMachine vm, Token token) {
738 return make(vm, Short.parseShort(token.image));
739 }
740
741 static LValue makeLong(VirtualMachine vm, Token token) {
742 return make(vm, Long.parseLong(token.image));
743 }
744
745 static LValue makeByte(VirtualMachine vm, Token token) {
746 return make(vm, Byte.parseByte(token.image));
747 }
748
749 static LValue makeString(VirtualMachine vm,
750 Token token) throws ParseException {
751 int len = token.image.length();
752 return make(vm, token.image.substring(1,len-1));
753 }
754
755 static LValue makeNull(VirtualMachine vm,
756 Token token) throws ParseException {
757 return new LValueConstant(null);
758 }
759
760 static LValue makeThisObject(VirtualMachine vm,
761 ExpressionParser.GetFrame frameGetter,
762 Token token) throws ParseException {
763 if (frameGetter == null) {
764 throw new ParseException("No current thread");
765 } else {
766 try {
767 StackFrame frame = frameGetter.get();
768 ObjectReference thisObject = frame.thisObject();
769
770 if (thisObject==null) {
771 throw new ParseException(
772 "No 'this'. In native or static method");
773 } else {
774 return new LValueConstant(thisObject);
775 }
776 } catch (IncompatibleThreadStateException exc) {
777 throw new ParseException("Thread not suspended");
778 }
779 }
780 }
781
782 static LValue makeNewObject(VirtualMachine vm,
783 ExpressionParser.GetFrame frameGetter,
784 String className, List<Value> arguments) throws ParseException {
785 List<ReferenceType> classes = vm.classesByName(className);
786 if (classes.size() == 0) {
787 throw new ParseException("No class named: " + className);
788 }
789
790 if (classes.size() > 1) {
791 throw new ParseException("More than one class named: " +
792 className);
793 }
794 ReferenceType refType = classes.get(0);
795
796
797 if (!(refType instanceof ClassType)) {
798 throw new ParseException("Cannot create instance of interface " +
799 className);
800 }
801
802 ClassType classType = (ClassType)refType;
803 List<Method> methods = new ArrayList<Method>(classType.methods()); // writable
804 Iterator<Method> iter = methods.iterator();
805 while (iter.hasNext()) {
806 Method method = iter.next();
807 if (!method.isConstructor()) {
808 iter.remove();
809 }
810 }
811 Method constructor = LValue.resolveOverload(methods, arguments);
812
813 ObjectReference newObject;
814 try {
815 ThreadReference thread = frameGetter.get().thread();
816 newObject = classType.newInstance(thread, constructor, arguments, 0);
817 } catch (InvocationException ie) {
818 throw new ParseException("Exception in " + className + " constructor: " +
819 ie.exception().referenceType().name());
820 } catch (IncompatibleThreadStateException exc) {
821 throw new ParseException("Thread not suspended");
822 } catch (Exception e) {
823 /*
824 * TO DO: Better error handling
825 */
826 throw new ParseException("Unable to create " + className + " instance");
827 }
828 return new LValueConstant(newObject);
829 }
830
831 private static LValue nFields(LValue lval,
832 StringTokenizer izer,
833 ThreadReference thread)
834 throws ParseException {
835 if (!izer.hasMoreTokens()) {
836 return lval;
837 } else {
838 return nFields(lval.memberLValue(izer.nextToken(), thread), izer, thread);
839 }
840 }
841
842 static LValue makeName(VirtualMachine vm,
843 ExpressionParser.GetFrame frameGetter,
844 String name) throws ParseException {
845 StringTokenizer izer = new StringTokenizer(name, ".");
846 String first = izer.nextToken();
847 // check local variables
848 if (frameGetter != null) {
849 try {
850 StackFrame frame = frameGetter.get();
851 ThreadReference thread = frame.thread();
852 LocalVariable var;
853 try {
854 var = frame.visibleVariableByName(first);
855 } catch (AbsentInformationException e) {
856 var = null;
857 }
858 if (var != null) {
859 return nFields(new LValueLocal(frame, var), izer, thread);
860 } else {
861 ObjectReference thisObject = frame.thisObject();
862 if (thisObject != null) {
863 // check if it is a field of 'this'
864 LValue thisLValue = new LValueConstant(thisObject);
865 LValue fv;
866 try {
867 fv = thisLValue.memberLValue(first, thread);
868 } catch (ParseException exc) {
869 fv = null;
870 }
871 if (fv != null) {
872 return nFields(fv, izer, thread);
873 }
874 }
875 }
876 // check for class name
877 while (izer.hasMoreTokens()) {
878 List<ReferenceType> classes = vm.classesByName(first);
879 if (classes.size() > 0) {
880 if (classes.size() > 1) {
881 throw new ParseException("More than one class named: " +
882 first);
883 } else {
884 ReferenceType refType = classes.get(0);
885 LValue lval = new LValueStaticMember(refType,
886 izer.nextToken(), thread);
887 return nFields(lval, izer, thread);
888 }
889 }
890 first = first + '.' + izer.nextToken();
891 }
892 } catch (IncompatibleThreadStateException exc) {
893 throw new ParseException("Thread not suspended");
894 }
895 }
896 throw new ParseException("Name unknown: " + name);
897 }
898
899 static String stringValue(LValue lval, ExpressionParser.GetFrame frameGetter
900 ) throws ParseException {
901 Value val = lval.getMassagedValue(frameGetter);
902 if (val == null) {
903 return "null";
904 }
905 if (val instanceof StringReference) {
906 return ((StringReference)val).value();
907 }
908 return val.toString(); // is this correct in all cases?
909 }
910
911 static LValue booleanOperation(VirtualMachine vm, Token token,
912 LValue rightL,
913 LValue leftL) throws ParseException {
914 String op = token.image;
915 Value right = rightL.interiorGetValue();
916 Value left = leftL.interiorGetValue();
917 if ( !(right instanceof PrimitiveValue) ||
918 !(left instanceof PrimitiveValue) ) {
919 if (op.equals("==")) {
920 return make(vm, right.equals(left));
921 } else if (op.equals("!=")) {
922 return make(vm, !right.equals(left));
923 } else {
924 throw new ParseException("Operands or '" + op +
925 "' must be primitive");
926 }
927 }
928 // can compare any numeric doubles
929 double rr = ((PrimitiveValue)right).doubleValue();
930 double ll = ((PrimitiveValue)left).doubleValue();
931 boolean res;
932 if (op.equals("<")) {
933 res = rr < ll;
934 } else if (op.equals(">")) {
935 res = rr > ll;
936 } else if (op.equals("<=")) {
937 res = rr <= ll;
938 } else if (op.equals(">=")) {
939 res = rr >= ll;
940 } else if (op.equals("==")) {
941 res = rr == ll;
942 } else if (op.equals("!=")) {
943 res = rr != ll;
944 } else {
945 throw new ParseException("Unknown operation: " + op);
946 }
947 return make(vm, res);
948 }
949
950 static LValue operation(VirtualMachine vm, Token token,
951 LValue rightL, LValue leftL,
952 ExpressionParser.GetFrame frameGetter
953 ) throws ParseException {
954 String op = token.image;
955 Value right = rightL.interiorGetValue();
956 Value left = leftL.interiorGetValue();
957 if ((right instanceof StringReference) ||
958 (left instanceof StringReference)) {
959 if (op.equals("+")) {
960 // If one is an ObjectRef, we will need to invoke
961 // toString on it, so we need the thread.
962 return make(vm, stringValue(rightL, frameGetter) +
963 stringValue(leftL, frameGetter));
964 }
965 }
966 if ((right instanceof ObjectReference) ||
967 (left instanceof ObjectReference)) {
968 if (op.equals("==")) {
969 return make(vm, right.equals(left));
970 } else if (op.equals("!=")) {
971 return make(vm, !right.equals(left));
972 } else {
973 throw new ParseException("Invalid operation '" +
974 op + "' on an Object");
975 }
976 }
977 if ((right instanceof BooleanValue) ||
978 (left instanceof BooleanValue)) {
979 throw new ParseException("Invalid operation '" +
980 op + "' on a Boolean");
981 }
982 // from here on, we know it is a integer kind of type
983 PrimitiveValue primRight = (PrimitiveValue)right;
984 PrimitiveValue primLeft = (PrimitiveValue)left;
985 if ((primRight instanceof DoubleValue) ||
986 (primLeft instanceof DoubleValue)) {
987 double rr = primRight.doubleValue();
988 double ll = primLeft.doubleValue();
989 double res;
990 if (op.equals("+")) {
991 res = rr + ll;
992 } else if (op.equals("-")) {
993 res = rr - ll;
994 } else if (op.equals("*")) {
995 res = rr * ll;
996 } else if (op.equals("/")) {
997 res = rr / ll;
998 } else {
999 throw new ParseException("Unknown operation: " + op);
1000 }
1001 return make(vm, res);
1002 }
1003 if ((primRight instanceof FloatValue) ||
1004 (primLeft instanceof FloatValue)) {
1005 float rr = primRight.floatValue();
1006 float ll = primLeft.floatValue();
1007 float res;
1008 if (op.equals("+")) {
1009 res = rr + ll;
1010 } else if (op.equals("-")) {
1011 res = rr - ll;
1012 } else if (op.equals("*")) {
1013 res = rr * ll;
1014 } else if (op.equals("/")) {
1015 res = rr / ll;
1016 } else {
1017 throw new ParseException("Unknown operation: " + op);
1018 }
1019 return make(vm, res);
1020 }
1021 if ((primRight instanceof LongValue) ||
1022 (primLeft instanceof LongValue)) {
1023 long rr = primRight.longValue();
1024 long ll = primLeft.longValue();
1025 long res;
1026 if (op.equals("+")) {
1027 res = rr + ll;
1028 } else if (op.equals("-")) {
1029 res = rr - ll;
1030 } else if (op.equals("*")) {
1031 res = rr * ll;
1032 } else if (op.equals("/")) {
1033 res = rr / ll;
1034 } else {
1035 throw new ParseException("Unknown operation: " + op);
1036 }
1037 return make(vm, res);
1038 } else {
1039 int rr = primRight.intValue();
1040 int ll = primLeft.intValue();
1041 int res;
1042 if (op.equals("+")) {
1043 res = rr + ll;
1044 } else if (op.equals("-")) {
1045 res = rr - ll;
1046 } else if (op.equals("*")) {
1047 res = rr * ll;
1048 } else if (op.equals("/")) {
1049 res = rr / ll;
1050 } else {
1051 throw new ParseException("Unknown operation: " + op);
1052 }
1053 return make(vm, res);
1054 }
1055 }
1056}