/interpreter/tags/at2-build270707/src/edu/vub/at/objects/natives/NATClosure.java

http://ambienttalk.googlecode.com/ · Java · 232 lines · 102 code · 20 blank · 110 comment · 12 complexity · 1ff7355bf7b800e9c352b8e73921a756 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * NATClosure.java created on Jul 23, 2006 at 3:22:23 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. */
  28. package edu.vub.at.objects.natives;
  29. import edu.vub.at.exceptions.InterpreterException;
  30. import edu.vub.at.exceptions.XIllegalOperation;
  31. import edu.vub.at.exceptions.signals.SignalEscape;
  32. import edu.vub.at.objects.ATBoolean;
  33. import edu.vub.at.objects.ATClosure;
  34. import edu.vub.at.objects.ATContext;
  35. import edu.vub.at.objects.ATMethod;
  36. import edu.vub.at.objects.ATObject;
  37. import edu.vub.at.objects.ATTable;
  38. import edu.vub.at.objects.coercion.NativeTypeTags;
  39. import edu.vub.at.objects.mirrors.NativeClosure;
  40. /**
  41. * A NATClosure instance represents a first-class AmbientTalk closure.
  42. * A closure is modelled as a pair (method, context), where the method
  43. * contains the pure function (function name, arguments and body).
  44. *
  45. * The single most important operation to be performed on a closure is applying it.
  46. * This will give rise to the application of its underlying method within the context
  47. * wrapped by the closure.
  48. *
  49. * @author smostinc
  50. */
  51. public class NATClosure extends NATByRef implements ATClosure {
  52. // these instance variables are inherited and used by a NativeClosure as well.
  53. protected ATMethod method_;
  54. protected ATContext context_;
  55. /**
  56. * This constructor creates a closure with a bound dynamic receiver, and it is
  57. * called after the succesful lookup of a receiverful message.
  58. * @param method the method being wrapped into a closure.
  59. * @param implementor the object in which the definition is nested.
  60. * @param receiver the object where the lookup was initiated.
  61. */
  62. public NATClosure(ATMethod method, ATObject implementor, ATObject receiver) throws InterpreterException {
  63. this(method, new NATContext(
  64. /* scope = implementor (to be extended with a callframe upon closure application) */
  65. implementor,
  66. /* self = ` start of lookup ` */
  67. receiver));
  68. }
  69. public NATClosure(ATMethod method, ATContext context) {
  70. method_ = method;
  71. context_ = context;
  72. }
  73. /**
  74. * To apply a closure, apply its underlying method with the context of the closure,
  75. * rather than the runtime context of the invoker.
  76. */
  77. public ATObject base_apply(ATTable arguments) throws InterpreterException {
  78. return method_.base_apply(arguments, this.base_context());
  79. }
  80. /**
  81. * To apply a closure in a given scope, apply its underlying method with a new context
  82. * constructed from the scope object.
  83. */
  84. public ATObject base_applyInScope(ATTable args, ATObject scope) throws InterpreterException {
  85. return method_.base_applyInScope(args, new NATContext(scope, scope));
  86. }
  87. /**
  88. * receiver is a zero-argument block closure returning a boolean
  89. * @param body a zero-argument block closure
  90. *
  91. * def whileTrue: body {
  92. * self.apply().ifTrue: {
  93. * body();
  94. * self.whileTrue: body
  95. * }
  96. * }
  97. */
  98. public ATObject base_whileTrue_(final ATClosure body) throws InterpreterException {
  99. /* ATObject result = NATNil._INSTANCE_;
  100. while (this.meta_apply(NATTable.EMPTY).asNativeBoolean().javaValue) {
  101. result = body.meta_apply(NATTable.EMPTY);
  102. }
  103. return result; */
  104. ATBoolean cond;
  105. while (true) {
  106. // cond = self.apply()
  107. cond = this.base_apply(NATTable.EMPTY).asBoolean();
  108. if(cond.isNativeBoolean()) {
  109. // cond is a native boolean, perform the conditional ifTrue: test natively
  110. if (cond.asNativeBoolean().javaValue) {
  111. // execute body and continue while loop
  112. body.base_apply(NATTable.EMPTY);
  113. continue;
  114. } else {
  115. // return nil
  116. return OBJNil._INSTANCE_;
  117. }
  118. } else {
  119. // cond is a user-defined boolean, do a recursive send
  120. return cond.base_ifTrue_(new NativeClosure(this) {
  121. public ATObject base_apply(ATTable args) throws InterpreterException {
  122. // if user-defined bool is true, execute body and recurse
  123. body.base_apply(NATTable.EMPTY);
  124. return base_whileTrue_(body);
  125. }
  126. });
  127. }
  128. }
  129. }
  130. /**
  131. * The following is a pseudo-code implementation of escape. The important difference
  132. * between the native implementation and this pseudo-code is that the 'escaping exception'
  133. * can *not* be caught at the AmbientTalk level. The SignalEscape is a truly native exception.
  134. *
  135. * def block.escape() {
  136. * def returned := false;
  137. * def quit(@args) {
  138. * if: (returned) then: {
  139. * raise: XIllegalOperation.new("Cannot quit, escape activation already returned")
  140. * } else: {
  141. * raise: SignalEscape.new(block, if: (args.isEmpty()) then: nil else: args[1])
  142. * }
  143. * };
  144. *
  145. * try: {
  146. * block(quit);
  147. * } catch: SignalEscape using: {|e|
  148. * if: (e.block == block) then: {
  149. * e.val
  150. * } else: {
  151. * raise: e
  152. * }
  153. * } finally: { // doesn't yet exist in AT/2
  154. * returned := true;
  155. * }
  156. * }
  157. */
  158. public ATObject base_escape() throws InterpreterException {
  159. final QuitClosureFrame f = new QuitClosureFrame();
  160. NativeClosure quit = new NativeClosure(this) {
  161. public ATObject base_apply(ATTable args) throws InterpreterException {
  162. if (f.alreadyReturned) {
  163. throw new XIllegalOperation("Cannot quit, escape activation already returned");
  164. } else {
  165. ATObject val;
  166. if (args.base_isEmpty().asNativeBoolean().javaValue) {
  167. val = OBJNil._INSTANCE_;
  168. } else {
  169. val = get(args, 1);
  170. }
  171. throw new SignalEscape(this.scope_.asClosure(), val);
  172. }
  173. }
  174. };
  175. try {
  176. return this.base_apply(NATTable.atValue(new ATObject[] { quit }));
  177. } catch(SignalEscape e) {
  178. if (e.originatingBlock == this) {
  179. return e.returnedValue;
  180. } else {
  181. // propagate the signal, it did not originate from this block
  182. throw e;
  183. }
  184. } finally {
  185. f.alreadyReturned = true;
  186. }
  187. }
  188. // helper class to get around the fact that Java has no true closures and hence
  189. // does not allow access to mutable lexically scoped free variables
  190. static private class QuitClosureFrame {
  191. /** if true, the escape block has already been exited */
  192. public boolean alreadyReturned = false;
  193. }
  194. public ATContext base_context() throws InterpreterException {
  195. return context_;
  196. }
  197. public ATMethod base_method() {
  198. return method_;
  199. }
  200. public ATClosure asClosure() {
  201. return this;
  202. }
  203. public NATText meta_print() throws InterpreterException {
  204. return NATText.atValue("<closure:"+method_.base_name()+">");
  205. }
  206. public ATTable meta_typeTags() throws InterpreterException {
  207. return NATTable.of(NativeTypeTags._CLOSURE_);
  208. }
  209. public ATObject meta_clone() throws InterpreterException {
  210. return this;
  211. }
  212. }