/interpreter/tags/at2-build190607/src/edu/vub/at/objects/mirrors/NativeClosure.java
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}