public LHS toLHS(CallStack callstack, Interpreter interpreter) throws EvalError { try { return getName(callstack.top()).toLHS(callstack, interpreter); } catch (UtilEvalError e) { throw e.toEvalError(this, callstack); } }
Object toObject(CallStack callstack, Interpreter interpreter, boolean forceClass) throws EvalError { try { return getName(callstack.top()).toObject(callstack, interpreter, forceClass); } catch (UtilEvalError e) { throw e.toEvalError(this, callstack); } }
public Class toClass(CallStack callstack, Interpreter interpreter) throws EvalError { try { return getName(callstack.top()).toClass(); } catch (ClassNotFoundException e) { throw new EvalError(e.getMessage(), this, callstack); } catch (UtilEvalError e2) { // ClassPathException is a type of UtilEvalError throw e2.toEvalError(this, callstack); } }
/** * Construct the array from the initializer syntax. * * @param baseType the base class type of the array (no dimensionality) * @param dimensions the top number of dimensions of the array e.g. 2 for a String [][]; */ public Object eval(Class baseType, int dimensions, CallStack callstack, Interpreter interpreter) throws EvalError { int numInitializers = jjtGetNumChildren(); // allocate the array to store the initializers int[] dima = new int[dimensions]; // description of the array // The other dimensions default to zero and are assigned when // the values are set. dima[0] = numInitializers; Object initializers = Array.newInstance(baseType, dima); // Evaluate the initializers for (int i = 0; i < numInitializers; i++) { SimpleNode node = (SimpleNode) jjtGetChild(i); Object currentInitializer; if (node instanceof BSHArrayInitializer) { if (dimensions < 2) throw new EvalError("Invalid Location for Intializer, position: " + i, this, callstack); currentInitializer = ((BSHArrayInitializer) node).eval(baseType, dimensions - 1, callstack, interpreter); } else currentInitializer = node.eval(callstack, interpreter); if (currentInitializer == Primitive.VOID) throw new EvalError("Void in array initializer, position" + i, this, callstack); // Determine if any conversion is necessary on the initializers. // // Quick test to see if conversions apply: // If the dimensionality of the array is 1 then the elements of // the initializer can be primitives or boxable types. If it is // greater then the values must be array (object) types and there // are currently no conversions that we do on those. // If we have conversions on those in the future then we need to // get the real base type here instead of the dimensionless one. Object value = currentInitializer; if (dimensions == 1) { // We do a bsh cast here. strictJava should be able to affect // the cast there when we tighten control try { value = Types.castObject(currentInitializer, baseType, Types.CAST); } catch (UtilEvalError e) { throw e.toEvalError("Error in array initializer", this, callstack); } // unwrap any primitive, map voids to null, etc. value = Primitive.unwrap(value); } // store the value in the array try { Array.set(initializers, i, value); } catch (IllegalArgumentException e) { Interpreter.debug("illegal arg" + e); throwTypeError(baseType, currentInitializer, i, callstack); } catch (ArrayStoreException e) { // I think this can happen Interpreter.debug("arraystore" + e); throwTypeError(baseType, currentInitializer, i, callstack); } } return initializers; }
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); Class rhs = ((BSHType) jjtGetChild(1)).getType(callstack, interpreter); /* // 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 normally an instanceof anything. But for internal use we'll test true for the bsh.Primitive class. i.e. (5 instanceof bsh.Primitive) will be true */ if (lhs instanceof Primitive) if (rhs == lib.bsh.Primitive.class) return new Primitive(true); else return new Primitive(false); // General case - performe the instanceof based on assignability boolean ret = Types.isJavaBaseAssignable(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 (UtilEvalError e) { throw e.toEvalError(this, callstack); } } /* Doing the following makes it hard to use untyped vars... e.g. if ( arg == null ) ...what if arg is a primitive? The answer is that we should test only if the var is typed...? need to get that info here... else { // Do we have a mixture of primitive values and non-primitives ? // (primitiveValue = not null, not void) 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("Operator: '" + tokenImage[kind] +"' inappropriate for object / primitive combination.", this, callstack ); // 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, callstack); else if (lhs == Primitive.NULL || rhs == Primitive.NULL) throw new EvalError("illegal use of null value or 'null' literal", this, callstack); throw new EvalError( "Operator: '" + tokenImage[kind] + "' inappropriate for objects", this, callstack); } }
public Object eval(CallStack callstack, Interpreter interpreter) throws EvalError { Class elementType = null; SimpleNode expression; SimpleNode statement = null; NameSpace enclosingNameSpace = callstack.top(); SimpleNode firstNode = ((SimpleNode) jjtGetChild(0)); int nodeCount = jjtGetNumChildren(); if (firstNode instanceof BSHType) { elementType = ((BSHType) firstNode).getType(callstack, interpreter); expression = ((SimpleNode) jjtGetChild(1)); if (nodeCount > 2) { statement = ((SimpleNode) jjtGetChild(2)); } } else { expression = firstNode; if (nodeCount > 1) { statement = ((SimpleNode) jjtGetChild(1)); } } BlockNameSpace eachNameSpace = new BlockNameSpace(enclosingNameSpace); callstack.swap(eachNameSpace); final Object iteratee = expression.eval(callstack, interpreter); if (iteratee == Primitive.NULL) { throw new EvalError( "The collection, array, map, iterator, or " + "enumeration portion of a for statement cannot be null.", this, callstack); } CollectionManager cm = CollectionManager.getCollectionManager(); if (!cm.isBshIterable(iteratee)) { throw new EvalError("Can't iterate over type: " + iteratee.getClass(), this, callstack); } BshIterator iterator = cm.getBshIterator(iteratee); Object returnControl = Primitive.VOID; while (iterator.hasNext()) { try { Object value = iterator.next(); if (value == null) { value = Primitive.NULL; } if (elementType != null) { eachNameSpace.setTypedVariable( varName /*name*/, elementType /*type*/, value /*value*/, new Modifiers() /*none*/); } else { eachNameSpace.setVariable(varName, value, false); } } catch (UtilEvalError e) { throw e.toEvalError("for loop iterator variable:" + varName, this, callstack); } boolean breakout = false; // switch eats a multi-level break here? if (statement != null) { // not empty statement Object ret = statement.eval(callstack, interpreter); if (ret instanceof ReturnControl) { switch (((ReturnControl) ret).kind) { case RETURN: returnControl = ret; breakout = true; break; case CONTINUE: break; case BREAK: breakout = true; break; } } } if (breakout) { break; } } callstack.swap(enclosingNameSpace); return returnControl; }