KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > Primitive


1 /*****************************************************************************
2  * *
3  * This file is part of the BeanShell Java Scripting distribution. *
4  * Documentation and updates may be found at http://www.beanshell.org/ *
5  * *
6  * Sun Public License Notice: *
7  * *
8  * The contents of this file are subject to the Sun Public License Version *
9  * 1.0 (the "License"); you may not use this file except in compliance with *
10  * the License. A copy of the License is available at http://www.sun.com *
11  * *
12  * The Original Code is BeanShell. The Initial Developer of the Original *
13  * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
14  * (C) 2000. All Rights Reserved. *
15  * *
16  * GNU Public License Notice: *
17  * *
18  * Alternatively, the contents of this file may be used under the terms of *
19  * the GNU Lesser General Public License (the "LGPL"), in which case the *
20  * provisions of LGPL are applicable instead of those above. If you wish to *
21  * allow use of your version of this file only under the terms of the LGPL *
22  * and not to allow others to use your version of this file under the SPL, *
23  * indicate your decision by deleting the provisions above and replace *
24  * them with the notice and other provisions required by the LGPL. If you *
25  * do not delete the provisions above, a recipient may use your version of *
26  * this file under either the SPL or the LGPL. *
27  * *
28  * Patrick Niemeyer (pat@pat.net) *
29  * Author of Learning Java, O'Reilly & Associates *
30  * http://www.pat.net/~pat/ *
31  * *
32  *****************************************************************************/

33
34
35 package bsh;
36
37 import java.util.Hashtable JavaDoc;
38
39 /**
40     Wrapper for primitive types in Bsh. This is package public because it
41     is used in the implementation of some bsh commands.
42
43     See the note in LHS.java about wrapping objects.
44 */

45 /*
46     Note: this class is final because we may test == Primitive.class in places.
47     If we need to change that search for those tests.
48 */

49 public final class Primitive implements ParserConstants, java.io.Serializable JavaDoc
50 {
51     /*
52     static Hashtable primitiveToWrapper = new Hashtable();
53     static Hashtable wrapperToPrimitive = new Hashtable();
54     static {
55         primitiveToWrapper.put( Boolean.TYPE, Boolean.class );
56         primitiveToWrapper.put( Byte.TYPE, Byte.class );
57         primitiveToWrapper.put( Short.TYPE, Short.class );
58         primitiveToWrapper.put( Character.TYPE, Character.class );
59         primitiveToWrapper.put( Integer.TYPE, Integer.class );
60         primitiveToWrapper.put( Long.TYPE, Long.class );
61         primitiveToWrapper.put( Float.TYPE, Float.class );
62         primitiveToWrapper.put( Double.TYPE, Double.class );
63         wrapperToPrimitive.put( Boolean.class, Boolean.TYPE );
64         wrapperToPrimitive.put( Byte.class, Byte.TYPE );
65         wrapperToPrimitive.put( Short.class, Short.TYPE );
66         wrapperToPrimitive.put( Character.class, Character.TYPE );
67         wrapperToPrimitive.put( Integer.class, Integer.TYPE );
68         wrapperToPrimitive.put( Long.class, Long.TYPE );
69         wrapperToPrimitive.put( Float.class, Float.TYPE );
70         wrapperToPrimitive.put( Double.class, Double.TYPE );
71     }
72     */

73     static Hashtable JavaDoc wrapperMap = new Hashtable JavaDoc();
74     static {
75         wrapperMap.put( Boolean.TYPE, Boolean JavaDoc.class );
76         wrapperMap.put( Byte.TYPE, Byte JavaDoc.class );
77         wrapperMap.put( Short.TYPE, Short JavaDoc.class );
78         wrapperMap.put( Character.TYPE, Character JavaDoc.class );
79         wrapperMap.put( Integer.TYPE, Integer JavaDoc.class );
80         wrapperMap.put( Long.TYPE, Long JavaDoc.class );
81         wrapperMap.put( Float.TYPE, Float JavaDoc.class );
82         wrapperMap.put( Double.TYPE, Double JavaDoc.class );
83         wrapperMap.put( Boolean JavaDoc.class, Boolean.TYPE );
84         wrapperMap.put( Byte JavaDoc.class, Byte.TYPE );
85         wrapperMap.put( Short JavaDoc.class, Short.TYPE );
86         wrapperMap.put( Character JavaDoc.class, Character.TYPE );
87         wrapperMap.put( Integer JavaDoc.class, Integer.TYPE );
88         wrapperMap.put( Long JavaDoc.class, Long.TYPE );
89         wrapperMap.put( Float JavaDoc.class, Float.TYPE );
90         wrapperMap.put( Double JavaDoc.class, Double.TYPE );
91     }
92
93     /** The primitive value stored in its java.lang wrapper class */
94     private Object JavaDoc value;
95
96     private static class Special implements java.io.Serializable JavaDoc
97     {
98         private Special() { }
99
100         public static final Special NULL_VALUE = new Special();
101         public static final Special VOID_TYPE = new Special();
102     }
103
104     /*
105         NULL means "no value".
106         This ia a placeholder for primitive null value.
107     */

108     public static final Primitive NULL = new Primitive(Special.NULL_VALUE);
109
110     /**
111         VOID means "no type".
112         Strictly speaking, this makes no sense here. But for practical
113         reasons we'll consider the lack of a type to be a special value.
114     */

115     public static final Primitive VOID = new Primitive(Special.VOID_TYPE);
116
117     // private to prevent invocation with param that isn't a primitive-wrapper
118
public Primitive( Object JavaDoc value )
119     {
120         if ( value == null )
121             throw new InterpreterError(
122                 "Use Primitve.NULL instead of Primitive(null)");
123
124         if ( value != Special.NULL_VALUE
125             && value != Special.VOID_TYPE &&
126             !isWrapperType( value.getClass() )
127         )
128             throw new InterpreterError( "Not a wrapper type: "+value);
129
130         this.value = value;
131     }
132
133     public Primitive(boolean value) { this(new Boolean JavaDoc(value)); }
134     public Primitive(byte value) { this(new Byte JavaDoc(value)); }
135     public Primitive(short value) { this(new Short JavaDoc(value)); }
136     public Primitive(char value) { this(new Character JavaDoc(value)); }
137     public Primitive(int value) { this(new Integer JavaDoc(value)); }
138     public Primitive(long value) { this(new Long JavaDoc(value)); }
139     public Primitive(float value) { this(new Float JavaDoc(value)); }
140     public Primitive(double value) { this(new Double JavaDoc(value)); }
141
142     /**
143         Return the primitive value stored in its java.lang wrapper class
144     */

145     public Object JavaDoc getValue()
146     {
147         if ( value == Special.NULL_VALUE )
148             return null;
149         else
150         if ( value == Special.VOID_TYPE )
151                 throw new InterpreterError("attempt to unwrap void type");
152         else
153             return value;
154     }
155
156     public String JavaDoc toString()
157     {
158         if(value == Special.NULL_VALUE)
159             return "null";
160         else if(value == Special.VOID_TYPE)
161             return "void";
162         else
163             return value.toString();
164     }
165
166     /**
167         Get the corresponding Java primitive TYPE class for this Primitive.
168         @return the primitive TYPE class type of the value or Void.TYPE for
169         Primitive.VOID or null value for type of Primitive.NULL
170     */

171     public Class JavaDoc getType()
172     {
173         if ( this == Primitive.VOID )
174             return Void.TYPE;
175
176         // NULL return null as type... we currently use null type to indicate
177
// loose typing throughout bsh.
178
if ( this == Primitive.NULL )
179             return null;
180
181         return unboxType( value.getClass() );
182     }
183
184     /**
185         Perform a binary operation on two Primitives or wrapper types.
186         If both original args were Primitives return a Primitive result
187         else it was mixed (wrapper/primitive) return the wrapper type.
188         The exception is for boolean operations where we will return the
189         primitive type either way.
190     */

191     public static Object JavaDoc binaryOperation(
192         Object JavaDoc obj1, Object JavaDoc obj2, int kind)
193         throws UtilEvalError
194     {
195         // special primitive types
196
if ( obj1 == NULL || obj2 == NULL )
197             throw new UtilEvalError(
198                 "Null value or 'null' literal in binary operation");
199         if ( obj1 == VOID || obj2 == VOID )
200             throw new UtilEvalError(
201             "Undefined variable, class, or 'void' literal in binary operation");
202
203         // keep track of the original types
204
Class JavaDoc lhsOrgType = obj1.getClass();
205         Class JavaDoc rhsOrgType = obj2.getClass();
206
207         // Unwrap primitives
208
if ( obj1 instanceof Primitive )
209             obj1 = ((Primitive)obj1).getValue();
210         if ( obj2 instanceof Primitive )
211             obj2 = ((Primitive)obj2).getValue();
212
213         Object JavaDoc[] operands = promotePrimitives(obj1, obj2);
214         Object JavaDoc lhs = operands[0];
215         Object JavaDoc rhs = operands[1];
216
217         if(lhs.getClass() != rhs.getClass())
218             throw new UtilEvalError("Type mismatch in operator. "
219             + lhs.getClass() + " cannot be used with " + rhs.getClass() );
220
221         Object JavaDoc result;
222         try {
223             result = binaryOperationImpl( lhs, rhs, kind );
224         } catch ( ArithmeticException JavaDoc e ) {
225             throw new UtilTargetError( "Arithemetic Exception in binary op", e);
226         }
227
228         // If both original args were Primitives return a Primitive result
229
// else it was mixed (wrapper/primitive) return the wrapper type
230
// Exception is for boolean result, return the primitive
231
if ( (lhsOrgType == Primitive.class && rhsOrgType == Primitive.class)
232             || result instanceof Boolean JavaDoc
233         )
234             return new Primitive( result );
235         else
236             return result;
237     }
238
239     static Object JavaDoc binaryOperationImpl( Object JavaDoc lhs, Object JavaDoc rhs, int kind )
240         throws UtilEvalError
241     {
242         if(lhs instanceof Boolean JavaDoc)
243             return booleanBinaryOperation((Boolean JavaDoc)lhs, (Boolean JavaDoc)rhs, kind);
244         else if(lhs instanceof Integer JavaDoc)
245             return intBinaryOperation( (Integer JavaDoc)lhs, (Integer JavaDoc)rhs, kind );
246         else if(lhs instanceof Long JavaDoc)
247             return longBinaryOperation((Long JavaDoc)lhs, (Long JavaDoc)rhs, kind);
248         else if(lhs instanceof Float JavaDoc)
249             return floatBinaryOperation((Float JavaDoc)lhs, (Float JavaDoc)rhs, kind);
250         else if(lhs instanceof Double JavaDoc)
251             return doubleBinaryOperation( (Double JavaDoc)lhs, (Double JavaDoc)rhs, kind);
252         else
253             throw new UtilEvalError("Invalid types in binary operator" );
254     }
255
256     static Boolean JavaDoc booleanBinaryOperation(Boolean JavaDoc B1, Boolean JavaDoc B2, int kind)
257     {
258         boolean lhs = B1.booleanValue();
259         boolean rhs = B2.booleanValue();
260
261         switch(kind)
262         {
263             case EQ:
264                 return new Boolean JavaDoc(lhs == rhs);
265
266             case NE:
267                 return new Boolean JavaDoc(lhs != rhs);
268
269             case BOOL_OR:
270             case BOOL_ORX:
271                 return new Boolean JavaDoc( lhs || rhs );
272
273             case BOOL_AND:
274             case BOOL_ANDX:
275                 return new Boolean JavaDoc( lhs && rhs );
276
277             default:
278                 throw new InterpreterError("unimplemented binary operator");
279         }
280     }
281
282     // returns Object covering both Long and Boolean return types
283
static Object JavaDoc longBinaryOperation(Long JavaDoc L1, Long JavaDoc L2, int kind)
284     {
285         long lhs = L1.longValue();
286         long rhs = L2.longValue();
287
288         switch(kind)
289         {
290             // boolean
291
case LT:
292             case LTX:
293                 return new Boolean JavaDoc(lhs < rhs);
294
295             case GT:
296             case GTX:
297                 return new Boolean JavaDoc(lhs > rhs);
298
299             case EQ:
300                 return new Boolean JavaDoc(lhs == rhs);
301
302             case LE:
303             case LEX:
304                 return new Boolean JavaDoc(lhs <= rhs);
305
306             case GE:
307             case GEX:
308                 return new Boolean JavaDoc(lhs >= rhs);
309
310             case NE:
311                 return new Boolean JavaDoc(lhs != rhs);
312
313             // arithmetic
314
case PLUS:
315                 return new Long JavaDoc(lhs + rhs);
316
317             case MINUS:
318                 return new Long JavaDoc(lhs - rhs);
319
320             case STAR:
321                 return new Long JavaDoc(lhs * rhs);
322
323             case SLASH:
324                 return new Long JavaDoc(lhs / rhs);
325
326             case MOD:
327                 return new Long JavaDoc(lhs % rhs);
328
329             // bitwise
330
case LSHIFT:
331             case LSHIFTX:
332                 return new Long JavaDoc(lhs << rhs);
333
334             case RSIGNEDSHIFT:
335             case RSIGNEDSHIFTX:
336                 return new Long JavaDoc(lhs >> rhs);
337
338             case RUNSIGNEDSHIFT:
339             case RUNSIGNEDSHIFTX:
340                 return new Long JavaDoc(lhs >>> rhs);
341
342             case BIT_AND:
343             case BIT_ANDX:
344                 return new Long JavaDoc(lhs & rhs);
345
346             case BIT_OR:
347             case BIT_ORX:
348                 return new Long JavaDoc(lhs | rhs);
349
350             case XOR:
351                 return new Long JavaDoc(lhs ^ rhs);
352
353             default:
354                 throw new InterpreterError(
355                     "Unimplemented binary long operator");
356         }
357     }
358
359     // returns Object covering both Integer and Boolean return types
360
static Object JavaDoc intBinaryOperation(Integer JavaDoc I1, Integer JavaDoc I2, int kind)
361     {
362         int lhs = I1.intValue();
363         int rhs = I2.intValue();
364
365         switch(kind)
366         {
367             // boolean
368
case LT:
369             case LTX:
370                 return new Boolean JavaDoc(lhs < rhs);
371
372             case GT:
373             case GTX:
374                 return new Boolean JavaDoc(lhs > rhs);
375
376             case EQ:
377                 return new Boolean JavaDoc(lhs == rhs);
378
379             case LE:
380             case LEX:
381                 return new Boolean JavaDoc(lhs <= rhs);
382
383             case GE:
384             case GEX:
385                 return new Boolean JavaDoc(lhs >= rhs);
386
387             case NE:
388                 return new Boolean JavaDoc(lhs != rhs);
389
390             // arithmetic
391
case PLUS:
392                 return new Integer JavaDoc(lhs + rhs);
393
394             case MINUS:
395                 return new Integer JavaDoc(lhs - rhs);
396
397             case STAR:
398                 return new Integer JavaDoc(lhs * rhs);
399
400             case SLASH:
401                 return new Integer JavaDoc(lhs / rhs);
402
403             case MOD:
404                 return new Integer JavaDoc(lhs % rhs);
405
406             // bitwise
407
case LSHIFT:
408             case LSHIFTX:
409                 return new Integer JavaDoc(lhs << rhs);
410
411             case RSIGNEDSHIFT:
412             case RSIGNEDSHIFTX:
413                 return new Integer JavaDoc(lhs >> rhs);
414
415             case RUNSIGNEDSHIFT:
416             case RUNSIGNEDSHIFTX:
417                 return new Integer JavaDoc(lhs >>> rhs);
418
419             case BIT_AND:
420             case BIT_ANDX:
421                 return new Integer JavaDoc(lhs & rhs);
422
423             case BIT_OR:
424             case BIT_ORX:
425                 return new Integer JavaDoc(lhs | rhs);
426
427             case XOR:
428                 return new Integer JavaDoc(lhs ^ rhs);
429
430             default:
431                 throw new InterpreterError(
432                     "Unimplemented binary integer operator");
433         }
434     }
435
436     // returns Object covering both Double and Boolean return types
437
static Object JavaDoc doubleBinaryOperation(Double JavaDoc D1, Double JavaDoc D2, int kind)
438         throws UtilEvalError
439     {
440         double lhs = D1.doubleValue();
441         double rhs = D2.doubleValue();
442
443         switch(kind)
444         {
445             // boolean
446
case LT:
447             case LTX:
448                 return new Boolean JavaDoc(lhs < rhs);
449
450             case GT:
451             case GTX:
452                 return new Boolean JavaDoc(lhs > rhs);
453
454             case EQ:
455                 return new Boolean JavaDoc(lhs == rhs);
456
457             case LE:
458             case LEX:
459                 return new Boolean JavaDoc(lhs <= rhs);
460
461             case GE:
462             case GEX:
463                 return new Boolean JavaDoc(lhs >= rhs);
464
465             case NE:
466                 return new Boolean JavaDoc(lhs != rhs);
467
468             // arithmetic
469
case PLUS:
470                 return new Double JavaDoc(lhs + rhs);
471
472             case MINUS:
473                 return new Double JavaDoc(lhs - rhs);
474
475             case STAR:
476                 return new Double JavaDoc(lhs * rhs);
477
478             case SLASH:
479                 return new Double JavaDoc(lhs / rhs);
480
481             case MOD:
482                 return new Double JavaDoc(lhs % rhs);
483
484             // can't shift floating-point values
485
case LSHIFT:
486             case LSHIFTX:
487             case RSIGNEDSHIFT:
488             case RSIGNEDSHIFTX:
489             case RUNSIGNEDSHIFT:
490             case RUNSIGNEDSHIFTX:
491                 throw new UtilEvalError("Can't shift doubles");
492
493             default:
494                 throw new InterpreterError(
495                     "Unimplemented binary double operator");
496         }
497     }
498     // returns Object covering both Long and Boolean return types
499
static Object JavaDoc floatBinaryOperation(Float JavaDoc F1, Float JavaDoc F2, int kind)
500         throws UtilEvalError
501     {
502         float lhs = F1.floatValue();
503         float rhs = F2.floatValue();
504
505         switch(kind)
506         {
507             // boolean
508
case LT:
509             case LTX:
510                 return new Boolean JavaDoc(lhs < rhs);
511
512             case GT:
513             case GTX:
514                 return new Boolean JavaDoc(lhs > rhs);
515
516             case EQ:
517                 return new Boolean JavaDoc(lhs == rhs);
518
519             case LE:
520             case LEX:
521                 return new Boolean JavaDoc(lhs <= rhs);
522
523             case GE:
524             case GEX:
525                 return new Boolean JavaDoc(lhs >= rhs);
526
527             case NE:
528                 return new Boolean JavaDoc(lhs != rhs);
529
530             // arithmetic
531
case PLUS:
532                 return new Float JavaDoc(lhs + rhs);
533
534             case MINUS:
535                 return new Float JavaDoc(lhs - rhs);
536
537             case STAR:
538                 return new Float JavaDoc(lhs * rhs);
539
540             case SLASH:
541                 return new Float JavaDoc(lhs / rhs);
542
543             case MOD:
544                 return new Float JavaDoc(lhs % rhs);
545
546             // can't shift floats
547
case LSHIFT:
548             case LSHIFTX:
549             case RSIGNEDSHIFT:
550             case RSIGNEDSHIFTX:
551             case RUNSIGNEDSHIFT:
552             case RUNSIGNEDSHIFTX:
553                 throw new UtilEvalError("Can't shift floats ");
554
555             default:
556                 throw new InterpreterError(
557                     "Unimplemented binary float operator");
558         }
559     }
560
561     /**
562         Promote primitive wrapper type to to Integer wrapper type
563     */

564     static Object JavaDoc promoteToInteger(Object JavaDoc wrapper )
565     {
566         if(wrapper instanceof Character JavaDoc)
567             return new Integer JavaDoc(((Character JavaDoc)wrapper).charValue());
568         else if((wrapper instanceof Byte JavaDoc) || (wrapper instanceof Short JavaDoc))
569             return new Integer JavaDoc(((Number JavaDoc)wrapper).intValue());
570
571         return wrapper;
572     }
573
574     /**
575         Promote the pair of primitives to the maximum type of the two.
576         e.g. [int,long]->[long,long]
577     */

578     static Object JavaDoc[] promotePrimitives(Object JavaDoc lhs, Object JavaDoc rhs)
579     {
580         lhs = promoteToInteger(lhs);
581         rhs = promoteToInteger(rhs);
582
583         if((lhs instanceof Number JavaDoc) && (rhs instanceof Number JavaDoc))
584         {
585             Number JavaDoc lnum = (Number JavaDoc)lhs;
586             Number JavaDoc rnum = (Number JavaDoc)rhs;
587
588             boolean b;
589
590             if((b = (lnum instanceof Double JavaDoc)) || (rnum instanceof Double JavaDoc))
591             {
592                 if(b)
593                     rhs = new Double JavaDoc(rnum.doubleValue());
594                 else
595                     lhs = new Double JavaDoc(lnum.doubleValue());
596             }
597             else if((b = (lnum instanceof Float JavaDoc)) || (rnum instanceof Float JavaDoc))
598             {
599                 if(b)
600                     rhs = new Float JavaDoc(rnum.floatValue());
601                 else
602                     lhs = new Float JavaDoc(lnum.floatValue());
603             }
604             else if((b = (lnum instanceof Long JavaDoc)) || (rnum instanceof Long JavaDoc))
605             {
606                 if(b)
607                     rhs = new Long JavaDoc(rnum.longValue());
608                 else
609                     lhs = new Long JavaDoc(lnum.longValue());
610             }
611         }
612
613         return new Object JavaDoc[] { lhs, rhs };
614     }
615
616     public static Primitive unaryOperation(Primitive val, int kind)
617         throws UtilEvalError
618     {
619         if (val == NULL)
620             throw new UtilEvalError(
621                 "illegal use of null object or 'null' literal");
622         if (val == VOID)
623             throw new UtilEvalError(
624                 "illegal use of undefined object or 'void' literal");
625
626         Class JavaDoc operandType = val.getType();
627         Object JavaDoc operand = promoteToInteger(val.getValue());
628
629         if ( operand instanceof Boolean JavaDoc )
630             return new Primitive(booleanUnaryOperation((Boolean JavaDoc)operand, kind));
631         else if(operand instanceof Integer JavaDoc)
632         {
633             int result = intUnaryOperation((Integer JavaDoc)operand, kind);
634
635             // ++ and -- must be cast back the original type
636
if(kind == INCR || kind == DECR)
637             {
638                 if(operandType == Byte.TYPE)
639                     return new Primitive((byte)result);
640                 if(operandType == Short.TYPE)
641                     return new Primitive((short)result);
642                 if(operandType == Character.TYPE)
643                     return new Primitive((char)result);
644             }
645
646             return new Primitive(result);
647         }
648         else if(operand instanceof Long JavaDoc)
649             return new Primitive(longUnaryOperation((Long JavaDoc)operand, kind));
650         else if(operand instanceof Float JavaDoc)
651             return new Primitive(floatUnaryOperation((Float JavaDoc)operand, kind));
652         else if(operand instanceof Double JavaDoc)
653             return new Primitive(doubleUnaryOperation((Double JavaDoc)operand, kind));
654         else
655             throw new InterpreterError(
656                 "An error occurred. Please call technical support.");
657     }
658
659     static boolean booleanUnaryOperation(Boolean JavaDoc B, int kind)
660         throws UtilEvalError
661     {
662         boolean operand = B.booleanValue();
663         switch(kind)
664         {
665             case BANG:
666                 return !operand;
667             default:
668                 throw new UtilEvalError("Operator inappropriate for boolean");
669         }
670     }
671
672     static int intUnaryOperation(Integer JavaDoc I, int kind)
673     {
674         int operand = I.intValue();
675
676         switch(kind)
677         {
678             case PLUS:
679                 return operand;
680             case MINUS:
681                 return -operand;
682             case TILDE:
683                 return ~operand;
684             case INCR:
685                 return operand + 1;
686             case DECR:
687                 return operand - 1;
688             default:
689                 throw new InterpreterError("bad integer unaryOperation");
690         }
691     }
692
693     static long longUnaryOperation(Long JavaDoc L, int kind)
694     {
695         long operand = L.longValue();
696
697         switch(kind)
698         {
699             case PLUS:
700                 return operand;
701             case MINUS:
702                 return -operand;
703             case TILDE:
704                 return ~operand;
705             case INCR:
706                 return operand + 1;
707             case DECR:
708                 return operand - 1;
709             default:
710                 throw new InterpreterError("bad long unaryOperation");
711         }
712     }
713
714     static float floatUnaryOperation(Float JavaDoc F, int kind)
715     {
716         float operand = F.floatValue();
717
718         switch(kind)
719         {
720             case PLUS:
721                 return operand;
722             case MINUS:
723                 return -operand;
724             default:
725                 throw new InterpreterError("bad float unaryOperation");
726         }
727     }
728
729     static double doubleUnaryOperation(Double JavaDoc D, int kind)
730     {
731         double operand = D.doubleValue();
732
733         switch(kind)
734         {
735             case PLUS:
736                 return operand;
737             case MINUS:
738                 return -operand;
739             default:
740                 throw new InterpreterError("bad double unaryOperation");
741         }
742     }
743
744     public int intValue() throws UtilEvalError
745     {
746         if(value instanceof Number JavaDoc)
747             return((Number JavaDoc)value).intValue();
748         else
749             throw new UtilEvalError("Primitive not a number");
750     }
751
752     public boolean booleanValue() throws UtilEvalError
753     {
754         if(value instanceof Boolean JavaDoc)
755             return((Boolean JavaDoc)value).booleanValue();
756         else
757             throw new UtilEvalError("Primitive not a boolean");
758     }
759
760     /**
761         Determine if this primitive is a numeric type.
762         i.e. not boolean, null, or void (but including char)
763     */

764     public boolean isNumber() {
765         return ( !(value instanceof Boolean JavaDoc)
766             && !(this == NULL) && !(this == VOID) );
767     }
768
769     public Number JavaDoc numberValue() throws UtilEvalError
770     {
771         Object JavaDoc value = this.value;
772
773         // Promote character to Number type for these purposes
774
if (value instanceof Character JavaDoc)
775             value = new Integer JavaDoc(((Character JavaDoc)value).charValue());
776
777         if (value instanceof Number JavaDoc)
778             return (Number JavaDoc)value;
779         else
780             throw new UtilEvalError("Primitive not a number");
781     }
782
783     /**
784         Primitives compare equal with other Primitives containing an equal
785         wrapped value.
786     */

787     public boolean equals( Object JavaDoc obj )
788     {
789         if ( obj instanceof Primitive )
790             return ((Primitive)obj).value.equals( this.value );
791         else
792             return false;
793     }
794
795     /**
796         The hash of the Primitive is tied to the hash of the wrapped value but
797         shifted so that they are not the same.
798     */

799     public int hashCode()
800     {
801         return this.value.hashCode() * 21; // arbitrary
802
}
803
804     /**
805         Unwrap primitive values and map voids to nulls.
806         Non Primitive types remain unchanged.
807
808         @param obj object type which may be bsh.Primitive
809         @return corresponding "normal" Java type, "unwrapping"
810             any bsh.Primitive types to their wrapper types.
811     */

812     public static Object JavaDoc unwrap( Object JavaDoc obj )
813     {
814         // map voids to nulls for the outside world
815
if (obj == Primitive.VOID)
816             return null;
817
818         // unwrap primitives
819
if (obj instanceof Primitive)
820             return((Primitive)obj).getValue();
821         else
822             return obj;
823     }
824
825     /*
826         Unwrap Primitive wrappers to their java.lang wrapper values.
827         e.g. Primitive(42) becomes Integer(42)
828         @see #unwrap( Object )
829     */

830     public static Object JavaDoc [] unwrap( Object JavaDoc[] args )
831     {
832         Object JavaDoc [] oa = new Object JavaDoc[ args.length ];
833         for(int i=0; i<args.length; i++)
834             oa[i] = unwrap( args[i] );
835         return oa;
836     }
837
838     /*
839     */

840     public static Object JavaDoc [] wrap( Object JavaDoc[] args, Class JavaDoc [] paramTypes )
841     {
842         if ( args == null )
843             return null;
844
845         Object JavaDoc [] oa = new Object JavaDoc[ args.length ];
846         for(int i=0; i<args.length; i++)
847             oa[i] = wrap( args[i], paramTypes[i] );
848         return oa;
849     }
850
851     /**
852         Wrap primitive values (as indicated by type param) and nulls in the
853         Primitive class. Values not primitive or null are left unchanged.
854         Primitive values are represented by their wrapped values in param value.
855         <p/>
856         The value null is mapped to Primitive.NULL.
857         Any value specified with type Void.TYPE is mapped to Primitive.VOID.
858     */

859     public static Object JavaDoc wrap(
860         Object JavaDoc value, Class JavaDoc type )
861     {
862         if ( type == Void.TYPE )
863             return Primitive.VOID;
864
865         if ( value == null )
866             return Primitive.NULL;
867
868         if ( type.isPrimitive() )
869             return new Primitive( value );
870
871         return value;
872     }
873
874
875     /**
876         Get the appropriate default value per JLS 4.5.4
877     */

878     public static Primitive getDefaultValue( Class JavaDoc type )
879     {
880         if ( type == null || !type.isPrimitive() )
881             return Primitive.NULL;
882         if ( type == Boolean.TYPE )
883             return new Primitive( false );
884
885         // non boolean primitive, get appropriate flavor of zero
886
try {
887             return new Primitive((int)0).castToType( type, Types.CAST );
888         } catch ( UtilEvalError e ) {
889             throw new InterpreterError( "bad cast" );
890         }
891     }
892
893     /**
894         Get the corresponding java.lang wrapper class for the primitive TYPE
895         class.
896         e.g. Integer.TYPE -> Integer.class
897     */

898     public static Class JavaDoc boxType( Class JavaDoc primitiveType )
899     {
900         Class JavaDoc c = (Class JavaDoc)wrapperMap.get( primitiveType );
901         if ( c != null )
902             return c;
903         throw new InterpreterError(
904             "Not a primitive type: "+ primitiveType );
905     }
906
907     /**
908         Get the corresponding primitive TYPE class for the java.lang wrapper
909         class type.
910         e.g. Integer.class -> Integer.TYPE
911     */

912     public static Class JavaDoc unboxType( Class JavaDoc wrapperType )
913     {
914         Class JavaDoc c = (Class JavaDoc)wrapperMap.get( wrapperType );
915         if ( c != null )
916             return c;
917         throw new InterpreterError(
918             "Not a primitive wrapper type: "+wrapperType );
919     }
920
921     /**
922         Cast this bsh.Primitive value to a new bsh.Primitive value
923         This is usually a numeric type cast. Other cases include:
924             A boolean can be cast to boolen
925             null can be cast to any object type and remains null
926             Attempting to cast a void causes an exception
927         @param toType is the java object or primitive TYPE class
928     */

929     public Primitive castToType( Class JavaDoc toType, int operation )
930         throws UtilEvalError
931     {
932         return castPrimitive(
933             toType, getType()/*fromType*/, this/*fromValue*/,
934             false/*checkOnly*/, operation );
935     }
936
937     /*
938         Cast or check a cast of a primitive type to another type.
939         Normally both types are primitive (e.g. numeric), but a null value
940         (no type) may be cast to any type.
941         <p/>
942
943         @param toType is the target type of the cast. It is normally a
944         java primitive TYPE, but in the case of a null cast can be any object
945         type.
946
947         @param fromType is the java primitive TYPE type of the primitive to be
948         cast or null, to indicate that the fromValue was null or void.
949
950         @param fromValue is, optionally, the value to be converted. If
951         checkOnly is true fromValue must be null. If checkOnly is false,
952         fromValue must be non-null (Primitive.NULL is of course valid).
953     */

954     static Primitive castPrimitive(
955         Class JavaDoc toType, Class JavaDoc fromType, Primitive fromValue,
956         boolean checkOnly, int operation )
957         throws UtilEvalError
958     {
959         /*
960             Lots of preconditions checked here...
961             Once things are running smoothly we might comment these out
962             (That's what assertions are for).
963         */

964         if ( checkOnly && fromValue != null )
965             throw new InterpreterError("bad cast param 1");
966         if ( !checkOnly && fromValue == null )
967             throw new InterpreterError("bad cast param 2");
968         if ( fromType != null && !fromType.isPrimitive() )
969             throw new InterpreterError("bad fromType:" +fromType);
970         if ( fromValue == Primitive.NULL && fromType != null )
971             throw new InterpreterError("inconsistent args 1");
972         if ( fromValue == Primitive.VOID && fromType != Void.TYPE )
973             throw new InterpreterError("inconsistent args 2");
974
975         // can't cast void to anything
976
if ( fromType == Void.TYPE )
977             if ( checkOnly )
978                 return Types.INVALID_CAST;
979             else
980                 throw Types.castError( Reflect.normalizeClassName(toType),
981                     "void value", operation );
982
983         // unwrap Primitive fromValue to its wrapper value, etc.
984
Object JavaDoc value = null;
985         if ( fromValue != null )
986             value = fromValue.getValue();
987
988         if ( toType.isPrimitive() )
989         {
990             // Trying to cast null to primitive type?
991
if ( fromType == null )
992                 if ( checkOnly )
993                     return Types.INVALID_CAST;
994                 else
995                     throw Types.castError(
996                         "primitive type:" + toType, "Null value", operation );
997
998             // fall through
999
} else
1000        {
1001            // Trying to cast primitive to an object type
1002
// Primitive.NULL can be cast to any object type
1003
if ( fromType == null )
1004                return checkOnly ? Types.VALID_CAST :
1005                    Primitive.NULL;
1006
1007            if ( checkOnly )
1008                return Types.INVALID_CAST;
1009            else
1010                throw Types.castError(
1011                        "object type:" + toType, "primitive value", operation);
1012        }
1013
1014        // can only cast boolean to boolean
1015
if ( fromType == Boolean.TYPE )
1016        {
1017            if ( toType != Boolean.TYPE )
1018                if ( checkOnly )
1019                    return Types.INVALID_CAST;
1020                else
1021                    throw Types.castError( toType, fromType, operation );
1022
1023            return checkOnly ? Types.VALID_CAST :
1024                fromValue;
1025        }
1026
1027        // Do numeric cast
1028

1029        // Only allow legal Java assignment unless we're a CAST operation
1030
if ( operation == Types.ASSIGNMENT
1031            && !Types.isJavaAssignable( toType, fromType )
1032        ) {
1033            if ( checkOnly )
1034                return Types.INVALID_CAST;
1035            else
1036                throw Types.castError( toType, fromType, operation );
1037        }
1038
1039        return checkOnly ? Types.VALID_CAST :
1040            new Primitive( castWrapper(toType, value) );
1041    }
1042
1043    public static boolean isWrapperType( Class JavaDoc type )
1044    {
1045        return wrapperMap.get( type ) != null && !type.isPrimitive();
1046    }
1047
1048    /**
1049        Cast a primitive value represented by its java.lang wrapper type to the
1050        specified java.lang wrapper type. e.g. Byte(5) to Integer(5) or
1051        Integer(5) to Byte(5)
1052        @param toType is the java TYPE type
1053        @param value is the value in java.lang wrapper.
1054        value may not be null.
1055    */

1056    static Object JavaDoc castWrapper(
1057        Class JavaDoc toType, Object JavaDoc value )
1058    {
1059        if ( !toType.isPrimitive() )
1060            throw new InterpreterError("invalid type in castWrapper: "+toType);
1061        if ( value == null )
1062            throw new InterpreterError("null value in castWrapper, guard");
1063        if ( value instanceof Boolean JavaDoc )
1064        {
1065            if ( toType != Boolean.TYPE )
1066                throw new InterpreterError("bad wrapper cast of boolean");
1067            else
1068                return value;
1069        }
1070
1071        // first promote char to Number type to avoid duplicating code
1072
if ( value instanceof Character JavaDoc )
1073            value = new Integer JavaDoc(((Character JavaDoc)value).charValue());
1074
1075        if ( !(value instanceof Number JavaDoc) )
1076            throw new InterpreterError("bad type in cast");
1077
1078        Number JavaDoc number = (Number JavaDoc)value;
1079
1080        if (toType == Byte.TYPE)
1081            return new Byte JavaDoc(number.byteValue());
1082        if (toType == Short.TYPE)
1083            return new Short JavaDoc(number.shortValue());
1084        if (toType == Character.TYPE)
1085            return new Character JavaDoc((char)number.intValue());
1086        if (toType == Integer.TYPE)
1087            return new Integer JavaDoc(number.intValue());
1088        if (toType == Long.TYPE)
1089            return new Long JavaDoc(number.longValue());
1090        if (toType == Float.TYPE)
1091            return new Float JavaDoc(number.floatValue());
1092        if (toType == Double.TYPE)
1093            return new Double JavaDoc(number.doubleValue());
1094
1095        throw new InterpreterError("error in wrapper cast");
1096    }
1097
1098}
1099
Popular Tags