Initial Commit
[packages] / xemacs-packages / jde / java / src / jde / debugger / expr / LValue.java
1 /*
2  * @(#)LValue.java      1.17 99/05/21
3  *
4  * Copyright (c) 1997-1999 by Sun Microsystems, Inc. All Rights Reserved.
5  * 
6  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
7  * modify and redistribute this software in source and binary code form,
8  * provided that i) this copyright notice and license appear on all copies of
9  * the software; and ii) Licensee does not utilize the software in a manner
10  * which is disparaging to Sun.
11  * 
12  * This software is provided "AS IS," without a warranty of any kind. ALL
13  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
14  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
15  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
16  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
17  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
18  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
19  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
20  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
21  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
22  * POSSIBILITY OF SUCH DAMAGES.
23  * 
24  * This software is not designed or intended for use in on-line control of
25  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
26  * the design, construction, operation or maintenance of any nuclear
27  * facility. Licensee represents and warrants that it will not use or
28  * redistribute the Software for such purposes.
29  */
30
31 package jde.debugger.expr;
32
33 import com.sun.jdi.*;
34 import java.util.*;
35
36 abstract class LValue {
37
38     abstract Value getValue() throws InvocationException, 
39                                      IncompatibleThreadStateException,
40                                      InvalidTypeException,
41                                      ClassNotLoadedException;
42
43     abstract void setValue0(Value value) 
44                    throws ParseException, InvalidTypeException, 
45                           ClassNotLoadedException;
46
47     abstract void invokeWith(List arguments) throws ParseException;
48
49     void setValue(Value value) throws ParseException {
50         try {
51             setValue0(value);
52         } catch (InvalidTypeException exc) {
53             throw new ParseException(
54                 "Attempt to set value of incorrect type" +
55                 exc);
56         } catch (ClassNotLoadedException exc) {
57             throw new ParseException(
58                 "Attempt to set value before " + exc.className() + " was loaded" +
59                 exc);
60         }
61     }        
62
63     void setValue(LValue lval) throws ParseException {
64         setValue(lval.interiorGetValue());
65     }
66
67     LValue memberLValue(ExpressionParser.GetFrame frameGetter, 
68                         String fieldName) throws ParseException {
69         try {
70             return memberLValue(fieldName, frameGetter.get().thread());
71         } catch (IncompatibleThreadStateException exc) {
72             throw new ParseException("Thread not suspended");
73         }
74     }
75
76     LValue memberLValue(String fieldName, ThreadReference thread) throws ParseException {
77         return new LValueInstanceMember(interiorGetValue(), fieldName, thread);
78     }
79
80     Value interiorGetValue() throws ParseException {
81         Value value;
82         try {
83             value = getValue();
84         } catch (InvocationException e) {
85             throw new ParseException("Unable to complete expression. Exception " +
86                                      e.exception() + " thrown");
87         } catch (IncompatibleThreadStateException itse) {
88             throw new ParseException("Unable to complete expression. Thread " +
89                                      "not suspended for method invoke");
90         } catch (InvalidTypeException ite) {
91             throw new ParseException("Unable to complete expression. Method " +
92                                      "argument type mismatch");
93         } catch (ClassNotLoadedException tnle) {
94             throw new ParseException("Unable to complete expression. Method " +
95                                      "argument type " + tnle.className() + 
96                                      " not yet loaded");
97         }
98 //        if (value == null) {
99 //            throw new ParseException("Cannot invoke a void method within an expression");
100 //        }
101         return value;
102     }
103
104     LValue arrayElementLValue(LValue lval) throws ParseException {
105         Value indexValue = lval.interiorGetValue();
106         int index;
107         if ( (indexValue instanceof IntegerValue) ||
108              (indexValue instanceof ShortValue) ||
109              (indexValue instanceof ByteValue) ||
110              (indexValue instanceof CharValue) ) {
111             index = ((PrimitiveValue)indexValue).intValue();
112         } else {
113             throw new ParseException("Array index must be a integer type");
114         }
115         return new LValueArrayElement(interiorGetValue(), index);
116     }
117
118     public String toString() {
119         try {
120             return interiorGetValue().toString();
121         } catch (ParseException e) {
122             return "<Parse Exception>";
123         }
124     }
125
126     static final int STATIC = 0;
127     static final int INSTANCE = 1;
128
129     static Field fieldByName(ReferenceType refType, String name, int kind) {
130         /*
131          * TO DO: Note that this currently fails to find superclass
132          * or implemented interface fields. This is due to a temporary
133          * limititation of RefType.fieldByName. Once that method is 
134          * fixed, superclass fields will be found.
135          */
136         Field field = refType.fieldByName(name);
137         if (field != null) {
138             boolean isStatic = field.isStatic();
139             if (((kind == STATIC) && !isStatic) || 
140                 ((kind == INSTANCE) && isStatic)) {
141                 field = null;
142             }
143         }
144 /***
145         System.err.println("fieldByName: " + refType.name() + " " +
146                                              name + " " +
147                                              kind + " " + 
148                                              (field != null));
149 ***/
150         return field;
151     }
152
153     static List methodsByName(ReferenceType refType, String name, int kind) {
154         List list = refType.methodsByName(name);
155         Iterator iter = list.iterator();
156         while (iter.hasNext()) {
157             Method method = (Method)iter.next();
158             boolean isStatic = method.isStatic();
159             if (((kind == STATIC) && !isStatic) || 
160                 ((kind == INSTANCE) && isStatic)) {
161                 iter.remove();
162             }
163         }
164         return list;
165     }
166
167     static List primitiveTypeNames = new ArrayList();
168     static {
169         primitiveTypeNames.add("boolean");
170         primitiveTypeNames.add("byte");
171         primitiveTypeNames.add("char");
172         primitiveTypeNames.add("short");
173         primitiveTypeNames.add("int");
174         primitiveTypeNames.add("long");
175         primitiveTypeNames.add("float");
176         primitiveTypeNames.add("double");
177     }
178
179     static boolean argumentsMatch(List argNames, List arguments) {
180         if (argNames.size() != arguments.size()) {
181             return false;
182         }
183         Iterator nameIter = argNames.iterator();
184         Iterator valIter = arguments.iterator();
185         while (nameIter.hasNext()) {
186             String argTypeName = (String)nameIter.next();
187             Value value = (Value)valIter.next();
188             /*
189              * For now we require exact match
190              */
191             if (value == null) {
192                 // Null values can be passed to any non-primitive argument
193                 if (primitiveTypeNames.contains(argTypeName)) {
194                     return false;
195                 }
196             } else if (!argTypeName.equals(value.type().name())) {
197                 return false;
198             }
199         }
200         return true;
201     }
202
203     static Method resolveOverload(List overloads, List arguments) 
204                                        throws ParseException {
205         Iterator iter = overloads.iterator();
206         while (iter.hasNext()) {
207             Method method = (Method)iter.next();
208             List argNames = method.argumentTypeNames();
209             if (argumentsMatch(argNames, arguments)) {
210                 return method;
211             }
212         }
213         throw new ParseException("Arguments match no method");
214     }
215
216     private static class LValueLocal extends LValue {
217         final StackFrame frame;
218         final LocalVariable var;
219
220         LValueLocal(StackFrame frame, LocalVariable var) {
221             this.frame = frame;
222             this.var = var;
223         }
224         
225         Value getValue() {
226             return frame.getValue(var);
227         }
228
229         void setValue0(Value val) throws InvalidTypeException, 
230                                          ClassNotLoadedException {
231             frame.setValue(var, val);
232         }
233
234         void invokeWith(List arguments) throws ParseException {
235             throw new ParseException(var.name() + " is not a method");
236         }
237     }
238
239     private static class LValueInstanceMember extends LValue {
240         final ObjectReference obj;
241         final ThreadReference thread;
242         final Field matchingField;
243         final List overloads;
244         Method matchingMethod = null;
245         List methodArguments = null;
246
247         LValueInstanceMember(Value value, 
248                             String memberName, 
249                             ThreadReference thread) throws ParseException {
250             if (!(value instanceof ObjectReference)) {
251                 throw new ParseException(
252                        "Cannot access field of primitive type: " + value);
253             }
254             this.obj = (ObjectReference)value;
255             this.thread = thread;
256             ReferenceType refType = obj.referenceType();
257             /*
258              * Can't tell yet whether this LValue will be accessed as a
259              * field or method, so we keep track of all the possibilities
260              */
261             matchingField = LValue.fieldByName(refType, memberName, 
262                                                LValue.INSTANCE);
263             overloads = LValue.methodsByName(refType, memberName,
264                                               LValue.INSTANCE);
265             if ((matchingField == null) && overloads.size() == 0) {
266                 throw new ParseException("No instance field or method with the name "
267                                + memberName + " in " + refType.name());
268             }
269         }
270         
271         Value getValue() throws InvocationException, InvalidTypeException,
272                                 ClassNotLoadedException, IncompatibleThreadStateException {
273             if (matchingMethod == null) {
274                 return obj.getValue(matchingField);
275             } else {
276                 return obj.invokeMethod(thread, matchingMethod, methodArguments, 0);
277             }
278         }
279
280         void setValue0(Value val) throws ParseException, 
281                                          InvalidTypeException,
282                                          ClassNotLoadedException {
283             if (matchingMethod != null) {
284                 throw new ParseException("Cannot assign to a method invocation");
285             }
286             obj.setValue(matchingField, val);
287         }
288
289         void invokeWith(List arguments) throws ParseException {
290             if (matchingMethod != null) {
291                 throw new ParseException("Invalid consecutive invocations");
292             }
293             methodArguments = arguments;
294             matchingMethod = LValue.resolveOverload(overloads, arguments);
295         }
296     }
297
298     private static class LValueStaticMember extends LValue {
299         final ReferenceType refType;
300         final ThreadReference thread;
301         final Field matchingField;
302         final List overloads;
303         Method matchingMethod = null;
304         List methodArguments = null;
305
306         LValueStaticMember(ReferenceType refType, 
307                           String memberName,
308                           ThreadReference thread) throws ParseException {
309             this.refType = refType;
310             this.thread = thread;
311             /*
312              * Can't tell yet whether this LValue will be accessed as a
313              * field or method, so we keep track of all the possibilities
314              */
315             matchingField = LValue.fieldByName(refType, memberName, 
316                                                LValue.STATIC);
317             overloads = LValue.methodsByName(refType, memberName,
318                                               LValue.STATIC);
319             if ((matchingField == null) && overloads.size() == 0) {
320                 throw new ParseException("No static field or method with the name "
321                                + memberName + " in " + refType.name());
322             }
323         }
324         
325         Value getValue() throws InvocationException, InvalidTypeException,
326                                 ClassNotLoadedException, IncompatibleThreadStateException {
327             if (matchingMethod == null) {
328                 return refType.getValue(matchingField);
329             } else if (refType instanceof ClassType) {
330                 ClassType clazz = (ClassType)refType;
331                 return clazz.invokeMethod(thread, matchingMethod, methodArguments, 0);
332             } else {
333                 throw new InvalidTypeException("Cannot invoke static method on " +
334                                          refType.name());
335             }
336         }
337
338         void setValue0(Value val) 
339                            throws ParseException, InvalidTypeException,
340                                   ClassNotLoadedException {
341             if (matchingMethod != null) {
342                 throw new ParseException("Cannot assign to a method invocation");
343             }
344             if (!(refType instanceof ClassType)) {
345                 throw new ParseException(
346                        "Cannot set interface field: " + refType);
347             }
348             ((ClassType)refType).setValue(matchingField, val);
349         }
350
351         void invokeWith(List arguments) throws ParseException {
352             if (matchingMethod != null) {
353                 throw new ParseException("Invalid consecutive invocations");
354             }
355             methodArguments = arguments;
356             matchingMethod = LValue.resolveOverload(overloads, arguments);
357         }
358     }
359
360     private static class LValueArrayElement extends LValue {
361         final ArrayReference array;
362         final int index;
363
364         LValueArrayElement(Value value, int index) throws ParseException {
365             if (!(value instanceof ArrayReference)) {
366                 throw new ParseException(
367                        "Must be array type: " + value);
368             }
369             this.array = (ArrayReference)value;
370             this.index = index;
371         }
372         
373         Value getValue() {
374             return array.getValue(index);
375         }
376
377         void setValue0(Value val) throws InvalidTypeException, 
378                                          ClassNotLoadedException  {
379             array.setValue(index, val);
380         }
381
382         void invokeWith(List arguments) throws ParseException {
383             throw new ParseException("Array element is not a method");
384         }
385     }
386
387     private static class LValueConstant extends LValue {
388         final Value value;
389
390         LValueConstant(Value value) {
391             this.value = value;
392         }
393         
394         Value getValue() {
395             return value;
396         }
397
398         void setValue0(Value val) throws ParseException {
399             throw new ParseException("Cannot set constant: " + value);
400         }
401
402         void invokeWith(List arguments) throws ParseException {
403             throw new ParseException("Constant is not a method");
404         }
405     }
406
407     static LValue make(VirtualMachine vm, boolean val) {
408         return new LValueConstant(vm.mirrorOf(val));
409     }
410
411     static LValue make(VirtualMachine vm, byte val) {
412         return new LValueConstant(vm.mirrorOf(val));
413     }
414
415     static LValue make(VirtualMachine vm, char val) {
416         return new LValueConstant(vm.mirrorOf(val));
417     }
418
419     static LValue make(VirtualMachine vm, short val) {
420         return new LValueConstant(vm.mirrorOf(val));
421     }
422
423     static LValue make(VirtualMachine vm, int val) {
424         return new LValueConstant(vm.mirrorOf(val));
425     }
426
427     static LValue make(VirtualMachine vm, long val) {
428         return new LValueConstant(vm.mirrorOf(val));
429     }
430
431     static LValue make(VirtualMachine vm, float val) {
432         return new LValueConstant(vm.mirrorOf(val));
433     }
434
435     static LValue make(VirtualMachine vm, double val) {
436         return new LValueConstant(vm.mirrorOf(val));
437     }
438
439     static LValue make(VirtualMachine vm, String val) throws ParseException {
440         return new LValueConstant(vm.mirrorOf(val));
441     }
442
443     static LValue makeBoolean(VirtualMachine vm, Token token) {
444         return make(vm, token.image.charAt(0) == 't');
445     }
446
447     static LValue makeCharacter(VirtualMachine vm, Token token) {
448         return make(vm, token.image.charAt(1));
449     }
450
451     static LValue makeFloat(VirtualMachine vm, Token token) {
452         return make(vm, Float.valueOf(token.image).floatValue());
453     }
454
455     static LValue makeDouble(VirtualMachine vm, Token token) {
456         return make(vm, Double.valueOf(token.image).doubleValue());
457     }
458
459     static LValue makeInteger(VirtualMachine vm, Token token) {
460         return make(vm, Integer.parseInt(token.image));
461     }
462
463     static LValue makeShort(VirtualMachine vm, Token token) {
464         return make(vm, Short.parseShort(token.image));
465     }
466
467     static LValue makeLong(VirtualMachine vm, Token token) {
468         return make(vm, Long.parseLong(token.image));
469     }
470
471     static LValue makeByte(VirtualMachine vm, Token token) {
472         return make(vm, Byte.parseByte(token.image));
473     }
474
475     static LValue makeString(VirtualMachine vm, 
476                              Token token) throws ParseException {
477         int len = token.image.length();
478         return make(vm, token.image.substring(1,len-1));
479     }
480
481     static LValue makeNull(VirtualMachine vm, 
482                            Token token) throws ParseException {
483         return new LValueConstant(null);
484     }
485
486     static LValue makeThisObject(VirtualMachine vm, 
487                                  ExpressionParser.GetFrame frameGetter, 
488                                  Token token) throws ParseException {
489         if (frameGetter == null) {
490             throw new ParseException("No current thread");
491         } else {
492             try {
493                 StackFrame frame = frameGetter.get();
494                 ObjectReference thisObject = frame.thisObject();
495                 if (thisObject == null) {
496                     throw new ParseException(
497                         "No 'this'.  In native or static method");
498                 } else {
499                     return new LValueConstant(thisObject);
500                 }
501             } catch (IncompatibleThreadStateException exc) {
502                 throw new ParseException("Thread not suspended");
503             }
504         }
505     }
506
507     static LValue makeNewObject(VirtualMachine vm, 
508                                  ExpressionParser.GetFrame frameGetter, 
509                                 String className, List arguments) throws ParseException {
510         List classes = vm.classesByName(className);
511         if (classes.size() == 0) {
512             throw new ParseException("No class named: " + className);
513         }
514
515         if (classes.size() > 1) {
516             throw new ParseException("More than one class named: " +
517                                      className);
518         }
519         ReferenceType refType = (ReferenceType)classes.get(0);
520
521
522         if (!(refType instanceof ClassType)) {
523             throw new ParseException("Cannot create instance of interface " +
524                                      className);
525         }
526
527         ClassType classType = (ClassType)refType;
528         List methods = new ArrayList(classType.methods()); // writable
529         Iterator iter = methods.iterator();
530         while (iter.hasNext()) {
531             Method method = (Method)iter.next();
532             if (!method.isConstructor()) {
533                 iter.remove();
534             }
535         }
536         Method constructor = LValue.resolveOverload(methods, arguments);
537
538         ObjectReference newObject;
539         try {
540             ThreadReference thread = frameGetter.get().thread();
541             newObject = classType.newInstance(thread, constructor, arguments, 0);
542         } catch (InvocationException ie) {
543             throw new ParseException("Exception in " + className + " constructor: " + 
544                                      ie.exception().referenceType().name());
545         } catch (IncompatibleThreadStateException exc) {
546             throw new ParseException("Thread not suspended");
547         } catch (Exception e) {
548             /*
549              * TO DO: Better error handling
550              */
551             throw new ParseException("Unable to create " + className + " instance");
552         }
553         return new LValueConstant(newObject);
554     }
555
556     private static LValue nFields(LValue lval, 
557                                   StringTokenizer izer,
558                                   ThreadReference thread) 
559                                           throws ParseException {
560         if (!izer.hasMoreTokens()) {
561             return lval;
562         } else {
563             return nFields(lval.memberLValue(izer.nextToken(), thread), izer, thread);
564         }                    
565     }
566
567     static LValue makeName(VirtualMachine vm, 
568                            ExpressionParser.GetFrame frameGetter, 
569                            String name) throws ParseException {
570         StringTokenizer izer = new StringTokenizer(name, ".");
571         String first = izer.nextToken();
572
573         // check local variables
574         if (frameGetter != null) {
575             try {
576                 StackFrame frame = frameGetter.get();
577                 ThreadReference thread = frame.thread();
578                 LocalVariable var;
579                 try {
580                     var = frame.visibleVariableByName(first);
581                 } catch (AbsentInformationException e) {
582                     var = null;
583                 }
584                 if (var != null) {
585                     return nFields(new LValueLocal(frame, var), izer, thread);
586                 } else {
587                     ObjectReference thisObject = frame.thisObject();
588                     if (thisObject != null) {
589                         // check if it is a field of 'this'
590                         LValue thisLValue = new LValueConstant(thisObject);
591                         LValue fv;
592                         try {
593                             fv = thisLValue.memberLValue(first, thread);
594                         } catch (ParseException exc) {
595                             fv = null;
596                         }
597                         if (fv != null) {
598                             return nFields(fv, izer, thread);
599                         }
600                     }
601                 }
602                 // check for class name
603                 while (izer.hasMoreTokens()) {
604                     List classes = vm.classesByName(first);
605                     if (classes.size() > 0) {
606                         if (classes.size() > 1) {
607                             throw new ParseException("More than one class named: " +
608                                                      first);
609                         } else {
610                             ReferenceType refType = (ReferenceType)classes.get(0);
611                             LValue lval = new LValueStaticMember(refType, 
612                                                             izer.nextToken(), thread);
613                             return nFields(lval, izer, thread);
614                         }
615                     }
616                     first = first + '.' + izer.nextToken();
617                 }
618             } catch (IncompatibleThreadStateException exc) {
619                 throw new ParseException("Thread not suspended");
620             }
621         }
622         throw new ParseException("Name unknown: " + name);
623     }
624
625     static String stringValue(Value val) {
626         if (val instanceof StringReference) {
627             return ((StringReference)val).value();
628         } else if (val instanceof ObjectReference) {
629             return ((ObjectReference)val).toString();  // TODO
630         } else if (val == null) {
631             return "null";  
632         } else {
633             return val.toString();  // TODO not correct in all cases
634         }
635     }
636
637     static LValue booleanOperation(VirtualMachine vm, Token token, 
638                             LValue rightL, 
639                             LValue leftL) throws ParseException {
640         String op = token.image;
641         Value right = rightL.interiorGetValue();
642         Value left = leftL.interiorGetValue();
643         if ( !(right instanceof PrimitiveValue) || 
644              !(left instanceof PrimitiveValue) ) {
645             if (op.equals("==")) {
646                 return make(vm, right.equals(left));
647             } else if (op.equals("!=")) {
648                 return make(vm, !right.equals(left));
649             } else {
650                 throw new ParseException("Operands or '" + op + 
651                                      "' must be primitive");
652             }
653         }
654         // can compare any numeric doubles
655         double rr = ((PrimitiveValue)right).doubleValue();
656         double ll = ((PrimitiveValue)left).doubleValue();
657         boolean res;
658         if (op.equals("<")) {
659             res = rr < ll;
660         } else if (op.equals(">")) {
661             res = rr > ll;
662         } else if (op.equals("<=")) {
663             res = rr <= ll;
664         } else if (op.equals(">=")) {
665             res = rr >= ll;
666         } else if (op.equals("==")) {
667             res = rr == ll;
668         } else if (op.equals("!=")) {
669             res = rr != ll;
670         } else {
671             throw new ParseException("Unknown operation: " + op);
672         }
673         return make(vm, res);
674     }                                
675
676     static LValue operation(VirtualMachine vm, Token token, 
677                             LValue rightL, 
678                             LValue leftL) throws ParseException {
679         String op = token.image;
680         Value right = rightL.interiorGetValue();
681         Value left = leftL.interiorGetValue();
682         if ((right instanceof StringReference) ||
683                               (left instanceof StringReference)) {
684             if (op.equals("+")) {
685                 return make(vm, stringValue(right) + stringValue(left));
686             }
687         }
688         if ((right instanceof ObjectReference) ||
689                               (left instanceof ObjectReference)) {
690             if (op.equals("==")) {
691                 return make(vm, right.equals(left));
692             } else if (op.equals("!=")) {
693                 return make(vm, !right.equals(left));
694             } else {
695                 throw new ParseException("Invalid operation '" +
696                                          op + "' on an Object");
697             }
698         }
699         if ((right instanceof BooleanValue) ||
700                               (left instanceof BooleanValue)) {
701             throw new ParseException("Invalid operation '" +
702                                      op + "' on a Boolean");
703         }
704         // from here on, we know it is a integer kind of type
705         PrimitiveValue primRight = (PrimitiveValue)right;
706         PrimitiveValue primLeft = (PrimitiveValue)left;
707         if ((primRight instanceof DoubleValue) ||
708                               (primLeft instanceof DoubleValue)) {
709             double rr = primRight.doubleValue();
710             double ll = primLeft.doubleValue();
711             double res;
712             if (op.equals("+")) {
713                 res = rr + ll;
714             } else if (op.equals("-")) {
715                 res = rr - ll;
716             } else if (op.equals("*")) {
717                 res = rr * ll;
718             } else if (op.equals("/")) {
719                 res = rr / ll;
720             } else {
721                 throw new ParseException("Unknown operation: " + op);
722             }
723             return make(vm, res);
724         }
725         if ((primRight instanceof FloatValue) ||
726                               (primLeft instanceof FloatValue)) {
727             float rr = primRight.floatValue();
728             float ll = primLeft.floatValue();
729             float res;
730             if (op.equals("+")) {
731                 res = rr + ll;
732             } else if (op.equals("-")) {
733                 res = rr - ll;
734             } else if (op.equals("*")) {
735                 res = rr * ll;
736             } else if (op.equals("/")) {
737                 res = rr / ll;
738             } else {
739                 throw new ParseException("Unknown operation: " + op);
740             }
741             return make(vm, res);
742         }
743         if ((primRight instanceof LongValue) ||
744                               (primLeft instanceof LongValue)) {
745             long rr = primRight.longValue();
746             long ll = primLeft.longValue();
747             long res;
748             if (op.equals("+")) {
749                 res = rr + ll;
750             } else if (op.equals("-")) {
751                 res = rr - ll;
752             } else if (op.equals("*")) {
753                 res = rr * ll;
754             } else if (op.equals("/")) {
755                 res = rr / ll;
756             } else {
757                 throw new ParseException("Unknown operation: " + op);
758             }
759             return make(vm, res);
760         } else {
761             int rr = primRight.intValue();
762             int ll = primLeft.intValue();
763             int res;
764             if (op.equals("+")) {
765                 res = rr + ll;
766             } else if (op.equals("-")) {
767                 res = rr - ll;
768             } else if (op.equals("*")) {
769                 res = rr * ll;
770             } else if (op.equals("/")) {
771                 res = rr / ll;
772             } else {
773                 throw new ParseException("Unknown operation: " + op);
774             }
775             return make(vm, res);
776         }
777     }   
778 }