001: package gnu.kawa.reflect;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.*;
005: import gnu.mapping.Location; // As opposed to gnu.bytecode.Location.
006: import gnu.expr.*;
007:
008: public class FieldLocation extends ClassMemberLocation {
009: Declaration decl;
010: /** The cached location of the field, if final.
011: * This is the value of this Location. Howeve, if INDIRECT_LOCATION is
012: * set and CONSTANT is cleared, then we need to do an extra indirection. */
013: Object value;
014: static final int SETUP_DONE = 1; // FIXME - do we still need this?
015:
016: /** Flag that indicates that field value has type Location.
017: * Hence <code>get</code> of this Location requires an extra indirection. */
018: static final int INDIRECT_LOCATION = 2;
019: /** The actual value (following any indirection) is constant.
020: * I.e. if INDIRECT_LOCATION is set, then that Location has isConstant set,
021: * Otherwise the actual value is a final field. */
022: static final int CONSTANT = 4;
023: /** Flag that indicates that the value field has been set.
024: * If INDIRECT_LOCATION has been set, but not CONSTANT, then
025: * the <code>value</code> is a Location we need to indirect.
026: * If CONSTANT is set, then this is the actual (final) value.
027: * Not set unless at least one of INDIRECT_LOCATION or CONSTANT are set. */
028: static final int VALUE_SET = 8;
029: // The PROCEDURE and SYNTAX flags aren't current used by getDeclaration,
030: // but probably should be, assuming we can count on them.
031: public static final int PROCEDURE = 16;
032: public static final int SYNTAX = 32;
033: /** True if the flags <code>PROCEDURE|SYNTAX|INDIRECT_LOCATION|CONSTANT</code>
034: * are valid. */
035: public static final int KIND_FLAGS_SET = 64;
036: private int flags;
037:
038: public boolean isIndirectLocation() {
039: return (flags & INDIRECT_LOCATION) != 0;
040: }
041:
042: public void setProcedure() {
043: flags |= PROCEDURE | CONSTANT | KIND_FLAGS_SET;
044: }
045:
046: public void setSyntax() {
047: flags |= SYNTAX | CONSTANT | KIND_FLAGS_SET;
048: }
049:
050: void setKindFlags() {
051: String fname = getMemberName();
052: gnu.bytecode.Field fld = getDeclaringClass().getDeclaredField(
053: fname);
054: int fflags = fld.getModifiers();
055: Type ftype = fld.getType();
056: if (ftype.isSubtype(Compilation.typeLocation))
057: flags |= INDIRECT_LOCATION;
058: if ((fflags & Access.FINAL) != 0) {
059: if ((flags & INDIRECT_LOCATION) == 0) {
060: flags |= CONSTANT;
061: if (ftype.isSubtype(Compilation.typeProcedure))
062: flags |= PROCEDURE;
063: if (ftype.isSubtype(ClassType.make("kawa.lang.Syntax")))
064: flags |= SYNTAX;
065: } else {
066: Location loc = (Location) getFieldValue();
067: if (loc instanceof FieldLocation) {
068: FieldLocation floc = (FieldLocation) loc;
069: if ((floc.flags & KIND_FLAGS_SET) == 0)
070: floc.setKindFlags();
071: flags |= (floc.flags & (SYNTAX | PROCEDURE | CONSTANT));
072: if ((floc.flags & CONSTANT) != 0) {
073: if ((floc.flags & VALUE_SET) != 0) {
074: value = floc.value;
075: flags |= VALUE_SET;
076: }
077: } else {
078: value = floc;
079: flags |= VALUE_SET;
080: }
081: } else if (loc.isConstant()) {
082: Object val = loc.get(null);
083: // if (val == null) ????;
084: if (val instanceof Procedure)
085: flags |= PROCEDURE;
086: if (val instanceof kawa.lang.Syntax) // FIXME
087: flags |= SYNTAX;
088: flags |= CONSTANT | VALUE_SET;
089: value = val;
090: }
091: }
092: }
093: flags |= KIND_FLAGS_SET;
094: }
095:
096: public boolean isProcedureOrSyntax() {
097: if ((flags & KIND_FLAGS_SET) == 0)
098: setKindFlags();
099: return (flags & (PROCEDURE + SYNTAX)) != 0;
100: }
101:
102: public FieldLocation(Object instance, String cname, String fname) {
103: super (instance, ClassType.make(cname), fname);
104: }
105:
106: public FieldLocation(Object instance, ClassType type, String mname) {
107: super (instance, type, mname);
108: }
109:
110: public void setDeclaration(Declaration decl) {
111: this .decl = decl;
112: }
113:
114: public Field getField() {
115: return type.getDeclaredField(mname);
116: }
117:
118: /** Get the type of the field. */
119: public Type getFType() {
120: return type.getDeclaredField(mname).getType();
121: }
122:
123: public synchronized Declaration getDeclaration() {
124: if ((flags & KIND_FLAGS_SET) == 0)
125: setKindFlags();
126: Declaration d = decl;
127: if (d == null) {
128: String fname = getMemberName();
129: ClassType t = getDeclaringClass();
130: gnu.bytecode.Field procField = t.getDeclaredField(fname);
131: if (procField == null)
132: return null;
133: ModuleInfo info = ModuleInfo.find(t.getName());
134: ModuleExp mexp = info.getModuleExp();
135: for (d = mexp.firstDecl(); d != null; d = d.nextDecl()) {
136: if (d.field != null && d.field.getName().equals(fname))
137: break;
138: }
139: if (d == null)
140: throw new RuntimeException("no field found for " + this );
141: decl = d;
142: }
143: return d;
144: }
145:
146: void setup() {
147: synchronized (this ) {
148: if ((flags & SETUP_DONE) != 0)
149: return;
150: super .setup();
151: if ((flags & KIND_FLAGS_SET) == 0)
152: setKindFlags();
153: flags |= SETUP_DONE;
154: }
155: }
156:
157: public Object get(Object defaultValue) {
158: try {
159: setup();
160: } catch (Throwable ex) {
161: return defaultValue;
162: }
163: Object v;
164: if ((flags & VALUE_SET) != 0) {
165: v = value;
166: if ((flags & CONSTANT) != 0)
167: return v;
168: } else {
169: v = getFieldValue();
170: if ((type.getDeclaredField(mname).getModifiers() & Access.FINAL) != 0) {
171: flags |= VALUE_SET;
172: if ((flags & INDIRECT_LOCATION) == 0)
173: flags |= CONSTANT;
174: value = v;
175: }
176: }
177: if ((flags & INDIRECT_LOCATION) != 0) {
178: Object unb = Location.UNBOUND;
179: Location loc = (Location) v;
180: v = loc.get(unb);
181: if (v == unb)
182: return defaultValue;
183: if (loc.isConstant()) {
184: flags |= CONSTANT;
185: value = v;
186: }
187: }
188: return v;
189: }
190:
191: private Object getFieldValue() {
192: super .setup(); // Set rfield, if needed.
193: try {
194: return rfield.get(instance);
195: } catch (Throwable ex) {
196: throw WrappedException.wrapIfNeeded(ex);
197: }
198: }
199:
200: public void set(Object newValue) {
201: setup();
202: if ((flags & INDIRECT_LOCATION) == 0) {
203: try {
204: rfield.set(instance, newValue);
205: } catch (Throwable ex) {
206: throw WrappedException.wrapIfNeeded(ex);
207: }
208: } else {
209: Object v;
210: if ((flags & VALUE_SET) != 0)
211: v = value;
212: else {
213: flags |= VALUE_SET;
214: v = getFieldValue();
215: value = v;
216: }
217: ((Location) v).set(newValue);
218: }
219: }
220:
221: public boolean isConstant() {
222: if ((flags & KIND_FLAGS_SET) == 0)
223: setKindFlags();
224: if ((flags & CONSTANT) != 0)
225: return true;
226: if (isIndirectLocation()) {
227: Object v;
228: if ((flags & VALUE_SET) != 0)
229: v = value;
230: else {
231: try {
232: setup();
233: } catch (Throwable ex) {
234: return false;
235: }
236: v = getFieldValue();
237: flags |= VALUE_SET;
238: value = v;
239: }
240: return ((Location) v).isConstant();
241: }
242: return false;
243: }
244:
245: public boolean isBound() {
246: if ((flags & KIND_FLAGS_SET) == 0)
247: setKindFlags();
248: if ((flags & CONSTANT) != 0 || (flags & INDIRECT_LOCATION) == 0)
249: return true;
250: Object v;
251: if ((flags & VALUE_SET) != 0)
252: v = value;
253: else {
254: try {
255: setup();
256: } catch (Throwable ex) {
257: return false;
258: }
259: v = getFieldValue();
260: flags |= VALUE_SET;
261: value = v;
262: }
263: return ((Location) v).isBound();
264: }
265:
266: public static FieldLocation make(Object instance, Declaration decl) {
267: gnu.bytecode.Field fld = decl.field;
268: ClassType ctype = fld.getDeclaringClass();
269: FieldLocation loc = new FieldLocation(instance, ctype, fld
270: .getName());
271: loc.setDeclaration(decl);
272: //maybe setKindFlags();
273: return loc;
274: }
275:
276: public static FieldLocation make(/*Object name,*/Object instance,
277: String cname, String fldName) {
278: return new FieldLocation(/*name,*/instance, ClassType
279: .make(cname), fldName);
280: }
281:
282: public String toString() {
283: StringBuffer sbuf = new StringBuffer();
284: sbuf.append("FieldLocation[");
285: if (instance != null) {
286: sbuf.append(instance);
287: sbuf.append(' ');
288: }
289: sbuf.append(type.getName());
290: sbuf.append('.');
291: sbuf.append(mname);
292: /* DEBGUGGING:
293: sbuf.append(" #:");
294: sbuf.append(id);
295: */
296: sbuf.append(']');
297: return sbuf.toString();
298: }
299: }
|