PageRenderTime 112ms CodeModel.GetById 24ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 1ms

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

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