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: import java.lang.reflect.Field;
035: import java.util.Hashtable;
036:
037: /**
038: An LHS is a wrapper for an variable, field, or property. It ordinarily
039: holds the "left hand side" of an assignment and may be either resolved to
040: a value or assigned a value.
041: <p>
042:
043: There is one special case here termed METHOD_EVAL where the LHS is used
044: in an intermediate evaluation of a chain of suffixes and wraps a method
045: invocation. In this case it may only be resolved to a value and cannot be
046: assigned. (You can't assign a value to the result of a method call e.g.
047: "foo() = 5;").
048: <p>
049: */
050: class LHS implements ParserConstants, java.io.Serializable {
051: NameSpace nameSpace;
052: /** The assignment should be to a local variable */
053: boolean localVar;
054:
055: /**
056: Identifiers for the various types of LHS.
057: */
058: static final int VARIABLE = 0, FIELD = 1, PROPERTY = 2, INDEX = 3,
059: METHOD_EVAL = 4;
060:
061: int type;
062:
063: String varName;
064: String propName;
065: Field field;
066: Object object;
067: int index;
068:
069: /**
070: @param localVar if true the variable is set directly in the This
071: reference's local scope. If false recursion to look for the variable
072: definition in parent's scope is allowed. (e.g. the default case for
073: undefined vars going to global).
074: */
075: LHS(NameSpace nameSpace, String varName, boolean localVar) {
076: type = VARIABLE;
077: this .localVar = localVar;
078: this .varName = varName;
079: this .nameSpace = nameSpace;
080: }
081:
082: /**
083: Static field LHS Constructor.
084: This simply calls Object field constructor with null object.
085: */
086: LHS(Field field) {
087: type = FIELD;
088: this .object = null;
089: this .field = field;
090: }
091:
092: /**
093: Object field LHS Constructor.
094: */
095: LHS(Object object, Field field) {
096: if (object == null)
097: throw new NullPointerException("constructed empty LHS");
098:
099: type = FIELD;
100: this .object = object;
101: this .field = field;
102: }
103:
104: /**
105: Object property LHS Constructor.
106: */
107: LHS(Object object, String propName) {
108: if (object == null)
109: throw new NullPointerException("constructed empty LHS");
110:
111: type = PROPERTY;
112: this .object = object;
113: this .propName = propName;
114: }
115:
116: /**
117: Array index LHS Constructor.
118: */
119: LHS(Object array, int index) {
120: if (array == null)
121: throw new NullPointerException("constructed empty LHS");
122:
123: type = INDEX;
124: this .object = array;
125: this .index = index;
126: }
127:
128: public Object getValue() throws UtilEvalError {
129: if (type == VARIABLE)
130: return nameSpace.getVariableOrProperty(varName, null);
131: // return nameSpace.getVariable( varName );
132:
133: if (type == FIELD)
134: try {
135: Object o = field.get(object);
136: return Primitive.wrap(o, field.getType());
137: } catch (IllegalAccessException e2) {
138: throw new UtilEvalError("Can't read field: " + field);
139: }
140:
141: if (type == PROPERTY) {
142: // return the raw type here... we don't know what it's supposed
143: // to be...
144: CollectionManager cm = CollectionManager
145: .getCollectionManager();
146: if (cm.isMap(object))
147: return cm.getFromMap(object/*map*/, propName);
148: else
149: try {
150: return Reflect.getObjectProperty(object, propName);
151: } catch (ReflectError e) {
152: Interpreter.debug(e.getMessage());
153: throw new UtilEvalError("No such property: "
154: + propName);
155: }
156: }
157:
158: if (type == INDEX)
159: try {
160: return Reflect.getIndex(object, index);
161: } catch (Exception e) {
162: throw new UtilEvalError("Array access: " + e);
163: }
164:
165: throw new InterpreterError("LHS type");
166: }
167:
168: /**
169: Assign a value to the LHS.
170: */
171: public Object assign(Object val, boolean strictJava)
172: throws UtilEvalError {
173: if (type == VARIABLE) {
174: // Set the variable in namespace according to localVar flag
175: if (localVar)
176: nameSpace.setLocalVariableOrProperty(varName, val,
177: strictJava);
178: else
179: nameSpace.setVariableOrProperty(varName, val,
180: strictJava);
181: } else if (type == FIELD) {
182: try {
183: // This should probably be in Reflect.java
184: ReflectManager.RMSetAccessible(field);
185: field.set(object, Primitive.unwrap(val));
186: return val;
187: } catch (NullPointerException e) {
188: throw new UtilEvalError("LHS (" + field.getName()
189: + ") not a static field.");
190: } catch (IllegalAccessException e2) {
191: throw new UtilEvalError("LHS (" + field.getName()
192: + ") can't access field: " + e2);
193: } catch (IllegalArgumentException e3) {
194: String type = val instanceof Primitive ? ((Primitive) val)
195: .getType().getName()
196: : val.getClass().getName();
197: throw new UtilEvalError("Argument type mismatch. "
198: + (val == null ? "null" : type)
199: + " not assignable to field " + field.getName());
200: }
201: } else if (type == PROPERTY) {
202: CollectionManager cm = CollectionManager
203: .getCollectionManager();
204: if (cm.isMap(object))
205: cm.putInMap(object/*map*/, propName, Primitive
206: .unwrap(val));
207: else
208: try {
209: Reflect.setObjectProperty(object, propName, val);
210: } catch (ReflectError e) {
211: Interpreter.debug("Assignment: " + e.getMessage());
212: throw new UtilEvalError("No such property: "
213: + propName);
214: }
215: } else if (type == INDEX)
216: try {
217: Reflect.setIndex(object, index, val);
218: } catch (UtilTargetError e1) { // pass along target error
219: throw e1;
220: } catch (Exception e) {
221: throw new UtilEvalError("Assignment: " + e.getMessage());
222: }
223: else
224: throw new InterpreterError("unknown lhs");
225:
226: return val;
227: }
228:
229: public String toString() {
230: return "LHS: "
231: + ((field != null) ? "field = " + field.toString() : "")
232: + (varName != null ? " varName = " + varName : "")
233: + (nameSpace != null ? " nameSpace = "
234: + nameSpace.toString() : "");
235: }
236: }
|