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