0001: /*****************************************************************************
0002: * *
0003: * This file is part of the BeanShell Java Scripting distribution. *
0004: * Documentation and updates may be found at http://www.beanshell.org/ *
0005: * *
0006: * Sun Public License Notice: *
0007: * *
0008: * The contents of this file are subject to the Sun Public License Version *
0009: * 1.0 (the "License"); you may not use this file except in compliance with *
0010: * the License. A copy of the License is available at http://www.sun.com *
0011: * *
0012: * The Original Code is BeanShell. The Initial Developer of the Original *
0013: * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
0014: * (C) 2000. All Rights Reserved. *
0015: * *
0016: * GNU Public License Notice: *
0017: * *
0018: * Alternatively, the contents of this file may be used under the terms of *
0019: * the GNU Lesser General Public License (the "LGPL"), in which case the *
0020: * provisions of LGPL are applicable instead of those above. If you wish to *
0021: * allow use of your version of this file only under the terms of the LGPL *
0022: * and not to allow others to use your version of this file under the SPL, *
0023: * indicate your decision by deleting the provisions above and replace *
0024: * them with the notice and other provisions required by the LGPL. If you *
0025: * do not delete the provisions above, a recipient may use your version of *
0026: * this file under either the SPL or the LGPL. *
0027: * *
0028: * Patrick Niemeyer (pat@pat.net) *
0029: * Author of Learning Java, O'Reilly & Associates *
0030: * http://www.pat.net/~pat/ *
0031: * *
0032: *****************************************************************************/package org.gjt.sp.jedit.bsh;
0033:
0034: import java.util.Hashtable;
0035:
0036: /**
0037: Wrapper for primitive types in Bsh. This is package public because it
0038: is used in the implementation of some bsh commands.
0039:
0040: See the note in LHS.java about wrapping objects.
0041: */
0042: /*
0043: Note: this class is final because we may test == Primitive.class in places.
0044: If we need to change that search for those tests.
0045: */
0046: public final class Primitive implements ParserConstants,
0047: java.io.Serializable {
0048: /*
0049: static Hashtable primitiveToWrapper = new Hashtable();
0050: static Hashtable wrapperToPrimitive = new Hashtable();
0051: static {
0052: primitiveToWrapper.put( Boolean.TYPE, Boolean.class );
0053: primitiveToWrapper.put( Byte.TYPE, Byte.class );
0054: primitiveToWrapper.put( Short.TYPE, Short.class );
0055: primitiveToWrapper.put( Character.TYPE, Character.class );
0056: primitiveToWrapper.put( Integer.TYPE, Integer.class );
0057: primitiveToWrapper.put( Long.TYPE, Long.class );
0058: primitiveToWrapper.put( Float.TYPE, Float.class );
0059: primitiveToWrapper.put( Double.TYPE, Double.class );
0060: wrapperToPrimitive.put( Boolean.class, Boolean.TYPE );
0061: wrapperToPrimitive.put( Byte.class, Byte.TYPE );
0062: wrapperToPrimitive.put( Short.class, Short.TYPE );
0063: wrapperToPrimitive.put( Character.class, Character.TYPE );
0064: wrapperToPrimitive.put( Integer.class, Integer.TYPE );
0065: wrapperToPrimitive.put( Long.class, Long.TYPE );
0066: wrapperToPrimitive.put( Float.class, Float.TYPE );
0067: wrapperToPrimitive.put( Double.class, Double.TYPE );
0068: }
0069: */
0070: static Hashtable wrapperMap = new Hashtable();
0071: static {
0072: wrapperMap.put(Boolean.TYPE, Boolean.class);
0073: wrapperMap.put(Byte.TYPE, Byte.class);
0074: wrapperMap.put(Short.TYPE, Short.class);
0075: wrapperMap.put(Character.TYPE, Character.class);
0076: wrapperMap.put(Integer.TYPE, Integer.class);
0077: wrapperMap.put(Long.TYPE, Long.class);
0078: wrapperMap.put(Float.TYPE, Float.class);
0079: wrapperMap.put(Double.TYPE, Double.class);
0080: wrapperMap.put(Boolean.class, Boolean.TYPE);
0081: wrapperMap.put(Byte.class, Byte.TYPE);
0082: wrapperMap.put(Short.class, Short.TYPE);
0083: wrapperMap.put(Character.class, Character.TYPE);
0084: wrapperMap.put(Integer.class, Integer.TYPE);
0085: wrapperMap.put(Long.class, Long.TYPE);
0086: wrapperMap.put(Float.class, Float.TYPE);
0087: wrapperMap.put(Double.class, Double.TYPE);
0088: }
0089:
0090: /** The primitive value stored in its java.lang wrapper class */
0091: private Object value;
0092:
0093: private static class Special implements java.io.Serializable {
0094: private Special() {
0095: }
0096:
0097: public static final Special NULL_VALUE = new Special();
0098: public static final Special VOID_TYPE = new Special();
0099: }
0100:
0101: /*
0102: NULL means "no value".
0103: This ia a placeholder for primitive null value.
0104: */
0105: public static final Primitive NULL = new Primitive(
0106: Special.NULL_VALUE);
0107:
0108: /**
0109: VOID means "no type".
0110: Strictly speaking, this makes no sense here. But for practical
0111: reasons we'll consider the lack of a type to be a special value.
0112: */
0113: public static final Primitive VOID = new Primitive(
0114: Special.VOID_TYPE);
0115:
0116: // private to prevent invocation with param that isn't a primitive-wrapper
0117: public Primitive(Object value) {
0118: if (value == null)
0119: throw new InterpreterError(
0120: "Use Primitve.NULL instead of Primitive(null)");
0121:
0122: if (value != Special.NULL_VALUE && value != Special.VOID_TYPE
0123: && !isWrapperType(value.getClass()))
0124: throw new InterpreterError("Not a wrapper type: " + value);
0125:
0126: this .value = value;
0127: }
0128:
0129: public Primitive(boolean value) {
0130: this (new Boolean(value));
0131: }
0132:
0133: public Primitive(byte value) {
0134: this (new Byte(value));
0135: }
0136:
0137: public Primitive(short value) {
0138: this (new Short(value));
0139: }
0140:
0141: public Primitive(char value) {
0142: this (new Character(value));
0143: }
0144:
0145: public Primitive(int value) {
0146: this (new Integer(value));
0147: }
0148:
0149: public Primitive(long value) {
0150: this (new Long(value));
0151: }
0152:
0153: public Primitive(float value) {
0154: this (new Float(value));
0155: }
0156:
0157: public Primitive(double value) {
0158: this (new Double(value));
0159: }
0160:
0161: /**
0162: Return the primitive value stored in its java.lang wrapper class
0163: */
0164: public Object getValue() {
0165: if (value == Special.NULL_VALUE)
0166: return null;
0167: else if (value == Special.VOID_TYPE)
0168: throw new InterpreterError("attempt to unwrap void type");
0169: else
0170: return value;
0171: }
0172:
0173: public String toString() {
0174: if (value == Special.NULL_VALUE)
0175: return "null";
0176: else if (value == Special.VOID_TYPE)
0177: return "void";
0178: else
0179: return value.toString();
0180: }
0181:
0182: /**
0183: Get the corresponding Java primitive TYPE class for this Primitive.
0184: @return the primitive TYPE class type of the value or Void.TYPE for
0185: Primitive.VOID or null value for type of Primitive.NULL
0186: */
0187: public Class getType() {
0188: if (this == Primitive.VOID)
0189: return Void.TYPE;
0190:
0191: // NULL return null as type... we currently use null type to indicate
0192: // loose typing throughout bsh.
0193: if (this == Primitive.NULL)
0194: return null;
0195:
0196: return unboxType(value.getClass());
0197: }
0198:
0199: /**
0200: Perform a binary operation on two Primitives or wrapper types.
0201: If both original args were Primitives return a Primitive result
0202: else it was mixed (wrapper/primitive) return the wrapper type.
0203: The exception is for boolean operations where we will return the
0204: primitive type either way.
0205: */
0206: public static Object binaryOperation(Object obj1, Object obj2,
0207: int kind) throws UtilEvalError {
0208: // special primitive types
0209: if (obj1 == NULL || obj2 == NULL)
0210: throw new UtilEvalError(
0211: "Null value or 'null' literal in binary operation");
0212: if (obj1 == VOID || obj2 == VOID)
0213: throw new UtilEvalError(
0214: "Undefined variable, class, or 'void' literal in binary operation");
0215:
0216: // keep track of the original types
0217: Class lhsOrgType = obj1.getClass();
0218: Class rhsOrgType = obj2.getClass();
0219:
0220: // Unwrap primitives
0221: if (obj1 instanceof Primitive)
0222: obj1 = ((Primitive) obj1).getValue();
0223: if (obj2 instanceof Primitive)
0224: obj2 = ((Primitive) obj2).getValue();
0225:
0226: Object[] operands = promotePrimitives(obj1, obj2);
0227: Object lhs = operands[0];
0228: Object rhs = operands[1];
0229:
0230: if (lhs.getClass() != rhs.getClass())
0231: throw new UtilEvalError("Type mismatch in operator. "
0232: + lhs.getClass() + " cannot be used with "
0233: + rhs.getClass());
0234:
0235: Object result;
0236: try {
0237: result = binaryOperationImpl(lhs, rhs, kind);
0238: } catch (ArithmeticException e) {
0239: throw new UtilTargetError(
0240: "Arithemetic Exception in binary op", e);
0241: }
0242:
0243: // If both original args were Primitives return a Primitive result
0244: // else it was mixed (wrapper/primitive) return the wrapper type
0245: // Exception is for boolean result, return the primitive
0246: if ((lhsOrgType == Primitive.class && rhsOrgType == Primitive.class)
0247: || result instanceof Boolean)
0248: return new Primitive(result);
0249: else
0250: return result;
0251: }
0252:
0253: static Object binaryOperationImpl(Object lhs, Object rhs, int kind)
0254: throws UtilEvalError {
0255: if (lhs instanceof Boolean)
0256: return booleanBinaryOperation((Boolean) lhs, (Boolean) rhs,
0257: kind);
0258: else if (lhs instanceof Integer)
0259: return intBinaryOperation((Integer) lhs, (Integer) rhs,
0260: kind);
0261: else if (lhs instanceof Long)
0262: return longBinaryOperation((Long) lhs, (Long) rhs, kind);
0263: else if (lhs instanceof Float)
0264: return floatBinaryOperation((Float) lhs, (Float) rhs, kind);
0265: else if (lhs instanceof Double)
0266: return doubleBinaryOperation((Double) lhs, (Double) rhs,
0267: kind);
0268: else
0269: throw new UtilEvalError("Invalid types in binary operator");
0270: }
0271:
0272: static Boolean booleanBinaryOperation(Boolean B1, Boolean B2,
0273: int kind) {
0274: boolean lhs = B1.booleanValue();
0275: boolean rhs = B2.booleanValue();
0276:
0277: switch (kind) {
0278: case EQ:
0279: return new Boolean(lhs == rhs);
0280:
0281: case NE:
0282: return new Boolean(lhs != rhs);
0283:
0284: case BOOL_OR:
0285: case BOOL_ORX:
0286: return new Boolean(lhs || rhs);
0287:
0288: case BOOL_AND:
0289: case BOOL_ANDX:
0290: return new Boolean(lhs && rhs);
0291:
0292: default:
0293: throw new InterpreterError("unimplemented binary operator");
0294: }
0295: }
0296:
0297: // returns Object covering both Long and Boolean return types
0298: static Object longBinaryOperation(Long L1, Long L2, int kind) {
0299: long lhs = L1.longValue();
0300: long rhs = L2.longValue();
0301:
0302: switch (kind) {
0303: // boolean
0304: case LT:
0305: case LTX:
0306: return new Boolean(lhs < rhs);
0307:
0308: case GT:
0309: case GTX:
0310: return new Boolean(lhs > rhs);
0311:
0312: case EQ:
0313: return new Boolean(lhs == rhs);
0314:
0315: case LE:
0316: case LEX:
0317: return new Boolean(lhs <= rhs);
0318:
0319: case GE:
0320: case GEX:
0321: return new Boolean(lhs >= rhs);
0322:
0323: case NE:
0324: return new Boolean(lhs != rhs);
0325:
0326: // arithmetic
0327: case PLUS:
0328: return new Long(lhs + rhs);
0329:
0330: case MINUS:
0331: return new Long(lhs - rhs);
0332:
0333: case STAR:
0334: return new Long(lhs * rhs);
0335:
0336: case SLASH:
0337: return new Long(lhs / rhs);
0338:
0339: case MOD:
0340: return new Long(lhs % rhs);
0341:
0342: // bitwise
0343: case LSHIFT:
0344: case LSHIFTX:
0345: return new Long(lhs << rhs);
0346:
0347: case RSIGNEDSHIFT:
0348: case RSIGNEDSHIFTX:
0349: return new Long(lhs >> rhs);
0350:
0351: case RUNSIGNEDSHIFT:
0352: case RUNSIGNEDSHIFTX:
0353: return new Long(lhs >>> rhs);
0354:
0355: case BIT_AND:
0356: case BIT_ANDX:
0357: return new Long(lhs & rhs);
0358:
0359: case BIT_OR:
0360: case BIT_ORX:
0361: return new Long(lhs | rhs);
0362:
0363: case XOR:
0364: return new Long(lhs ^ rhs);
0365:
0366: default:
0367: throw new InterpreterError(
0368: "Unimplemented binary long operator");
0369: }
0370: }
0371:
0372: // returns Object covering both Integer and Boolean return types
0373: static Object intBinaryOperation(Integer I1, Integer I2, int kind) {
0374: int lhs = I1.intValue();
0375: int rhs = I2.intValue();
0376:
0377: switch (kind) {
0378: // boolean
0379: case LT:
0380: case LTX:
0381: return new Boolean(lhs < rhs);
0382:
0383: case GT:
0384: case GTX:
0385: return new Boolean(lhs > rhs);
0386:
0387: case EQ:
0388: return new Boolean(lhs == rhs);
0389:
0390: case LE:
0391: case LEX:
0392: return new Boolean(lhs <= rhs);
0393:
0394: case GE:
0395: case GEX:
0396: return new Boolean(lhs >= rhs);
0397:
0398: case NE:
0399: return new Boolean(lhs != rhs);
0400:
0401: // arithmetic
0402: case PLUS:
0403: return new Integer(lhs + rhs);
0404:
0405: case MINUS:
0406: return new Integer(lhs - rhs);
0407:
0408: case STAR:
0409: return new Integer(lhs * rhs);
0410:
0411: case SLASH:
0412: return new Integer(lhs / rhs);
0413:
0414: case MOD:
0415: return new Integer(lhs % rhs);
0416:
0417: // bitwise
0418: case LSHIFT:
0419: case LSHIFTX:
0420: return new Integer(lhs << rhs);
0421:
0422: case RSIGNEDSHIFT:
0423: case RSIGNEDSHIFTX:
0424: return new Integer(lhs >> rhs);
0425:
0426: case RUNSIGNEDSHIFT:
0427: case RUNSIGNEDSHIFTX:
0428: return new Integer(lhs >>> rhs);
0429:
0430: case BIT_AND:
0431: case BIT_ANDX:
0432: return new Integer(lhs & rhs);
0433:
0434: case BIT_OR:
0435: case BIT_ORX:
0436: return new Integer(lhs | rhs);
0437:
0438: case XOR:
0439: return new Integer(lhs ^ rhs);
0440:
0441: default:
0442: throw new InterpreterError(
0443: "Unimplemented binary integer operator");
0444: }
0445: }
0446:
0447: // returns Object covering both Double and Boolean return types
0448: static Object doubleBinaryOperation(Double D1, Double D2, int kind)
0449: throws UtilEvalError {
0450: double lhs = D1.doubleValue();
0451: double rhs = D2.doubleValue();
0452:
0453: switch (kind) {
0454: // boolean
0455: case LT:
0456: case LTX:
0457: return new Boolean(lhs < rhs);
0458:
0459: case GT:
0460: case GTX:
0461: return new Boolean(lhs > rhs);
0462:
0463: case EQ:
0464: return new Boolean(lhs == rhs);
0465:
0466: case LE:
0467: case LEX:
0468: return new Boolean(lhs <= rhs);
0469:
0470: case GE:
0471: case GEX:
0472: return new Boolean(lhs >= rhs);
0473:
0474: case NE:
0475: return new Boolean(lhs != rhs);
0476:
0477: // arithmetic
0478: case PLUS:
0479: return new Double(lhs + rhs);
0480:
0481: case MINUS:
0482: return new Double(lhs - rhs);
0483:
0484: case STAR:
0485: return new Double(lhs * rhs);
0486:
0487: case SLASH:
0488: return new Double(lhs / rhs);
0489:
0490: case MOD:
0491: return new Double(lhs % rhs);
0492:
0493: // can't shift floating-point values
0494: case LSHIFT:
0495: case LSHIFTX:
0496: case RSIGNEDSHIFT:
0497: case RSIGNEDSHIFTX:
0498: case RUNSIGNEDSHIFT:
0499: case RUNSIGNEDSHIFTX:
0500: throw new UtilEvalError("Can't shift doubles");
0501:
0502: default:
0503: throw new InterpreterError(
0504: "Unimplemented binary double operator");
0505: }
0506: }
0507:
0508: // returns Object covering both Long and Boolean return types
0509: static Object floatBinaryOperation(Float F1, Float F2, int kind)
0510: throws UtilEvalError {
0511: float lhs = F1.floatValue();
0512: float rhs = F2.floatValue();
0513:
0514: switch (kind) {
0515: // boolean
0516: case LT:
0517: case LTX:
0518: return new Boolean(lhs < rhs);
0519:
0520: case GT:
0521: case GTX:
0522: return new Boolean(lhs > rhs);
0523:
0524: case EQ:
0525: return new Boolean(lhs == rhs);
0526:
0527: case LE:
0528: case LEX:
0529: return new Boolean(lhs <= rhs);
0530:
0531: case GE:
0532: case GEX:
0533: return new Boolean(lhs >= rhs);
0534:
0535: case NE:
0536: return new Boolean(lhs != rhs);
0537:
0538: // arithmetic
0539: case PLUS:
0540: return new Float(lhs + rhs);
0541:
0542: case MINUS:
0543: return new Float(lhs - rhs);
0544:
0545: case STAR:
0546: return new Float(lhs * rhs);
0547:
0548: case SLASH:
0549: return new Float(lhs / rhs);
0550:
0551: case MOD:
0552: return new Float(lhs % rhs);
0553:
0554: // can't shift floats
0555: case LSHIFT:
0556: case LSHIFTX:
0557: case RSIGNEDSHIFT:
0558: case RSIGNEDSHIFTX:
0559: case RUNSIGNEDSHIFT:
0560: case RUNSIGNEDSHIFTX:
0561: throw new UtilEvalError("Can't shift floats ");
0562:
0563: default:
0564: throw new InterpreterError(
0565: "Unimplemented binary float operator");
0566: }
0567: }
0568:
0569: /**
0570: Promote primitive wrapper type to to Integer wrapper type
0571: */
0572: static Object promoteToInteger(Object wrapper) {
0573: if (wrapper instanceof Character)
0574: return new Integer(((Character) wrapper).charValue());
0575: else if ((wrapper instanceof Byte)
0576: || (wrapper instanceof Short))
0577: return new Integer(((Number) wrapper).intValue());
0578:
0579: return wrapper;
0580: }
0581:
0582: /**
0583: Promote the pair of primitives to the maximum type of the two.
0584: e.g. [int,long]->[long,long]
0585: */
0586: static Object[] promotePrimitives(Object lhs, Object rhs) {
0587: lhs = promoteToInteger(lhs);
0588: rhs = promoteToInteger(rhs);
0589:
0590: if ((lhs instanceof Number) && (rhs instanceof Number)) {
0591: Number lnum = (Number) lhs;
0592: Number rnum = (Number) rhs;
0593:
0594: boolean b;
0595:
0596: if ((b = (lnum instanceof Double))
0597: || (rnum instanceof Double)) {
0598: if (b)
0599: rhs = new Double(rnum.doubleValue());
0600: else
0601: lhs = new Double(lnum.doubleValue());
0602: } else if ((b = (lnum instanceof Float))
0603: || (rnum instanceof Float)) {
0604: if (b)
0605: rhs = new Float(rnum.floatValue());
0606: else
0607: lhs = new Float(lnum.floatValue());
0608: } else if ((b = (lnum instanceof Long))
0609: || (rnum instanceof Long)) {
0610: if (b)
0611: rhs = new Long(rnum.longValue());
0612: else
0613: lhs = new Long(lnum.longValue());
0614: }
0615: }
0616:
0617: return new Object[] { lhs, rhs };
0618: }
0619:
0620: public static Primitive unaryOperation(Primitive val, int kind)
0621: throws UtilEvalError {
0622: if (val == NULL)
0623: throw new UtilEvalError(
0624: "illegal use of null object or 'null' literal");
0625: if (val == VOID)
0626: throw new UtilEvalError(
0627: "illegal use of undefined object or 'void' literal");
0628:
0629: Class operandType = val.getType();
0630: Object operand = promoteToInteger(val.getValue());
0631:
0632: if (operand instanceof Boolean)
0633: return new Primitive(booleanUnaryOperation(
0634: (Boolean) operand, kind));
0635: else if (operand instanceof Integer) {
0636: int result = intUnaryOperation((Integer) operand, kind);
0637:
0638: // ++ and -- must be cast back the original type
0639: if (kind == INCR || kind == DECR) {
0640: if (operandType == Byte.TYPE)
0641: return new Primitive((byte) result);
0642: if (operandType == Short.TYPE)
0643: return new Primitive((short) result);
0644: if (operandType == Character.TYPE)
0645: return new Primitive((char) result);
0646: }
0647:
0648: return new Primitive(result);
0649: } else if (operand instanceof Long)
0650: return new Primitive(longUnaryOperation((Long) operand,
0651: kind));
0652: else if (operand instanceof Float)
0653: return new Primitive(floatUnaryOperation((Float) operand,
0654: kind));
0655: else if (operand instanceof Double)
0656: return new Primitive(doubleUnaryOperation((Double) operand,
0657: kind));
0658: else
0659: throw new InterpreterError(
0660: "An error occurred. Please call technical support.");
0661: }
0662:
0663: static boolean booleanUnaryOperation(Boolean B, int kind)
0664: throws UtilEvalError {
0665: boolean operand = B.booleanValue();
0666: switch (kind) {
0667: case BANG:
0668: return !operand;
0669: default:
0670: throw new UtilEvalError(
0671: "Operator inappropriate for boolean");
0672: }
0673: }
0674:
0675: static int intUnaryOperation(Integer I, int kind) {
0676: int operand = I.intValue();
0677:
0678: switch (kind) {
0679: case PLUS:
0680: return operand;
0681: case MINUS:
0682: return -operand;
0683: case TILDE:
0684: return ~operand;
0685: case INCR:
0686: return operand + 1;
0687: case DECR:
0688: return operand - 1;
0689: default:
0690: throw new InterpreterError("bad integer unaryOperation");
0691: }
0692: }
0693:
0694: static long longUnaryOperation(Long L, int kind) {
0695: long operand = L.longValue();
0696:
0697: switch (kind) {
0698: case PLUS:
0699: return operand;
0700: case MINUS:
0701: return -operand;
0702: case TILDE:
0703: return ~operand;
0704: case INCR:
0705: return operand + 1;
0706: case DECR:
0707: return operand - 1;
0708: default:
0709: throw new InterpreterError("bad long unaryOperation");
0710: }
0711: }
0712:
0713: static float floatUnaryOperation(Float F, int kind) {
0714: float operand = F.floatValue();
0715:
0716: switch (kind) {
0717: case PLUS:
0718: return operand;
0719: case MINUS:
0720: return -operand;
0721: default:
0722: throw new InterpreterError("bad float unaryOperation");
0723: }
0724: }
0725:
0726: static double doubleUnaryOperation(Double D, int kind) {
0727: double operand = D.doubleValue();
0728:
0729: switch (kind) {
0730: case PLUS:
0731: return operand;
0732: case MINUS:
0733: return -operand;
0734: default:
0735: throw new InterpreterError("bad double unaryOperation");
0736: }
0737: }
0738:
0739: public int intValue() throws UtilEvalError {
0740: if (value instanceof Number)
0741: return ((Number) value).intValue();
0742: else
0743: throw new UtilEvalError("Primitive not a number");
0744: }
0745:
0746: public boolean booleanValue() throws UtilEvalError {
0747: if (value instanceof Boolean)
0748: return ((Boolean) value).booleanValue();
0749: else
0750: throw new UtilEvalError("Primitive not a boolean");
0751: }
0752:
0753: /**
0754: Determine if this primitive is a numeric type.
0755: i.e. not boolean, null, or void (but including char)
0756: */
0757: public boolean isNumber() {
0758: return (!(value instanceof Boolean) && !(this == NULL) && !(this == VOID));
0759: }
0760:
0761: public Number numberValue() throws UtilEvalError {
0762: Object value = this .value;
0763:
0764: // Promote character to Number type for these purposes
0765: if (value instanceof Character)
0766: value = new Integer(((Character) value).charValue());
0767:
0768: if (value instanceof Number)
0769: return (Number) value;
0770: else
0771: throw new UtilEvalError("Primitive not a number");
0772: }
0773:
0774: /**
0775: Primitives compare equal with other Primitives containing an equal
0776: wrapped value.
0777: */
0778: public boolean equals(Object obj) {
0779: if (obj instanceof Primitive)
0780: return ((Primitive) obj).value.equals(this .value);
0781: else
0782: return false;
0783: }
0784:
0785: /**
0786: The hash of the Primitive is tied to the hash of the wrapped value but
0787: shifted so that they are not the same.
0788: */
0789: public int hashCode() {
0790: return this .value.hashCode() * 21; // arbitrary
0791: }
0792:
0793: /**
0794: Unwrap primitive values and map voids to nulls.
0795: Non Primitive types remain unchanged.
0796:
0797: @param obj object type which may be bsh.Primitive
0798: @return corresponding "normal" Java type, "unwrapping"
0799: any bsh.Primitive types to their wrapper types.
0800: */
0801: public static Object unwrap(Object obj) {
0802: // map voids to nulls for the outside world
0803: if (obj == Primitive.VOID)
0804: return null;
0805:
0806: // unwrap primitives
0807: if (obj instanceof Primitive)
0808: return ((Primitive) obj).getValue();
0809: else
0810: return obj;
0811: }
0812:
0813: /*
0814: Unwrap Primitive wrappers to their java.lang wrapper values.
0815: e.g. Primitive(42) becomes Integer(42)
0816: @see #unwrap( Object )
0817: */
0818: public static Object[] unwrap(Object[] args) {
0819: Object[] oa = new Object[args.length];
0820: for (int i = 0; i < args.length; i++)
0821: oa[i] = unwrap(args[i]);
0822: return oa;
0823: }
0824:
0825: /*
0826: */
0827: public static Object[] wrap(Object[] args, Class[] paramTypes) {
0828: if (args == null)
0829: return null;
0830:
0831: Object[] oa = new Object[args.length];
0832: for (int i = 0; i < args.length; i++)
0833: oa[i] = wrap(args[i], paramTypes[i]);
0834: return oa;
0835: }
0836:
0837: /**
0838: Wrap primitive values (as indicated by type param) and nulls in the
0839: Primitive class. Values not primitive or null are left unchanged.
0840: Primitive values are represented by their wrapped values in param value.
0841: <p/>
0842: The value null is mapped to Primitive.NULL.
0843: Any value specified with type Void.TYPE is mapped to Primitive.VOID.
0844: */
0845: public static Object wrap(Object value, Class type) {
0846: if (type == Void.TYPE)
0847: return Primitive.VOID;
0848:
0849: if (value == null)
0850: return Primitive.NULL;
0851:
0852: if (type.isPrimitive())
0853: return new Primitive(value);
0854:
0855: return value;
0856: }
0857:
0858: /**
0859: Get the appropriate default value per JLS 4.5.4
0860: */
0861: public static Primitive getDefaultValue(Class type) {
0862: if (type == null || !type.isPrimitive())
0863: return Primitive.NULL;
0864: if (type == Boolean.TYPE)
0865: return new Primitive(false);
0866:
0867: // non boolean primitive, get appropriate flavor of zero
0868: try {
0869: return new Primitive((int) 0).castToType(type, Types.CAST);
0870: } catch (UtilEvalError e) {
0871: throw new InterpreterError("bad cast");
0872: }
0873: }
0874:
0875: /**
0876: Get the corresponding java.lang wrapper class for the primitive TYPE
0877: class.
0878: e.g. Integer.TYPE -> Integer.class
0879: */
0880: public static Class boxType(Class primitiveType) {
0881: Class c = (Class) wrapperMap.get(primitiveType);
0882: if (c != null)
0883: return c;
0884: throw new InterpreterError("Not a primitive type: "
0885: + primitiveType);
0886: }
0887:
0888: /**
0889: Get the corresponding primitive TYPE class for the java.lang wrapper
0890: class type.
0891: e.g. Integer.class -> Integer.TYPE
0892: */
0893: public static Class unboxType(Class wrapperType) {
0894: Class c = (Class) wrapperMap.get(wrapperType);
0895: if (c != null)
0896: return c;
0897: throw new InterpreterError("Not a primitive wrapper type: "
0898: + wrapperType);
0899: }
0900:
0901: /**
0902: Cast this bsh.Primitive value to a new bsh.Primitive value
0903: This is usually a numeric type cast. Other cases include:
0904: A boolean can be cast to boolen
0905: null can be cast to any object type and remains null
0906: Attempting to cast a void causes an exception
0907: @param toType is the java object or primitive TYPE class
0908: */
0909: public Primitive castToType(Class toType, int operation)
0910: throws UtilEvalError {
0911: return castPrimitive(toType, getType()/*fromType*/,
0912: this /*fromValue*/, false/*checkOnly*/, operation);
0913: }
0914:
0915: /*
0916: Cast or check a cast of a primitive type to another type.
0917: Normally both types are primitive (e.g. numeric), but a null value
0918: (no type) may be cast to any type.
0919: <p/>
0920:
0921: @param toType is the target type of the cast. It is normally a
0922: java primitive TYPE, but in the case of a null cast can be any object
0923: type.
0924:
0925: @param fromType is the java primitive TYPE type of the primitive to be
0926: cast or null, to indicate that the fromValue was null or void.
0927:
0928: @param fromValue is, optionally, the value to be converted. If
0929: checkOnly is true fromValue must be null. If checkOnly is false,
0930: fromValue must be non-null (Primitive.NULL is of course valid).
0931: */
0932: static Primitive castPrimitive(Class toType, Class fromType,
0933: Primitive fromValue, boolean checkOnly, int operation)
0934: throws UtilEvalError {
0935: /*
0936: Lots of preconditions checked here...
0937: Once things are running smoothly we might comment these out
0938: (That's what assertions are for).
0939: */
0940: if (checkOnly && fromValue != null)
0941: throw new InterpreterError("bad cast param 1");
0942: if (!checkOnly && fromValue == null)
0943: throw new InterpreterError("bad cast param 2");
0944: if (fromType != null && !fromType.isPrimitive())
0945: throw new InterpreterError("bad fromType:" + fromType);
0946: if (fromValue == Primitive.NULL && fromType != null)
0947: throw new InterpreterError("inconsistent args 1");
0948: if (fromValue == Primitive.VOID && fromType != Void.TYPE)
0949: throw new InterpreterError("inconsistent args 2");
0950:
0951: // can't cast void to anything
0952: if (fromType == Void.TYPE)
0953: if (checkOnly)
0954: return Types.INVALID_CAST;
0955: else
0956: throw Types.castError(Reflect
0957: .normalizeClassName(toType), "void value",
0958: operation);
0959:
0960: // unwrap Primitive fromValue to its wrapper value, etc.
0961: Object value = null;
0962: if (fromValue != null)
0963: value = fromValue.getValue();
0964:
0965: if (toType.isPrimitive()) {
0966: // Trying to cast null to primitive type?
0967: if (fromType == null)
0968: if (checkOnly)
0969: return Types.INVALID_CAST;
0970: else
0971: throw Types.castError("primitive type:" + toType,
0972: "Null value", operation);
0973:
0974: // fall through
0975: } else {
0976: // Trying to cast primitive to an object type
0977: // Primitive.NULL can be cast to any object type
0978: if (fromType == null)
0979: return checkOnly ? Types.VALID_CAST : Primitive.NULL;
0980:
0981: if (checkOnly)
0982: return Types.INVALID_CAST;
0983: else
0984: throw Types.castError("object type:" + toType,
0985: "primitive value", operation);
0986: }
0987:
0988: // can only cast boolean to boolean
0989: if (fromType == Boolean.TYPE) {
0990: if (toType != Boolean.TYPE)
0991: if (checkOnly)
0992: return Types.INVALID_CAST;
0993: else
0994: throw Types.castError(toType, fromType, operation);
0995:
0996: return checkOnly ? Types.VALID_CAST : fromValue;
0997: }
0998:
0999: // Do numeric cast
1000:
1001: // Only allow legal Java assignment unless we're a CAST operation
1002: if (operation == Types.ASSIGNMENT
1003: && !Types.isJavaAssignable(toType, fromType)) {
1004: if (checkOnly)
1005: return Types.INVALID_CAST;
1006: else
1007: throw Types.castError(toType, fromType, operation);
1008: }
1009:
1010: return checkOnly ? Types.VALID_CAST : new Primitive(
1011: castWrapper(toType, value));
1012: }
1013:
1014: public static boolean isWrapperType(Class type) {
1015: return wrapperMap.get(type) != null && !type.isPrimitive();
1016: }
1017:
1018: /**
1019: Cast a primitive value represented by its java.lang wrapper type to the
1020: specified java.lang wrapper type. e.g. Byte(5) to Integer(5) or
1021: Integer(5) to Byte(5)
1022: @param toType is the java TYPE type
1023: @param value is the value in java.lang wrapper.
1024: value may not be null.
1025: */
1026: static Object castWrapper(Class toType, Object value) {
1027: if (!toType.isPrimitive())
1028: throw new InterpreterError("invalid type in castWrapper: "
1029: + toType);
1030: if (value == null)
1031: throw new InterpreterError(
1032: "null value in castWrapper, guard");
1033: if (value instanceof Boolean) {
1034: if (toType != Boolean.TYPE)
1035: throw new InterpreterError(
1036: "bad wrapper cast of boolean");
1037: else
1038: return value;
1039: }
1040:
1041: // first promote char to Number type to avoid duplicating code
1042: if (value instanceof Character)
1043: value = new Integer(((Character) value).charValue());
1044:
1045: if (!(value instanceof Number))
1046: throw new InterpreterError("bad type in cast");
1047:
1048: Number number = (Number) value;
1049:
1050: if (toType == Byte.TYPE)
1051: return new Byte(number.byteValue());
1052: if (toType == Short.TYPE)
1053: return new Short(number.shortValue());
1054: if (toType == Character.TYPE)
1055: return new Character((char) number.intValue());
1056: if (toType == Integer.TYPE)
1057: return new Integer(number.intValue());
1058: if (toType == Long.TYPE)
1059: return new Long(number.longValue());
1060: if (toType == Float.TYPE)
1061: return new Float(number.floatValue());
1062: if (toType == Double.TYPE)
1063: return new Double(number.doubleValue());
1064:
1065: throw new InterpreterError("error in wrapper cast");
1066: }
1067:
1068: }
|