/interpreter/tags/at2dist030708/src/edu/vub/at/objects/symbiosis/JavaConstructor.java

http://ambienttalk.googlecode.com/ · Java · 270 lines · 162 code · 40 blank · 68 comment · 23 complexity · abcaf0021118dd062b88df556789d597 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * JavaConstructor.java created on May 20, 2008 at 4:56:32 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.symbiosis;
  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.XNotInstantiatable;
  33. import edu.vub.at.exceptions.XTypeMismatch;
  34. import edu.vub.at.objects.ATBoolean;
  35. import edu.vub.at.objects.ATClosure;
  36. import edu.vub.at.objects.ATContext;
  37. import edu.vub.at.objects.ATMethod;
  38. import edu.vub.at.objects.ATObject;
  39. import edu.vub.at.objects.ATTable;
  40. import edu.vub.at.objects.coercion.NativeTypeTags;
  41. import edu.vub.at.objects.grammar.ATBegin;
  42. import edu.vub.at.objects.grammar.ATSymbol;
  43. import edu.vub.at.objects.mirrors.NativeClosure;
  44. import edu.vub.at.objects.natives.NATBoolean;
  45. import edu.vub.at.objects.natives.NATByRef;
  46. import edu.vub.at.objects.natives.NATContext;
  47. import edu.vub.at.objects.natives.NATNil;
  48. import edu.vub.at.objects.natives.NATNumber;
  49. import edu.vub.at.objects.natives.NATTable;
  50. import edu.vub.at.objects.natives.NATText;
  51. import edu.vub.at.objects.natives.grammar.AGBegin;
  52. import java.lang.reflect.Array;
  53. import java.lang.reflect.Constructor;
  54. import java.util.Vector;
  55. /**
  56. * JavaConstructor is a wrapper class encapsulating one or more java.lang.reflect.Constructor objects.
  57. * All methods in the choices array are overloaded constructors for the same class. The choices array
  58. * should never be empty!
  59. *
  60. * Since constructors do not need an receiver to become a full closure, this class implements both the
  61. * ATMethod and the ATJavaClosure interface. The latter ensures that constructors can be cast properly.
  62. *
  63. * @author smostinc
  64. */
  65. public class JavaConstructor extends NATByRef implements ATMethod, ATJavaClosure {
  66. protected final Class class_;
  67. protected final Constructor[] choices_;
  68. private ATContext context_ = null; // lazily initialized
  69. public JavaConstructor(Class clazz) {
  70. this(clazz, clazz.getConstructors());
  71. }
  72. public JavaConstructor(Class clazz, Constructor[] choices) {
  73. // assertion
  74. class_ = clazz;
  75. choices_ = choices;
  76. }
  77. // ATObject Interface implementation
  78. public ATBoolean base__opeql__opeql_(ATObject comparand) throws InterpreterException {
  79. return NATBoolean.atValue(this.equals(comparand));
  80. }
  81. /**
  82. * Two JavaConstructor instances are equal if they both represent a set of constructors
  83. * from the same declaring class.
  84. */
  85. public boolean equals(Object other) {
  86. if (other instanceof JavaConstructor) {
  87. JavaConstructor mth = (JavaConstructor) other;
  88. return (mth.class_ == this.class_);
  89. } else {
  90. return false;
  91. }
  92. }
  93. public ATTable meta_typeTags() throws InterpreterException {
  94. return NATTable.of(NativeTypeTags._METHOD_, NativeTypeTags._CLOSURE_);
  95. }
  96. // ATMethod Interface implementation
  97. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  98. return base_apply(arguments);
  99. }
  100. public ATObject base_applyInScope(ATTable arguments, ATContext ctx) throws InterpreterException {
  101. return base_apply(arguments);
  102. }
  103. public ATBegin base_bodyExpression() throws InterpreterException {
  104. // list all of the method signatures of the (possibly overloaded) Java method
  105. StringBuffer buff = new StringBuffer("Java implementation of: ");
  106. for (int i = 0; i < choices_.length; i++) {
  107. buff.append("\n");
  108. buff.append(choices_[i].toString());
  109. }
  110. buff.append("\n");
  111. return new AGBegin(NATTable.atValue(new ATObject[] { NATText.atValue(buff.toString()) }));
  112. }
  113. public ATSymbol base_name() throws InterpreterException {
  114. return NATNil._NEW_NAME_;
  115. }
  116. public ATTable base_parameters() throws InterpreterException {
  117. return Evaluator._ANON_MTH_ARGS_;
  118. }
  119. public ATTable base_annotations() throws InterpreterException {
  120. return NATTable.EMPTY;
  121. }
  122. public NATText meta_print() throws InterpreterException {
  123. return NATText.atValue("<java constructor:"+class_+">");
  124. }
  125. public ATMethod asMethod() throws XTypeMismatch {
  126. return this;
  127. }
  128. /**
  129. * When selected from a JavaClass object, the constructor needs to be wrapped in a dedicated
  130. * closure object. For constructors the JavaConstructor instance itself can be used.
  131. */
  132. public ATClosure base_wrap(ATObject lexicalScope, ATObject dynamicReceiver) {
  133. return this;
  134. }
  135. // ATJavaClosure Interface implementation
  136. public ATClosure asClosure() throws InterpreterException {
  137. return this;
  138. }
  139. public ATObject base_apply(ATTable arguments) throws InterpreterException {
  140. return Symbiosis.symbioticInstanceCreation(this, arguments.asNativeTable().elements_);
  141. }
  142. public ATObject base_applyInScope(ATTable arguments, ATObject scope) throws InterpreterException {
  143. return base_apply(arguments);
  144. }
  145. public ATContext base_context() throws InterpreterException {
  146. if(context_ == null) {
  147. JavaClass atClass = JavaClass.wrapperFor(class_);
  148. context_ = new NATContext(atClass, atClass);
  149. }
  150. return context_;
  151. }
  152. public ATObject base_escape() throws InterpreterException {
  153. throw new XIllegalOperation("Cannot call escape() in a Java Constructor");
  154. }
  155. public ATMethod base_method() throws InterpreterException {
  156. return this;
  157. }
  158. public ATObject base_whileTrue_(final ATClosure body) throws InterpreterException {
  159. final ATClosure test = this;
  160. ATBoolean cond;
  161. while (true) {
  162. // cond = self.apply()
  163. cond = this.base_apply(NATTable.EMPTY).asBoolean();
  164. if(cond.isNativeBoolean()) {
  165. // cond is a native boolean, perform the conditional ifTrue: test natively
  166. if (cond.asNativeBoolean().javaValue) {
  167. // execute body and continue while loop
  168. body.base_apply(NATTable.EMPTY);
  169. continue;
  170. } else {
  171. // return nil
  172. return Evaluator.getNil();
  173. }
  174. } else {
  175. // cond is a user-defined boolean, do a recursive send
  176. return cond.base_ifTrue_(new NativeClosure(this) {
  177. public ATObject base_apply(ATTable args) throws InterpreterException {
  178. // if user-defined bool is true, execute body and recurse
  179. body.base_apply(NATTable.EMPTY);
  180. return test.base_whileTrue_(body);
  181. }
  182. });
  183. }
  184. } }
  185. /**
  186. * For each Method in the wrapped JavaMethod's choices_, check whether it is compatible with
  187. * the given types. If so, add it to the choices_ array of the new JavaMethod.
  188. */
  189. public ATClosure base_cast(ATObject[] types) throws InterpreterException {
  190. // unwrap the JavaClass wrappers
  191. Class[] actualTypes = new Class[types.length];
  192. for (int i = 0; i < actualTypes.length; i++) {
  193. // Array types may be represented as one-arg tables of a type: [Type]
  194. // TODO: properly refactor the instanceof test
  195. // problem: cannot do base_isTable because JavaObject/JavaClass objects will say yes!
  196. if (types[i] instanceof NATTable) {
  197. // Array.newInstance([Type][1],0).getClass()
  198. actualTypes[i] = Array.newInstance(types[i].asTable().
  199. base_at(NATNumber.ONE).asJavaClassUnderSymbiosis().getWrappedClass(), 0).getClass();
  200. } else {
  201. actualTypes[i] = types[i].asJavaClassUnderSymbiosis().getWrappedClass();
  202. }
  203. }
  204. Vector matchingMethods = new Vector();
  205. for (int i = 0; i < choices_.length; i++) {
  206. if(matches(choices_[i].getParameterTypes(), actualTypes)) {
  207. matchingMethods.add(choices_[i]);
  208. }
  209. }
  210. Constructor[] matches = (Constructor[]) matchingMethods.toArray(new Constructor[matchingMethods.size()]);
  211. if (matches.length > 0) {
  212. return new JavaConstructor(class_, matches);
  213. } else {
  214. throw new XNotInstantiatable(class_);
  215. }
  216. }
  217. /**
  218. * Compares two Class arrays and returns true iff both arrays have equal size and all members are the same.
  219. */
  220. private static final boolean matches(Class[] formals, Class[] actuals) {
  221. if (formals.length != actuals.length)
  222. return false;
  223. for (int i = 0; i < formals.length; i++) {
  224. if (!(formals[i] == actuals[i])) {
  225. return false;
  226. }
  227. }
  228. return true;
  229. }
  230. }