PageRenderTime 82ms CodeModel.GetById 8ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist170907/src/edu/vub/at/objects/natives/NativeATObject.java

http://ambienttalk.googlecode.com/
Java | 911 lines | 505 code | 114 blank | 292 comment | 63 complexity | 97d9cac820dbcef3d45575e1e48e9361 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATNil.java created on Jul 13, 2006 at 9:38:51 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.natives.NATFarReference;
 34import edu.vub.at.actors.net.SerializationException;
 35import edu.vub.at.eval.Evaluator;
 36import edu.vub.at.exceptions.InterpreterException;
 37import edu.vub.at.exceptions.XIllegalOperation;
 38import edu.vub.at.exceptions.XSelectorNotFound;
 39import edu.vub.at.exceptions.XTypeMismatch;
 40import edu.vub.at.objects.ATBoolean;
 41import edu.vub.at.objects.ATClosure;
 42import edu.vub.at.objects.ATContext;
 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.ATNil;
 48import edu.vub.at.objects.ATNumber;
 49import edu.vub.at.objects.ATObject;
 50import edu.vub.at.objects.ATTable;
 51import edu.vub.at.objects.ATTypeTag;
 52import edu.vub.at.objects.coercion.NativeTypeTags;
 53import edu.vub.at.objects.grammar.ATAssignVariable;
 54import edu.vub.at.objects.grammar.ATAssignmentSymbol;
 55import edu.vub.at.objects.grammar.ATBegin;
 56import edu.vub.at.objects.grammar.ATDefinition;
 57import edu.vub.at.objects.grammar.ATExpression;
 58import edu.vub.at.objects.grammar.ATMessageCreation;
 59import edu.vub.at.objects.grammar.ATSplice;
 60import edu.vub.at.objects.grammar.ATStatement;
 61import edu.vub.at.objects.grammar.ATSymbol;
 62import edu.vub.at.objects.grammar.ATUnquoteSplice;
 63import edu.vub.at.objects.mirrors.NATMirage;
 64import edu.vub.at.objects.mirrors.NativeClosure;
 65import edu.vub.at.objects.mirrors.Reflection;
 66import edu.vub.at.objects.symbiosis.JavaClass;
 67import edu.vub.at.objects.symbiosis.JavaObject;
 68import edu.vub.at.util.logging.Logging;
 69
 70import java.io.InvalidObjectException;
 71import java.io.ObjectStreamException;
 72import java.io.Serializable;
 73
 74/**
 75 * This class implements default semantics for all test and conversion methods.
 76 * It also implements the default metaobject protocol semantics for native
 77 * AmbientTalk objects.
 78 * <p>
 79 * More specifically, this class encapsulates the behavior for:
 80 * <ul>
 81 *  <li>The behavior of all native objects.
 82 *  <li>The default behavior of all non-native objects.
 83 * </ul>
 84 * Native AmbientTalk objects contain no fields, only methods. Fields are represented
 85 * using accessor methods. Mutable fields also have a mutator method.
 86 * <p>
 87 * To allow for AmbientTalk language values to be unquoted into parsetrees,
 88 * a native object is considered to be a valid ambienttalk expression. 
 89 *
 90 * @author tvcutsem, smostinc
 91 */
 92public abstract class NativeATObject implements ATObject, ATExpression, Serializable {
 93	
 94    protected NativeATObject() {};
 95
 96    /**
 97     * Asynchronous messages ( o<-m( args )) sent in the context of an object o (i.e. 
 98     * sent in a method or closure where the self pseudovariable is bound to o)  are 
 99     * delegated to the base-level send method of the actor in which the object o is 
100     * contained.
101     */
102    public ATObject meta_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
103    	return OBJLexicalRoot._INSTANCE_.base_actor().base_send(receiver, message);
104    }
105
106    /**
107     * By default, when an object receives an incoming asynchronous message, it tells
108     * the message to process itself. The message's default behaviour is to subsequently
109     * invoke the method corresponding to the message's selector on this object.
110     */
111    public ATObject meta_receive(ATAsyncMessage message) throws InterpreterException {
112    	return message.base_process(this);
113    }
114    
115	/**
116	 * An ambienttalk object can respond to a message if a corresponding field or method exists
117	 * either in the receiver object locally, or in one of its dynamic parents.
118	 * Fields also implicitly define a mutator whose name has the form <tt>field:=</tt>.
119	 */
120	public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException {
121		if (this.hasLocalField(selector) || this.hasLocalMethod(selector)) {
122			return NATBoolean._TRUE_;
123		} else {
124			if (selector.isAssignmentSymbol()) {
125				if (this.hasLocalField(selector.asAssignmentSymbol().getFieldName())) {
126					return NATBoolean._TRUE_;
127				}
128			}
129		}
130		return base_super().meta_respondsTo(selector);
131	}
132
133    /**
134     * By default, when a selection is not understood by a primitive object, an error is raised.
135     */
136    public ATClosure meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException {
137        throw new XSelectorNotFound(selector, this);
138    }
139    
140    /* ------------------------------------------
141      * -- Slot accessing and mutating protocol --
142      * ------------------------------------------ */
143
144	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
145        throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass()));
146    }
147
148    /* ------------------------------------
149      * -- Extension and cloning protocol --
150      * ------------------------------------ */
151
152    public ATObject meta_clone() throws InterpreterException {
153        throw new XIllegalOperation("Cannot clone a native object of type " + this.getClass().getName());
154    }
155
156    public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
157        return Reflection.upInstanceCreation(this, initargs);
158    }
159    
160    /* ---------------------------------
161      * -- Structural Access Protocol  --
162      * --------------------------------- */
163
164    public ATNil meta_addField(ATField field) throws InterpreterException {
165        throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass()));
166    }
167
168    public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
169        throw new XIllegalOperation("Cannot add methods to " + Evaluator.valueNameOf(this.getClass()));
170    }
171
172    public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException {
173    	throw new XSelectorNotFound(fieldName, this);
174    }
175
176    public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException {
177        return Reflection.downBaseLevelMethod(this, methodName);
178    }
179
180    public ATTable meta_listFields() throws InterpreterException {
181    	return NATTable.EMPTY;
182    }
183
184    public ATTable meta_listMethods() throws InterpreterException {
185    	return NATTable.atValue(Reflection.downBaseLevelMethods(this));
186    }
187
188    /* ---------------------------------
189      * -- Abstract Grammar Protocol   --
190      * --------------------------------- */
191
192    /**
193     * All NATObjects which are not Abstract Grammar elements are self-evaluating.
194     */
195    public ATObject meta_eval(ATContext ctx) throws InterpreterException {
196        return this;
197    }
198
199    /**
200     * Quoting a native object returns itself, except for pure AG elements.
201     */
202    public ATObject meta_quote(ATContext ctx) throws InterpreterException {
203        return this;
204    }
205
206    public abstract NATText meta_print() throws InterpreterException;
207
208    /* ------------------------------
209      * -- ATObject Mirror Fields   --
210      * ------------------------------ */
211
212    /**
213     * Native objects have a SHARES-A parent link to 'nil', by default.
214     */
215    public ATBoolean meta_isExtensionOfParent() throws InterpreterException {
216        return NATBoolean.atValue((NATObject._SHARES_A_));
217    };
218
219    /**
220     * By default numbers, tables and so on have root as their lexical parent.
221     */
222    public ATObject impl_lexicalParent() throws InterpreterException {
223        return Evaluator.getGlobalLexicalScope();
224    }
225    
226	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
227		return NATBoolean.atValue(
228				this.getClass() == original.getClass());
229	}
230
231	public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException {
232		return this.meta_isCloneOf(object);
233	}
234	
235    /* ---------------------------------
236     * -- Type Testing and Querying --
237     * --------------------------------- */
238	
239    /**
240     * Native objects implement the type test non-recursively: only the type tags
241     * returned by {@link this#meta_getTypeTags()} are tested against.
242     */
243    public ATBoolean meta_isTaggedAs(ATTypeTag type) throws InterpreterException {
244    	ATObject[] types = this.meta_typeTags().asNativeTable().elements_;
245    	for (int i = 0; i < types.length; i++) {
246			if (types[i].asTypeTag().base_isSubtypeOf(type).asNativeBoolean().javaValue) {
247				return NATBoolean._TRUE_;
248			}
249		}
250    	return NATBoolean._FALSE_;
251    }
252    
253    /**
254     * By default, a native object (and also nil) has no type tags.
255     */
256    public ATTable meta_typeTags() throws InterpreterException {
257    	return NATTable.EMPTY;
258    }
259	
260    /* -----------------------------
261     * -- Object Passing protocol --
262     * ----------------------------- */
263
264    /**
265     * This method allows objects to decide which object should be serialized in their
266     * stead when they are passed as argument in an asynchronous message send that
267     * crosses actor boundaries.
268     */
269    public abstract ATObject meta_pass() throws InterpreterException;
270	
271	/**
272	 * Delegate the responsibility of serialization to the AT/2 meta-level 
273	 */
274	public Object writeReplace() throws ObjectStreamException {
275		try {
276			return this.meta_pass();
277		} catch(InterpreterException e) {
278			throw new InvalidObjectException("Failed to pass object " + this + ": " + e.getMessage());
279		}
280	}
281	
282    public abstract ATObject meta_resolve() throws InterpreterException;
283	
284	/**
285	 * Delegate the responsibility of deserialization to the AT/2 meta-level 
286	 */
287	public Object readResolve() throws ObjectStreamException {
288		try {
289			return this.meta_resolve();
290		} catch(InterpreterException e) {
291			throw new SerializationException(e);
292		}
293	}
294
295    /* ---------------------------------
296      * -- Value Conversion Protocol   --
297      * --------------------------------- */
298
299    public boolean isSymbol() throws InterpreterException {
300        return false;
301    }
302
303    public boolean isTable() throws InterpreterException {
304        return false;
305    }
306
307    public boolean isCallFrame() throws InterpreterException {
308        return false;
309    }
310
311    public boolean isUnquoteSplice() throws InterpreterException {
312        return false;
313    }
314
315    public boolean isVariableAssignment() throws InterpreterException {
316        return false;
317    }
318    
319    public boolean isSplice() throws InterpreterException {
320        return false;
321    }
322    
323    public boolean isMessageCreation() throws InterpreterException {
324    	return false;
325    }
326
327    public boolean isAmbientTalkObject() { 
328    	return false;
329    }
330    
331    public boolean isJavaObjectUnderSymbiosis() {
332    	return false;
333    }
334
335    public boolean isNativeBoolean() {
336        return false;
337    }
338    
339    public boolean isNativeText() {
340        return false;
341    }
342
343    public boolean isNativeField() {
344        return false;
345    }
346    
347    public boolean isTypeTag() throws InterpreterException {
348        return false;
349    }
350    
351    public ATClosure asClosure() throws InterpreterException {
352        throw new XTypeMismatch(ATClosure.class, this);
353    }
354
355    public ATSymbol asSymbol() throws InterpreterException {
356        throw new XTypeMismatch(ATSymbol.class, this);
357    }
358
359    public ATTable asTable() throws InterpreterException {
360        throw new XTypeMismatch(ATTable.class, this);
361    }
362
363    public ATBoolean asBoolean() throws InterpreterException {
364        throw new XTypeMismatch(ATBoolean.class, this);
365    }
366
367    public ATNumber asNumber() throws InterpreterException {
368        throw new XTypeMismatch(ATNumber.class, this);
369    }
370
371    public ATMessage asMessage() throws InterpreterException {
372        throw new XTypeMismatch(ATMessage.class, this);
373    }
374
375    public ATField asField() throws InterpreterException {
376        throw new XTypeMismatch(ATField.class, this);
377    }
378
379    public ATMethod asMethod() throws InterpreterException {
380        throw new XTypeMismatch(ATMethod.class, this);
381    }
382
383    public ATHandler asHandler() throws InterpreterException {
384    	throw new XTypeMismatch(ATHandler.class, this);
385    }
386
387    public ATTypeTag asTypeTag() throws InterpreterException {
388	    throw new XTypeMismatch(ATTypeTag.class, this);
389    }
390    
391    // Conversions for concurrency and distribution related object
392    public boolean isFarReference() {
393    	return false;
394    }
395    
396    public ATFarReference asFarReference() throws InterpreterException {
397  	    throw new XTypeMismatch(ATFarReference.class, this);
398  	}
399    
400    public ATAsyncMessage asAsyncMessage() throws InterpreterException {
401  	    throw new XTypeMismatch(ATAsyncMessage.class, this);
402  	}
403    
404    public ATActorMirror asActorMirror() throws InterpreterException {
405    	throw new XTypeMismatch(ATActorMirror.class, this);
406    }
407    
408    // Conversions for abstract grammar elements
409
410    public ATStatement asStatement() throws InterpreterException {
411        throw new XTypeMismatch(ATStatement.class, this);
412    }
413
414    public ATDefinition asDefinition() throws InterpreterException {
415        throw new XTypeMismatch(ATDefinition.class, this);
416    }
417
418    public ATExpression asExpression() throws InterpreterException {
419        return this;
420    }
421
422    public ATBegin asBegin() throws InterpreterException {
423        throw new XTypeMismatch(ATBegin.class, this);
424    }
425
426    public ATMessageCreation asMessageCreation() throws InterpreterException {
427        throw new XTypeMismatch(ATMessageCreation.class, this);
428    }
429
430    public ATUnquoteSplice asUnquoteSplice() throws InterpreterException {
431        throw new XTypeMismatch(ATUnquoteSplice.class, this);
432    }
433
434    public ATAssignVariable asVariableAssignment() throws InterpreterException {
435        throw new XTypeMismatch(ATAssignVariable.class, this);
436    }
437    
438    public ATSplice asSplice() throws InterpreterException {
439        throw new XTypeMismatch(ATSplice.class, this);
440    }
441    
442    // Conversions for native values
443    public NATObject asAmbientTalkObject() throws XTypeMismatch {
444    	throw new XTypeMismatch(NATObject.class, this);
445    }
446
447    public NATMirage asMirage() throws XTypeMismatch {
448    	throw new XTypeMismatch(NATMirage.class, this);
449    }
450
451    public NATNumber asNativeNumber() throws XTypeMismatch {
452        throw new XTypeMismatch(NATNumber.class, this);
453    }
454
455    public NATFraction asNativeFraction() throws XTypeMismatch {
456        throw new XTypeMismatch(NATFraction.class, this);
457    }
458
459    public NATText asNativeText() throws XTypeMismatch {
460    	throw new XTypeMismatch(NATText.class, this);
461    }
462
463    public NATTable asNativeTable() throws XTypeMismatch {
464        throw new XTypeMismatch(NATTable.class, this);
465    }
466
467    public NATBoolean asNativeBoolean() throws XTypeMismatch {
468        throw new XTypeMismatch(NATBoolean.class, this);
469    }
470    
471    public NATNumeric asNativeNumeric() throws XTypeMismatch {
472        throw new XTypeMismatch(NATNumeric.class, this);
473    }
474    
475    public NATFarReference asNativeFarReference() throws XTypeMismatch {
476    	throw new XTypeMismatch(NATFarReference.class, this);
477    }
478
479    public JavaObject asJavaObjectUnderSymbiosis() throws XTypeMismatch {
480    	throw new XTypeMismatch(JavaObject.class, this);
481    }
482    
483    public JavaClass asJavaClassUnderSymbiosis() throws XTypeMismatch {
484	    throw new XTypeMismatch(JavaClass.class, this);
485    }
486    
487    /**
488     * Only true objects have a dynamic pointer, native objects denote 'nil' to
489     * be their dynamic parent when asked for it. Note that, for native objects,
490     * 'super' is a read-only field (i.e. only an accessor for the virtual field exists).
491     */
492    public ATObject base_super() throws InterpreterException {
493        return OBJNil._INSTANCE_;
494    };
495
496    public String toString() {
497        return Evaluator.toString(this);
498    }
499    
500    /**
501     * Java method invocations of equals are transformed into
502     * AmbientTalk '==' method invocations.
503     */
504    public boolean equals(Object other) {
505    	try {
506    		if (other instanceof ATObject) {
507    			return this.base__opeql__opeql_((ATObject) other).asNativeBoolean().javaValue;
508    		}
509    	} catch (InterpreterException e) {
510    		Logging.Actor_LOG.warn("Error during equality testing:", e);
511    	}
512    	return false; 
513    }
514    
515    public ATBoolean impl_identityEquals(ATObject other) throws InterpreterException {
516    	return NATBoolean.atValue(other == this);
517    }
518    
519	/**
520	 * By default, two AmbientTalk objects are equal if they are the
521	 * same object, or one is a proxy for the same object.
522	 */
523    public ATBoolean base__opeql__opeql_(ATObject other) throws InterpreterException {
524		// by default, ATObjects use pointer equality
525		return NATBoolean.atValue(this == other);
526    }
527    
528    public ATObject base_new(ATObject[] initargs) throws InterpreterException {
529    	return this.meta_newInstance(NATTable.atValue(initargs));
530    }
531    
532    public ATObject base_init(ATObject[] initargs) throws InterpreterException {
533    	return OBJNil._INSTANCE_;
534    }
535    
536	/**
537	 * This method is used to evaluate code of the form <tt>selector(args)</tt>
538	 * or <tt>selector := arg</tt> within the scope of this object.
539	 * 
540	 * It dispatches to other implementation-level methods based on the selector.
541	 */
542	public ATObject impl_call(ATSymbol selector, ATTable arguments) throws InterpreterException {
543		if (selector.isAssignmentSymbol()) {
544			return this.impl_callMutator(selector.asAssignmentSymbol(), arguments);
545		} else {
546			return this.impl_callAccessor(selector, arguments);
547		}
548	}
549
550    /**
551	 * Implements the interpretation of <tt>f(arg)</tt> inside the scope of a
552	 * particular object.
553	 * 
554	 * - if f is bound to a local method, the method is applied
555	 * - if f is bound to a field:
556	 *   - if the field contains a closure, the closure is applied
557	 *   - otherwise, the field is treated as a nullary closure and 'applied'
558	 * - otherwise, the search for the selector continues in the lexical parent
559	 */
560	public ATObject impl_callAccessor(ATSymbol selector, ATTable arguments) throws InterpreterException {
561		if(this.hasLocalMethod(selector)) {
562			// apply the method with a context ctx where 
563			//  ctx.scope = the implementing scope, being this object
564			//  ctx.self  = the receiver, being in this case again the implementor
565			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, this));
566		} else {
567			if (this.hasLocalField(selector)) {
568				ATObject fieldValue = this.getLocalField(selector);
569				
570				if (fieldValue.meta_isTaggedAs(NativeTypeTags._CLOSURE_).asNativeBoolean().javaValue) {
571					return fieldValue.asClosure().base_apply(arguments);
572				} else {
573					NativeClosure.checkNullaryArguments(selector, arguments);
574					return fieldValue;
575				}
576			} else {
577				return this.impl_lexicalParent().impl_callAccessor(selector, arguments);
578			}
579		}
580	}
581
582    /**
583	 * Implements the interpretation of <tt>x := arg</tt> inside the scope of a
584	 * particular object.
585	 * 
586	 * - if x:= is bound to a local method, the method is applied
587	 * - if x is bound to a field, the field is assigned if exactly one argument is given
588	 * - otherwise, the search for the selector continues in the lexical parent
589	 */
590	public ATObject impl_callMutator(ATAssignmentSymbol selector, ATTable arguments) throws InterpreterException {
591		if(this.hasLocalMethod(selector)) {
592			// apply the method with a context ctx where 
593			//  ctx.scope = the implementing scope, being this object
594			//  ctx.self  = the receiver, being in this case again the implementor
595			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, this));
596		} else {
597			ATSymbol fieldSelector = selector.getFieldName();
598			if (this.hasLocalField(fieldSelector)) {
599				ATObject value = NativeClosure.checkUnaryArguments(selector, arguments);
600				this.setLocalField(fieldSelector, value);
601				return value;
602			} else {
603				return this.impl_lexicalParent().impl_callMutator(selector, arguments);
604			}
605		}
606	}	
607	
608    /**
609	 * Implements the interpretation of <tt>x</tt> inside the scope of a
610	 * particular object.
611	 * 
612	 * - if x is bound to a local method, the method is applied to <tt>[]</tt>
613	 * - if x is bound to a field, the field's value is returned (even if it
614	 *   contains a closure)
615	 * - otherwise, the search for the selector continues in the lexical parent
616	 */
617	public ATObject impl_callField(ATSymbol selector) throws InterpreterException {
618		// if selector is bound to a method, treat 'm' as 'm()'
619		if(this.hasLocalMethod(selector)) {
620			// apply the method with a context ctx where 
621			//  ctx.scope = the implementing scope, being this object
622			//  ctx.self  = the receiver, being in this case again the implementor
623			return this.getLocalMethod(selector).base_apply(NATTable.EMPTY, new NATContext(this, this));
624		} else {
625			if (this.hasLocalField(selector)) {
626				// simply return the field's value, regardless of whether it is bound to a
627				// closure or not
628				return this.getLocalField(selector);
629			} else {
630				return this.impl_lexicalParent().impl_callField(selector);
631			}
632		}
633	}
634	
635	/**
636	 * This method dispatches to specific invocation primitives
637	 * depending on whether or not the given selector denotes an assignment.
638	 */
639    public ATObject meta_invoke(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
640        // If the selector is an assignment symbol (i.e. `field:=) try to assign the corresponding field
641		if (selector.isAssignmentSymbol()) {
642			return this.impl_invokeMutator(receiver, selector.asAssignmentSymbol(), arguments);
643		} else {
644			return this.impl_invokeAccessor(receiver, selector, arguments);
645		}
646    }
647    
648    /**
649	 * Implements the interpretation of <tt>o.m(arg)</tt>.
650	 * 
651	 * - if m is bound to a local method of o, the method is applied
652	 * - if m is bound to a field of o:
653	 *   - if the field contains a closure, the closure is applied
654	 *   - otherwise, the field is treated as a nullary closure and 'applied'
655	 * - otherwise, the search for the selector continues in the dynamic parent
656	 */
657	public ATObject impl_invokeAccessor(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
658		if (this.hasLocalMethod(selector)) {
659			// immediately execute the method in the context ctx where
660			//  ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted
661			//  ctx.self  = the late bound receiver, being the passed receiver
662			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver));
663		} else {
664			if (this.hasLocalField(selector)) {
665				ATObject fieldValue = this.getLocalField(selector);
666				
667				if (fieldValue.meta_isTaggedAs(NativeTypeTags._CLOSURE_).asNativeBoolean().javaValue) {
668					return fieldValue.asClosure().base_apply(arguments);
669				} else {
670					NativeClosure.checkNullaryArguments(selector, arguments);
671					return fieldValue;
672				}
673			} else {
674				return base_super().impl_invokeAccessor(receiver, selector, arguments);
675			}
676		}
677	}
678	
679    /**
680	 * Implements the interpretation of <tt>o.x := arg</tt>.
681	 * 
682	 * - if x:= is bound to a local method of o, the method is applied to the arguments.
683	 * - if x is bound to a field of o, the field is treated as a unary mutator method
684	 *   that assigns the field and 'applied' to the given arguments.
685	 * - otherwise, the search for the selector continues in the dynamic parent
686	 */
687	public ATObject impl_invokeMutator(ATObject receiver, ATAssignmentSymbol selector, ATTable arguments) throws InterpreterException {
688		if (this.hasLocalMethod(selector)) {
689			// immediately execute the method in the context ctx where
690			//  ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted
691			//  ctx.self  = the late bound receiver, being the passed receiver
692			return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver));
693		} else {
694			// try to treat a local field as a mutator
695			ATSymbol fieldSelector = selector.getFieldName();
696			if (this.hasLocalField(fieldSelector)) {
697				ATObject value = NativeClosure.checkUnaryArguments(selector, arguments);
698				this.setLocalField(fieldSelector, value);
699				return value;
700			} else {
701				// if no field matching the selector exists, delegate to the parent
702				return base_super().impl_invokeMutator(receiver, selector, arguments);
703			}
704		}
705	}
706
707    /**
708	 * Implements the interpretation of <tt>o.x</tt>.
709	 * 
710	 * - if x is bound to a local method of o, the method is applied to <tt>[]</tt>
711	 * - if x is bound to a field of o, the field's value is returned (even if it
712	 *   contains a closure).
713	 * - otherwise, the search for the selector continues in the dynamic parent
714	 */
715	public ATObject meta_invokeField(ATObject receiver, ATSymbol selector) throws InterpreterException {
716		// if selector is bound to a method, treat 'o.m' as 'o.m()'
717		if (this.hasLocalMethod(selector)) {
718			// immediately execute the method in the context ctx where
719			//  ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted
720			//  ctx.self  = the late bound receiver, being the passed receiver
721			return this.getLocalMethod(selector).base_apply(NATTable.EMPTY, new NATContext(this, receiver));
722		} else {
723			if (this.hasLocalField(selector)) {
724				// return the field's value, regardless of whether it is a closure or not
725				return this.getLocalField(selector);
726			} else {
727				return base_super().meta_invokeField(receiver, selector);
728			}
729		}
730	}
731	
732    /**
733	 * This operation dispatches to more specific implementation-level methods depending
734	 * on the type of the selector.
735	 */
736	public ATClosure impl_lookup(ATSymbol selector) throws InterpreterException {
737		if (selector.isAssignmentSymbol()) {
738			return this.impl_lookupMutator(selector.asAssignmentSymbol());
739		} else {
740			return this.impl_lookupAccessor(selector);
741		}
742	}
743	
744    /**
745	 * Implements the interpretation of <tt>&f</tt> in the scope of this object.
746	 * 
747	 * - if f is bound to a local method, a closure wrapping the method is returned
748	 * - if f is bound to a field of o, an accessor closure is returned which yields
749	 * the field's value upon application.
750	 * - otherwise, the search for the selector continues in the lexical parent
751	 */
752	public ATClosure impl_lookupAccessor(final ATSymbol selector) throws InterpreterException {
753		if (this.hasLocalMethod(selector)) {
754			// return a new closure (mth, ctx) where
755			//  mth = the method found in this object
756			//  ctx.scope = the implementing scope, being this object
757			//  ctx.self  = the late bound receiver, being the passed receiver
758			//  ctx.super = the parent of the implementor
759			return this.getLocalMethod(selector).base_wrap(this, this);
760		} else {
761			// try to wrap a local field in an accessor
762			if(this.hasLocalField(selector)) {
763				final NativeATObject scope = this;
764				return new NativeClosure.Accessor(selector, this) {
765					public ATObject access() throws InterpreterException {
766						return scope.getLocalField(selector);
767					}
768				};
769			} else {
770				return this.impl_lexicalParent().impl_lookupAccessor(selector);
771			}
772		}
773	}
774
775    /**
776	 * Implements the interpretation of <tt>&f:=</tt> in the scope of this object.
777	 * 
778	 * - if f:= is bound to a local method, a closure wrapping the method is returned
779	 * - if f is bound to a field of o, a mutator closure is returned which assigns
780	 * the field upon application.
781	 * - otherwise, the search for the selector continues in the lexical parent
782	 */
783	public ATClosure impl_lookupMutator(ATAssignmentSymbol selector) throws InterpreterException {
784		if (this.hasLocalMethod(selector)) {
785			// return a new closure (mth, ctx) where
786			//  mth = the method found in this object
787			//  ctx.scope = the implementing scope, being this object
788			//  ctx.self  = the late bound receiver, being the passed receiver
789			//  ctx.super = the parent of the implementor
790			return this.getLocalMethod(selector).base_wrap(this, this);
791		} else {
792			final ATSymbol fieldSelector = selector.getFieldName();
793			// try to wrap a local field in a mutator
794			if(this.hasLocalField(fieldSelector)) {
795				final NativeATObject scope = this;
796				return new NativeClosure.Mutator(selector, this) {
797					public ATObject mutate(ATObject arg) throws InterpreterException {
798						scope.setLocalField(fieldSelector, arg);
799						return arg;
800					}
801				};
802			} else {
803				return this.impl_lexicalParent().impl_lookupMutator(selector);
804			}
805		}
806	}
807
808	/**
809	 * select should dispatch to specific selection primitives
810	 * depending on whether or not the given selector denotes an assignment.
811	 */
812    public ATClosure meta_select(ATObject receiver, final ATSymbol selector) throws InterpreterException {
813		if (selector.isAssignmentSymbol()) {
814			return this.impl_selectMutator(receiver, selector.asAssignmentSymbol());
815		} else {
816			return this.impl_selectAccessor(receiver, selector);
817		}
818    }
819    
820    /**
821	 * Implements the interpretation of <tt>o.&m</tt>.
822	 * 
823	 * - if m is bound to a local method, a closure wrapping the method is returned
824	 * - if m is bound to a field of o, an accessor closure is returned which yields
825	 * the field's value upon application.
826	 * - otherwise, the search for the selector continues in the dynamic parent
827	 */
828    public ATClosure impl_selectAccessor(ATObject receiver, final ATSymbol selector) throws InterpreterException {
829    	if (this.hasLocalMethod(selector)) {
830    		// return a new closure (mth, ctx) where
831    		//  mth = the method found in this object
832    		//  ctx.scope = the implementing scope, being this object
833    		//  ctx.self  = the late bound receiver, being the passed receiver
834    		//  ctx.super = the parent of the implementor
835    		return this.getLocalMethod(selector).base_wrap(this, receiver);
836    	} else {
837    		if (this.hasLocalField(selector)) {
838    			final NativeATObject scope = this;
839    			return new NativeClosure.Accessor(selector, this) {
840    				public ATObject access() throws InterpreterException {
841    					return scope.getLocalField(selector);
842    				}
843    			};
844    		} else {
845    			return base_super().impl_selectAccessor(receiver, selector);
846    		}
847    	}
848    }
849
850    /**
851	 * Implements the interpretation of <tt>o.&m:=</tt>.
852	 * 
853	 * - if m:= is bound to a local method, a closure wrapping the method is returned
854	 * - if m is bound to a field of o, a mutator closure is returned which assigns
855	 * the field upon application.
856	 * - otherwise, the search for the selector continues in the dynamic parent
857	 */
858    public ATClosure impl_selectMutator(ATObject receiver, final ATAssignmentSymbol selector) throws InterpreterException {
859    	if (this.hasLocalMethod(selector)) {
860    		// return a new closure (mth, ctx) where
861    		//  mth = the method found in this object
862    		//  ctx.scope = the implementing scope, being this object
863    		//  ctx.self  = the late bound receiver, being the passed receiver
864    		//  ctx.super = the parent of the implementor
865    		return this.getLocalMethod(selector).base_wrap(this, receiver);
866    	} else {
867    		// try to wrap a local field in a mutator
868    		final ATSymbol fieldSelector = selector.getFieldName();
869    		if (this.hasLocalField(fieldSelector)) {
870    			final NativeATObject scope = this;
871    			return new NativeClosure.Mutator(selector, this) {
872    				public ATObject mutate(ATObject arg) throws InterpreterException {
873    					scope.setLocalField(fieldSelector, arg);
874    					return arg;
875    				}
876    			};
877    		} else {
878    			// if no field matching the selector exists, delegate to the parent
879    			return base_super().impl_selectMutator(receiver, selector);
880    		}
881    	}
882    }
883	
884	/** native objects have no fields */
885	protected boolean hasLocalField(ATSymbol sym) throws InterpreterException {
886		return false;
887	}
888
889	/**
890	 * A native Java object has a local method if it implements a
891	 * native Java method corresponding to the selector prefixed by 'base_'.
892	 */
893	protected boolean hasLocalMethod(ATSymbol atSelector) throws InterpreterException {
894        String jSelector = Reflection.upBaseLevelSelector(atSelector);
895        return Reflection.upRespondsTo(this, jSelector);
896	}
897	
898	protected ATObject getLocalField(ATSymbol selector) throws InterpreterException {
899		throw new XSelectorNotFound(selector, this);
900	}
901	
902	protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
903		String methSelector = Reflection.upBaseLevelSelector(selector);
904		return Reflection.upMethodSelection(this, methSelector, selector);
905	}
906	
907	protected void setLocalField(ATSymbol selector, ATObject value) throws InterpreterException {
908		throw new XSelectorNotFound(selector, this);
909	}
910	
911}