PageRenderTime 57ms CodeModel.GetById 16ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
Java | 246 lines | 122 code | 24 blank | 100 comment | 22 complexity | 6a87fd72bd19f51aee1d8b7e1ff6800f 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.grammar.ATSymbol;
 38import edu.vub.at.objects.natives.NATClosure;
 39import edu.vub.at.objects.natives.NATContext;
 40import edu.vub.at.objects.natives.NATNumber;
 41import edu.vub.at.objects.natives.NATTable;
 42import edu.vub.at.objects.natives.NATText;
 43
 44/**
 45 * A NativeClosure is a wrapper class for a piece of Java code. The Java code is
 46 * presented to the AmbientTalk system as a closure. A NativeClosure is represented
 47 * as follows:
 48 * 
 49 * - Its encapsulating method is a 'dummy' NativeMethod ATMethod, with the following properties:
 50 *   - name = "nativelambda" (to distinguish it from 'ordinary' lambdas)
 51 *   - arguments = [ \@args ] (it takes an arbitrary number of arguments)
 52 *   - body = "Native implementation in {class}" (a string telling an inspector that
 53 *     this closure is natively implemented in the given Java class)
 54 *   - applying a nativelambda directly (without going through this NativeClosure)
 55 *     results in an error
 56 * - Its enclosed context consists of a triple (obj, obj, obj.super), where 'obj'
 57 *   is the Java object (implementing ATObject) that created this NativeClosure.
 58 *   
 59 * The method and context fields of a NativeClosure are lazily generated on demand
 60 * for efficiency reasons. Most of the time, a NativeClosure will not be introspected,
 61 * but only applied.
 62 * 
 63 * A NativeClosure can be used in two ways by Java code:
 64 *  1) As a generator for anonymous classes to generate 'anonymous lambdas':
 65 *     new NativeClosure(this) {
 66 *       public ATObject meta_apply(ATTable args) throws NATException {
 67 *         ...
 68 *       }
 69 *     }
 70 *  2) As a wrapper for an already existing NativeMethod:
 71 *     new NativeClosure(this, aJavaMethod);
 72 * 
 73 * @author tvc
 74 */
 75public class NativeClosure extends NATClosure {
 76
 77	protected final ATObject scope_;
 78	
 79	/**
 80	 * Create a new NativeClosure where meta_apply will be overridden by anonymous subclasses.
 81	 * @param scope the object creating this NativeClosure.
 82	 */
 83	public NativeClosure(ATObject scope) {
 84		this(scope, null);
 85	}
 86	
 87	/**
 88	 * Create a new NativeClosure where meta_apply will invoke the given Java Method.
 89	 * @param scope the object that should be used as a receiver for the corresponding method.
 90	 * @param meth a presumably native method
 91	 */
 92	public NativeClosure(ATObject scope, NativeMethod meth) {
 93		super(meth, null);
 94		scope_ = scope;
 95	}
 96
 97	/**
 98	 * Overridden to allow for lazy instantiation of the method.
 99	 * 
100	 * If receiver is an anonymous NativeClosure, an 'anonymous' NativeMethod is returned.
101	 * @return a NativeMethod wrapped by this NativeClosure.
102	 */
103	public ATMethod base_method() {
104		if (method_ == null)
105			method_ = new NativeAnonymousMethod(scope_.getClass());
106		return method_;
107	}
108
109	/**
110	 * Overridden to allow for lazy instantiation of the context.
111	 * 
112	 * A 'default' context is lazily constructed and returned.
113	 */
114	public ATContext base_context() throws InterpreterException {
115		if (context_ == null)
116			context_ = new NATContext(scope_, scope_);
117		return context_;
118	}
119
120	/**
121	 * Apply the NativeClosure, which either gives rise to executing a native piece of
122	 * code supplied by an anonymous subclass, or executes the wrapped NativeMethod.
123	 */
124	public ATObject base_apply(ATTable arguments) throws InterpreterException {
125		if (method_ == null) {
126			// this method is supposed to be overridden by an anonymous subclass
127			throw new RuntimeException("NativeClosure's base_apply not properly overridden by " + scope_.getClass());
128		} else {
129			return method_.base_apply(arguments, this.base_context());
130		}
131	}
132	
133	/**
134	 * A NativeClosure can also be directed to execute its wrapped NativeMethod in an
135	 * externally specified scope. Of course, for native calls or symbiotic calls, the
136	 * call will only succeed if the externally specified object is of the correct native type.
137	 */
138	public ATObject base_applyInScope(ATTable args, ATObject scope) throws InterpreterException {
139		if (method_ == null) {
140			// this method is supposed to be overridden by an anonymous subclass
141			throw new RuntimeException("NativeClosure's base_applyInScope not properly overridden by " + scope_.getClass());
142		} else {
143			return method_.base_applyInScope(args, new NATContext(scope, scope));
144		}
145	}
146	
147	public NATText meta_print() throws InterpreterException {
148		return NATText.atValue("<native closure:"+base_method().base_name().base_text().asNativeText().javaValue+">");
149	}
150	
151	/**
152	 * Auxiliary method to more easily extract arguments from an ATTable
153	 */
154	public ATObject get(ATTable args, int n) throws InterpreterException {
155		return args.base_at(NATNumber.atValue(n));
156	}
157
158	public int getNbr(ATTable args, int n) throws InterpreterException {
159		return args.base_at(NATNumber.atValue(n)).asNativeNumber().javaValue;
160	}
161	
162	public double getFrc(ATTable args, int n) throws InterpreterException {
163		return args.base_at(NATNumber.atValue(n)).asNativeFraction().javaValue;
164	}
165	
166	public String getTxt(ATTable args, int n) throws InterpreterException {
167		return args.base_at(NATNumber.atValue(n)).asNativeText().javaValue;
168	}
169	
170	public boolean getBln(ATTable args, int n) throws InterpreterException {
171		return args.base_at(NATNumber.atValue(n)).asNativeBoolean().javaValue;
172	}
173	
174	public Object[] getTab(ATTable args, int n) throws InterpreterException {
175		return args.base_at(NATNumber.atValue(n)).asNativeTable().elements_;
176	}
177	
178	public void checkArity(ATTable args, int required) throws InterpreterException {
179		int provided = args.base_length().asNativeNumber().javaValue;
180		if (provided != required) {
181			throw new XArityMismatch(Evaluator._ANON_MTH_NAM_.toString(), required, provided);
182		}
183	}
184	
185	public static void checkNullaryArguments(ATSymbol selector, ATTable args) throws InterpreterException {
186		if (args != NATTable.EMPTY)
187			throw new XArityMismatch("access to non-closure field " + selector.toString(), 0, args.base_length().asNativeNumber().javaValue);
188	}
189	
190    public static ATObject checkUnaryArguments(ATSymbol selector, ATTable args) throws InterpreterException {
191    	int len = args.base_length().asNativeNumber().javaValue;
192		if (len != 1)
193			throw new XArityMismatch("mutation of field " + selector.toString(), 1, len);
194		return args.base_at(NATNumber.ONE);
195	}
196	
197	/**
198	 * A zero-argument (0-ary) native closure representing an accessor.
199	 */
200	public static abstract class Accessor extends NativeClosure {
201		/** for debugging/error messages only */
202		private final ATSymbol name_;
203		public Accessor(ATSymbol name, ATObject scope) {
204			super(scope);
205			name_ = name;
206		}
207		public ATObject base_apply(ATTable args) throws InterpreterException {
208			if (args != NATTable.EMPTY) {
209				throw new XArityMismatch("accessor for " + name_, 0, args.base_length().asNativeNumber().javaValue);
210			} else {
211				return access();
212			}
213		}
214		protected abstract ATObject access() throws InterpreterException;
215		
216		public NATText meta_print() throws InterpreterException {
217			return NATText.atValue("<native closure:"+name_+">");
218		}
219	}
220	
221	/**
222	 * A one-argument (1-ary) native closure representing a mutator.
223	 */
224	public static abstract class Mutator extends NativeClosure {
225		/** for debugging/error messages only */
226		private final ATSymbol name_;
227		public Mutator(ATSymbol name, ATObject scope) {
228			super(scope);
229			name_ = name;
230		}
231		public ATObject base_apply(ATTable args) throws InterpreterException {
232			int len = args.base_length().asNativeNumber().javaValue;
233			if (len != 1) {
234				throw new XArityMismatch("mutator for " + name_, 1, len);
235			} else {
236				return mutate(args.base_at(NATNumber.ONE));
237			}
238		}
239		protected abstract ATObject mutate(ATObject val) throws InterpreterException;
240		
241		public NATText meta_print() throws InterpreterException {
242			return NATText.atValue("<native closure:"+name_+">");
243		}
244	}
245	
246}