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