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