PageRenderTime 15ms CodeModel.GetById 2ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

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