PageRenderTime 189ms CodeModel.GetById 142ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/bsh/Primitive.java

#
Java | 1098 lines | 716 code | 160 blank | 222 comment | 190 complexity | 93cbe78fc07039f71515a62198c32bac MD5 | raw file
   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
  35package org.gjt.sp.jedit.bsh;
  36
  37import java.util.Hashtable;
  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*/
  49public final class Primitive implements ParserConstants, java.io.Serializable
  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 wrapperMap = new Hashtable();
  74	static {
  75		wrapperMap.put( Boolean.TYPE, Boolean.class );
  76		wrapperMap.put( Byte.TYPE, Byte.class );
  77		wrapperMap.put( Short.TYPE, Short.class );
  78		wrapperMap.put( Character.TYPE, Character.class );
  79		wrapperMap.put( Integer.TYPE, Integer.class );
  80		wrapperMap.put( Long.TYPE, Long.class );
  81		wrapperMap.put( Float.TYPE, Float.class );
  82		wrapperMap.put( Double.TYPE, Double.class );
  83		wrapperMap.put( Boolean.class, Boolean.TYPE );
  84		wrapperMap.put( Byte.class, Byte.TYPE );
  85		wrapperMap.put( Short.class, Short.TYPE );
  86		wrapperMap.put( Character.class, Character.TYPE );
  87		wrapperMap.put( Integer.class, Integer.TYPE );
  88		wrapperMap.put( Long.class, Long.TYPE );
  89		wrapperMap.put( Float.class, Float.TYPE );
  90		wrapperMap.put( Double.class, Double.TYPE );
  91	}
  92
  93    /** The primitive value stored in its java.lang wrapper class */
  94    private Object value;
  95
  96    private static class Special implements java.io.Serializable
  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 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(value)); }
 134    public Primitive(byte value) { this(new Byte(value)); }
 135    public Primitive(short value) { this(new Short(value)); }
 136    public Primitive(char value) { this(new Character(value)); }
 137    public Primitive(int value) { this(new Integer(value)); }
 138    public Primitive(long value) { this(new Long(value)); }
 139    public Primitive(float value) { this(new Float(value)); }
 140    public Primitive(double value) { this(new Double(value)); }
 141
 142	/**
 143    	Return the primitive value stored in its java.lang wrapper class
 144	*/
 145    public Object 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 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 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 binaryOperation(
 192		Object obj1, Object 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 lhsOrgType = obj1.getClass();
 205		Class 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[] operands = promotePrimitives(obj1, obj2);
 214        Object lhs = operands[0];
 215        Object 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 result;
 222		try {
 223			result = binaryOperationImpl( lhs, rhs, kind );
 224		} catch ( ArithmeticException 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
 233		)
 234			return new Primitive( result );
 235		else
 236			return result;
 237    }
 238
 239    static Object binaryOperationImpl( Object lhs, Object rhs, int kind )
 240        throws UtilEvalError
 241	{
 242        if(lhs instanceof Boolean)
 243            return booleanBinaryOperation((Boolean)lhs, (Boolean)rhs, kind);
 244        else if(lhs instanceof Integer)
 245            return intBinaryOperation( (Integer)lhs, (Integer)rhs, kind );
 246        else if(lhs instanceof Long)
 247            return longBinaryOperation((Long)lhs, (Long)rhs, kind);
 248        else if(lhs instanceof Float)
 249            return floatBinaryOperation((Float)lhs, (Float)rhs, kind);
 250        else if(lhs instanceof Double)
 251            return doubleBinaryOperation( (Double)lhs, (Double)rhs, kind);
 252        else
 253            throw new UtilEvalError("Invalid types in binary operator" );
 254	}
 255
 256    static Boolean booleanBinaryOperation(Boolean B1, Boolean 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(lhs == rhs);
 265
 266            case NE:
 267                return new Boolean(lhs != rhs);
 268
 269            case BOOL_OR:
 270            case BOOL_ORX:
 271                return new Boolean( lhs || rhs );
 272
 273            case BOOL_AND:
 274            case BOOL_ANDX:
 275                return new Boolean( 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 longBinaryOperation(Long L1, Long 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(lhs < rhs);
 294
 295            case GT:
 296            case GTX:
 297                return new Boolean(lhs > rhs);
 298
 299            case EQ:
 300                return new Boolean(lhs == rhs);
 301
 302            case LE:
 303            case LEX:
 304                return new Boolean(lhs <= rhs);
 305
 306            case GE:
 307            case GEX:
 308                return new Boolean(lhs >= rhs);
 309
 310            case NE:
 311                return new Boolean(lhs != rhs);
 312
 313            // arithmetic
 314            case PLUS:
 315                return new Long(lhs + rhs);
 316
 317            case MINUS:
 318                return new Long(lhs - rhs);
 319
 320            case STAR:
 321                return new Long(lhs * rhs);
 322
 323            case SLASH:
 324                return new Long(lhs / rhs);
 325
 326            case MOD:
 327                return new Long(lhs % rhs);
 328
 329            // bitwise
 330            case LSHIFT:
 331            case LSHIFTX:
 332                return new Long(lhs << rhs);
 333
 334            case RSIGNEDSHIFT:
 335            case RSIGNEDSHIFTX:
 336                return new Long(lhs >> rhs);
 337
 338            case RUNSIGNEDSHIFT:
 339            case RUNSIGNEDSHIFTX:
 340                return new Long(lhs >>> rhs);
 341
 342            case BIT_AND:
 343            case BIT_ANDX:
 344                return new Long(lhs & rhs);
 345
 346            case BIT_OR:
 347            case BIT_ORX:
 348                return new Long(lhs | rhs);
 349
 350            case XOR:
 351                return new Long(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 intBinaryOperation(Integer I1, Integer 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(lhs < rhs);
 371
 372            case GT:
 373            case GTX:
 374                return new Boolean(lhs > rhs);
 375
 376            case EQ:
 377                return new Boolean(lhs == rhs);
 378
 379            case LE:
 380            case LEX:
 381                return new Boolean(lhs <= rhs);
 382
 383            case GE:
 384            case GEX:
 385                return new Boolean(lhs >= rhs);
 386
 387            case NE:
 388                return new Boolean(lhs != rhs);
 389
 390            // arithmetic
 391            case PLUS:
 392                return new Integer(lhs + rhs);
 393
 394            case MINUS:
 395                return new Integer(lhs - rhs);
 396
 397            case STAR:
 398                return new Integer(lhs * rhs);
 399
 400            case SLASH:
 401                return new Integer(lhs / rhs);
 402
 403            case MOD:
 404                return new Integer(lhs % rhs);
 405
 406            // bitwise
 407            case LSHIFT:
 408            case LSHIFTX:
 409                return new Integer(lhs << rhs);
 410
 411            case RSIGNEDSHIFT:
 412            case RSIGNEDSHIFTX:
 413                return new Integer(lhs >> rhs);
 414
 415            case RUNSIGNEDSHIFT:
 416            case RUNSIGNEDSHIFTX:
 417                return new Integer(lhs >>> rhs);
 418
 419            case BIT_AND:
 420            case BIT_ANDX:
 421                return new Integer(lhs & rhs);
 422
 423            case BIT_OR:
 424            case BIT_ORX:
 425                return new Integer(lhs | rhs);
 426
 427            case XOR:
 428                return new Integer(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 doubleBinaryOperation(Double D1, Double 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(lhs < rhs);
 449
 450            case GT:
 451            case GTX:
 452                return new Boolean(lhs > rhs);
 453
 454            case EQ:
 455                return new Boolean(lhs == rhs);
 456
 457            case LE:
 458            case LEX:
 459                return new Boolean(lhs <= rhs);
 460
 461            case GE:
 462            case GEX:
 463                return new Boolean(lhs >= rhs);
 464
 465            case NE:
 466                return new Boolean(lhs != rhs);
 467
 468            // arithmetic
 469            case PLUS:
 470                return new Double(lhs + rhs);
 471
 472            case MINUS:
 473                return new Double(lhs - rhs);
 474
 475            case STAR:
 476                return new Double(lhs * rhs);
 477
 478            case SLASH:
 479                return new Double(lhs / rhs);
 480
 481            case MOD:
 482                return new Double(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 floatBinaryOperation(Float F1, Float 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(lhs < rhs);
 511
 512            case GT:
 513            case GTX:
 514                return new Boolean(lhs > rhs);
 515
 516            case EQ:
 517                return new Boolean(lhs == rhs);
 518
 519            case LE:
 520            case LEX:
 521                return new Boolean(lhs <= rhs);
 522
 523            case GE:
 524            case GEX:
 525                return new Boolean(lhs >= rhs);
 526
 527            case NE:
 528                return new Boolean(lhs != rhs);
 529
 530            // arithmetic
 531            case PLUS:
 532                return new Float(lhs + rhs);
 533
 534            case MINUS:
 535                return new Float(lhs - rhs);
 536
 537            case STAR:
 538                return new Float(lhs * rhs);
 539
 540            case SLASH:
 541                return new Float(lhs / rhs);
 542
 543            case MOD:
 544                return new Float(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 promoteToInteger(Object wrapper )
 565    {
 566        if(wrapper instanceof Character)
 567            return new Integer(((Character)wrapper).charValue());
 568        else if((wrapper instanceof Byte) || (wrapper instanceof Short))
 569            return new Integer(((Number)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[] promotePrimitives(Object lhs, Object rhs)
 579    {
 580        lhs = promoteToInteger(lhs);
 581        rhs = promoteToInteger(rhs);
 582
 583        if((lhs instanceof Number) && (rhs instanceof Number))
 584        {
 585            Number lnum = (Number)lhs;
 586            Number rnum = (Number)rhs;
 587
 588            boolean b;
 589
 590            if((b = (lnum instanceof Double)) || (rnum instanceof Double))
 591            {
 592                if(b)
 593                    rhs = new Double(rnum.doubleValue());
 594                else
 595                    lhs = new Double(lnum.doubleValue());
 596            }
 597            else if((b = (lnum instanceof Float)) || (rnum instanceof Float))
 598            {
 599                if(b)
 600                    rhs = new Float(rnum.floatValue());
 601                else
 602                    lhs = new Float(lnum.floatValue());
 603            }
 604            else if((b = (lnum instanceof Long)) || (rnum instanceof Long))
 605            {
 606                if(b)
 607                    rhs = new Long(rnum.longValue());
 608                else
 609                    lhs = new Long(lnum.longValue());
 610            }
 611        }
 612
 613        return new Object[] { 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 operandType = val.getType();
 627        Object operand = promoteToInteger(val.getValue());
 628
 629        if ( operand instanceof Boolean )
 630            return new Primitive(booleanUnaryOperation((Boolean)operand, kind));
 631        else if(operand instanceof Integer)
 632        {
 633            int result = intUnaryOperation((Integer)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)
 649            return new Primitive(longUnaryOperation((Long)operand, kind));
 650        else if(operand instanceof Float)
 651            return new Primitive(floatUnaryOperation((Float)operand, kind));
 652        else if(operand instanceof Double)
 653            return new Primitive(doubleUnaryOperation((Double)operand, kind));
 654        else
 655            throw new InterpreterError(
 656				"An error occurred.  Please call technical support.");
 657    }
 658
 659    static boolean booleanUnaryOperation(Boolean 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 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 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 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 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)
 747            return((Number)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)
 755            return((Boolean)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) 
 766			&& !(this == NULL) && !(this == VOID) );
 767	}
 768
 769    public Number numberValue() throws UtilEvalError
 770    {
 771		Object value = this.value;
 772
 773		// Promote character to Number type for these purposes
 774		if (value instanceof Character)
 775			value = new Integer(((Character)value).charValue());
 776
 777        if (value instanceof Number)
 778            return (Number)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 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 unwrap( Object 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 [] unwrap( Object[] args )
 831    {
 832		Object [] oa = new Object[ 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 [] wrap( Object[] args, Class [] paramTypes )
 841    {
 842		if ( args == null )
 843			return null;
 844
 845		Object [] oa = new Object[ 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 wrap(
 860		Object value, Class 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 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 boxType( Class primitiveType )
 899	{
 900		Class c = (Class)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 unboxType( Class wrapperType )
 913	{
 914		Class c = (Class)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 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 toType, Class 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 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 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 castWrapper( 
1057		Class toType, Object 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 )
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 )
1073			value = new Integer(((Character)value).charValue());
1074
1075		if ( !(value instanceof Number) )
1076			throw new InterpreterError("bad type in cast");
1077
1078		Number number = (Number)value;
1079
1080		if (toType == Byte.TYPE)
1081			return new Byte(number.byteValue());
1082		if (toType == Short.TYPE)
1083			return new Short(number.shortValue());
1084		if (toType == Character.TYPE)
1085			return new Character((char)number.intValue());
1086		if (toType == Integer.TYPE)
1087			return new Integer(number.intValue());
1088		if (toType == Long.TYPE)
1089			return new Long(number.longValue());
1090		if (toType == Float.TYPE)
1091			return new Float(number.floatValue());
1092		if (toType == Double.TYPE)
1093			return new Double(number.doubleValue());
1094
1095		throw new InterpreterError("error in wrapper cast");
1096	}
1097
1098}