/interpreter/tags/at2dist030708/src/edu/vub/at/objects/natives/NATClosure.java

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