PageRenderTime 71ms CodeModel.GetById 17ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://ambienttalk.googlecode.com/
Java | 876 lines | 449 code | 97 blank | 330 comment | 67 complexity | 3a86130bf0ab7c16de182ff862c4a91f 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.ATFarReference;
 33import edu.vub.at.actors.ATLetter;
 34import edu.vub.at.eval.Evaluator;
 35import edu.vub.at.exceptions.InterpreterException;
 36import edu.vub.at.exceptions.XDuplicateSlot;
 37import edu.vub.at.exceptions.XSelectorNotFound;
 38import edu.vub.at.exceptions.XTypeMismatch;
 39import edu.vub.at.exceptions.XUndefinedSlot;
 40import edu.vub.at.objects.ATAbstractGrammar;
 41import edu.vub.at.objects.ATBoolean;
 42import edu.vub.at.objects.ATClosure;
 43import edu.vub.at.objects.ATField;
 44import edu.vub.at.objects.ATHandler;
 45import edu.vub.at.objects.ATMessage;
 46import edu.vub.at.objects.ATMethod;
 47import edu.vub.at.objects.ATMethodInvocation;
 48import edu.vub.at.objects.ATNil;
 49import edu.vub.at.objects.ATNumber;
 50import edu.vub.at.objects.ATObject;
 51import edu.vub.at.objects.ATTable;
 52import edu.vub.at.objects.ATTypeTag;
 53import edu.vub.at.objects.coercion.Coercer;
 54import edu.vub.at.objects.coercion.NativeTypeTags;
 55import edu.vub.at.objects.grammar.ATBegin;
 56import edu.vub.at.objects.grammar.ATDefinition;
 57import edu.vub.at.objects.grammar.ATMessageCreation;
 58import edu.vub.at.objects.grammar.ATSplice;
 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.natives.grammar.AGSymbol;
 63import edu.vub.at.util.logging.Logging;
 64
 65import java.io.IOException;
 66import java.util.Collection;
 67import java.util.HashSet;
 68import java.util.Iterator;
 69import java.util.LinkedList;
 70import java.util.Set;
 71import java.util.Vector;
 72
 73/**
 74 * Native implementation of a default ambienttalk object.
 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 * This is a pure form of implementation subclassing: we subclass NATCallframe only
 78 * for reusing the field definition/assignment protocol and for inheriting the
 79 * variable map, the state vector and the lexical parent.
 80 * <p>
 81 * NATObjects are one of the five native classes that (almost) fully implement the ATObject interface
 82 * (next to NATCallFrame, NATNil, NATMirage and JavaObject). The implementation is such that
 83 * a NATObject instance represents <b>both</b> a base-level AmbientTalk object, as well as a meta-level
 84 * AmbientTalk mirror on that object.
 85 * 
 86 * An AmbientTalk base-level object has the following structure:
 87 * <ul>
 88 *  <li> properties: a set of boolean flags denoting:
 89 *  <ul>
 90 *   <li> whether the dynamic parent is an IS_A or a SHARES_A parent
 91 *   <li> whether the object shares its variable map with clones
 92 *   <li> whether the object shares its method dictionary with clones
 93 *   <li> whether the object is an isolate (i.e. pass-by-copy)
 94 *  </ul>
 95 *  <li> a variable map, mapping variable names to indices into the state vector
 96 *  <li> a state vector, containing the field values of the object
 97 *  <li> a linked list containing custom field objects
 98 *  <li> a method dictionary, mapping selectors to methods
 99 *  <li> a dynamic object parent, to delegate select and invoke operations
100 *   ( this parent slot is represented by a true AmbientTalk field, rather than by an instance variable )
101 *  <li> a lexical object parent, to support lexical scoping
102 *  <li> a table of type tags that were attached to this object (for classification purposes)
103 * </ul>
104 * 
105 * @author tvcutsem
106 * @author smostinc
107 */
108public class NATObject extends NATCallframe implements ATObject {
109	
110	// The name of the field that points to the dynamic parent
111	public static final AGSymbol _SUPER_NAME_ = AGSymbol.jAlloc("super");
112	
113	// Auxiliary static methods to support the type of dynamic parent
114	public static final boolean _IS_A_ 		= true;
115	public static final boolean _SHARES_A_ 	= false;
116	
117	/**
118	 * This flag determines the type of parent pointer of this object. We distinguish two cases:
119	 *  - 1: an is-a link, which results in a recursive cloning of the parent when this object is cloned.
120	 *  - 0: a shares-a link, which ensures that clones of this object share the same parent.
121	 */
122	private static final byte _ISAPARENT_FLAG_ = 1<<0;
123	
124	/**
125	 * This flag determines whether or not the field map of this object is shared by other objects:
126	 *  - 1: the map is shared, so modifications must be performed on a copy
127	 *  - 0: the map is not shared, modifications may be directly performed on it
128	 *  
129	 * This flag is important for maintaining the semantics that clones are self-sufficient objects:
130	 * they share field names and methods only at the implementation-level.
131	 */
132	private static final byte _SHARE_MAP_FLAG_ = 1<<1;
133	
134	/**
135	 * Similar to _SHARE_MAP_FLAG__ but for determining the shared status of the method dictionary.
136	 */
137	private static final byte _SHARE_DCT_FLAG_ = 1<<2;
138	
139	/**
140	 * This flag determines whether or not the object is an isolate and hence pass-by-copy:
141	 *  - 1: the object is an isolate, pass-by-copy and no lexical parent except for the root
142	 *  - 0: the object is pass-by-reference and can have any lexical parent
143	 */
144	private static final byte _IS_ISOLATE_FLAG_ = 1<<3;
145
146	/**
147	 * An empty type tag array shared by those objects that do not have any type tags.
148	 */
149	public static final ATTypeTag[] _NO_TYPETAGS_ = new ATTypeTag[0];
150	
151	/**
152	 * The flags of an AmbientTalk object encode the following boolean information:
153	 *  Format: 0b0000idap where
154	 *   p = parent flag: if set, dynamic parent is 'is-a' parent, otherwise 'shares-a' parent
155	 *   a = shares map flag: if set, the map of this object is shared between clones
156	 *   d = shares dictionary flag: if set, the method dictionary of this object is shared between clones
157	 *   i = is isolate flag: if set, the object is passed by copy in inter-actor communication
158	 */
159	private byte flags_;
160	
161	// inherited from NATCallframe:
162	// private FieldMap 	variableMap_;
163	// private Vector	stateVector_;
164	// private LinkedList customFields_;
165	
166	/**
167	 * The method dictionary of this object. It maps method selectors to ATMethod objects.
168	 * Protected access modifier because {@link NATNil} needs to add primitive methods.
169	 */
170	protected MethodDictionary methodDictionary_;
171	
172	/**
173	 * The types with which this object has been tagged.
174	 */
175	protected ATTypeTag[] typeTags_;
176	
177	/* ------------------
178	 * -- Constructors --
179	 * ------------------ */
180	
181	/**
182	 * Constructs a new AmbientTalk object whose lexical parent is the
183	 * global scope and whose dynamic parent is the dynamic root.
184	 */
185	public NATObject() {
186		this(Evaluator.getGlobalLexicalScope());
187	}
188	
189	/**
190	 * Construct a new AmbientTalk object directly tagged with the given type tags.
191	 */
192	public NATObject(ATTypeTag[] tags) {
193		this(Evaluator.getGlobalLexicalScope(), tags);
194	}
195	
196	/**
197	 * Constructs a new ambienttalk object parametrised by a lexical scope. The 
198	 * object is thus not equipped with a pointer to a dynamic parent.
199	 * @param lexicalParent - the lexical scope in which the object's definition was nested
200	 */
201	public NATObject(ATObject lexicalParent) {
202		this(Evaluator.getNil(), lexicalParent, _SHARES_A_);
203	}
204	
205	/**
206	 * Constructs a new ambienttalk object parametrised by a lexical scope.
207	 * The object's dynamic parent is nil and is tagged with the given table of type tags
208	 */
209	public NATObject(ATObject lexicalParent, ATTypeTag[] tags) {
210		this(Evaluator.getNil(), lexicalParent, _SHARES_A_, tags);
211	}
212
213	/**
214	 * Constructs a new ambienttalk object with the given dynamic parent.
215	 * The lexical parent is assumed to be the global scope.
216	 * @param dynamicParent - the dynamic parent of the new object
217	 * @param parentType - the type of parent link
218	 */
219	public NATObject(ATObject dynamicParent, boolean parentType) {
220		this(dynamicParent, Evaluator.getGlobalLexicalScope(), parentType);
221	}
222
223	/**
224	 * Constructs a new ambienttalk object based on a set of parent pointers.
225	 * The object has no types.
226	 * @param dynamicParent - the parent object of the newly created object
227	 * @param lexicalParent - the lexical scope in which the object's definition was nested
228	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
229	 */
230	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType) {
231	   this(dynamicParent, lexicalParent, parentType, _NO_TYPETAGS_);
232	}
233	
234	/**
235	 * Constructs a new ambienttalk object based on a set of parent pointers.
236	 * The object is typed with the given types.
237	 * @param dynamicParent - the parent object of the newly created object
238	 * @param lexicalParent - the lexical scope in which the object's definition was nested
239	 * @param parentType - how this object extends its dynamic parent (is-a or shares-a)
240	 * @param tags - the type tags attached to this object
241	 */
242	public NATObject(ATObject dynamicParent, ATObject lexicalParent, boolean parentType, ATTypeTag[] tags) {
243		super(lexicalParent);
244		
245        // by default, an object has a shares-a parent, does not share its map
246		// or dictionary and is no isolate, so all flags are set to 0
247		flags_ = 0;
248		
249		typeTags_ = tags;
250		
251		methodDictionary_ = new MethodDictionary();
252		
253		// bind the dynamic parent to the field named 'super'
254		// we don't pass via meta_defineField as this would trigger mirages too early
255		variableMap_.put(_SUPER_NAME_);
256		stateVector_.add(dynamicParent);
257		
258		if (parentType) { // parentType == _IS_A_)
259			// requested an 'is-a' parent
260			setFlag(_ISAPARENT_FLAG_); // set is-a parent flag to 1
261		}
262		
263		try {
264            // if this object is tagged as at.types.Isolate, flag it as an isolate
265            // we cannot perform 'this.meta_isTypedAs(ISOLATE)' because this would trigger mirages too early
266			if (isLocallyTaggedAs(NativeTypeTags._ISOLATE_)
267			     || dynamicParent.meta_isTaggedAs(NativeTypeTags._ISOLATE_).asNativeBoolean().javaValue) {
268				setFlag(_IS_ISOLATE_FLAG_);
269				// isolates can only have the global lexical root as their lexical scope
270				lexicalParent_ = Evaluator.getGlobalLexicalScope();
271			}
272		} catch (InterpreterException e) {
273			// some custom type failed to match agains the Isolate type,
274			// the object is not considered an Isolate
275			Logging.Actor_LOG.error("Error testing for Isolate type, ignored:", e);
276		}
277	}
278	
279	/**
280	 * Constructs a new ambienttalk object as a clone of an existing object.
281	 * 
282	 * The caller of this method *must* ensure that the shares flags are set.
283	 * 
284	 * This constructor is responsible for manually re-initialising any custom field
285	 * objects, because the init method of such custom fields is parameterized by the
286	 * clone, which only comes into existence when this constructor runs.
287	 */
288	protected NATObject(FieldMap map,
289			         Vector state,
290			         LinkedList originalCustomFields,
291			         MethodDictionary methodDict,
292			         ATObject dynamicParent,
293			         ATObject lexicalParent,
294			         byte flags,
295			         ATTypeTag[] types) throws InterpreterException {
296		super(map, state, lexicalParent, null);
297		methodDictionary_ = methodDict;
298		
299		flags_ = flags; //a cloned object inherits all flags from original
300		
301		// clone inherits all types (this implies that clones of isolates are also isolates)
302		typeTags_ = types;
303		
304		// ==, new and init should already be present in the method dictionary
305		
306		// set the 'super' field to point to the new dynamic parent
307		setLocalField(_SUPER_NAME_, dynamicParent);
308		
309		// re-initialize all custom fields
310		if (originalCustomFields != null) {
311			customFields_ = new LinkedList();
312			Iterator it = originalCustomFields.iterator();
313			while (it.hasNext()) {
314				ATField field = (ATField) it.next();
315				customFields_.add(field.meta_newInstance(NATTable.of(this)).asField());
316			}
317		}
318	}
319	
320	/**
321	 * Initialize a new AmbientTalk object with the given closure.
322	 * 
323	 * The closure encapsulates:
324	 *  - the code with which to initialize the object
325	 *  - the lexical parent of the object (but that parent should already be set)
326	 *  - the lexically inherited fields for the object (the parameters of the closure)
327	 */
328	public void initializeWithCode(ATClosure code) throws InterpreterException {
329		ATMethod method = code.base_method();
330		
331		// if this object is an isolate and no lexical vars were specified to capture,
332		// calculate the set of free variables automatically
333		if (this.isFlagSet(_IS_ISOLATE_FLAG_) &&
334			method.base_parameters().base_isEmpty().asNativeBoolean().javaValue) {
335			
336			// calculate the set of free variables of the initialization expression
337			Set freeVars = method.base_bodyExpression().impl_freeVariables();
338			
339			// introduce a private scope object that will hold copies
340			// of the lexically free variables of the isolate
341			ATObject scope = new NATObject(Evaluator.getGlobalLexicalScope(), new ATTypeTag[] { NativeTypeTags._ISOLATE_ });
342			this.lexicalParent_ = scope;
343			
344			// add all these free variables manually as fields to the new isolate
345			Iterator it = freeVars.iterator();
346			while (it.hasNext()) {
347				ATSymbol freeVar = (ATSymbol) it.next();
348				// extra check to weed out special variables like "super" and variables available in the lexical root
349				if (! (Evaluator.getGlobalLexicalScope().meta_respondsTo(freeVar).asNativeBoolean().javaValue
350						|| OBJLexicalRoot._INSTANCE_.meta_respondsTo(freeVar).asNativeBoolean().javaValue)) {
351					try {
352						// lookup the variable in the lexical scope
353						ATClosure accessor = code.base_context().base_lexicalScope().impl_lookup(freeVar);
354						// only add the variable if it refers to a field, rather than to a method
355						if (accessor instanceof NativeClosure.Accessor) {
356							scope.meta_defineField(freeVar, accessor.base_apply(NATTable.EMPTY));
357						}
358					} catch(XUndefinedSlot exc) {
359						// silently ignore lexically free variables which cannot be found
360						// the assumption is that these variables will be bound by means of
361						// import statements
362						Logging.Actor_LOG.warn("Undefined lexically free var while constructing isolate: "+exc.getFieldName());
363					}
364				}
365			}
366			
367			// run the initialization code
368			code.base_applyInScope(NATTable.EMPTY, this);
369			
370		} else {
371			// for all mandatory parameters, evaluate the parameter
372			// in the current context
373			ATTable copiedBindings = Evaluator.evalMandatoryPars(
374					method.base_parameters(),
375					code.base_context());
376			// apply the initialization code to the evaluated parameter list
377			code.base_applyInScope(copiedBindings, this);	
378		}
379	}
380
381	/**
382	 * Invoke NATObject's primitive implementation, such that Java invocations of this
383	 * method have the same behaviour as AmbientTalk invocations.
384	 */
385    /*public ATObject base_init(ATObject[] initargs) throws InterpreterException {
386    	return this.meta_invoke(this, NATNil._INI_NAME_, NATTable.atValue(initargs));
387    }*/
388    
389    public ATBoolean base__opeql__opeql_(ATObject comparand) throws InterpreterException {
390    	return this.impl_invoke(this, NATNil._EQL_NAME_, NATTable.of(comparand)).asBoolean();
391    }
392
393	/* ------------------------------------------
394	 * -- Slot accessing and mutating protocol --
395	 * ------------------------------------------ */
396	
397	/**
398	 * When a new field is defined in an object, it is important to check whether or not
399	 * the field map is shared between clones or not. If it is shared, the map must be cloned first.
400	 * @throws InterpreterException 
401	 */
402	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
403		if (this.isFlagSet(_SHARE_MAP_FLAG_)) {
404			// copy the variable map
405			variableMap_ = variableMap_.copy();
406			// set the 'shares map' flag to false
407			unsetFlag(_SHARE_MAP_FLAG_);
408		}
409		return super.meta_defineField(name, value);
410	}
411	
412	/* ------------------------------------
413	 * -- Extension and cloning protocol --
414	 * ------------------------------------ */
415
416	/**
417	 * When cloning an object, it is first determined whether the parent
418	 * has to be shared by the clone, or whether the parent must also be cloned.
419	 * This depends on whether the dynamic parent is an 'is-a' parent or a 'shares-a'
420	 * parent. This is determined by the _ISAPARENT_FLAG_ object flag.
421	 * 
422	 * A cloned object shares with its original both the variable map
423	 * (to avoid having to copy space for field names) and the method dictionary
424	 * (method bindings are constant and can hence be shared).
425	 * 
426	 * Should either the original or the clone later modify the map or the dictionary
427	 * (at the meta-level), the map or dictionary will be copied first. Hence,
428	 * sharing between clones is an implementation-level optimization: clones
429	 * are completely self-sufficient and do not influence one another by meta-level operations.
430	 */
431	public ATObject meta_clone() throws InterpreterException {
432		ATObject dynamicParent;
433		if(this.isFlagSet(_ISAPARENT_FLAG_)) {
434			// IS-A Relation : clone the dynamic parent.
435			dynamicParent = base_super().meta_clone();
436		} else {
437			// SHARES_A Relation : share the dynamic parent.
438			dynamicParent = base_super();
439		}
440		
441		// ! set the shares flags of this object *and* of its clone
442		// both this object and the clone now share the map and method dictionary
443		setFlag(_SHARE_DCT_FLAG_);
444		setFlag(_SHARE_MAP_FLAG_);
445		
446		NATObject clone = this.createClone(variableMap_,
447				          (Vector) stateVector_.clone(), // shallow copy
448				          customFields_, // must be re-initialized by clone!
449				          methodDictionary_,
450				          dynamicParent,
451				          lexicalParent_,
452				          flags_, typeTags_);
453		
454		return clone;
455	}
456	
457	/**
458	 * When new is invoked on an object's mirror, the object is first cloned
459	 * by the mirror, after which the method named 'init' is invoked on it.
460	 * 
461	 * meta_newInstance(t) = base_init(t) o meta_clone
462	 * 
463	 * Care should be taken that a shares-a child implements its own init method
464	 * which does NOT perform a super-send. If this is not the case, then it is
465	 * possible that a shared parent is accidentally re-initialized because a
466	 * sharing child is cloned via new.
467	 */
468	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
469		ATObject clone = this.meta_clone();
470		clone.impl_invoke(clone, NATNil._INI_NAME_, initargs);
471		return clone;
472	}
473
474	public ATBoolean meta_isExtensionOfParent() throws InterpreterException {
475		return NATBoolean.atValue(isFlagSet(_ISAPARENT_FLAG_));
476	}
477	
478	/* ---------------------------------
479	 * -- Structural Access Protocol  --
480	 * --------------------------------- */
481
482	/**
483	 * When a method is added to an object, it is first checked whether the method does not
484	 * already exist. Also, care has to be taken that the method dictionary of an object
485	 * does not affect clones. Therefore, if the method dictionary is shared, a copy
486	 * of the dictionary is taken before adding the method.
487	 */
488	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
489		ATSymbol name = method.base_name();
490		if (this.hasLocalField(name) || this.hasLocalMethod(name)) {
491			throw new XDuplicateSlot(name);
492		} else {
493			// first check whether the method dictionary is shared
494			if (this.isFlagSet(_SHARE_DCT_FLAG_)) {
495				methodDictionary_ = (MethodDictionary) methodDictionary_.clone();
496				this.unsetFlag(_SHARE_DCT_FLAG_);
497			}
498			methodDictionary_.put(name, method);
499		}
500		return Evaluator.getNil();
501	}
502
503	public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
504		ATMethod result = (ATMethod)methodDictionary_.get(selector);
505		if(result == null) {
506			throw new XSelectorNotFound(selector, this);
507		} else {
508			return result;
509		}
510	}
511
512	public ATTable meta_listMethods() throws InterpreterException {
513		Collection methods = methodDictionary_.values();
514		return NATTable.atValue((ATObject[]) methods.toArray(new ATObject[methods.size()]));
515	}
516	
517	public ATObject meta_removeSlot(ATSymbol selector) throws InterpreterException {
518		if (this.hasLocalField(selector)) {
519			if (this.isFlagSet(_SHARE_MAP_FLAG_)) {
520				// copy the variable map
521				variableMap_ = variableMap_.copy();
522				// set the 'shares map' flag to false
523				unsetFlag(_SHARE_MAP_FLAG_);
524			}
525			return this.removeLocalField(selector);
526		} else {
527			return this.removeLocalMethod(selector);
528		}
529	}
530	
531	/**
532	 * The printed representation of an object summarizes its slots and type tags.
533	 */
534	public NATText meta_print() throws InterpreterException {
535		StringBuffer out = new StringBuffer("<obj:"+this.hashCode()+"{");
536
537		// (reflect: self).listSlots.filter: { |slot| !(slot.name == `super).or: { slot.name == `super:= }) }
538		ATObject[] slots = this.meta_listSlots().base_filter_(new NativeClosure(this) {
539			public ATObject base_apply(ATTable args) throws InterpreterException {
540				String name = args.base_at(NATNumber.ONE).asMethod().base_name().toString();
541				return NATBoolean.atValue(!(name.equals("super") || name.equals("super:=")));
542			}
543		}).asNativeTable().elements_;
544		
545		
546		if (slots.length > 0) {
547			out.append(slots[0].asMethod().base_name().toString());
548			for (int i = 1; i < slots.length; i++) {
549				out.append(",").append(slots[i].asMethod().base_name().toString());
550			}
551		}
552		
553		String slotnames = Evaluator.trunc(out.toString(),40);		
554		if (typeTags_.length > 0) {
555			out = new StringBuffer("}@[");
556			out.append(typeTags_[0].base_typeName().toString());
557			for (int i = 1; i < typeTags_.length; i++) {
558				out.append(",").append(typeTags_[i].base_typeName().toString());
559			}
560			out.append("]");
561			return NATText.atValue(slotnames+out.toString()+">");
562		} else {
563			return NATText.atValue(slotnames+"}>");
564		}
565	}
566	
567	public boolean isCallFrame() {
568		return false;
569	}
570	
571	/* ---------------------
572	 * -- Mirror Fields   --
573	 * --------------------- */
574	
575	// protected methods, may be adapted by extensions
576	
577	protected NATObject createClone(FieldMap map,
578	         					  Vector state,
579	         					  LinkedList originalCustomFields,
580	         					  MethodDictionary methodDict,
581	         					  ATObject dynamicParent,
582	         					  ATObject lexicalParent,
583	         					  byte flags,
584	         					  ATTypeTag[] types) throws InterpreterException {
585		return new NATObject(map,
586	            state,
587	            originalCustomFields,
588	            methodDict,
589	            dynamicParent,
590	            lexicalParent,
591	            flags,
592	            types);
593	}
594		
595    /* ----------------------------------
596     * -- Object Relational Comparison --
597     * ---------------------------------- */
598    
599	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
600		if(original instanceof NATObject) {
601			MethodDictionary originalMethods = ((NATObject)original).methodDictionary_;
602			FieldMap originalVariables = ((NATObject)original).variableMap_;
603			
604			return NATBoolean.atValue(
605					methodDictionary_.isDerivedFrom(originalMethods) &
606					variableMap_.isDerivedFrom(originalVariables));
607		} else {
608			return NATBoolean._FALSE_;
609		}
610	}
611
612	public ATBoolean meta_isRelatedTo(final ATObject object) throws InterpreterException {
613		return this.meta_isCloneOf(object).base_or_(
614				new NativeClosure(this) {
615					public ATObject base_apply(ATTable args) throws InterpreterException {
616						return scope_.base_super().meta_isRelatedTo(object);
617					}
618				}).asBoolean();
619	}
620	
621    /* ---------------------------------
622     * -- Type Testing and Querying --
623     * --------------------------------- */
624	
625    /**
626     * Check whether one of the type tags of this object is a subtype of the given type.
627     * If not, then delegate the query to the dynamic parent.
628     */
629    public ATBoolean meta_isTaggedAs(ATTypeTag type) throws InterpreterException {
630    	if (isLocallyTaggedAs(type)) {
631    		return NATBoolean._TRUE_;
632    	} else {
633        	// no type tags match, ask the parent
634        	return base_super().meta_isTaggedAs(type);
635    	}
636    }
637    
638    /**
639     * Return the type tags that were directly attached to this object.
640     */
641    public ATTable meta_typeTags() throws InterpreterException {
642    	// make a copy of the internal type tag array to ensure that the types
643    	// of the object are immutable. Tables allow assignment!
644    	if (typeTags_.length == 0) {
645    		return NATTable.EMPTY;
646    	} else { 
647    		ATTypeTag[] types = new ATTypeTag[typeTags_.length];
648        	System.arraycopy(typeTags_, 0, types, 0, typeTags_.length);
649        	return NATTable.atValue(types);
650    	}
651    }
652    
653	// NATObject has to duplicate the NATByCopy implementation
654	// because NATObject inherits from NATByRef, and because Java has no
655	// multiple inheritance to override that implementation with that of
656    // NATByCopy if this object signifies an isolate.
657	
658    /**
659     * An isolate object does not return a proxy representation of itself
660     * during serialization, hence it is serialized itself. If the object
661     * is not an isolate, invoke the default behaviour for by-reference objects
662     */
663    public ATObject meta_pass() throws InterpreterException {
664    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
665    		return this;
666    	} else {
667    		return super.meta_pass();
668    	}
669    }
670	
671    /**
672     * An isolate object represents itself upon deserialization.
673     * If this object is not an isolate, the default behaviour for by-reference
674     * objects is invoked.
675     */
676    public ATObject meta_resolve() throws InterpreterException {
677    	if (isFlagSet(_IS_ISOLATE_FLAG_)) {
678    		// if my lexical parent is now remote, re-bind to the new local global lexical root
679    		// (objects with an isolate as their lexical parent keep the isolate instead)
680    		if (lexicalParent_.isFarReference()) {
681        		lexicalParent_ = Evaluator.getGlobalLexicalScope();    			
682    		}
683    		return this;
684    	} else {
685    		return super.meta_resolve();
686    	}
687    }
688    
689    /**
690     * This Java serialization hook is overridden merely to provide clearer error messages
691     * in the case of a failing deserialization.
692     */
693	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
694		try {
695			in.defaultReadObject();
696		} catch(ArrayStoreException e) {
697			Logging.Actor_LOG.fatal("Failed to deserialize instance of " + this.getClass(), e);
698			throw new IOException("Object deserialized as wrong type: " + e.getMessage()
699					+ ". Did you forget to make a type tag object an isolate?");
700		}
701	}
702    
703    /* ---------------------------------------
704	 * -- Conversion and Testing Protocol   --
705	 * --------------------------------------- */
706	
707	public NATObject asAmbientTalkObject() { return this; }
708	
709	/**
710	 * ALL asXXX methods return a coercer object which returns a proxy of the correct interface that will 'down'
711	 * subsequent Java base-level invocations to the AmbientTalk level.
712	 * 
713	 * Coercion only happens if the object is tagged with the correct type.
714	 */
715	private Object coerce(ATTypeTag requiredType, Class providedInterface) throws InterpreterException {
716		if (this.meta_isTaggedAs(requiredType).asNativeBoolean().javaValue) {
717			return Coercer.coerce(this, providedInterface);
718		} else {
719			// if the object does not possess the right type tag, raise a type error
720			throw new XTypeMismatch(providedInterface, this);
721		}
722	}
723	
724	public ATBoolean asBoolean() throws InterpreterException { return (ATBoolean) coerce(NativeTypeTags._BOOLEAN_, ATBoolean.class); }
725	public ATClosure asClosure() throws InterpreterException { return (ATClosure) coerce(NativeTypeTags._CLOSURE_, ATClosure.class); }
726	public ATField asField() throws InterpreterException { return (ATField) coerce(NativeTypeTags._FIELD_, ATField.class); }
727	public ATMessage asMessage() throws InterpreterException { return (ATMessage) coerce(NativeTypeTags._MESSAGE_, ATMessage.class); }
728	public ATMethod asMethod() throws InterpreterException { return (ATMethod) coerce(NativeTypeTags._METHOD_, ATMethod.class); }
729	public ATMethodInvocation asMethodInvocation() throws InterpreterException { return (ATMethodInvocation) coerce(NativeTypeTags._METHODINV_, ATMethodInvocation.class); }
730	public ATHandler asHandler() throws InterpreterException { return (ATHandler) coerce(NativeTypeTags._HANDLER_, ATHandler.class); }
731	public ATNumber asNumber() throws InterpreterException { return (ATNumber) coerce(NativeTypeTags._NUMBER_, ATNumber.class); }
732	public ATTable asTable() throws InterpreterException { return (ATTable) coerce(NativeTypeTags._TABLE_, ATTable.class); }
733    public ATAsyncMessage asAsyncMessage() throws InterpreterException { return (ATAsyncMessage) coerce(NativeTypeTags._ASYNCMSG_, ATAsyncMessage.class);}
734    public ATActorMirror asActorMirror() throws InterpreterException { return (ATActorMirror) coerce(NativeTypeTags._ACTORMIRROR_, ATActorMirror.class); }
735    public ATTypeTag asTypeTag() throws InterpreterException { return (ATTypeTag) coerce(NativeTypeTags._TYPETAG_, ATTypeTag.class); }
736	
737	public ATBegin asBegin() throws InterpreterException { return (ATBegin) coerce(NativeTypeTags._BEGIN_, ATBegin.class); }
738	public ATAbstractGrammar asAbstractGrammar() throws InterpreterException { return (ATAbstractGrammar) coerce(NativeTypeTags._ABSTRACTGRAMMAR_, ATAbstractGrammar.class); }
739    public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { return (ATUnquoteSplice) coerce(NativeTypeTags._UQSPLICE_, ATUnquoteSplice.class); }
740    public ATSymbol asSymbol() throws InterpreterException { return (ATSymbol) coerce(NativeTypeTags._SYMBOL_, ATSymbol.class); }
741    public ATSplice asSplice() throws InterpreterException { return (ATSplice) coerce(NativeTypeTags._SPLICE_, ATSplice.class); }
742	public ATDefinition asDefinition() throws InterpreterException { return (ATDefinition) coerce(NativeTypeTags._DEFINITION_, ATDefinition.class); }
743	public ATMessageCreation asMessageCreation() throws InterpreterException { return (ATMessageCreation) coerce(NativeTypeTags._MSGCREATION_, ATMessageCreation.class); }
744	public ATFarReference asFarReference() throws InterpreterException { return (ATFarReference) coerce(NativeTypeTags._FARREF_, ATFarReference.class); }
745	public ATLetter asLetter() throws InterpreterException { return (ATLetter) coerce(NativeTypeTags._LETTER_, ATLetter.class); }
746	
747	// ALL isXXX methods return true (can be overridden by programmer-defined base-level methods)
748	
749	public boolean isAmbientTalkObject() { return true; }
750	
751	// objects can only be 'cast' to a native category if they are marked with
752	// the appropriate native type
753	public boolean isSplice() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._SPLICE_).asNativeBoolean().javaValue; }
754	public boolean isSymbol() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._SYMBOL_).asNativeBoolean().javaValue; }
755	public boolean isTable() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._TABLE_).asNativeBoolean().javaValue; }
756	public boolean isUnquoteSplice() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._UQSPLICE_).asNativeBoolean().javaValue; }
757	public boolean isTypeTag() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._TYPETAG_).asNativeBoolean().javaValue; }
758	public boolean isFarReference() throws InterpreterException { return meta_isTaggedAs(NativeTypeTags._FARREF_).asNativeBoolean().javaValue; }
759	
760	// private methods
761	
762	private boolean isFlagSet(byte flag) {
763		return (flags_ & flag) != 0;
764	}
765
766	private void setFlag(byte flag) {
767		flags_ = (byte) (flags_ | flag);
768	}
769
770	private void unsetFlag(byte flag) {
771		flags_ = (byte) (flags_ & (~flag));
772	}
773	
774	protected boolean hasLocalMethod(ATSymbol selector) throws InterpreterException {
775		return methodDictionary_.containsKey(selector);
776	}
777	
778	protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
779		ATObject result = (ATObject) methodDictionary_.get(selector);
780		if(result == null) {
781			throw new XSelectorNotFound(selector, this);
782		} else {
783			return result.asMethod();
784		}
785	}
786	
787	protected ATMethod removeLocalMethod(ATSymbol selector) throws InterpreterException {
788		ATObject result = (ATObject) methodDictionary_.get(selector);
789		if (result == null) {
790			throw new XSelectorNotFound(selector, this);
791		} else {
792			// if the method dictionary is shared between clones...
793			if (this.isFlagSet(_SHARE_DCT_FLAG_)) {
794				// create a private shallow copy and flag that we're no longer sharing
795				methodDictionary_ = (MethodDictionary) methodDictionary_.clone();
796				this.unsetFlag(_SHARE_DCT_FLAG_);
797			}
798			methodDictionary_.remove(selector);
799			return result.asMethod();
800		}
801	}
802	
803	/**
804	 * Performs a type test for this object locally.
805	 * @return whether this object is tagged with a particular type tag or not.
806	 */
807	private boolean isLocallyTaggedAs(ATTypeTag tag) throws InterpreterException {
808    	for (int i = 0; i < typeTags_.length; i++) {
809			if (typeTags_[i].base_isSubtypeOf(tag).asNativeBoolean().javaValue) {
810				// if one type matches, return true
811				return true;
812			}
813		}
814		return false;
815	}
816	
817	/**
818	 * Auxiliary method to access the fields of an object and all of its super-objects up to (but excluding) nil.
819	 * Overridden fields of parent objects are not included.
820	 */
821	public static ATField[] listTransitiveFields(ATObject obj) throws InterpreterException {
822		Vector fields = new Vector();
823		HashSet encounteredNames = new HashSet(); // to filter duplicates
824		for (; obj != Evaluator.getNil() ; obj = obj.base_super()) {
825			ATObject[] localFields = obj.meta_listFields().asNativeTable().elements_;
826			for (int i = 0; i < localFields.length; i++) {
827				ATField field = localFields[i].asField();
828				ATSymbol fieldName = field.base_name();
829				if (!encounteredNames.contains(fieldName)) {
830					fields.add(field);
831					encounteredNames.add(fieldName);
832				}
833			}
834		}
835		return (ATField[]) fields.toArray(new ATField[fields.size()]);
836	}
837	
838	/**
839	 * Auxiliary method to access the methods of an object and all of its super-objects up to (but excluding) nil.
840	 * Overridden methods of parent objects are not included.
841	 */
842	public static ATMethod[] listTransitiveMethods(ATObject obj) throws InterpreterException {
843		Vector methods = new Vector();
844		HashSet encounteredNames = new HashSet(); // to filter duplicates		
845		for (; obj != Evaluator.getNil() ; obj = obj.base_super()) {
846			// fast-path for native objects
847			if (obj instanceof NATObject) {
848				Collection localMethods = ((NATObject) obj).methodDictionary_.values();
849				for (Iterator iter = localMethods.iterator(); iter.hasNext();) {
850					ATMethod localMethod = (ATMethod) iter.next();
851					ATSymbol methodName = localMethod.base_name();
852					if (!encounteredNames.contains(methodName)) {
853						methods.add(localMethod);
854						encounteredNames.add(methodName);
855					}
856				}
857			} else {
858				ATObject[] localMethods = obj.meta_listMethods().asNativeTable().elements_;
859				for (int i = 0; i < localMethods.length; i++) {
860					ATMethod localMethod = localMethods[i].asMethod();
861					ATSymbol methodName = localMethod.base_name();
862					if (!encounteredNames.contains(methodName)) {
863						methods.add(localMethod);
864						encounteredNames.add(methodName);
865					}
866				}
867			}
868		}
869		return (ATMethod[]) methods.toArray(new ATMethod[methods.size()]);
870	}
871
872	public void setLexicalParent(ATObject newLexParent) {
873		lexicalParent_ = newLexParent;
874	}
875	
876}