PageRenderTime 28ms CodeModel.GetById 10ms app.highlight 13ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at2-build060407/src/edu/vub/at/objects/natives/NATCallframe.java

http://ambienttalk.googlecode.com/
Java | 436 lines | 224 code | 50 blank | 162 comment | 49 complexity | ce89fa06290bfd19ceb4f16c4a4332a9 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATCallframe.java created on Jul 28, 2006 at 11:26:17 AM
  4 * (c) Programming Technology Lab, 2006 - 2007
  5 * Authors: Tom Van Cutsem & Stijn Mostinckx
  6 * 
  7 * Permission is hereby granted, free of charge, to any person
  8 * obtaining a copy of this software and associated documentation
  9 * files (the "Software"), to deal in the Software without
 10 * restriction, including without limitation the rights to use,
 11 * copy, modify, merge, publish, distribute, sublicense, and/or
 12 * sell copies of the Software, and to permit persons to whom the
 13 * Software is furnished to do so, subject to the following
 14 * conditions:
 15 *
 16 * The above copyright notice and this permission notice shall be
 17 * included in all copies or substantial portions of the Software.
 18 *
 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 26 * OTHER DEALINGS IN THE SOFTWARE.
 27 */
 28package edu.vub.at.objects.natives;
 29
 30import edu.vub.at.exceptions.InterpreterException;
 31import edu.vub.at.exceptions.XDuplicateSlot;
 32import edu.vub.at.exceptions.XIllegalOperation;
 33import edu.vub.at.exceptions.XSelectorNotFound;
 34import edu.vub.at.exceptions.XUndefinedField;
 35import edu.vub.at.objects.ATBoolean;
 36import edu.vub.at.objects.ATField;
 37import edu.vub.at.objects.ATMethod;
 38import edu.vub.at.objects.ATNil;
 39import edu.vub.at.objects.ATObject;
 40import edu.vub.at.objects.ATTable;
 41import edu.vub.at.objects.grammar.ATSymbol;
 42
 43import java.util.Iterator;
 44import java.util.LinkedList;
 45import java.util.Vector;
 46
 47/**
 48 * NATCallframe is a native implementation of a callframe. A callframe differs from
 49 * an ordinary object in the following regards:
 50 * - it has no dynamic parent
 51 * - it treats method definition as the addition of a closure to its variables.
 52 * - it cannot be extended nor cloned
 53 * 
 54 * Callframes can be regarded as 'field-only' objects. Fields are implemented as follows:
 55 *  - native fields are implemented efficiently using a 'map': the map datastructure maps
 56 *    selectors to indices into a state vector, such that field names can be shared efficiently
 57 *    across clones.
 58 *  - custom fields are collected in a linked list. Their lookup and assignment is slower,
 59 *    and when an object is cloned, the custom field objects are re-instantiated.
 60 *    The new clone is passed as the sole argument to 'new'.
 61 * 
 62 * @author tvcutsem
 63 * @author smostinc
 64 */
 65public class NATCallframe extends NATByRef implements ATObject {
 66	
 67	protected FieldMap 		variableMap_;
 68	protected final Vector	stateVector_;
 69	
 70    /**
 71     * The lexical parent 'scope' of this call frame/object.
 72     * A lexical scope should never travel along with an object when it is serialized,
 73     * hence it is declared transient. Serializable isolate objects will have to reset
 74     * this field upon deserialization.
 75     */
 76	protected transient ATObject lexicalParent_;
 77	
 78	protected LinkedList customFields_;
 79	
 80	public NATCallframe(ATObject lexicalParent) {
 81		variableMap_   = new FieldMap();
 82		stateVector_   = new Vector();
 83		lexicalParent_ = lexicalParent;
 84		customFields_ = null;
 85	}
 86	
 87	/**
 88	 * Used internally for cloning a callframe/object.
 89	 */
 90	protected NATCallframe(FieldMap varMap, Vector stateVector, ATObject lexicalParent, LinkedList customFields) {
 91		variableMap_ = varMap;
 92		stateVector_ = stateVector;
 93		lexicalParent_ = lexicalParent;
 94		customFields_ = customFields;
 95	}
 96
 97	/* ------------------------------
 98	 * -- Message Sending Protocol --
 99	 * ------------------------------ */
100	
101    /**
102	 * Normally, call frames are not used in receiverful method invocation expressions.
103	 * That is, normally, the content of call frames is accessed via the meta_lookup operation.
104	 * 
105	 * A meta_invoke operation on call frames is much more ad hoc than on real objects.
106	 * A call frame responds to an invocation by looking up the selector in its own fields (without delegating!)
107	 * and by applying the closure bound to that field.
108	 * 
109	 * The 'receiver' argument should always equal 'this' because call frames do not delegate!
110	 */
111	public ATObject meta_invoke(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
112		// assert(this == receiver)
113		return this.getLocalField(selector).asClosure().base_apply(arguments);
114	}
115	
116	/**
117	 * respondsTo is a mechanism to ask any object o whether it would respond to the
118	 * selection o.selector. A call frame implements respondsTo by checking whether
119	 * it contains a public field corresponding to the selector.
120	 * 
121	 * A call frame does not delegate to other objects to check
122	 * whether it can respond to a certain selector.
123	 */
124	public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException {
125		return NATBoolean.atValue(this.hasLocalField(selector));
126	}
127
128	/**
129	 * By default, when a selection is not understood by an AmbientTalk object or call frame, an error is raised.
130	 * 
131	 * Warning: this method overrides its parent method which has the exact same implementation.
132	 * This is done for purposes of clarity, by making NATCallframe implement all ATObject methods directly,
133	 * even if NATNil already provides a suitable implementation for these.
134	 */
135	public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException {
136		throw new XSelectorNotFound(selector, this);
137	}
138	
139	/* ------------------------------------------
140	 * -- Slot accessing and mutating protocol --
141	 * ------------------------------------------ */
142	
143	/**
144	 * This method is used in the evaluation of the code <tt>o.m</tt>.
145	 * When o is a call frame, the call frame is searched for a field 'm'.
146	 * If it is not found, a call frame does not delegate to any dynamic parent, and yields an error.
147	 */
148	public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException {
149		if (this.hasLocalField(selector)) {
150			return this.getLocalField(selector);
151		} else {
152			throw new XSelectorNotFound(selector, this);
153		}
154	}
155	
156	/**
157	 * This method is used to evaluate code of the form <tt>selector</tt> within the scope
158	 * of this call frame. A call frame resolves such a lookup request by checking whether
159	 * a field corresponding to the selector exists locally. If it does, the result is
160	 * returned. If it does not, the search continues recursively in the call frame's
161	 * lexical parent.
162	 */
163	public ATObject meta_lookup(ATSymbol selector) throws InterpreterException {
164		if (this.hasLocalField(selector)) {
165			return this.getLocalField(selector);
166		} else {
167			return lexicalParent_.meta_lookup(selector);
168		}
169	}
170
171	/**
172	 * A field can be added to either a call frame or an object.
173	 * In both cases, it is checked whether the field does not already exist.
174	 * If it does not, a new field is created and its value set to the given initial value.
175	 * @throws InterpreterException 
176	 */
177	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
178		if (this.hasLocalField(name)) {
179			// field already exists...
180			throw new XDuplicateSlot(XDuplicateSlot._FIELD_, name);			
181		} else {
182			boolean fieldAdded = variableMap_.put(name);
183			if (!fieldAdded) {
184				throw new RuntimeException("Assertion failed: field not added to map while not duplicate");
185			}
186			// field now defined, add its value to the state vector
187			stateVector_.add(value);
188		}
189		return NATNil._INSTANCE_;
190	}
191	
192	/**
193	 * A field can be assigned in either a call frame or an object.
194	 * In both cases, if the field exists locally, it is set to the new value.
195	 * If it does not exist locally, the assignment is performed on the lexical parent.
196	 */
197	public ATNil meta_assignVariable(ATSymbol name, ATObject value) throws InterpreterException {
198		if (this.setLocalField(name, value)) {
199			// field found and set locally
200			return NATNil._INSTANCE_;
201		} else {
202			// The lexical parent chain is followed for assignments. This implies
203			// that assignments on dynamic parents are disallowed.
204			return lexicalParent_.meta_assignVariable(name, value);
205		}
206	}
207	
208	/**
209	 * Assigning a call frame's field externally is possible and is treated
210	 * as if it were a variable assignment. Hence, if <tt>o</tt> is a call frame,
211	 * then <tt>o.m := x</tt> follows the same evaluation semantics as those of
212	 * <tt>m := x</tt> when performed in the scope of <tt>o</tt>.
213	 */
214	public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException {
215		return this.meta_assignVariable(name, value);
216	}
217
218	/* ------------------------------------
219	 * -- Extension and cloning protocol --
220	 * ------------------------------------ */
221
222	public ATObject meta_clone() throws InterpreterException {
223		throw new XIllegalOperation("Cannot clone a call frame, clone its owning object instead.");
224	}
225
226	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
227		throw new XIllegalOperation("Cannot create a new instance of a call frame, new its owning object instead.");
228	}
229
230	/* ---------------------------------
231	 * -- Structural Access Protocol  --
232	 * --------------------------------- */
233	
234	public ATNil meta_addField(ATField field) throws InterpreterException {
235		// when adding a native field, revert to the more optimized implementation using the map
236		if (field.isNativeField()) {
237			return this.meta_defineField(field.base_getName(), field.base_readField());
238		}
239		
240		ATSymbol name = field.base_getName();
241		if (this.hasLocalField(name)) {
242			// field already exists...
243			throw new XDuplicateSlot(XDuplicateSlot._FIELD_, name);			
244		} else {
245			// add a clone of the field initialized with its new host
246			field = field.base_new(new ATObject[] { this }).asField();
247			
248			// add the field to the list of custom fields, which is created lazily
249			if (customFields_ == null) {
250				customFields_ = new LinkedList();
251			}
252			// append the custom field object
253			customFields_.add(field);
254		}
255		return NATNil._INSTANCE_;
256	}
257	
258	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
259		throw new XIllegalOperation("Cannot add method "+
260								   method.base_getName().base_getText().asNativeText().javaValue +
261				                    " to a call frame. Add it as a closure field instead.");
262	}
263	
264	public ATField meta_grabField(ATSymbol selector) throws InterpreterException {
265		if (this.hasLocalNativeField(selector)) {
266			return new NATField(selector, this);
267		} else {
268			ATField fld = this.getLocalCustomField(selector);
269			if (fld != null) {
270				return fld;
271			} else {
272				throw new XUndefinedField("field grabbed", selector.toString());
273			}
274		}
275	}
276
277	public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
278		throw new XSelectorNotFound(selector, this);
279	}
280
281	public ATTable meta_listFields() throws InterpreterException {
282		ATObject[] nativeFields = new ATObject[stateVector_.size()];
283		ATSymbol[] fieldNames = variableMap_.listFields();
284		// native fields first
285		for (int i = 0; i < fieldNames.length; i++) {
286			nativeFields[i] = new NATField(fieldNames[i], this);
287		}
288		if (customFields_ == null) {
289			// no custom fields
290			return NATTable.atValue(nativeFields);
291		} else {
292			ATObject[] customFields = (ATObject[]) customFields_.toArray(new ATObject[customFields_.size()]);
293			return NATTable.atValue(NATTable.collate(nativeFields, customFields));
294		}
295	}
296
297	public ATTable meta_listMethods() throws InterpreterException {
298		return NATTable.EMPTY;
299	}
300	
301	public NATText meta_print() throws InterpreterException {
302		return NATText.atValue("<callframe>");
303	}
304	
305	/* ---------------------
306	 * -- Mirror Fields   --
307	 * --------------------- */
308	
309	/**
310	 * Auxiliary method to dynamically select the 'super' field from this object.
311	 * Note that this method is part of the base-level interface to an object.
312	 * 
313	 * Also note that this method performs the behaviour equivalent to evaluating
314	 * 'super' and not 'self.super', which could lead to infinite loops.
315	 */
316	public ATObject base_getSuper() throws InterpreterException {
317		return this.meta_lookup(NATObject._SUPER_NAME_);
318	};
319	
320	public ATObject meta_getLexicalParent() throws InterpreterException {
321		return lexicalParent_;
322	}
323
324	/* --------------------------
325	 * -- Conversion Protocol  --
326	 * -------------------------- */
327	
328	public boolean isCallFrame() {
329		return true;
330	}
331	
332	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
333		if(	(original instanceof NATCallframe) &
334			! (original instanceof NATObject)) {
335			FieldMap originalVariables = ((NATCallframe)original).variableMap_;
336			
337			return NATBoolean.atValue(
338					variableMap_.isDerivedFrom(originalVariables));
339		} else {
340			return NATBoolean._FALSE_;
341		}
342	}
343
344	public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException {
345		return super.meta_isRelatedTo(object);
346	}
347	
348    /* -----------------------------
349     * -- Object Passing protocol --
350     * ----------------------------- */
351	
352	// protected methods, only to be used by NATCallframe and NATObject
353
354	protected boolean hasLocalField(ATSymbol selector) throws InterpreterException {
355		return hasLocalNativeField(selector) || hasLocalCustomField(selector);
356	}
357	
358	protected boolean hasLocalNativeField(ATSymbol selector) {
359		return variableMap_.get(selector) != -1;
360	}
361	
362	protected boolean hasLocalCustomField(ATSymbol selector) throws InterpreterException {
363		if (customFields_ == null) {
364			return false;
365		} else {
366			Iterator it = customFields_.iterator();
367			while (it.hasNext()) {
368				ATField field = (ATField) it.next();
369				if (field.base_getName().equals(selector)) {
370					return true;
371				}
372			}
373			return false;
374		}
375	}
376	
377	/**
378	 * Reads out the value of either a native or a custom field.
379	 * @throws XSelectorNotFound if no native or custom field with the given name exists locally.
380	 */
381	protected ATObject getLocalField(ATSymbol selector) throws InterpreterException {
382		int index = variableMap_.get(selector);
383		if(index != -1) {
384			return (ATObject) (stateVector_.get(index));
385		} else {
386			ATField fld = getLocalCustomField(selector);
387			if (fld != null) {
388				return fld.base_readField();
389			} else {
390				throw new XSelectorNotFound(selector, this);
391			}
392		}
393	}
394	
395	/**
396	 * @return a custom field matching the given selector or null if such a field does not exist
397	 */
398	protected ATField getLocalCustomField(ATSymbol selector) throws InterpreterException {
399		if (customFields_ == null) {
400			return null;
401		} else {
402			Iterator it = customFields_.iterator();
403			while (it.hasNext()) {
404				ATField field = (ATField) it.next();
405				if (field.base_getName().equals(selector)) {
406					return field;
407				}
408			}
409			return null;
410		}
411	}
412	
413	
414	
415	/**
416	 * Set a given field if it exists.
417	 * @return whether the field existed (and the assignment has been performed)
418	 */
419	protected boolean setLocalField(ATSymbol selector, ATObject value) throws InterpreterException {
420		int index = variableMap_.get(selector);
421		if(index != -1) {
422			// field exists, modify the state vector
423			stateVector_.set(index, value);
424			return true;
425		} else {
426			ATField fld = getLocalCustomField(selector);
427			if (fld != null) {
428				fld.base_writeField(value);
429				return true;
430			} else {
431				return false;
432			}
433		}
434	}
435	
436}