PageRenderTime 19ms CodeModel.GetById 10ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/bsh/BSHCastExpression.java

#
Java | 203 lines | 99 code | 24 blank | 80 comment | 42 complexity | c80e0570bd5683239c74c9f26c929738 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	Implement casts.
 39
 40	I think it should be possible to simplify some of the code here by
 41	using the NameSpace.getAssignableForm() method, but I haven't looked 
 42	into it.
 43*/
 44class BSHCastExpression extends SimpleNode {
 45
 46    public BSHCastExpression(int id) { super(id); }
 47
 48	/**
 49		@return the result of the cast.
 50	*/
 51	public Object eval(
 52		CallStack callstack, Interpreter interpreter ) throws EvalError
 53    {
 54		NameSpace namespace = callstack.top();
 55        Class toType = ((BSHType)jjtGetChild(0)).getType( 
 56			callstack, interpreter );
 57		SimpleNode expression = (SimpleNode)jjtGetChild(1);
 58
 59        // evaluate the expression
 60        Object fromValue = expression.eval(callstack, interpreter);
 61        Class fromType = fromValue.getClass();
 62
 63		try {
 64			return castObject( fromValue, toType );
 65		} catch ( UtilEvalError e ) {
 66			throw e.toEvalError( this, callstack  );
 67		}
 68    }
 69
 70	/**
 71		Cast an object to a new type.
 72		This method can handle bsh.Primitive types (representing primitive 
 73		casts) as well as arbitrary object casts.
 74		@param fromValue an Object or bsh.Primitive primitive value 
 75		@param toType the class type of the cast result, which may include
 76		primitive types, e.g. Byte.TYPE
 77	*/
 78	public static Object castObject( Object fromValue, Class toType )
 79		throws UtilEvalError
 80	{
 81        Class fromType = fromValue.getClass();
 82
 83		// The compiler isn't smart enough to allow me to leave this unassigned
 84		// even though it is clearly assigned in all cases below.
 85        Object result = null;
 86
 87		// Going to a primitive type
 88        if ( toType.isPrimitive() ) 
 89			if ( fromValue instanceof Primitive )
 90				result = castPrimitive( (Primitive)fromValue, toType );
 91			else
 92				// cannot convert from object to primitive
 93                castError(fromValue.getClass(), toType);
 94        else 
 95			// Going to an object type
 96			if ( fromValue instanceof Primitive )
 97				// let castPrimitive handle trivial but legit case of NULL
 98				result = castPrimitive( (Primitive)fromValue, toType );
 99			else
100				// Can we use the proxy mechanism to cast a bsh.This to 
101				// the correct interface?
102				if ( Capabilities.canGenerateInterfaces() &&
103					(fromValue instanceof bsh.This) && toType.isInterface() ) 
104						result = ((bsh.This)fromValue).getInterface( toType );
105				else 
106					// Could probably add getAssignableForm here to allow 
107					// special bsh widening converions... wrappers to wrappers
108					if ( toType.isInstance(fromValue ) )
109						result = fromValue;
110					else
111						castError(fromType, toType);
112
113		if ( result == null )
114			throw new InternalError("bad construct somewhere...");
115
116		return result;
117	}
118
119	/**
120		Wrap up the ClassCastException in a TargetError so that it can
121		be caught...
122		Node user should catch and add the node
123	*/
124    public static void castError(Class from, Class to) throws UtilEvalError {
125		castError( 
126			Reflect.normalizeClassName(from), Reflect.normalizeClassName(to) );
127    }
128
129    public static void castError(String from, String to) throws UtilEvalError 
130	{
131		Exception cce = new ClassCastException("Illegal cast. Cannot cast " +
132            from + " to " + to );
133		throw new UtilTargetError( cce );
134    }
135
136	/**
137		Cast the bsh.Primitive value to a new bsh.Primitive value
138		This is usually a numeric type cast.  Other cases include:
139			boolean can be cast to boolen
140			null can be cast to any object type
141			void cannot be cast to anything
142	*/
143	public static Primitive castPrimitive( Primitive primValue, Class toType ) 
144		throws UtilEvalError
145	{
146		// can't cast void to anything
147		if ( primValue == Primitive.VOID )
148			castError( "void value", Reflect.normalizeClassName(toType) );
149
150		// unwrap, etc.
151		Object value = primValue.getValue();
152		Class fromType = primValue.getType();
153
154		// Trying to cast primitive to an object type?
155		// only works for Primitive.NULL
156		if ( !toType.isPrimitive() )
157			if ( primValue != Primitive.NULL )
158				castError("primitive value", "object type:" + toType);
159			else
160				return primValue;
161
162		// can only cast boolean to boolean
163		if ( fromType == Boolean.TYPE )
164		{
165			if ( toType != Boolean.TYPE )
166				castError(fromType, toType);
167			else 
168				return primValue;
169		}
170
171		// trying to do numeric promotion
172
173		// first promote char to Number type to avoid duplicating code
174		if (value instanceof Character)
175			value = new Integer(((Character)value).charValue());
176
177		if (value instanceof Number)
178		{
179			Number number = (Number)value;
180
181			if (toType == Byte.TYPE)
182				value = new Primitive(number.byteValue());
183			else if(toType == Short.TYPE)
184				value = new Primitive(number.shortValue());
185			else if(toType == Character.TYPE)
186				value = new Primitive((char)number.intValue());
187			else if(toType == Integer.TYPE)
188				value = new Primitive(number.intValue());
189			else if(toType == Long.TYPE)
190				value = new Primitive(number.longValue());
191			else if(toType == Float.TYPE)
192				value = new Primitive(number.floatValue());
193			else if(toType == Double.TYPE)
194				value = new Primitive(number.doubleValue());
195			else
196				castError(fromType, toType);
197
198			return (Primitive)value;
199		} 
200
201		throw new UtilEvalError("unknown type in cast");
202	}
203}