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); } }
/** * Set the value of a the variable 'name' through this namespace. The variable may be an existing * or non-existing variable. It may live in this namespace or in a parent namespace if recurse is * true. * * <p>Note: This method is not public and does *not* know about LOCALSCOPING. Its caller methods * must set recurse intelligently in all situations (perhaps based on LOCALSCOPING). * * <p>Note: this method is primarily intended for use internally. If you use this method outside * of the bsh package and wish to set variables with primitive values you will have to wrap them * using bsh.Primitive. * * @see bsh.Primitive * <p>Setting a new variable (which didn't exist before) or removing a variable causes a * namespace change. * @param strictJava specifies whether strict java rules are applied. * @param recurse determines whether we will search for the variable in our parent's scope before * assigning locally. */ void setVariable(String name, Object value, boolean strictJava, boolean recurse) throws UtilEvalError { ensureVariables(); // primitives should have been wrapped if (value == null) throw new InterpreterError("null variable value"); // Locate the variable definition if it exists. Variable existing = getVariableImpl(name, recurse); // Found an existing variable here (or above if recurse allowed) if (existing != null) { try { existing.setValue(value, Variable.ASSIGNMENT); } catch (UtilEvalError e) { throw new UtilEvalError("Variable assignment: " + name + ": " + e.getMessage()); } } else // No previous variable definition found here (or above if recurse) { if (strictJava) throw new UtilEvalError("(Strict Java mode) Assignment to undeclared variable: " + name); // If recurse, set global untyped var, else set it here. // NameSpace varScope = recurse ? getGlobal() : this; // This modification makes default allocation local NameSpace varScope = this; varScope.variables.put(name, new Variable(name, value, null /*modifiers*/)); // nameSpaceChanged() on new variable addition nameSpaceChanged(); } }
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; }