PageRenderTime 79ms CodeModel.GetById 15ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-0-pre5/bsh/Primitive.java

#
Java | 789 lines | 537 code | 146 blank | 106 comment | 118 complexity | fbc4418d0e1fe2347f65d0b635c5750e 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 bsh;
 36
 37/**
 38    Wrapper for primitive types in Bsh.  This is package public because it 
 39	is used in the implementation of some bsh commands.
 40
 41    See the note in LHS.java about wrapping objects.
 42*/
 43public class Primitive implements ParserConstants, java.io.Serializable
 44{
 45    // stored internally in java.lang. wrappers
 46    private Object value;
 47
 48    private static class Special implements java.io.Serializable
 49    {
 50        private Special() { }
 51
 52        public static final Special NULL_VALUE = new Special();
 53        public static final Special VOID_TYPE = new Special();
 54    }
 55
 56    /*
 57        NULL means "no value".
 58        This ia a placeholder for primitive null value.
 59    */
 60    public static final Primitive NULL = new Primitive(Special.NULL_VALUE);
 61
 62    /**
 63        VOID means "no type".
 64        Strictly speaking, this makes no sense here.  But for practical
 65        reasons we'll consider the lack of a type to be a special value.
 66    */
 67    public static final Primitive VOID = new Primitive(Special.VOID_TYPE);
 68
 69    // private to prevent invocation with param that isn't a primitive-wrapper
 70    private Primitive(Object value)
 71    {
 72        if(value == null)
 73            throw new InterpreterError(
 74				"Use Primitve.NULL instead of Primitive(null)");
 75
 76        this.value = value;
 77    }
 78
 79    public Primitive(Number number) { this((Object)number); }
 80
 81    public Primitive(Boolean value) { this((Object)value); }
 82    public Primitive(Byte value) { this((Object)value); }
 83    public Primitive(Short value) { this((Object)value); }
 84    public Primitive(Character value) { this((Object)value); }
 85    public Primitive(Integer value) { this((Object)value); }
 86    public Primitive(Long value) { this((Object)value); }
 87    public Primitive(Float value) { this((Object)value); }
 88    public Primitive(Double value) { this((Object)value); }
 89
 90    public Primitive(boolean value) { this(new Boolean(value)); }
 91    public Primitive(byte value) { this(new Byte(value)); }
 92    public Primitive(short value) { this(new Short(value)); }
 93    public Primitive(char value) { this(new Character(value)); }
 94    public Primitive(int value) { this(new Integer(value)); }
 95    public Primitive(long value) { this(new Long(value)); }
 96    public Primitive(float value) { this(new Float(value)); }
 97    public Primitive(double value) { this(new Double(value)); }
 98
 99    public Object getValue()
100    {
101        if(value == Special.NULL_VALUE)
102            return null;
103        else if(value == Special.VOID_TYPE)
104                throw new InterpreterError("attempt to unwrap void type");
105        else
106            return value;
107    }
108
109    public String toString()
110    {
111        if(value == Special.NULL_VALUE)
112            return "null";
113        else if(value == Special.VOID_TYPE)
114            return "void";
115        else
116            return value.toString();
117    }
118
119    public Class getType()
120    {
121        return getType(value);
122    }
123
124    private Class getType(Object o)
125    {
126        if(o instanceof Boolean)
127            return Boolean.TYPE;
128        else if(o instanceof Byte)
129            return Byte.TYPE;
130        else if(o instanceof Short)
131            return Short.TYPE;
132        else if(o instanceof Character)
133            return Character.TYPE;
134        else if(o instanceof Integer)
135            return Integer.TYPE;
136        else if(o instanceof Long)
137            return Long.TYPE;
138        else if(o instanceof Float)
139            return Float.TYPE;
140        else if(o instanceof Double)
141            return Double.TYPE;
142
143        return null;
144    }
145
146/*
147    public static Primitive binaryOperation(
148		Primitive p1, Primitive p2, int kind )
149        throws EvalError
150    {
151		return new Primitive( binaryOperation( p1, p2, kind ) );
152    }
153*/
154
155	/**
156		Allow primitive operations on wrapper types such as Integer and Boolean.
157		This is static so that it can be reached from wherever...
158	*/
159    public static Object binaryOperation(
160		Object obj1, Object obj2, int kind)
161        throws EvalError
162    {
163		// special primitive types
164        if(obj1 == NULL || obj2 == NULL)
165            throw new EvalError(
166				"Null value or 'null' literal in binary operation");
167        if(obj1 == VOID || obj2 == VOID)
168            throw new EvalError(
169			"Undefined variable, class, or 'void' literal in binary operation");
170
171		// keep track of the original types
172		Class lhsOrgType = obj1.getClass();
173		Class rhsOrgType = obj2.getClass();
174
175		// Unwrap primitives
176        if(obj1 instanceof Primitive)
177            obj1 = ((Primitive)obj1).getValue();
178        if(obj2 instanceof Primitive)
179            obj2 = ((Primitive)obj2).getValue();
180
181        Object[] operands = promotePrimitives(obj1, obj2);
182        Object lhs = operands[0];
183        Object rhs = operands[1];
184
185        if(lhs.getClass() != rhs.getClass())
186            throw new EvalError("type mismatch in operator.  " 
187			+ lhs.getClass() + " cannot be used with " + rhs.getClass() );
188
189		Object result;
190		try {
191			result = binaryOperationImpl( lhs, rhs, kind );
192		} catch ( ArithmeticException e ) {
193			throw new TargetError("Arithemetic Exception in binary op", e);
194		}
195
196		// If both original args were Primitives return a Primitive result
197		// else it was mixed (wrapper/primitive) return the wrapper type
198		if ( lhsOrgType == Primitive.class && rhsOrgType == Primitive.class )
199			return new Primitive( result );
200		else
201			return result;
202    }
203
204    static Object binaryOperationImpl( Object lhs, Object rhs, int kind )
205        throws EvalError
206	{
207        if(lhs instanceof Boolean)
208            return booleanBinaryOperation((Boolean)lhs, (Boolean)rhs, kind);
209        else if(lhs instanceof Integer)
210            return intBinaryOperation( (Integer)lhs, (Integer)rhs, kind );
211        else if(lhs instanceof Long)
212            return longBinaryOperation((Long)lhs, (Long)rhs, kind);
213        else if(lhs instanceof Float)
214            return floatBinaryOperation((Float)lhs, (Float)rhs, kind);
215        else if(lhs instanceof Double)
216            return doubleBinaryOperation( (Double)lhs, (Double)rhs, kind);
217        else
218            throw new EvalError("Invalid types in binary operator" );
219	}
220
221
222    static Boolean booleanBinaryOperation(Boolean B1, Boolean B2, int kind)
223        throws EvalError
224    {
225        boolean lhs = B1.booleanValue();
226        boolean rhs = B2.booleanValue();
227
228        switch(kind)
229        {
230            case EQ:
231                return new Boolean(lhs == rhs);
232
233            case NE:
234                return new Boolean(lhs != rhs);
235
236            case BOOL_OR:
237            case BOOL_ORX:
238                return new Boolean( lhs || rhs );
239
240            case BOOL_AND:
241            case BOOL_ANDX:
242                return new Boolean( lhs && rhs );
243
244            default:
245                throw new InterpreterError("unimplemented binary operator");
246        }
247    }
248
249    // returns Object covering both Long and Boolean return types
250    static Object longBinaryOperation(Long L1, Long L2, int kind)
251    {
252        long lhs = L1.longValue();
253        long rhs = L2.longValue();
254
255        switch(kind)
256        {
257            // boolean
258            case LT:
259            case LTX:
260                return new Boolean(lhs < rhs);
261
262            case GT:
263            case GTX:
264                return new Boolean(lhs > rhs);
265
266            case EQ:
267                return new Boolean(lhs == rhs);
268
269            case LE:
270            case LEX:
271                return new Boolean(lhs <= rhs);
272
273            case GE:
274            case GEX:
275                return new Boolean(lhs >= rhs);
276
277            case NE:
278                return new Boolean(lhs != rhs);
279
280            // arithmetic
281            case PLUS:
282                return new Long(lhs + rhs);
283
284            case MINUS:
285                return new Long(lhs - rhs);
286
287            case STAR:
288                return new Long(lhs * rhs);
289
290            case SLASH:
291                return new Long(lhs / rhs);
292
293            case MOD:
294                return new Long(lhs % rhs);
295
296            // bitwise
297            case LSHIFT:
298            case LSHIFTX:
299                return new Long(lhs << rhs);
300
301            case RSIGNEDSHIFT:
302            case RSIGNEDSHIFTX:
303                return new Long(lhs >> rhs);
304
305            case RUNSIGNEDSHIFT:
306            case RUNSIGNEDSHIFTX:
307                return new Long(lhs >>> rhs);
308
309            case BIT_AND:
310            case BIT_ANDX:
311                return new Long(lhs & rhs);
312
313            case BIT_OR:
314            case BIT_ORX:
315                return new Long(lhs | rhs);
316
317            case XOR:
318                return new Long(lhs ^ rhs);
319
320            default:
321                throw new InterpreterError("Unimplemented binary long operator");
322        }
323    }
324
325    // returns Object covering both Integer and Boolean return types
326    static Object intBinaryOperation(Integer I1, Integer I2, int kind)
327    {
328        int lhs = I1.intValue();
329        int rhs = I2.intValue();
330
331        switch(kind)
332        {
333            // boolean
334            case LT:
335            case LTX:
336                return new Boolean(lhs < rhs);
337
338            case GT:
339            case GTX:
340                return new Boolean(lhs > rhs);
341
342            case EQ:
343                return new Boolean(lhs == rhs);
344
345            case LE:
346            case LEX:
347                return new Boolean(lhs <= rhs);
348
349            case GE:
350            case GEX:
351                return new Boolean(lhs >= rhs);
352
353            case NE:
354                return new Boolean(lhs != rhs);
355
356            // arithmetic
357            case PLUS:
358                return new Integer(lhs + rhs);
359
360            case MINUS:
361                return new Integer(lhs - rhs);
362
363            case STAR:
364                return new Integer(lhs * rhs);
365
366            case SLASH:
367                return new Integer(lhs / rhs);
368
369            case MOD:
370                return new Integer(lhs % rhs);
371
372            // bitwise
373            case LSHIFT:
374            case LSHIFTX:
375                return new Integer(lhs << rhs);
376
377            case RSIGNEDSHIFT:
378            case RSIGNEDSHIFTX:
379                return new Integer(lhs >> rhs);
380
381            case RUNSIGNEDSHIFT:
382            case RUNSIGNEDSHIFTX:
383                return new Integer(lhs >>> rhs);
384
385            case BIT_AND:
386            case BIT_ANDX:
387                return new Integer(lhs & rhs);
388
389            case BIT_OR:
390            case BIT_ORX:
391                return new Integer(lhs | rhs);
392
393            case XOR:
394                return new Integer(lhs ^ rhs);
395
396            default:
397                throw new InterpreterError("Unimplemented binary integer operator");
398        }
399    }
400
401    // returns Object covering both Double and Boolean return types
402    static Object doubleBinaryOperation(Double D1, Double D2, int kind)
403        throws EvalError
404    {
405        double lhs = D1.doubleValue();
406        double rhs = D2.doubleValue();
407
408        switch(kind)
409        {
410            // boolean
411            case LT:
412            case LTX:
413                return new Boolean(lhs < rhs);
414
415            case GT:
416            case GTX:
417                return new Boolean(lhs > rhs);
418
419            case EQ:
420                return new Boolean(lhs == rhs);
421
422            case LE:
423            case LEX:
424                return new Boolean(lhs <= rhs);
425
426            case GE:
427            case GEX:
428                return new Boolean(lhs >= rhs);
429
430            case NE:
431                return new Boolean(lhs != rhs);
432
433            // arithmetic
434            case PLUS:
435                return new Double(lhs + rhs);
436
437            case MINUS:
438                return new Double(lhs - rhs);
439
440            case STAR:
441                return new Double(lhs * rhs);
442
443            case SLASH:
444                return new Double(lhs / rhs);
445
446            case MOD:
447                return new Double(lhs % rhs);
448
449            // can't shift floating-point values
450            case LSHIFT:
451            case LSHIFTX:
452            case RSIGNEDSHIFT:
453            case RSIGNEDSHIFTX:
454            case RUNSIGNEDSHIFT:
455            case RUNSIGNEDSHIFTX:
456                throw new EvalError("Can't shift doubles");
457
458            default:
459                throw new InterpreterError("Unimplemented binary double operator");
460        }
461    }
462    // returns Object covering both Long and Boolean return types
463    static Object floatBinaryOperation(Float F1, Float F2, int kind)
464        throws EvalError
465    {
466        float lhs = F1.floatValue();
467        float rhs = F2.floatValue();
468
469        switch(kind)
470        {
471            // boolean
472            case LT:
473            case LTX:
474                return new Boolean(lhs < rhs);
475
476            case GT:
477            case GTX:
478                return new Boolean(lhs > rhs);
479
480            case EQ:
481                return new Boolean(lhs == rhs);
482
483            case LE:
484            case LEX:
485                return new Boolean(lhs <= rhs);
486
487            case GE:
488            case GEX:
489                return new Boolean(lhs >= rhs);
490
491            case NE:
492                return new Boolean(lhs != rhs);
493
494            // arithmetic
495            case PLUS:
496                return new Float(lhs + rhs);
497
498            case MINUS:
499                return new Float(lhs - rhs);
500
501            case STAR:
502                return new Float(lhs * rhs);
503
504            case SLASH:
505                return new Float(lhs / rhs);
506
507            case MOD:
508                return new Float(lhs % rhs);
509
510            // can't shift floats
511            case LSHIFT:
512            case LSHIFTX:
513            case RSIGNEDSHIFT:
514            case RSIGNEDSHIFTX:
515            case RUNSIGNEDSHIFT:
516            case RUNSIGNEDSHIFTX:
517                throw new EvalError("Can't shift floats ");
518
519            default:
520                throw new InterpreterError("Unimplemented binary float operator");
521        }
522    }
523
524	/**
525		Promote primitive wrapper type to to Integer wrapper type
526		Can we use the castPrimitive() (in BSHCastExpression) for this?
527	*/
528    static Object promoteToInteger(Object primitive)
529    {
530        if(primitive instanceof Character)
531            return new Integer(((Character)primitive).charValue());
532        else if((primitive instanceof Byte) || (primitive instanceof Short))
533            return new Integer(((Number)primitive).intValue());
534
535        return primitive;
536    }
537
538	/**
539		Promote the pair of primitives to the maximum type of the two.
540		e.g. [int,long]->[long,long]
541	*/
542    static Object[] promotePrimitives(Object lhs, Object rhs)
543    {
544        lhs = promoteToInteger(lhs);
545        rhs = promoteToInteger(rhs);
546
547        if((lhs instanceof Number) && (rhs instanceof Number))
548        {
549            Number lnum = (Number)lhs;
550            Number rnum = (Number)rhs;
551
552            boolean b;
553
554            if((b = (lnum instanceof Double)) || (rnum instanceof Double))
555            {
556                if(b)
557                    rhs = new Double(rnum.doubleValue());
558                else
559                    lhs = new Double(lnum.doubleValue());
560            }
561            else if((b = (lnum instanceof Float)) || (rnum instanceof Float))
562            {
563                if(b)
564                    rhs = new Float(rnum.floatValue());
565                else
566                    lhs = new Float(lnum.floatValue());
567            }
568            else if((b = (lnum instanceof Long)) || (rnum instanceof Long))
569            {
570                if(b)
571                    rhs = new Long(rnum.longValue());
572                else
573                    lhs = new Long(lnum.longValue());
574            }
575        }
576
577        return new Object[] { lhs, rhs };
578    }
579
580    public static Primitive unaryOperation(Primitive val, int kind)
581        throws EvalError
582    {
583        if(val == NULL)
584            throw new EvalError("illegal use of null object or 'null' literal");
585        if(val == VOID)
586            throw new EvalError("illegal use of undefined object or 'void' literal");
587
588        Class operandType = val.getType();
589        Object operand = promoteToInteger(val.getValue());
590
591        if(operand instanceof Boolean)
592            return new Primitive(booleanUnaryOperation((Boolean)operand, kind));
593        else if(operand instanceof Integer)
594        {
595            int result = intUnaryOperation((Integer)operand, kind);
596
597            // ++ and -- must be cast back the original type
598            if(kind == INCR || kind == DECR)
599            {
600                if(operandType == Byte.TYPE)
601                    return new Primitive((byte)result);
602                if(operandType == Short.TYPE)
603                    return new Primitive((short)result);
604                if(operandType == Character.TYPE)
605                    return new Primitive((char)result);
606            }
607
608            return new Primitive(result);
609        }
610        else if(operand instanceof Long)
611            return new Primitive(longUnaryOperation((Long)operand, kind));
612        else if(operand instanceof Float)
613            return new Primitive(floatUnaryOperation((Float)operand, kind));
614        else if(operand instanceof Double)
615            return new Primitive(doubleUnaryOperation((Double)operand, kind));
616        else
617            throw new InterpreterError("An error occurred.  Please call technical support.");
618    }
619
620    static boolean booleanUnaryOperation(Boolean B, int kind) throws EvalError
621    {
622        boolean operand = B.booleanValue();
623        switch(kind)
624        {
625            case BANG:
626                return !operand;
627
628            default:
629                throw new EvalError("Operator inappropriate for boolean");
630        }
631    }
632
633    static int intUnaryOperation(Integer I, int kind)
634    {
635        int operand = I.intValue();
636
637        switch(kind)
638        {
639            case PLUS:
640                return operand;
641
642            case MINUS:
643                return -operand;
644
645            case TILDE:
646                return ~operand;
647
648            case INCR:
649                return operand + 1;
650
651            case DECR:
652                return operand - 1;
653
654            default:
655                throw new InterpreterError("bad integer unaryOperation");
656        }
657    }
658
659    static long longUnaryOperation(Long L, int kind)
660    {
661        long operand = L.longValue();
662
663        switch(kind)
664        {
665            case PLUS:
666                return operand;
667
668            case MINUS:
669                return -operand;
670
671            case TILDE:
672                return ~operand;
673
674            case INCR:
675                return operand + 1;
676
677            case DECR:
678                return operand - 1;
679
680            default:
681                throw new InterpreterError("bad long unaryOperation");
682        }
683    }
684
685    static float floatUnaryOperation(Float F, int kind)
686    {
687        float operand = F.floatValue();
688
689        switch(kind)
690        {
691            case PLUS:
692                return operand;
693
694            case MINUS:
695                return -operand;
696
697            default:
698                throw new InterpreterError("bad float unaryOperation");
699        }
700    }
701
702    static double doubleUnaryOperation(Double D, int kind)
703    {
704        double operand = D.doubleValue();
705
706        switch(kind)
707        {
708            case PLUS:
709                return operand;
710
711            case MINUS:
712                return -operand;
713
714            default:
715                throw new InterpreterError("bad double unaryOperation");
716        }
717    }
718
719    public int intValue() throws EvalError
720    {
721        if(value instanceof Number)
722            return((Number)value).intValue();
723        else
724            throw new EvalError("Primitive not a number");
725    }
726
727    public boolean booleanValue() throws EvalError
728    {
729        if(value instanceof Boolean)
730            return((Boolean)value).booleanValue();
731        else
732            throw new EvalError("Primitive not a boolean");
733    }
734
735	/**
736		Are we a numeric type:
737		i.e. not boolean, null, or void
738		(but including char)
739	*/
740	public boolean isNumber() {
741		return ( !(value instanceof Boolean) 
742			&& !(this == NULL) && !(this == VOID) );
743	}
744
745    public Number numberValue() throws EvalError
746    {
747		Object value = this.value;
748
749		// Promote character to Number type for these purposes
750		if (value instanceof Character)
751			value = new Integer(((Character)value).charValue());
752
753        if (value instanceof Number)
754            return (Number)value;
755        else
756            throw new EvalError("Primitive not a number");
757    }
758
759	public boolean equals( Object obj ) {
760		if ( obj instanceof Primitive )
761			return ((Primitive)obj).value.equals( this.value );
762		else
763			return obj.equals( this.value );
764	}
765
766	/**
767		Unwrap primitive values and map voids to nulls.
768		Normal (non Primitive) types remain unchanged.
769		@param obj object type which may be bsh.Primitive
770		@return corresponding "normal" Java type, "unwrapping" 
771			any bsh.Primitive types to their wrapper types.
772	*/
773	public static Object unwrap( Object obj ) {
774		if ( obj == null )
775			return null;
776
777        // map voids to nulls for the outside world
778        if(obj == Primitive.VOID)
779            return null;
780
781        // unwrap primitives
782        if(obj instanceof Primitive)
783            return((Primitive)obj).getValue();
784        else
785            return obj;
786	}
787
788
789}