/jEdit/tags/jedit-4-1-pre5/bsh/BSHBinaryExpression.java
Java | 215 lines | 85 code | 24 blank | 106 comment | 50 complexity | 1cd6163ce9a6cc2c07f58acccb65c87d MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
- /*****************************************************************************
- * *
- * This file is part of the BeanShell Java Scripting distribution. *
- * Documentation and updates may be found at http://www.beanshell.org/ *
- * *
- * Sun Public License Notice: *
- * *
- * The contents of this file are subject to the Sun Public License Version *
- * 1.0 (the "License"); you may not use this file except in compliance with *
- * the License. A copy of the License is available at http://www.sun.com *
- * *
- * The Original Code is BeanShell. The Initial Developer of the Original *
- * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
- * (C) 2000. All Rights Reserved. *
- * *
- * GNU Public License Notice: *
- * *
- * Alternatively, the contents of this file may be used under the terms of *
- * the GNU Lesser General Public License (the "LGPL"), in which case the *
- * provisions of LGPL are applicable instead of those above. If you wish to *
- * allow use of your version of this file only under the terms of the LGPL *
- * and not to allow others to use your version of this file under the SPL, *
- * indicate your decision by deleting the provisions above and replace *
- * them with the notice and other provisions required by the LGPL. If you *
- * do not delete the provisions above, a recipient may use your version of *
- * this file under either the SPL or the LGPL. *
- * *
- * Patrick Niemeyer (pat@pat.net) *
- * Author of Learning Java, O'Reilly & Associates *
- * http://www.pat.net/~pat/ *
- * *
- *****************************************************************************/
- package bsh;
- /**
- Implement binary expressions...
- Note: this is too complicated... need some cleanup and simplification.
- @see Primitive.binaryOperation
- */
- class BSHBinaryExpression extends SimpleNode
- implements ParserConstants
- {
- public int kind;
- BSHBinaryExpression(int id) { super(id); }
- public Object eval( CallStack callstack, Interpreter interpreter)
- throws EvalError
- {
- Object lhs = ((SimpleNode)jjtGetChild(0)).eval(callstack, interpreter);
- /*
- Doing instanceof? Next node is a type.
- */
- if (kind == INSTANCEOF)
- {
- // null object ref is not instance of any type
- if ( lhs == Primitive.NULL )
- return new Primitive(false);
- /*
- // primitive (number or void) cannot be tested for instanceof
- if (lhs instanceof Primitive)
- throw new EvalError("Cannot be instance of primitive type." );
- */
- // Primitive (number or void) is not an instanceof anything
- if (lhs instanceof Primitive)
- return new Primitive(false);
- // General case - performe the instanceof based on assignability
- NameSpace namespace = callstack.top();
- Class rhs = ((BSHType)jjtGetChild(1)).getType(namespace);
- boolean ret = (Reflect.isAssignableFrom(rhs, lhs.getClass()));
- return new Primitive(ret);
- }
- // The following two boolean checks were tacked on.
- // This could probably be smoothed out.
- /*
- Look ahead and short circuit evaluation of the rhs if:
- we're a boolean AND and the lhs is false.
- */
- if ( kind == BOOL_AND || kind == BOOL_ANDX ) {
- Object obj = lhs;
- if ( isPrimitiveValue(lhs) )
- obj = ((Primitive)lhs).getValue();
- if ( obj instanceof Boolean &&
- ( ((Boolean)obj).booleanValue() == false ) )
- return new Primitive(false);
- }
- /*
- Look ahead and short circuit evaluation of the rhs if:
- we're a boolean AND and the lhs is false.
- */
- if ( kind == BOOL_OR || kind == BOOL_ORX ) {
- Object obj = lhs;
- if ( isPrimitiveValue(lhs) )
- obj = ((Primitive)lhs).getValue();
- if ( obj instanceof Boolean &&
- ( ((Boolean)obj).booleanValue() == true ) )
- return new Primitive(true);
- }
- // end stuff that was tacked on for boolean short-circuiting.
- /*
- Are both the lhs and rhs either wrappers or primitive values?
- do binary op
- */
- boolean isLhsWrapper = isWrapper( lhs );
- Object rhs = ((SimpleNode)jjtGetChild(1)).eval(callstack, interpreter);
- boolean isRhsWrapper = isWrapper( rhs );
- if (
- ( isLhsWrapper || isPrimitiveValue( lhs ) )
- && ( isRhsWrapper || isPrimitiveValue( rhs ) )
- )
- {
- // Special case for EQ on two wrapper objects
- if ( (isLhsWrapper && isRhsWrapper && kind == EQ))
- {
- /*
- Don't auto-unwrap wrappers (preserve identity semantics)
- FALL THROUGH TO OBJECT OPERATIONS BELOW.
- */
- } else
- try {
- return Primitive.binaryOperation(lhs, rhs, kind);
- } catch ( TargetError e ) {
- // this doesn't really help... need to catch it higher?
- e.reThrow( this );
- }
- }
- /*
- Do we have a mixture of primitive values and non-primitives ?
- (primitiveValue = not null, not void)
- god, this is getting ugly...
- */
- /*
- Removing this restriction for now...
- int primCount = 0;
- if ( isPrimitiveValue( lhs ) )
- ++primCount;
- if ( isPrimitiveValue( rhs ) )
- ++primCount;
- if ( primCount > 1 )
- // both primitive types, should have been handled above
- throw new InterpreterError("should not be here");
- else if ( primCount == 1 )
- // mixture of one and the other
- throw new EvalError( "Invalid use of primitive and non-primitive"
- +" values in binary operation.");
- // else fall through to handle both non-primitive types
- // end check for primitive and non-primitive mix
- */
- /*
- Treat lhs and rhs as arbitrary objects and do the operation.
- (including NULL and VOID represented by their Primitive types)
- */
- //System.out.println("binary op arbitrary obj: {"+lhs+"}, {"+rhs+"}");
- switch(kind)
- {
- case EQ:
- return new Primitive((lhs == rhs));
- case NE:
- return new Primitive((lhs != rhs));
- case PLUS:
- if(lhs instanceof String || rhs instanceof String)
- return lhs.toString() + rhs.toString();
- // FALL THROUGH TO DEFAULT CASE!!!
- default:
- if(lhs instanceof Primitive || rhs instanceof Primitive)
- if(lhs == Primitive.VOID || rhs == Primitive.VOID)
- throw new EvalError(
- "illegal use of undefined variable, class, or 'void' literal", this);
- else
- if(lhs == Primitive.NULL || rhs == Primitive.NULL)
- throw new EvalError(
- "illegal use of null value or 'null' literal", this);
- throw new EvalError("Operator: '" + tokenImage[kind] +
- "' inappropriate for objects", this);
- }
- }
- /*
- object is a non-null and non-void Primitive type
- */
- private boolean isPrimitiveValue( Object obj ) {
- return ( (obj instanceof Primitive)
- && (obj != Primitive.VOID) && (obj != Primitive.NULL) );
- }
- /*
- object is a java.lang wrapper for boolean, char, or number type
- */
- private boolean isWrapper( Object obj ) {
- return ( obj instanceof Boolean ||
- obj instanceof Character || obj instanceof Number );
- }
- }