PageRenderTime 71ms CodeModel.GetById 24ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at_build150307/src/edu/vub/at/objects/natives/NATObject.java

http://ambienttalk.googlecode.com/
Java | 946 lines | 444 code | 98 blank | 404 comment | 69 complexity | af59d6691c9622dc16d8c804aad163cf MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATObject.java created on Jul 13, 2006 at 3:52:15 PM
  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.actors.ATActorMirror;
 31import edu.vub.at.actors.ATAsyncMessage;
 32import edu.vub.at.actors.net.Logging;
 33import edu.vub.at.eval.Evaluator;
 34import edu.vub.at.exceptions.InterpreterException;
 35import edu.vub.at.exceptions.XArityMismatch;
 36import edu.vub.at.exceptions.XDuplicateSlot;
 37import edu.vub.at.exceptions.XSelectorNotFound;
 38import edu.vub.at.exceptions.XTypeMismatch;
 39import edu.vub.at.objects.ATBoolean;
 40import edu.vub.at.objects.ATClosure;
 41import edu.vub.at.objects.ATContext;
 42import edu.vub.at.objects.ATField;
 43import edu.vub.at.objects.ATHandler;
 44import edu.vub.at.objects.ATMessage;
 45import edu.vub.at.objects.ATMethod;
 46import edu.vub.at.objects.ATNil;
 47import edu.vub.at.objects.ATNumber;
 48import edu.vub.at.objects.ATObject;
 49import edu.vub.at.objects.ATStripe;
 50import edu.vub.at.objects.ATTable;
 51import edu.vub.at.objects.coercion.Coercer;
 52import edu.vub.at.objects.coercion.NativeStripes;
 53import edu.vub.at.objects.grammar.ATBegin;
 54import edu.vub.at.objects.grammar.ATDefinition;
 55import edu.vub.at.objects.grammar.ATExpression;
 56import edu.vub.at.objects.grammar.ATMessageCreation;
 57import edu.vub.at.objects.grammar.ATSplice;
 58import edu.vub.at.objects.grammar.ATStatement;
 59import edu.vub.at.objects.grammar.ATSymbol;
 60import edu.vub.at.objects.grammar.ATUnquoteSplice;
 61import edu.vub.at.objects.mirrors.NativeClosure;
 62import edu.vub.at.objects.mirrors.PrimitiveMethod;
 63import edu.vub.at.objects.natives.grammar.AGSplice;
 64import edu.vub.at.objects.natives.grammar.AGSymbol;
 65
 66import java.util.Collection;
 67import java.util.HashSet;
 68import java.util.Iterator;
 69import java.util.LinkedList;
 70import java.util.Vector;
 71
 72/**
 73 * Native implementation of a default ambienttalk object.
 74 * 
 75 * Although a native AmbientTalk object is implemented as a subtype of callframes,
 76 * the reality is that call frames are a special kind of object.
 77 * 
 78 * This is a pure form of implementation subclassing: we subclass NATCallframe only
 79 * for reusing the field definition/assignment protocol and for inheriting the
 80 * variable map, the state vector and the lexical parent.
 81 * 
 82 * NATObjects are one of the five native classes that fully implement the ATObject interface
 83 * (next to NATCallFrame, NATNil, NATMirage and NATSuperObject). The implementation is such that
 84 * a NATObject instance represents *both* a base-level AmbientTalk object, as well as a meta-level
 85 * AmbientTalk mirror on that object.
 86 * 
 87 * An AmbientTalk base-level object has the following structure:
 88 * - properties: a set of boolean flags denoting:
 89 *   - whether the dynamic parent is an IS_A or a SHARES_A parent
 90 *   - whether the object shares its variable map with clones
 91 *   - whether the object shares its method dictionary with clones
 92 *   - whether the object is an isolate (i.e. pass-by-copy)
 93 *   - whether the object is a mirror (a meta-level object of a corresponding base-level object)
 94 * - a variable map, mapping variable names to indices into the state vector
 95 * - a state vector, containing the field values of the object
 96 * - a linked list containing custom field objects
 97 * - a method dictionary, mapping selectors to methods
 98 * - a dynamic object parent, to delegate select and invoke operations
 99 *   ( this parent slot is represented by a true AmbientTalk field, rather than by an instance variable )
100 * - a lexical object parent, to support lexical scoping
101 * - a table of stripes that were attached to this object (for classification purposes)
102 * 
103 * @author tvcutsem
104 * @author smostinc
105 */
106public class NATObject extends NATCallframe implements ATObject {
107	
108	// The name of the field that points to the dynamic parent
109	public static final AGSymbol _SUPER_NAME_ = AGSymbol.jAlloc("super");
110	
111	// The names of the primitive methods
112	public static final AGSymbol _EQL_NAME_ = AGSymbol.jAlloc("==");
113	public static final AGSymbol _NEW_NAME_ = AGSymbol.jAlloc("new");
114	public static final AGSymbol _INI_NAME_ = AGSymbol.jAlloc("init");
115	
116	// The primitive methods themselves
117	
118	/** def ==(comparand) { nil } */
119	private static final PrimitiveMethod _PRIM_EQL_ = new PrimitiveMethod(
120			_EQL_NAME_, NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("comparand")})) {
121		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
122			if (!arguments.base_getLength().equals(NATNumber.ONE)) {
123				throw new XArityMismatch("==", 1, arguments.base_getLength().asNativeNumber().javaValue);
124			}
125			return ctx.base_getLexicalScope().base__opeql__opeql_(arguments.base_at(NATNumber.ONE));
126		}
127	};
128	/** def new(@initargs) { nil } */
129	private static final PrimitiveMethod _PRIM_NEW_ = new PrimitiveMethod(
130			_NEW_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
131		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
132			return ctx.base_getLexicalScope().base_new(arguments.asNativeTable().elements_);
133		}
134	};
135	/** def init(@initargs) { nil } */
136	private static final PrimitiveMethod _PRIM_INI_ = new PrimitiveMethod(
137			_INI_NAME_, NATTable.atValue(new ATObject[] { new AGSplice(AGSymbol.jAlloc("initargs")) })) {
138		public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
139			return ctx.base_getLexicalScope().asAmbientTalkObject().prim_init(ctx.base_getSelf(), arguments.asNativeTable().elements_);
140		}
141	};
142	
143	/**
144	 * Does the selector signify a 'primitive' method, present in each AmbientTalk object?
145	 */
146	public static boolean isPrimitive(ATSymbol name) {
147		return name.equals(_EQL_NAME_) || name.equals(_NEW_NAME_) || name.equals(_INI_NAME_);
148	}
149	
150	// Auxiliary static methods to support the type of dynamic parent
151	public static final boolean _IS_A_ 		= true;
152	public static final boolean _SHARES_A_ 	= false;
153	
154	/**
155	 * This flag determines the type of parent pointer of this object. We distinguish two cases:
156	 *  - 1: an is-a link, which results in a recursive cloning of the parent when this object is cloned.
157	 *  - 0: a shares-a link, which ensures that clones of this object share the same parent.
158	 */
159	private static final byte _ISAPARENT_FLAG_ = 1<<0;
160	
161	/**
162	 * This flag determines whether or not the field map of this object is shared by other objects:
163	 *  - 1: the map is shared, so modifications must be performed on a copy
164	 *  - 0: the map is not shared, modifications may be directly performed on it
165	 *  
166	 * This flag is important for maintaining the semantics that clones are self-sufficient objects:
167	 * they share field names and methods only at the implementation-level.
168	 */
169	private static final byte _SHARE_MAP_FLAG_ = 1<<1;
170	
171	/**
172	 * Similar to _SHARE_MAP_FLAG__ but for determining the shared status of the method dictionary.
173	 */
174	private static final byte _SHARE_DCT_FLAG_ = 1<<2;
175	
176	/**
177	 * This flag determines whether or not the object is an isolate and hence pass-by-copy:
178	 *  - 1: the object is an isolate, pass-by-copy and no lexical parent except for the root
179	 *  - 0: the object is pass-by-reference and can have any lexical parent
180	 */
181	private static final byte _IS_ISOLATE_FLAG_ = 1<<3;
182
183	/**
184	 * An empty stripe array shared by those objects that do not have any stripes.
185	 */
186	public static final ATStripe[] _NO_STRIPES_ = new ATStripe[0];
187	
188	/**
189	 * The flags of an AmbientTalk object encode the following boolean information:
190	 *  Format: 0b0000idap where
191	 *   p = parent flag: if set, dynamic parent is 'is-a' parent, otherwise 'shares-a' parent
192	 *   a = shares map flag: if set, the map of this object is shared between clones
193	 *   d = shares dictionary flag: if set, the method dictionary of this object is shared between clones
194	 *   i = is isolate flag: if set, the object is passed by copy in inter-actor communication
195	 */
196	private byte flags_;
197	
198	// inherited from NATCallframe:
199	// private FieldMap 	variableMap_;
200	// private Vector	stateVector_;
201	// private LinkedList customFields_;
202	
203	/**
204	 * The method dictionary of this object. It maps method selectors to ATMethod objects.
205	 */
206	private MethodDictionary methodDictionary_;
207	
208	/**
209	 * The stripes with which this object has been striped.
210	 */
211	protected ATStripe[] stripes_;
212	
213	/* ------------------
214	 * -- Constructors --
215	 * ------------------ */
216	
217	/**
218	 * Creates an object striped with the at.stripes.Isolate stripe.
219	 * Such an object is called an isolate because:
220	 *  - it has no access to an enclosing lexical scope (except for the root lexical scope)
221	 *  - it can therefore be passed by copy
222	 */
223	public static NATObject createIsolate() {
224		return new NATObject(new ATStripe[] { NativeStripes._ISOLATE_ });
225	}
226	
227	/**
228	 * Constructs a new AmbientTalk object whose lexical parent is the
229	 * global scope and whose dynamic parent is the dynamic root.
230	 */
231	public NATObject() {
232		this(Evaluator.getGlobalLexicalScope());
233	}
234	
235	public NATObject(ATStripe[] stripes) {
236		this(Evaluator.getGlobalLexicalScope(), stripes);
237	}
238	
239	/**
240	 * Constructs a new ambienttalk object parametrised by a lexical scope. The 
241	 * object is thus not equipped with a pointer to a dynamic parent.
242	 * @param lexicalParent - the lexical scope in which the object's definition was nested
243	 */
244	public NATObject(ATObject lexicalParent) {
245		this(NATNil._INSTANCE_, lexicalParent, _SHARES_A_);
246	}
247	
248	/**
249	 * Constructs a new ambienttalk object parametrised by a lexical scope.
250	 * The object's dynamic parent is nil and is striped with the given table of stripes
251	 */
252	public NATObject(ATObject lexicalParent, ATStripe[] stripes) {
253		this(NATNil._INSTANCE_, lexicalParent, _SHARES_A_, stripes);
254	}
255
256	/**
257	 * Constructs a new ambienttalk object with the given dynamic parent.
258	 * The lexical parent is assumed to be the global scope.
259	 * @param dynamicParent - the dynamic parent of the new object
260	 * @param parentType - the type of parent link
261	 */
262	public NATObject(ATObject dynamicParent, boolean parentType) {
263		this(dynamicParent, Evaluator.getGlobalLexicalScope(), parentType);
264	}
265
266	/**
267	 * Constructs a new ambienttalk object based on a set of parent pointers.
268	 * The object has no stripes.
269	 * @param dynamicParent - the parent object of the newly created object
270	 * @param lexicalParent - the lexical scope in which the object's definition was nested
271	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
272	 */
273	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType) {
274	   this(dynamicParent, lexicalParent, parentType, _NO_STRIPES_);
275	}
276	
277	/**
278	 * Constructs a new ambienttalk object based on a set of parent pointers.
279	 * The object is striped with the given stripes.
280	 * @param dynamicParent - the parent object of the newly created object
281	 * @param lexicalParent - the lexical scope in which the object's definition was nested
282	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
283	 * @param stripes - the stripes attached to this object
284	 */
285	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType, ATStripe[] stripes) {
286		super(lexicalParent);
287		
288        // by default, an object has a shares-a parent, does not share its map
289		// or dictionary and is no isolate, so all flags are set to 0
290		flags_ = 0;
291		
292		stripes_ = stripes;
293		
294		methodDictionary_ = new MethodDictionary();
295		
296		// bind the dynamic parent to the field named 'super'
297		// we don't pass via meta_defineField as this would trigger mirages too early
298		variableMap_.put(_SUPER_NAME_);
299		stateVector_.add(dynamicParent);
300		
301		// add ==, new and init to the method dictionary directly
302		// we don't pass via meta_addMethod as this would trigger mirages too early
303		methodDictionary_.put(_EQL_NAME_, _PRIM_EQL_);
304		methodDictionary_.put(_NEW_NAME_, _PRIM_NEW_);
305		methodDictionary_.put(_INI_NAME_, _PRIM_INI_);
306		
307		if (parentType) { // parentType == _IS_A_)
308			// requested an 'is-a' parent
309			setFlag(_ISAPARENT_FLAG_); // set is-a parent flag to 1
310		}
311		
312		try {
313            // if this object is striped as at.stripes.Isolate, flag it as an isolate
314            // we cannot perform 'this.meta_isStripedWith(ISOLATE)' because this would trigger mirages too early
315			if (isLocallyStripedWith(NativeStripes._ISOLATE_)
316			     || dynamicParent.meta_isStripedWith(NativeStripes._ISOLATE_).asNativeBoolean().javaValue) {
317				setFlag(_IS_ISOLATE_FLAG_);
318				// isolates can only have the global lexical root as their lexical scope
319				lexicalParent_ = Evaluator.getGlobalLexicalScope();
320			}
321		} catch (InterpreterException e) {
322			// some custom stripe failed to match agains the Isolate stripe,
323			// the object is not considered an Isolate
324			Logging.Actor_LOG.error("Error testing for Isolate stripe, ignored:", e);
325		}
326	}
327	
328	/**
329	 * Constructs a new ambienttalk object as a clone of an existing object.
330	 * 
331	 * The caller of this method *must* ensure that the shares flags are set.
332	 * 
333	 * This constructor is responsible for manually re-initialising any custom field
334	 * objects, because the init method of such custom fields is parameterized by the
335	 * clone, which only comes into existence when this constructor runs.
336	 */
337	protected NATObject(FieldMap map,
338			         Vector state,
339			         LinkedList originalCustomFields,
340			         MethodDictionary methodDict,
341			         ATObject dynamicParent,
342			         ATObject lexicalParent,
343			         byte flags,
344			         ATStripe[] stripes) throws InterpreterException {
345		super(map, state, lexicalParent, null);
346		methodDictionary_ = methodDict;
347		
348		flags_ = flags; //a cloned object inherits all flags from original
349		
350		// clone inherits all stripes (this implies that clones of isolates are also isolates)
351		stripes_ = stripes;
352		
353		// ==, new and init should already be present in the method dictionary
354		
355		// set the 'super' field to point to the new dynamic parent
356		setLocalField(_SUPER_NAME_, dynamicParent);
357		
358		// re-initialize all custom fields
359		if (originalCustomFields != null) {
360			customFields_ = new LinkedList();
361			Iterator it = originalCustomFields.iterator();
362			while (it.hasNext()) {
363				ATField field = (ATField) it.next();
364				customFields_.add(field.base_new(new ATObject[] { this }).asField());
365			}
366		}
367	}
368	
369	/**
370	 * Initialize a new AmbientTalk object with the given closure.
371	 * 
372	 * The closure encapsulates:
373	 *  - the code with which to initialize the object
374	 *  - the lexical parent of the object (but that parent should already be set)
375	 *  - the lexically inherited fields for the object (the parameters of the closure)
376	 */
377	public void initializeWithCode(ATClosure code) throws InterpreterException {
378		NATTable copiedBindings = Evaluator.evalMandatoryPars(
379				code.base_getMethod().base_getParameters(),
380				code.base_getContext());
381		code.base_applyInScope(copiedBindings, this);
382	}
383
384	/**
385	 * Invoke NATObject's primitive implementation, such that Java invocations of this
386	 * method have the same behaviour as AmbientTalk invocations.
387	 */
388    public ATObject base_init(ATObject[] initargs) throws InterpreterException {
389    	return this.prim_init(this, initargs);
390    }
391	
392	/**
393	 * The primitive implementation of init in objects is to invoke the init
394	 * method of their parent.
395	 * @param self the object that originally received the 'init' message.
396	 * 
397	 * def init(@args) {
398	 *   super^init(@args)
399	 * }
400	 */
401    private ATObject prim_init(ATObject self, ATObject[] initargs) throws InterpreterException {
402    	ATObject parent = base_getSuper();
403    	return parent.meta_invoke(self, Evaluator._INIT_, NATTable.atValue(initargs));
404    }
405	
406	/* ------------------------------
407	 * -- Message Sending Protocol --
408	 * ------------------------------ */
409	
410	/**
411	 * Invocations on an object ( <tt>o.m( args )</tt> ) are handled by looking up the requested
412	 * selector in the dynamic parent chain of the receiver. This dynamic lookup process
413	 * yields exactly the same result as a selection (e.g. <tt>o.m</tt>). The result
414	 * ought to be a closure (a method and its corresponding evaluation context), which
415	 * is applied to the provided arguments.
416	 * 
417	 * The code for meta_invoke is actually equivalent to
418	 * <code>return this.meta_select(receiver, selector).asClosure().meta_apply(arguments);</code>
419	 * but has a specialized implementation for performance reasons (no unnecessary closure is created)
420	 */
421	public ATObject meta_invoke(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
422		if (this.hasLocalField(selector)) {
423			return this.getLocalField(selector).asClosure().base_apply(arguments);
424		} else if (this.hasLocalMethod(selector)) {
425			// immediately execute the method in the context ctx where
426			//  ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted
427			//  ctx.self  = the late bound receiver, being the passed receiver
428			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver));
429		} else {
430			return base_getSuper().meta_invoke(receiver, selector, arguments);
431		}
432	}
433	
434	/**
435	 * An ambienttalk object can respond to a message if a corresponding field or method exists
436	 * either in the receiver object locally, or in one of its dynamic parents.
437	 */
438	public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException {
439		if (this.hasLocalField(selector) || this.hasLocalMethod(selector))
440			return NATBoolean._TRUE_;
441		else
442			return base_getSuper().meta_respondsTo(selector);
443	}
444
445
446	/* ------------------------------------------
447	 * -- Slot accessing and mutating protocol --
448	 * ------------------------------------------ */
449	
450	/**
451	 * meta_select is used to evaluate code of the form <tt>o.m</tt>.
452	 * 
453	 * To select a slot from an object:
454	 *  - first, the list of fields of the current receiver ('this') is searched.
455	 *    If a matching field exists, its value is returned.
456	 *  - second, the list of methods of the current receiver is searched.
457	 *    If a matching method exists, it is returned, but wrapped in a closure.
458	 *    This wrapping is vital to ensure that the method is paired with the correct 'self'.
459	 *    This 'self' does not necessarily equal 'this'.
460	 *  - third, the search for the slot is carried out recursively in the dynamic parent.
461	 *    As such, slot selection traverses the dynamic parent chain up to a dynamic root.
462	 *    The dynamic root deals with an unbound slot by sending the 'doesNotUnderstand' message
463	 *    to the original receiver.
464	 *    
465	 * @param receiver the original receiver of the selection
466	 * @param selector the selector to look up
467	 * @return the value of the found field, or a closure wrapping a found method
468	 */
469	public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException {
470		if (this.hasLocalField(selector)) {
471			return this.getLocalField(selector);
472		} else if (this.hasLocalMethod(selector)) {
473			// return a new closure (mth, ctx) where
474			//  mth = the method found in this object
475			//  ctx.scope = the implementing scope, being this object
476			//  ctx.self  = the late bound receiver, being the passed receiver
477			//  ctx.super = the parent of the implementor
478			return new NATClosure(this.getLocalMethod(selector), this, receiver);
479		} else {
480			return base_getSuper().meta_select(receiver, selector);
481		}
482	}
483	
484	/**
485	 * This method corresponds to code of the form ( x ) within the scope of this 
486	 * object. It searches for the requested selector among the methods and fields 
487	 * of the object and its dynamic parents.
488	 * 
489	 * Overridden from NATCallframe to take methods into account as well.
490	 * 
491	 * This method is used to evaluate code of the form <tt>selector</tt> within the scope
492	 * of this object. An object resolves such a lookup request as follows:
493	 *  - If a field corresponding to the selector exists locally, the field's value is returned.
494	 *  - If a method corresponding to the selector exists locally, the method is wrapped
495	 *    using the current object itself as implementor AND as 'self'.
496	 *    The reason for setting the closure's 'self' to the implementor is because a lookup can only
497	 *    be initiated by the object itself or a lexically nested one. Lexical nesting, however, has
498	 *    nothing to do with dynamic delegation, and it would be wrong to bind 'self' to a nested object
499	 *    which need not be a dynamic child of the implementor.
500	 *    
501	 *  - Otherwise, the search continues recursively in the object's lexical parent.
502	 */
503	public ATObject meta_lookup(ATSymbol selector) throws InterpreterException {
504		if (this.hasLocalField(selector)) {
505			return this.getLocalField(selector);
506		} else if (this.hasLocalMethod(selector)) {
507			// return a new closure (mth, ctx) where
508			//  mth = the method found in this object
509			//  ctx.scope = the implementing scope, being this object
510			//  ctx.self  = the receiver, being in this case again the implementor
511			return new NATClosure(this.getLocalMethod(selector),this, this);
512		} else {
513			return lexicalParent_.meta_lookup(selector);
514		}
515	}
516	
517	/**
518	 * When a new field is defined in an object, it is important to check whether or not
519	 * the field map is shared between clones or not. If it is shared, the map must be cloned first.
520	 * @throws InterpreterException 
521	 */
522	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
523		if (this.isFlagSet(_SHARE_MAP_FLAG_)) {
524			// copy the variable map
525			variableMap_ = variableMap_.copy();
526			// set the 'shares map' flag to false
527			unsetFlag(_SHARE_MAP_FLAG_);
528		}
529		return super.meta_defineField(name, value);
530	}
531	
532	/** 
533	 * meta_assignField is used to evaluate code of the form <tt>o.m := v</tt>.
534	 * 
535	 * To assign a field in an object:
536	 *  - first, the list of fields of the current receiver ('this') is searched.
537	 *    If a matching field exists, its value is set.
538	 *  - If the field is not found, the search for the slot is carried out recursively in the dynamic parent.
539	 *    As such, field assignment traverses the dynamic parent chain up to a dynamic root.
540	 *    The dynamic root deals with an unbound field by throwing an error.
541	 * @param value the value to assign to the field
542	 * @param selector the field to assign
543	 *    
544	 * @return NIL
545	 */
546	public ATNil meta_assignField(ATObject receiver, ATSymbol selector, ATObject value) throws InterpreterException {
547		if (this.setLocalField(selector, value)) {
548			return NATNil._INSTANCE_;
549		} else {
550			return base_getSuper().meta_assignField(receiver, selector, value);
551		}
552	}
553	
554	/* ------------------------------------
555	 * -- Extension and cloning protocol --
556	 * ------------------------------------ */
557
558	/**
559	 * When cloning an object, it is first determined whether the parent
560	 * has to be shared by the clone, or whether the parent must also be cloned.
561	 * This depends on whether the dynamic parent is an 'is-a' parent or a 'shares-a'
562	 * parent. This is determined by the _ISAPARENT_FLAG_ object flag.
563	 * 
564	 * A cloned object shares with its original both the variable map
565	 * (to avoid having to copy space for field names) and the method dictionary
566	 * (method bindings are constant and can hence be shared).
567	 * 
568	 * Should either the original or the clone later modify the map or the dictionary
569	 * (at the meta-level), the map or dictionary will be copied first. Hence,
570	 * sharing between clones is an implementation-level optimization: clones
571	 * are completely self-sufficient and do not influence one another by meta-level operations.
572	 */
573	public ATObject meta_clone() throws InterpreterException {
574		ATObject dynamicParent;
575		if(this.isFlagSet(_ISAPARENT_FLAG_)) {
576			// IS-A Relation : clone the dynamic parent.
577			dynamicParent = base_getSuper().meta_clone();
578		} else {
579			// SHARES_A Relation : share the dynamic parent.
580			dynamicParent = base_getSuper();
581		}
582		
583		// ! set the shares flags of this object *and* of its clone
584		// both this object and the clone now share the map and method dictionary
585		setFlag(_SHARE_DCT_FLAG_);
586		setFlag(_SHARE_MAP_FLAG_);
587		
588		NATObject clone = this.createClone(variableMap_,
589				          (Vector) stateVector_.clone(), // shallow copy
590				          customFields_, // must be re-initialized by clone!
591				          methodDictionary_,
592				          dynamicParent,
593				          lexicalParent_,
594				          flags_, stripes_);
595		
596		return clone;
597	}
598	
599	/**
600	 * When new is invoked on an object's mirror, the object is first cloned
601	 * by the mirror, after which the method named 'init' is invoked on it.
602	 * 
603	 * meta_newInstance(t) = base_init(t) o meta_clone
604	 * 
605	 * Care should be taken that a shares-a child implements its own init method
606	 * which does NOT perform a super-send. If this is not the case, then it is
607	 * possible that a shared parent is accidentally re-initialized because a
608	 * sharing child is cloned via new.
609	 */
610	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
611		ATObject clone = this.meta_clone();
612		clone.meta_invoke(clone, Evaluator._INIT_, initargs);
613		return clone;
614	}
615
616	public ATBoolean meta_isExtensionOfParent() throws InterpreterException {
617		return NATBoolean.atValue(isFlagSet(_ISAPARENT_FLAG_));
618	}
619	
620	/* ---------------------------------
621	 * -- Structural Access Protocol  --
622	 * --------------------------------- */
623
624	/**
625	 * When a method is added to an object, it is first checked whether the method does not
626	 * already exist. Also, care has to be taken that the method dictionary of an object
627	 * does not affect clones. Therefore, if the method dictionary is shared, a copy
628	 * of the dictionary is taken before adding the method.
629	 * 
630	 * One exception to method addition are primitive methods: if the method added
631	 * would conflict with a primitive method, the primitive is replaced by the new
632	 * method instead.
633	 */
634	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
635		ATSymbol name = method.base_getName();
636		if (methodDictionary_.containsKey(name) && !isPrimitive(name)) {
637			throw new XDuplicateSlot(XDuplicateSlot._METHOD_, name);
638		} else {
639			// first check whether the method dictionary is shared
640			if (this.isFlagSet(_SHARE_DCT_FLAG_)) {
641				methodDictionary_ = (MethodDictionary) methodDictionary_.clone();
642				this.unsetFlag(_SHARE_DCT_FLAG_);
643			}
644			methodDictionary_.put(name, method);
645		}
646		return NATNil._INSTANCE_;
647	}
648
649	public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
650		ATMethod result = (ATMethod)methodDictionary_.get(selector);
651		if(result == null) {
652			throw new XSelectorNotFound(selector, this);
653		} else {
654			return result;
655		}
656	}
657
658	public ATTable meta_listMethods() throws InterpreterException {
659		Collection methods = methodDictionary_.values();
660		return NATTable.atValue((ATObject[]) methods.toArray(new ATObject[methods.size()]));
661	}
662	
663	public NATText meta_print() throws InterpreterException {
664		if (stripes_.length == 0) {
665			return NATText.atValue("<object:"+this.hashCode()+">");
666		} else {
667			return NATText.atValue("<object:"+this.hashCode()+
668					               Evaluator.printElements(stripes_, "[", ",", "]").javaValue+">");
669		}
670	}
671	
672	public boolean isCallFrame() {
673		return false;
674	}
675	
676	/* ---------------------
677	 * -- Mirror Fields   --
678	 * --------------------- */
679	
680	// protected methods, may be adapted by extensions
681	
682	protected NATObject createClone(FieldMap map,
683	         					  Vector state,
684	         					  LinkedList originalCustomFields,
685	         					  MethodDictionary methodDict,
686	         					  ATObject dynamicParent,
687	         					  ATObject lexicalParent,
688	         					  byte flags,
689	         					  ATStripe[] stripes) throws InterpreterException {
690		return new NATObject(map,
691	            state,
692	            originalCustomFields,
693	            methodDict,
694	            dynamicParent,
695	            lexicalParent,
696	            flags,
697	            stripes);
698	}
699		
700    /* ----------------------------------
701     * -- Object Relational Comparison --
702     * ---------------------------------- */
703    
704	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
705		if(original instanceof NATObject) {
706			MethodDictionary originalMethods = ((NATObject)original).methodDictionary_;
707			FieldMap originalVariables = ((NATObject)original).variableMap_;
708			
709			return NATBoolean.atValue(
710					methodDictionary_.isDerivedFrom(originalMethods) &
711					variableMap_.isDerivedFrom(originalVariables));
712		} else {
713			return NATBoolean._FALSE_;
714		}
715	}
716
717	public ATBoolean meta_isRelatedTo(final ATObject object) throws InterpreterException {
718		return this.meta_isCloneOf(object).base_or_(
719				new NativeClosure(this) {
720					public ATObject base_apply(ATTable args) throws InterpreterException {
721						return scope_.base_getSuper().meta_isRelatedTo(object);
722					}
723				}).asBoolean();
724	}
725	
726    /* ---------------------------------
727     * -- Stripe Testing and Querying --
728     * --------------------------------- */
729	
730    /**
731     * Check whether one of the stripes of this object is a substripe of the given stripe.
732     * If not, then delegate the query to the dynamic parent.
733     */
734    public ATBoolean meta_isStripedWith(ATStripe stripe) throws InterpreterException {
735    	if (isLocallyStripedWith(stripe)) {
736    		return NATBoolean._TRUE_;
737    	} else {
738        	// no stripes match, ask the parent
739        	return base_getSuper().meta_isStripedWith(stripe);
740    	}
741    }
742    
743    /**
744     * Return the stripes that were directly attached to this object.
745     */
746    public ATTable meta_getStripes() throws InterpreterException {
747    	// make a copy of the internal stripes array to ensure that the stripes
748    	// of the object are immutable. Tables allow assignment!
749    	if (stripes_.length == 0) {
750    		return NATTable.EMPTY;
751    	} else { 
752    		ATStripe[] stripes = new ATStripe[stripes_.length];
753        	System.arraycopy(stripes_, 0, stripes, 0, stripes_.length);
754        	return NATTable.atValue(stripes);
755    	}
756    }
757    
758    
759	// NATObject has to duplicate the NATByCopy implementation
760	// because NATObject inherits from NATByRef, and because Java has no
761	// multiple inheritance to override that implementation with that of
762    // NATByCopy if this object signifies an isolate.
763	
764    /**
765     * An isolate object does not return a proxy representation of itself
766     * during serialization, hence it is serialized itself. If the object
767     * is not an isolate, invoke the default behaviour for by-reference objects
768     */
769    public ATObject meta_pass() throws InterpreterException {
770    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
771    		return this;
772    	} else {
773    		return super.meta_pass();
774    	}
775    }
776	
777    /**
778     * An isolate object represents itself upon deserialization.
779     * If this object is not an isolate, the default behaviour for by-reference
780     * objects is invoked.
781     */
782    public ATObject meta_resolve() throws InterpreterException {
783    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
784    		// re-bind to the new local global lexical root
785    		lexicalParent_ = Evaluator.getGlobalLexicalScope();
786    		return this;
787    	} else {
788    		return super.meta_resolve();
789    	}
790    }
791    
792    /* ---------------------------------------
793	 * -- Conversion and Testing Protocol   --
794	 * --------------------------------------- */
795	
796	public NATObject asAmbientTalkObject() { return this; }
797	
798	/**
799	 * ALL asXXX methods return a coercer object which returns a proxy of the correct interface that will 'down'
800	 * subsequent Java base-level invocations to the AmbientTalk level.
801	 * 
802	 * Coercion only happens if the object is striped with the correct stripe.
803	 */
804	private Object coerce(ATStripe requiredStripe, Class providedInterface) throws InterpreterException {
805		if (this.meta_isStripedWith(requiredStripe).asNativeBoolean().javaValue) {
806			return Coercer.coerce(this, providedInterface);
807		} else {
808			// if the object does not possess the right stripe, raise a type error
809			throw new XTypeMismatch(providedInterface, this);
810		}
811	}
812	
813	public ATBoolean asBoolean() throws InterpreterException { return (ATBoolean) coerce(NativeStripes._BOOLEAN_, ATBoolean.class); }
814	public ATClosure asClosure() throws InterpreterException { return (ATClosure) coerce(NativeStripes._CLOSURE_, ATClosure.class); }
815	public ATExpression asExpression() throws InterpreterException { return (ATExpression) coerce(NativeStripes._EXPRESSION_, ATExpression.class); }
816	public ATField asField() throws InterpreterException { return (ATField) coerce(NativeStripes._FIELD_, ATField.class); }
817	public ATMessage asMessage() throws InterpreterException { return (ATMessage) coerce(NativeStripes._MESSAGE_, ATMessage.class); }
818	public ATMethod asMethod() throws InterpreterException { return (ATMethod) coerce(NativeStripes._METHOD_, ATMethod.class); }
819	public ATHandler asHandler() throws InterpreterException { return (ATHandler) coerce(NativeStripes._HANDLER_, ATHandler.class); }
820	public ATNumber asNumber() throws InterpreterException { return (ATNumber) coerce(NativeStripes._NUMBER_, ATNumber.class); }
821	public ATTable asTable() throws InterpreterException { return (ATTable) coerce(NativeStripes._TABLE_, ATTable.class); }
822    public ATAsyncMessage asAsyncMessage() throws InterpreterException { return (ATAsyncMessage) coerce(NativeStripes._ASYNCMSG_, ATAsyncMessage.class);}
823    public ATActorMirror asActorMirror() throws InterpreterException { return (ATActorMirror) coerce(NativeStripes._ACTORMIRROR_, ATActorMirror.class); }
824    public ATStripe asStripe() throws InterpreterException { return (ATStripe) coerce(NativeStripes._STRIPE_, ATStripe.class); }
825	
826	public ATBegin asBegin() throws InterpreterException { return (ATBegin) coerce(NativeStripes._BEGIN_, ATBegin.class); }
827	public ATStatement asStatement() throws InterpreterException { return (ATStatement) coerce(NativeStripes._STATEMENT_, ATStatement.class); }
828    public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { return (ATUnquoteSplice) coerce(NativeStripes._UQSPLICE_, ATUnquoteSplice.class); }
829    public ATSymbol asSymbol() throws InterpreterException { return (ATSymbol) coerce(NativeStripes._SYMBOL_, ATSymbol.class); }
830    public ATSplice asSplice() throws InterpreterException { return (ATSplice) coerce(NativeStripes._SPLICE_, ATSplice.class); }
831	public ATDefinition asDefinition() throws InterpreterException { return (ATDefinition) coerce(NativeStripes._DEFINITION_, ATDefinition.class); }
832	public ATMessageCreation asMessageCreation() throws InterpreterException { return (ATMessageCreation) coerce(NativeStripes._MSGCREATION_, ATMessageCreation.class); }
833	
834	// ALL isXXX methods return true (can be overridden by programmer-defined base-level methods)
835	
836	public boolean isAmbientTalkObject() { return true; }
837	
838	// objects can only be 'cast' to a native category if they are marked with
839	// the appropriate native stripe
840	public boolean isBoolean() throws InterpreterException { return meta_isStripedWith(NativeStripes._BOOLEAN_).asNativeBoolean().javaValue; }
841	public boolean isClosure() throws InterpreterException { return meta_isStripedWith(NativeStripes._CLOSURE_).asNativeBoolean().javaValue; }
842	public boolean isMethod() throws InterpreterException { return meta_isStripedWith(NativeStripes._METHOD_).asNativeBoolean().javaValue; }
843	public boolean isSplice() throws InterpreterException { return meta_isStripedWith(NativeStripes._SPLICE_).asNativeBoolean().javaValue; }
844	public boolean isSymbol() throws InterpreterException { return meta_isStripedWith(NativeStripes._SYMBOL_).asNativeBoolean().javaValue; }
845	public boolean isTable() throws InterpreterException { return meta_isStripedWith(NativeStripes._TABLE_).asNativeBoolean().javaValue; }
846	public boolean isUnquoteSplice() throws InterpreterException { return meta_isStripedWith(NativeStripes._UQSPLICE_).asNativeBoolean().javaValue; }
847	public boolean isStripe() throws InterpreterException { return meta_isStripedWith(NativeStripes._STRIPE_).asNativeBoolean().javaValue; }
848	
849	
850	// private methods
851	
852	private boolean isFlagSet(byte flag) {
853		return (flags_ & flag) != 0;
854	}
855
856	private void setFlag(byte flag) {
857		flags_ = (byte) (flags_ | flag);
858	}
859
860	private void unsetFlag(byte flag) {
861		flags_ = (byte) (flags_ & (~flag));
862	}
863	
864	private boolean hasLocalMethod(ATSymbol selector) {
865		return methodDictionary_.containsKey(selector);
866	}
867	
868	private ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
869		ATMethod result = ((ATObject) methodDictionary_.get(selector)).asMethod();
870		if(result == null) {
871			throw new XSelectorNotFound(selector, this);
872		} else {
873			return result;
874		}
875	}
876	
877	/**
878	 * Performs a stripe test for this object locally.
879	 * @return whether this object is striped with a particular stripe or not.
880	 */
881	private boolean isLocallyStripedWith(ATStripe stripe) throws InterpreterException {
882    	for (int i = 0; i < stripes_.length; i++) {
883			if (stripes_[i].base_isSubstripeOf(stripe).asNativeBoolean().javaValue) {
884				// if one stripe matches, return true
885				return true;
886			}
887		}
888		return false;
889	}
890	
891	/**
892	 * Auxiliary method to access the fields of an object and all of its super-objects up to (but excluding) nil.
893	 * Overridden fields of parent objects are not included.
894	 */
895	public static ATField[] listTransitiveFields(ATObject obj) throws InterpreterException {
896		Vector fields = new Vector();
897		HashSet encounteredNames = new HashSet(); // to filter duplicates
898		for (; obj != NATNil._INSTANCE_ ; obj = obj.base_getSuper()) {
899			ATObject[] localFields = obj.meta_listFields().asNativeTable().elements_;
900			for (int i = 0; i < localFields.length; i++) {
901				ATField field = localFields[i].asField();
902				ATSymbol fieldName = field.base_getName();
903				if (!encounteredNames.contains(fieldName)) {
904					fields.add(field);
905					encounteredNames.add(fieldName);
906				}
907			}
908		}
909		return (ATField[]) fields.toArray(new ATField[fields.size()]);
910	}
911	
912	/**
913	 * Auxiliary method to access the methods of an object and all of its super-objects up to (but excluding) nil.
914	 * Overridden methods of parent objects are not included.
915	 */
916	public static ATMethod[] listTransitiveMethods(ATObject obj) throws InterpreterException {
917		Vector methods = new Vector();
918		HashSet encounteredNames = new HashSet(); // to filter duplicates		
919		for (; obj != NATNil._INSTANCE_ ; obj = obj.base_getSuper()) {
920			// fast-path for native objects
921			if (obj instanceof NATObject) {
922				Collection localMethods = ((NATObject) obj).methodDictionary_.values();
923				for (Iterator iter = localMethods.iterator(); iter.hasNext();) {
924					ATMethod localMethod = (ATMethod) iter.next();
925					ATSymbol methodName = localMethod.base_getName();
926					if (!encounteredNames.contains(methodName)) {
927						methods.add(localMethod);
928						encounteredNames.add(methodName);
929					}
930				}
931			} else {
932				ATObject[] localMethods = obj.meta_listMethods().asNativeTable().elements_;
933				for (int i = 0; i < localMethods.length; i++) {
934					ATMethod localMethod = localMethods[i].asMethod();
935					ATSymbol methodName = localMethod.base_getName();
936					if (!encounteredNames.contains(methodName)) {
937						methods.add(localMethod);
938						encounteredNames.add(methodName);
939					}
940				}
941			}
942		}
943		return (ATMethod[]) methods.toArray(new ATMethod[methods.size()]);
944	}
945	
946}