PageRenderTime 75ms CodeModel.GetById 66ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 227 lines | 89 code | 21 blank | 117 comment | 52 complexity | 22c581144fdcfa0a658846d41eb64a07 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
 37/**
 38	Implement binary expressions...
 39	Note: this is too complicated... need some cleanup and simplification.
 40	@see Primitive.binaryOperation
 41*/
 42class BSHBinaryExpression extends SimpleNode 
 43	implements ParserConstants 
 44{
 45    public int kind;
 46
 47    BSHBinaryExpression(int id) { super(id); }
 48
 49    public Object eval( CallStack callstack, Interpreter interpreter)  
 50		throws EvalError
 51    {
 52        Object lhs = ((SimpleNode)jjtGetChild(0)).eval(callstack, interpreter);
 53
 54		/*
 55			Doing instanceof?  Next node is a type.
 56		*/
 57        if (kind == INSTANCEOF)
 58        {
 59			// null object ref is not instance of any type
 60			if ( lhs == Primitive.NULL )
 61				return new Primitive(false);
 62
 63            Class rhs = ((BSHType)jjtGetChild(1)).getType( 
 64				callstack, interpreter );
 65		/*
 66			// primitive (number or void) cannot be tested for instanceof
 67            if (lhs instanceof Primitive)
 68				throw new EvalError("Cannot be instance of primitive type." );
 69		*/
 70			/*
 71				Primitive (number or void) is not normally an instanceof
 72				anything.  But for internal use we'll test true for the
 73				bsh.Primitive class.  
 74				i.e. (5 instanceof bsh.Primitive) will be true
 75			*/
 76			if ( lhs instanceof Primitive )
 77				if ( rhs == org.gjt.sp.jedit.bsh.Primitive.class )
 78					return new Primitive(true);
 79				else
 80					return new Primitive(false);
 81
 82			// General case - performe the instanceof based on assignability
 83            boolean ret = Types.isJavaBaseAssignable( rhs, lhs.getClass() );
 84            return new Primitive(ret);
 85        }
 86
 87
 88		// The following two boolean checks were tacked on.
 89		// This could probably be smoothed out.
 90
 91		/*
 92			Look ahead and short circuit evaluation of the rhs if:
 93				we're a boolean AND and the lhs is false.
 94		*/
 95		if ( kind == BOOL_AND || kind == BOOL_ANDX ) {
 96			Object obj = lhs;
 97			if ( isPrimitiveValue(lhs) )
 98				obj = ((Primitive)lhs).getValue();
 99			if ( obj instanceof Boolean && 
100				( ((Boolean)obj).booleanValue() == false ) )
101				return new Primitive(false);
102		}
103		/*
104			Look ahead and short circuit evaluation of the rhs if:
105				we're a boolean AND and the lhs is false.
106		*/
107		if ( kind == BOOL_OR || kind == BOOL_ORX ) {
108			Object obj = lhs;
109			if ( isPrimitiveValue(lhs) )
110				obj = ((Primitive)lhs).getValue();
111			if ( obj instanceof Boolean && 
112				( ((Boolean)obj).booleanValue() == true ) )
113				return new Primitive(true);
114		}
115
116		// end stuff that was tacked on for boolean short-circuiting.
117
118		/*
119			Are both the lhs and rhs either wrappers or primitive values?
120			do binary op
121		*/
122		boolean isLhsWrapper = isWrapper( lhs );
123        Object rhs = ((SimpleNode)jjtGetChild(1)).eval(callstack, interpreter);
124		boolean isRhsWrapper = isWrapper( rhs );
125		if ( 
126			( isLhsWrapper || isPrimitiveValue( lhs ) )
127			&& ( isRhsWrapper || isPrimitiveValue( rhs ) )
128		)
129        {
130			// Special case for EQ on two wrapper objects
131			if ( (isLhsWrapper && isRhsWrapper && kind == EQ)) 
132			{
133				/*  
134					Don't auto-unwrap wrappers (preserve identity semantics)
135					FALL THROUGH TO OBJECT OPERATIONS BELOW.
136				*/
137			} else
138				try {
139					return Primitive.binaryOperation(lhs, rhs, kind);
140				} catch ( UtilEvalError e ) {
141					throw e.toEvalError( this, callstack  );
142				}
143        }
144	/*
145	Doing the following makes it hard to use untyped vars...
146	e.g. if ( arg == null ) ...what if arg is a primitive?
147	The answer is that we should test only if the var is typed...?
148	need to get that info here...
149
150		else
151		{
152		// Do we have a mixture of primitive values and non-primitives ?  
153		// (primitiveValue = not null, not void)
154
155		int primCount = 0;
156		if ( isPrimitiveValue( lhs ) )
157			++primCount;
158		if ( isPrimitiveValue( rhs ) )
159			++primCount;
160
161		if ( primCount > 1 )
162			// both primitive types, should have been handled above
163			throw new InterpreterError("should not be here");
164		else 
165		if ( primCount == 1 )
166			// mixture of one and the other
167			throw new EvalError("Operator: '" + tokenImage[kind]
168				+"' inappropriate for object / primitive combination.", 
169				this, callstack );
170
171		// else fall through to handle both non-primitive types
172
173		// end check for primitive and non-primitive mix 
174		}
175	*/
176
177		/*
178			Treat lhs and rhs as arbitrary objects and do the operation.
179			(including NULL and VOID represented by their Primitive types)
180		*/
181		//System.out.println("binary op arbitrary obj: {"+lhs+"}, {"+rhs+"}");
182        switch(kind)
183        {
184            case EQ:
185                return new Primitive((lhs == rhs));
186
187            case NE:
188                return new Primitive((lhs != rhs));
189
190            case PLUS:
191                if(lhs instanceof String || rhs instanceof String)
192                    return lhs.toString() + rhs.toString();
193
194            // FALL THROUGH TO DEFAULT CASE!!!
195
196            default:
197                if(lhs instanceof Primitive || rhs instanceof Primitive)
198                    if ( lhs == Primitive.VOID || rhs == Primitive.VOID )
199                        throw new EvalError(
200				"illegal use of undefined variable, class, or 'void' literal", 
201							this, callstack );
202                    else 
203					if ( lhs == Primitive.NULL || rhs == Primitive.NULL )
204                        throw new EvalError(
205				"illegal use of null value or 'null' literal", this, callstack);
206
207                throw new EvalError("Operator: '" + tokenImage[kind] +
208                    "' inappropriate for objects", this, callstack );
209        }
210    }
211
212	/*
213		object is a non-null and non-void Primitive type
214	*/
215	private boolean isPrimitiveValue( Object obj ) {
216        return ( (obj instanceof Primitive) 
217			&& (obj != Primitive.VOID) && (obj != Primitive.NULL) );
218	}
219
220	/*
221		object is a java.lang wrapper for boolean, char, or number type
222	*/
223	private boolean isWrapper( Object obj ) {
224        return ( obj instanceof Boolean || 
225			obj instanceof Character || obj instanceof Number );
226	}
227}