PageRenderTime 22ms CodeModel.GetById 14ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/interpreter/tags/at_build150307/src/edu/vub/at/objects/mirrors/NativeClosure.java

http://ambienttalk.googlecode.com/
Java | 183 lines | 73 code | 18 blank | 92 comment | 12 complexity | 7a415fcc2b45092f6a70eda9c5b1f13c MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NativeClosure.java created on 10-aug-2006 at 8:30:08
  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.mirrors;
 29
 30import edu.vub.at.eval.Evaluator;
 31import edu.vub.at.exceptions.InterpreterException;
 32import edu.vub.at.exceptions.XArityMismatch;
 33import edu.vub.at.objects.ATContext;
 34import edu.vub.at.objects.ATMethod;
 35import edu.vub.at.objects.ATObject;
 36import edu.vub.at.objects.ATTable;
 37import edu.vub.at.objects.natives.NATClosure;
 38import edu.vub.at.objects.natives.NATContext;
 39import edu.vub.at.objects.natives.NATNumber;
 40import edu.vub.at.objects.natives.NATText;
 41
 42/**
 43 * A NativeClosure is a wrapper class for a piece of Java code. The Java code is
 44 * presented to the AmbientTalk system as a closure. A NativeClosure is represented
 45 * as follows:
 46 * 
 47 * - Its encapsulating method is a 'dummy' NativeMethod ATMethod, with the following properties:
 48 *   - name = "nativelambda" (to distinguish it from 'ordinary' lambdas)
 49 *   - arguments = [ \@args ] (it takes an arbitrary number of arguments)
 50 *   - body = "Native implementation in {class}" (a string telling an inspector that
 51 *     this closure is natively implemented in the given Java class)
 52 *   - applying a nativelambda directly (without going through this NativeClosure)
 53 *     results in an error
 54 * - Its enclosed context consists of a triple (obj, obj, obj.super), where 'obj'
 55 *   is the Java object (implementing ATObject) that created this NativeClosure.
 56 *   
 57 * The method and context fields of a NativeClosure are lazily generated on demand
 58 * for efficiency reasons. Most of the time, a NativeClosure will not be introspected,
 59 * but only applied.
 60 * 
 61 * A NativeClosure can be used in two ways by Java code:
 62 *  1) As a generator for anonymous classes to generate 'anonymous lambdas':
 63 *     new NativeClosure(this) {
 64 *       public ATObject meta_apply(ATTable args) throws NATException {
 65 *         ...
 66 *       }
 67 *     }
 68 *  2) As a wrapper for an already existing NativeMethod:
 69 *     new NativeClosure(this, aJavaMethod);
 70 * 
 71 * @author tvc
 72 */
 73public class NativeClosure extends NATClosure {
 74
 75	protected final ATObject scope_;
 76	
 77	/**
 78	 * Create a new NativeClosure where meta_apply will be overridden by anonymous subclasses.
 79	 * @param scope the object creating this NativeClosure.
 80	 */
 81	public NativeClosure(ATObject scope) {
 82		this(scope, null);
 83	}
 84	
 85	/**
 86	 * Create a new NativeClosure where meta_apply will invoke the given Java Method.
 87	 * @param scope the object that should be used as a receiver for the corresponding method.
 88	 * @param meth a presumably native method
 89	 */
 90	public NativeClosure(ATObject scope, NativeMethod meth) {
 91		super(meth, null);
 92		scope_ = scope;
 93	}
 94
 95	/**
 96	 * Overridden to allow for lazy instantiation of the method.
 97	 * 
 98	 * If receiver is an anonymous NativeClosure, an 'anonymous' NativeMethod is returned.
 99	 * @return a NativeMethod wrapped by this NativeClosure.
100	 */
101	public ATMethod base_getMethod() {
102		if (method_ == null)
103			method_ = new NativeAnonymousMethod(scope_.getClass());
104		return method_;
105	}
106
107	/**
108	 * Overridden to allow for lazy instantiation of the context.
109	 * 
110	 * A 'default' context is lazily constructed and returned.
111	 */
112	public ATContext base_getContext() throws InterpreterException {
113		if (context_ == null)
114			context_ = new NATContext(scope_, scope_);
115		return context_;
116	}
117
118	/**
119	 * Apply the NativeClosure, which either gives rise to executing a native piece of
120	 * code supplied by an anonymous subclass, or executes the wrapped NativeMethod.
121	 */
122	public ATObject base_apply(ATTable arguments) throws InterpreterException {
123		if (method_ == null) {
124			// this method is supposed to be overridden by an anonymous subclass
125			throw new RuntimeException("NativeClosure's base_apply not properly overridden by " + scope_.getClass());
126		} else {
127			return method_.base_apply(arguments, this.base_getContext());
128		}
129	}
130	
131	/**
132	 * A NativeClosure can also be directed to execute its wrapped NativeMethod in an
133	 * externally specified scope. Of course, for native calls or symbiotic calls, the
134	 * call will only succeed if the externally specified object is of the correct native type.
135	 */
136	public ATObject base_applyInScope(ATTable args, ATObject scope) throws InterpreterException {
137		if (method_ == null) {
138			// this method is supposed to be overridden by an anonymous subclass
139			throw new RuntimeException("NativeClosure's base_applyInScope not properly overridden by " + scope_.getClass());
140		} else {
141			return method_.base_applyInScope(args, new NATContext(scope, scope));
142		}
143	}
144	
145	public NATText meta_print() throws InterpreterException {
146		return NATText.atValue("<native closure:"+base_getMethod().base_getName().base_getText().asNativeText().javaValue+">");
147	}
148	
149	/**
150	 * Auxiliary method to more easily extract arguments from an ATTable
151	 */
152	public ATObject get(ATTable args, int n) throws InterpreterException {
153		return args.base_at(NATNumber.atValue(n));
154	}
155
156	public int getNbr(ATTable args, int n) throws InterpreterException {
157		return args.base_at(NATNumber.atValue(n)).asNativeNumber().javaValue;
158	}
159	
160	public double getFrc(ATTable args, int n) throws InterpreterException {
161		return args.base_at(NATNumber.atValue(n)).asNativeFraction().javaValue;
162	}
163	
164	public String getTxt(ATTable args, int n) throws InterpreterException {
165		return args.base_at(NATNumber.atValue(n)).asNativeText().javaValue;
166	}
167	
168	public boolean getBln(ATTable args, int n) throws InterpreterException {
169		return args.base_at(NATNumber.atValue(n)).asNativeBoolean().javaValue;
170	}
171	
172	public Object[] getTab(ATTable args, int n) throws InterpreterException {
173		return args.base_at(NATNumber.atValue(n)).asNativeTable().elements_;
174	}
175	
176	public void checkArity(ATTable args, int required) throws InterpreterException {
177		int provided = args.base_getLength().asNativeNumber().javaValue;
178		if (provided != required) {
179			throw new XArityMismatch(Evaluator._ANON_MTH_NAM_.toString(), required, provided);
180		}
181	}
182	
183}