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

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