001: /*****************************************************************************
002: * *
003: * This file is part of the BeanShell Java Scripting distribution. *
004: * Documentation and updates may be found at http://www.beanshell.org/ *
005: * *
006: * Sun Public License Notice: *
007: * *
008: * The contents of this file are subject to the Sun Public License Version *
009: * 1.0 (the "License"); you may not use this file except in compliance with *
010: * the License. A copy of the License is available at http://www.sun.com *
011: * *
012: * The Original Code is BeanShell. The Initial Developer of the Original *
013: * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
014: * (C) 2000. All Rights Reserved. *
015: * *
016: * GNU Public License Notice: *
017: * *
018: * Alternatively, the contents of this file may be used under the terms of *
019: * the GNU Lesser General Public License (the "LGPL"), in which case the *
020: * provisions of LGPL are applicable instead of those above. If you wish to *
021: * allow use of your version of this file only under the terms of the LGPL *
022: * and not to allow others to use your version of this file under the SPL, *
023: * indicate your decision by deleting the provisions above and replace *
024: * them with the notice and other provisions required by the LGPL. If you *
025: * do not delete the provisions above, a recipient may use your version of *
026: * this file under either the SPL or the LGPL. *
027: * *
028: * Patrick Niemeyer (pat@pat.net) *
029: * Author of Learning Java, O'Reilly & Associates *
030: * http://www.pat.net/~pat/ *
031: * *
032: *****************************************************************************/package bsh;
033:
034: class BSHAssignment extends SimpleNode implements ParserConstants {
035: public int operator;
036:
037: BSHAssignment(int id) {
038: super (id);
039: }
040:
041: public Object eval(CallStack callstack, Interpreter interpreter)
042: throws EvalError {
043: BSHPrimaryExpression lhsNode = (BSHPrimaryExpression) jjtGetChild(0);
044:
045: if (lhsNode == null)
046: throw new InterpreterError("Error, null LHSnode");
047:
048: boolean strictJava = interpreter.getStrictJava();
049: LHS lhs = lhsNode.toLHS(callstack, interpreter);
050: if (lhs == null)
051: throw new InterpreterError("Error, null LHS");
052:
053: // For operator-assign operations save the lhs value before evaluating
054: // the rhs. This is correct Java behavior for postfix operations
055: // e.g. i=1; i+=i++; // should be 2 not 3
056: Object lhsValue = null;
057: if (operator != ASSIGN) // assign doesn't need the pre-value
058: try {
059: lhsValue = lhs.getValue();
060: } catch (UtilEvalError e) {
061: throw e.toEvalError(this , callstack);
062: }
063:
064: SimpleNode rhsNode = (SimpleNode) jjtGetChild(1);
065:
066: Object rhs;
067:
068: // implement "blocks" foo = { };
069: // if ( rhsNode instanceof BSHBlock )
070: // rsh =
071: // else
072: rhs = rhsNode.eval(callstack, interpreter);
073:
074: if (rhs == Primitive.VOID)
075: throw new EvalError("Void assignment.", this , callstack);
076:
077: try {
078: switch (operator) {
079: case ASSIGN:
080: return lhs.assign(rhs, strictJava);
081:
082: case PLUSASSIGN:
083: return lhs.assign(operation(lhsValue, rhs, PLUS),
084: strictJava);
085:
086: case MINUSASSIGN:
087: return lhs.assign(operation(lhsValue, rhs, MINUS),
088: strictJava);
089:
090: case STARASSIGN:
091: return lhs.assign(operation(lhsValue, rhs, STAR),
092: strictJava);
093:
094: case SLASHASSIGN:
095: return lhs.assign(operation(lhsValue, rhs, SLASH),
096: strictJava);
097:
098: case ANDASSIGN:
099: case ANDASSIGNX:
100: return lhs.assign(operation(lhsValue, rhs, BIT_AND),
101: strictJava);
102:
103: case ORASSIGN:
104: case ORASSIGNX:
105: return lhs.assign(operation(lhsValue, rhs, BIT_OR),
106: strictJava);
107:
108: case XORASSIGN:
109: return lhs.assign(operation(lhsValue, rhs, XOR),
110: strictJava);
111:
112: case MODASSIGN:
113: return lhs.assign(operation(lhsValue, rhs, MOD),
114: strictJava);
115:
116: case LSHIFTASSIGN:
117: case LSHIFTASSIGNX:
118: return lhs.assign(operation(lhsValue, rhs, LSHIFT),
119: strictJava);
120:
121: case RSIGNEDSHIFTASSIGN:
122: case RSIGNEDSHIFTASSIGNX:
123: return lhs.assign(
124: operation(lhsValue, rhs, RSIGNEDSHIFT),
125: strictJava);
126:
127: case RUNSIGNEDSHIFTASSIGN:
128: case RUNSIGNEDSHIFTASSIGNX:
129: return lhs.assign(operation(lhsValue, rhs,
130: RUNSIGNEDSHIFT), strictJava);
131:
132: default:
133: throw new InterpreterError(
134: "unimplemented operator in assignment BSH");
135: }
136: } catch (UtilEvalError e) {
137: throw e.toEvalError(this , callstack);
138: }
139: }
140:
141: private Object operation(Object lhs, Object rhs, int kind)
142: throws UtilEvalError {
143: /*
144: Implement String += value;
145: According to the JLS, value may be anything.
146: In BeanShell, we'll disallow VOID (undefined) values.
147: (or should we map them to the empty string?)
148: */
149: if (lhs instanceof String && rhs != Primitive.VOID) {
150: if (kind != PLUS)
151: throw new UtilEvalError(
152: "Use of non + operator with String LHS");
153:
154: return (String) lhs + rhs;
155: }
156:
157: if (lhs instanceof Primitive || rhs instanceof Primitive)
158: if (lhs == Primitive.VOID || rhs == Primitive.VOID)
159: throw new UtilEvalError(
160: "Illegal use of undefined object or 'void' literal");
161: else if (lhs == Primitive.NULL || rhs == Primitive.NULL)
162: throw new UtilEvalError(
163: "Illegal use of null object or 'null' literal");
164:
165: if ((lhs instanceof Boolean || lhs instanceof Character
166: || lhs instanceof Number || lhs instanceof Primitive)
167: && (rhs instanceof Boolean || rhs instanceof Character
168: || rhs instanceof Number || rhs instanceof Primitive)) {
169: return Primitive.binaryOperation(lhs, rhs, kind);
170: }
171:
172: throw new UtilEvalError("Non primitive value in operator: "
173: + lhs.getClass() + " " + tokenImage[kind] + " "
174: + rhs.getClass());
175: }
176: }
|