PageRenderTime 49ms CodeModel.GetById 3ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2-build060407/src/edu/vub/at/objects/mirrors/Reflection.java

http://ambienttalk.googlecode.com/
Java | 761 lines | 330 code | 47 blank | 384 comment | 55 complexity | 2641625ce40453f3e621243f2d7e03dd MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * Reflection.java created on 10-aug-2006 at 16:19:17
  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.mirrors;
 29
 30import edu.vub.at.exceptions.InterpreterException;
 31import edu.vub.at.exceptions.XArityMismatch;
 32import edu.vub.at.exceptions.XIllegalArgument;
 33import edu.vub.at.exceptions.XSelectorNotFound;
 34import edu.vub.at.exceptions.XUndefinedField;
 35import edu.vub.at.objects.ATField;
 36import edu.vub.at.objects.ATMethod;
 37import edu.vub.at.objects.ATObject;
 38import edu.vub.at.objects.ATTable;
 39import edu.vub.at.objects.grammar.ATSymbol;
 40import edu.vub.at.objects.natives.NATException;
 41import edu.vub.at.objects.natives.NATTable;
 42import edu.vub.at.objects.natives.grammar.AGSymbol;
 43import edu.vub.at.objects.symbiosis.Symbiosis;
 44import edu.vub.util.Matcher;
 45import edu.vub.util.Pattern;
 46
 47import java.lang.reflect.Method;
 48import java.util.Vector;
 49
 50/**
 51 * Reflection is an auxiliary class meant to serve as a repository for methods
 52 * related to 'up' and 'down' Java values properly into and out of the AmbientTalk base level.
 53 * 
 54 * Keep the following mental picture in mind:
 55 * 
 56 *                ^        Java = implementation-level          |
 57 *  to deify      |        Java AT objects = meta-level         | to reify
 58 *  (= to up)     | ------------------------------------------  | (= to down)
 59 *  (= to absorb) |         AmbientTalk = base-level            v (= to reflect)
 60 * 
 61 * Although deification and reification are more accurate terms, we will use 'up' and 'down'
 62 * because they are the clearest terminology, and clarity matters.
 63 * 
 64 * In this class, the following conventions hold:
 65 *  - methods start with either 'up' or 'down', denoting whether they deify or reify something
 66 *  - arguments start with either 'j' or 'at', denoting whether they represent Java or AmbientTalk values
 67 *  With 'java values' is meant 'java objects representing mirrors'
 68 * 
 69 * @author tvc
 70 */
 71public final class Reflection {
 72	
 73	public static final String _BASE_PREFIX_ = "base_";
 74	public static final String _BGET_PREFIX_ = "base_get";
 75	public static final String _BSET_PREFIX_ = "base_set";
 76	
 77	public static final String _META_PREFIX_ = "meta_";
 78	public static final String _MGET_PREFIX_ = "meta_get";
 79	public static final String _MSET_PREFIX_ = "meta_set";
 80	
 81	/**
 82	 * A selector passed from the Java to the AmbientTalk level undergoes the following transformations:
 83	 * 
 84	 * - any pattern of the form _op{code}_ is transformed to a symbol corresponding to the operator code
 85	 *  Operator codes are:
 86	 *   pls -> +
 87	 *   mns -> -
 88	 *   tms -> *
 89	 *   div -> /
 90	 *   bsl -> \
 91	 *   and -> &
 92	 *   not -> !
 93	 *   gtx -> >
 94	 *   ltx -> <
 95	 *   eql -> =
 96	 *   til -> ~
 97	 *   que -> ?
 98	 *   rem -> %
 99	 * - any underscores (_) are replaced by colons (:)
100	 */
101	public static final ATSymbol downSelector(String jSelector) {
102		return AGSymbol.jAlloc(javaToAmbientTalkSelector(jSelector));
103	}
104	
105	/**
106	 * Transforms a Java selector prefixed with base_ into an AmbientTalk selector without the prefix.
107	 */
108	public static final ATSymbol downBaseLevelSelector(String jSelector) throws InterpreterException {
109		if (jSelector.startsWith(Reflection._BASE_PREFIX_)) {
110			return downSelector(stripPrefix(jSelector, Reflection._BASE_PREFIX_));
111		} else if (jSelector.startsWith(Reflection._MGET_PREFIX_)) {
112			return downFieldName(stripPrefix(jSelector, Reflection._MGET_PREFIX_));
113		} else if (jSelector.startsWith(Reflection._MSET_PREFIX_)) {
114			return downFieldName(stripPrefix(jSelector, Reflection._MSET_PREFIX_));
115		} else if (jSelector.startsWith(Reflection._META_PREFIX_)) {
116			return downSelector(stripPrefix(jSelector, Reflection._META_PREFIX_));
117		} else {
118			throw new XIllegalArgument("Illegal base level selector to down: " + jSelector);
119		}
120	}
121	
122	/**
123	 * Transforms a Java selector prefixed with meta_ into an AmbientTalk selector without the prefix.
124	 */
125	public static final ATSymbol downMetaLevelSelector(String jSelector) throws InterpreterException {
126		if (jSelector.startsWith(Reflection._META_PREFIX_)) {
127			return downSelector(stripPrefix(jSelector, Reflection._META_PREFIX_));
128		} else {
129			throw new XIllegalArgument("Illegal meta level selector to down: " + jSelector);
130		}
131	}
132	
133	/**
134	 * Transforms a Java selector prefixed with base_get into an equivalent AmbientTalk selector.
135	 * 
136	 * Example:
137	 *  downBaseFieldAccessSelector("base_getReceiver") => ATSymbol("receiver")
138	 */
139	public static final ATSymbol downBaseFieldAccessSelector(String jSelector) throws InterpreterException {
140		if (jSelector.startsWith(Reflection._BGET_PREFIX_)) {
141			return downFieldName(stripPrefix(jSelector, Reflection._BGET_PREFIX_));
142		} else {
143			throw new XIllegalArgument("Illegal base level accessor to down: " + jSelector);
144		}
145	}
146
147	/**
148	 * Transforms a Java selector prefixed with base_set into an equivalent AmbientTalk selector.
149	 * 
150	 * Example:
151	 *  downBaseFieldMutationSelector("base_setReceiver") => ATSymbol("receiver")
152	 */
153	public static final ATSymbol downBaseFieldMutationSelector(String jSelector) throws InterpreterException {
154		if (jSelector.startsWith(Reflection._BSET_PREFIX_)) {
155			return downFieldName(stripPrefix(jSelector, Reflection._BSET_PREFIX_));
156		} else {
157			throw new XIllegalArgument("Illegal base level mutator to down: " + jSelector);
158		}
159	}
160
161	/**
162	 * Transforms a Java selector prefixed with meta_get into an equivalent AmbientTalk selector
163	 * 
164	 * Example:
165	 *  downMetaFieldAccessSelector("meta_getReceiver") => ATSymbol("receiver")
166	 */
167	public static final ATSymbol downMetaFieldAccessSelector(String jSelector) throws InterpreterException {
168		if (jSelector.startsWith(Reflection._MGET_PREFIX_)) {
169			return downFieldName(stripPrefix(jSelector, Reflection._MGET_PREFIX_));
170		} else {
171			throw new XIllegalArgument("Illegal meta level accessor to down: " + jSelector);
172		}
173	}
174	
175	/**
176	 * Transforms a Java selector prefixed with meta_set into an equivalent AmbientTalk selector.
177	 * 
178	 * Example:
179	 *  downMetaFieldMutationSelector("meta_setReceiver") => ATSymbol("receiver")
180	 */
181	public static final ATSymbol downMetaFieldMutationSelector(String jSelector) throws InterpreterException {
182		if (jSelector.startsWith(Reflection._MSET_PREFIX_)) {
183			return downFieldName(stripPrefix(jSelector, Reflection._MSET_PREFIX_));
184		} else {
185			throw new XIllegalArgument("Illegal meta level mutator to down: " + jSelector);
186		}
187	}
188	
189	/**
190	 * A field name "Field" passed from the Java to the AmbientTalk level undergoes the following transformations:
191	 * 
192	 *  - the same transformations applicable to downSelector
193	 *    @see Reflection#downSelector(String)
194	 *  - the first letter is transformed into lower case (as it was uppercased for Java conventions)
195	 */
196	public static final ATSymbol downFieldName(String jName) throws InterpreterException {
197		char[] charArray = jName.toCharArray();
198		charArray[0] = Character.toLowerCase(charArray[0]);
199		return downSelector(new String(charArray));
200	}
201	
202	/**
203	 * A selector passed from the AmbientTalk to the Java level undergoes the following transformations:
204	 * 
205	 * - any colons (:) are replaced by underscores (_)
206	 * - any operator symbol is replaced by _op{code}_ where code is generated as follows:
207	 *  Operator codes are:
208	 *   + -> pls
209	 *   - -> mns
210	 *   * -> tms
211	 *   / -> div
212	 *   \ -> bsl
213	 *   & -> and
214	 *   ! -> not
215	 *   > -> gtx
216	 *   < -> ltx
217	 *   = -> eql
218	 *   ~ -> til
219	 *   ? -> que
220	 *   % -> rem
221	 */
222	public static final String upSelector(ATSymbol atSelector) throws InterpreterException {
223		// : -> _
224		String nam = atSelector.base_getText().asNativeText().javaValue;
225        // Backport from JDK 1.4 to 1.3
226		// nam = nam.replaceAll(":", "_");
227        nam = Pattern.compile(":").matcher(new StringBuffer(nam)).replaceAll("_");
228        
229		// operator symbol -> _op{code}_
230		Matcher m = symbol.matcher(new StringBuffer(nam));
231		StringBuffer sb = new StringBuffer();
232		while (m.find()) {
233			// find every occurence of a non-word character and convert it into a symbol
234			String oprCode = symbol2oprCode(m.group(0));
235			// only add the _op prefix and _ postfix if the code has been found...
236			m.appendReplacement(sb, (oprCode.length() == 3) ? "_op" + oprCode  + "_" : oprCode);
237		}
238		m.appendTail(sb);
239		return sb.toString();
240	}
241	
242	/**
243	 * Transforms an AmbientTalk selector into a Java-level selector prefixed with base_.
244	 */
245	public static final String upBaseLevelSelector(ATSymbol atSelector) throws InterpreterException {
246		return Reflection._BASE_PREFIX_ + upSelector(atSelector);
247	}
248
249	/**
250	 * Transforms an AmbientTalk selector into a Java-level selector prefixed with meta_.
251	 */
252	public static final String upMetaLevelSelector(ATSymbol atSelector) throws InterpreterException {
253		return Reflection._META_PREFIX_ + upSelector(atSelector);
254	}
255	
256	/**
257	 * A field name "field" passed from the AmbientTalk to the Java level undergoes the following transformations:
258	 * 
259	 *  - the same transformations applicable to upSelector
260	 *    @see Reflection#upSelector(ATSymbol)
261	 *  - the first letter is transformed into upper case such that it can be accessed using respectively
262	 *    "getField" | "setField" methods at the Java level.  
263	 */
264	public static final String upFieldName(ATSymbol atName) throws InterpreterException {
265		char[] charArray = upSelector(atName).toCharArray();
266		charArray[0] = Character.toUpperCase(charArray[0]);
267		return new String(charArray);
268	}
269	
270	/**
271	 * Transforms an AmbientTalk selector into an equivalent Java selector uppercased and prefixed with "base_get".
272	 * 
273	 * Example:
274	 *  upBaseFieldAccessSelector(ATSymbol('receiver')) => "base_getReceiver"
275	 */
276	public static final String upBaseFieldAccessSelector(ATSymbol atName) throws InterpreterException {
277		return Reflection._BGET_PREFIX_ + upFieldName(atName);
278	}
279
280	/**
281	 * Transforms an AmbientTalk selector into an equivalent Java selector uppercased and prefixed with "base_set".
282	 * 
283	 * Example:
284	 *  upBaseFieldMutationSelector(ATSymbol('receiver')) => "base_setReceiver"
285	 */
286	public static final String upBaseFieldMutationSelector(ATSymbol atName) throws InterpreterException {
287		return Reflection._BSET_PREFIX_ + upFieldName(atName);
288	}
289
290	/**
291	 * Transforms an AmbientTalk selector into an equivalent Java selector uppercased and prefixed with "meta_get".
292	 * 
293	 * Example:
294	 *  upMetaFieldAccessSelector(ATSymbol('receiver')) => "meta_getReceiver"
295	 */
296	public static final String upMetaFieldAccessSelector(ATSymbol atName) throws InterpreterException {
297		return Reflection._MGET_PREFIX_ + upFieldName(atName);
298	}
299	
300	/**
301	 * Transforms an AmbientTalk selector into an equivalent Java selector uppercased and prefixed with "meta_set".
302	 * 
303	 * Example:
304	 *  upMetaFieldMutationSelector(ATSymbol('receiver')) => "meta_setReceiver"
305	 */
306	public static final String upMetaFieldMutationSelector(ATSymbol atName) throws InterpreterException {
307		return Reflection._MSET_PREFIX_ + upFieldName(atName);
308	}
309	
310	/**
311	 * Constructs an AmbientTalk ATField from a pair of accessor/mutator methods of
312	 * a Java object. Given an object obj and a String sel, it is checked whether
313	 *  a) obj has a method named getPrefix + Sel, if so, a field can be created
314	 *  b) obj has a method named setPrefix + Sel, if so, the field is mutable, otherwise it is read-only
315	 *
316	 * The accessor method cannot take any arguments, the mutator method must have a unary arity.
317	 *
318	 * @param natObject the native AT object in whose class the accessor/mutator methods should be found
319	 * @param atSelector the AmbientTalk name of the field
320	 * @return a reified field, which may either be read-only or mutable depending on available methods
321	 * 
322	 * Example:
323	 *  eval "(reflect: msg).getField('selector')" where msg is a NATMessage
324	 *  => downField(aNATMessage, "selector", "base_get", "base_set")
325	 *  => NATMessage must have a zero-arg method base_getSelector and optionally base_setSelector
326	 */
327	public static final ATField downField(ATObject natObject, ATSymbol atSelector,
328			                              String getPrefix, String setPrefix) throws InterpreterException {
329		String fieldName = upFieldName(atSelector);
330		try {
331			Method accessorMethod = JavaInterfaceAdaptor.getNativeATMethod(natObject.getClass(), natObject, getPrefix + fieldName, atSelector);
332			Method mutatorMethod = null;
333			try {
334				mutatorMethod = JavaInterfaceAdaptor.getNativeATMethod(natObject.getClass(), natObject, setPrefix + fieldName, atSelector);
335			} catch (XSelectorNotFound e) {
336				// no setter, return a read-only field
337			}
338			return new NativeField(natObject, atSelector, accessorMethod, mutatorMethod);
339		} catch (XSelectorNotFound e) {
340			// selector not found exceptions have to be translated to field not found exceptions
341			throw new XUndefinedField("field access", atSelector.toString());
342		}
343	}
344	
345	public static final ATField downBaseLevelField(ATObject natObject, ATSymbol atSelector) throws InterpreterException {
346		return downField(natObject, atSelector, Reflection._BGET_PREFIX_, Reflection._BSET_PREFIX_);
347	}
348	
349	public static final ATField downMetaLevelField(ATObject natObject, ATSymbol atSelector) throws InterpreterException {
350		return downField(natObject, atSelector, Reflection._MGET_PREFIX_, Reflection._MSET_PREFIX_);
351	}
352	
353	/**
354	 * Constructs an AmbientTalk ATMethod from a Java method.
355	 * Given an object obj and a String sel, it is checked whether obj has a method
356	 * named sel. If so, the corresponding Java method is wrapped in a NativeMethod.
357	 * If not, the downing fails.
358	 *
359	 * @param natObject the native AmbientTalk object in whose class the method should be found
360	 * @param jSelector a selector which should yield a method in natObject
361	 * @param origName the original AmbientTalk name of the method
362	 * @return a reified method wrapping the Java method
363	 * 
364	 * Example:
365	 *  eval "(reflect: tbl).getMethod('at')" where tbl is a NATTable
366	 *  => downMethod(aNATTable, "base_at")
367	 *  => NATTable must have a method named base_at
368	 *  
369	 * Callers should use the more specialised 'downBaseLevelMethod' and 'downMetaLevelMethod'
370	 * methods to specify the prefix of the method to be found
371	 */
372	public static final ATMethod downMethod(ATObject natObject, String jSelector, ATSymbol origName) throws InterpreterException {
373		return new NativeMethod(JavaInterfaceAdaptor.getNativeATMethod(natObject.getClass(), natObject, jSelector, origName), origName);
374	}
375	
376	public static final ATMethod downBaseLevelMethod(ATObject natObject, ATSymbol atSelector) throws InterpreterException {
377		return downMethod(natObject, upBaseLevelSelector(atSelector), atSelector);
378	}
379	
380	public static final ATMethod downMetaLevelMethod(ATObject natObject, ATSymbol atSelector) throws InterpreterException {
381		return downMethod(natObject, upMetaLevelSelector(atSelector), atSelector);
382	}
383
384	/**
385	 * downInvocation takes an implicit Java invocation and turns it into an explicit
386	 * AmbientTalk invocation process. This happens when Java code sends normal
387	 * Java messages to AmbientTalk objects (wrapped by a mirage).
388	 * 
389	 * @param atRcvr the AmbientTalk object having received the Java method invocation
390	 * @param jSelector the Java selector, to be converted to an AmbientTalk selector
391	 * @param jArgs the arguments to the Java method invocation (normally all args are ATObjects)
392	 * jArgs may be null, indicating that there are no arguments
393	 * @return the return value of the AmbientTalk method invoked via the java invocation.
394	 * 
395	 * Example:
396	 *  in Java: "tbl.base_at(1)" where tbl is an ATTable coercer wrapping aNATObject
397	 *  => downInvocation(aNATObject, "base_at", ATObject[] { ATNumber(1) })
398	 *  => aNATObject must implement a method named "at"
399	 *  
400	 * Depending on the prefix of the invoked Java method selector, the following translation should occur:
401	 *  - obj.base_selector(args) => obj.meta_invoke(obj, selector, args)
402	 *  - obj.base_getSelector() => obj.meta_select(obj, selector)
403	 *  - obj.base_setSelector(x) => obj.meta_assignField(selector, x)
404	 *  - obj.meta_selector(args) => obj.meta_selector(args)
405	 *  - obj.meta_set|getSelector(args) => obj.meta_set|getSelector(args)
406	 *  - obj.selector(args) => either obj.selector(args) if selector is understood natively
407	 *                          or     obj.meta_invoke(obj, selector, args) otherwise
408	 */
409	public static final ATObject downInvocation(ATObject atRcvr, Method jMethod, ATObject[] jArgs) throws InterpreterException {
410		String jSelector = jMethod.getName();
411		if (jArgs == null) { jArgs = NATTable.EMPTY.elements_; }
412		
413		if (jSelector.startsWith(Reflection._BGET_PREFIX_)) {
414			// obj.base_getSelector() => obj.meta_select(obj, selector)
415			if (jArgs.length != 0) {
416				throw new XArityMismatch(downBaseFieldAccessSelector(jSelector).toString(), 0, jArgs.length);
417			}
418			return atRcvr.meta_select(atRcvr, downBaseFieldAccessSelector(jSelector));
419		} else if (jSelector.startsWith(Reflection._BSET_PREFIX_)) {
420			// obj.base_setSelector(x) => obj.meta_assignField(selector, x)
421			if (jArgs.length != 1) {
422				throw new XArityMismatch(downBaseFieldMutationSelector(jSelector).toString(), 1, jArgs.length);
423			}
424			return atRcvr.meta_assignField(atRcvr, downBaseFieldMutationSelector(jSelector), jArgs[0]);
425		} else if (jSelector.startsWith(Reflection._BASE_PREFIX_)) {
426			// obj.base_selector(args) => obj.meta_invoke(obj, selector, args)
427			return atRcvr.meta_invoke(atRcvr, downBaseLevelSelector(jSelector), NATTable.atValue(jArgs));
428		} else if (jSelector.startsWith(Reflection._META_PREFIX_)) {
429			// obj.meta_selector(args) => obj.meta_selector(args)
430			return JavaInterfaceAdaptor.invokeNativeATMethod(jMethod, atRcvr, jArgs);
431		} else {
432			// atRcvr can respond to the given method natively
433			if (jMethod.getDeclaringClass().isInstance(atRcvr)) {
434				return JavaInterfaceAdaptor.invokeNativeATMethod(jMethod, atRcvr, jArgs);
435			} else {
436			    // obj.selector(args) => obj.meta_invoke(obj, selector, args)
437			    return atRcvr.meta_invoke(atRcvr, downSelector(jSelector), NATTable.atValue(jArgs));
438			}
439		}
440	}
441
442	/**
443	 * upInvocation takes an explicit AmbientTalk method invocation and turns it into an
444	 * implicitly performed Java invocation.
445	 * 
446	 * Depending on whether the AmbientTalk invocation happens at the base-level or the meta-level
447	 * (i.e. the receiver denotes a base-level object or a mirror), the jSelector parameter will have
448	 * a different prefix.
449	 * 
450	 * @param atOrigRcvr the original AmbientTalk object that received the invocation
451	 * @param jSelector the selector of the message to be invoked, converted to a Java selector
452	 * @param atArgs the arguments to the AmbientTalk method invocation
453	 * @return the return value of the Java method invoked via the java invocation.
454	 * 
455	 * Example:
456	 *  eval "tbl.at(1)" where tbl is a NATTable
457	 *  => upInvocation(aNATTable, "base_at", ATObject[] { ATNumber(1) })
458	 *  => NATTable must have a method named base_at
459	 * 
460	 * Example:
461	 *  eval "(reflect: tbl).invoke(tbl, "at", [1])" where tbl is a NATTable
462	 *  => upInvocation(aNATTable, "meta_invoke", ATObject[] { aNATTable, ATSymbol('at'), ATTable([ATNumber(1)]) })
463	 *  => NATTable must have a method named meta_invoke
464	 */
465	public static final ATObject upInvocation(ATObject atOrigRcvr, String jSelector, ATSymbol atSelector, ATTable atArgs) throws InterpreterException {
466		return JavaInterfaceAdaptor.invokeNativeATMethod(
467				    atOrigRcvr.getClass(),
468				    atOrigRcvr,
469					jSelector,
470					atSelector, atArgs.asNativeTable().elements_);
471	}
472	
473	/**
474	 * upRespondsTo transforms an explicit AmbientTalk respondsTo meta-level request
475	 * into an implicit check whether the given jRcvr java object has a method
476	 * corresponding to the given selector, prefixed with base_
477	 * 
478	 * @param jRcvr the Java object being queried for a certain selector
479	 * @param jSelector the selector of the message to be invoked, converted to a Java selector
480	 * @return a boolean indicating whether the jRcvr implements a method corresponding to base_ + atSelector
481	 * 
482	 * Example:
483	 *  eval "(reflect: [1,2,3]).respondsTo("at")" where the receiver of repondsTo is a NATTable
484	 *  => upRespondsTo(aNATTable, "at")
485	 *  => NATTable must have a method named base_at
486	 */
487	public static final boolean upRespondsTo(ATObject jRcvr,String jSelector) throws InterpreterException {
488		return JavaInterfaceAdaptor.hasApplicableJavaMethod(
489				jRcvr.getClass(),
490				jSelector);
491	}
492
493//	/**
494//	 * downSelection takes an implicit Java selection (in the guise of invoking a getter method)
495//	 * and turns it into an explicit AmbientTalk selection process. This happens when Java code sends normal
496//	 * Java messages to AmbientTalk objects (wrapped by a mirage).
497//	 * 
498//	 * @param atRcvr the AmbientTalk object having received the Java selection
499//	 * @param jSelector the Java selector, without the 'get' prefix, to be converted to an AmbientTalk selector
500//	 * @return the value of the AmbientTalk field selected by the java selection.
501//	 * 
502//	 * Example:
503//	 *  in Java: "msg.getSelector()" where msg is am ATMessage mirage wrapping a NATObject
504//	 *  => downSelection(aNATObject, "selector")
505//	 *  => aNATObject must implement a field named "selector"
506//	 * The get prefix is normally stripped off by a mirage
507//	 */
508//	public static final ATObject downSelection(ATObject atRcvr, String jSelector) {
509//		return null;
510//	}
511	
512	/**
513	 * upFieldSelection takes an explicit AmbientTalk field selection and turns it into 
514	 * an implicitly performed Java selection by invoking a getter method, if such a getter method
515	 * exists. 
516	 * 
517	 * @param atOrigRcvr the original AmbientTalk object that received the selection
518	 * @param jSelector the selector of the message to be invoked, already converted to a Java selector
519	 * @return the return value of the Java getter method invoked via the AmbientTalk selection.
520	 * 
521	 * Example:
522	 *  eval "msg.selector" where msg is a NATMessage
523	 *  => upSelection(aNATMessage, "selector")
524	 *  => NATMessage must have a zero-argument method named getSelector
525	 *  
526	 */
527	public static final ATObject upFieldSelection(ATObject atOrigRcvr, String jSelector, ATSymbol atSelector) throws InterpreterException {
528		return JavaInterfaceAdaptor.invokeNativeATMethod(
529				atOrigRcvr.getClass(),
530				atOrigRcvr,
531				jSelector,
532				atSelector, NATTable.EMPTY.elements_);		
533	}
534	
535	/**
536	 * upFieldAssignment takes an explicit AmbientTalk field assignment and turns it into 
537	 * an implicitly performed Java field assignment by invoking a mutator method, if such a method
538	 * exists. 
539	 * 
540	 * @param atOrigRcvr the original AmbientTalk object that received the assignField request
541	 * @param jSelector the selector of the message to be invoked, already converted to a Java selector
542	 * @return the return value of the Java mutator method invoked via the AmbientTalk assignField request.
543	 * 
544	 * Example:
545	 *  eval "msg.selector := v" where msg is a NATMessage
546	 *  => upFieldAssignment(aNATMessage, "selector", v)
547	 *  => NATMessage must have a one-argument method named base_setSelector
548	 *  
549	 */
550	public static final ATObject upFieldAssignment(ATObject atOrigRcvr, String jSelector, ATSymbol atSelector, ATObject value) throws InterpreterException {
551		return JavaInterfaceAdaptor.invokeNativeATMethod(
552				atOrigRcvr.getClass(),
553				atOrigRcvr,
554				jSelector,
555				atSelector, new ATObject[] { value });
556	}
557	
558	/**
559	 * upMethodSelection takes an explicit AmbientTalk field selection and checks whether 
560	 * a Java method exists that matches the selector. If so, this method is wrapped in a 
561	 * NativeClosure and returned.
562	 * 
563	 * @param atOrigRcvr the original AmbientTalk object that received the selection
564	 * @param jSelector the selector of the message to be invoked, converted to a Java selector
565	 * @return a closure wrapping the method selected via the AmbientTalk selection.
566	 * 
567	 * Example:
568	 *  eval "[1,2,3].at"
569	 *  => upSelection(aNATTable, "at")
570	 *  => either NATTable must have a method base_at, which is then wrapped
571	 */
572	public static final NativeClosure upMethodSelection(ATObject atOrigRcvr, String jSelector, ATSymbol origSelector) throws InterpreterException {
573		Method m = JavaInterfaceAdaptor.getNativeATMethod(atOrigRcvr.getClass(), atOrigRcvr, jSelector, origSelector);
574		return new NativeClosure(atOrigRcvr, new NativeMethod(m, origSelector));
575	}
576	
577	/**
578	 * upInstanceCreation takes an explicit AmbientTalk 'new' invocation and turns it into an
579	 * implicit Java instance creation by calling a constructor. The initargs are upped as well
580	 * and are passed as arguments to the constructor.
581	 * 
582	 * @param jRcvr the Java object having received the call to new
583	 * @param atInitargs the arguments to the constructor
584	 * @return a new instance of a Java class
585	 * @throws InterpreterException
586	 */
587	public static final ATObject upInstanceCreation(ATObject jRcvr, ATTable atInitargs) throws InterpreterException {
588		ATObject[] args = atInitargs.asNativeTable().elements_;
589		return JavaInterfaceAdaptor.createNativeATObject(jRcvr.getClass(), args);
590	}
591	
592	public static final ATObject upExceptionCreation(InterpreterException jRcvr, ATTable atInitargs) throws InterpreterException {
593		ATObject[] args = atInitargs.asNativeTable().elements_;
594		//return JavaInterfaceAdaptor.createNativeATObject(jRcvr.getClass(), args);
595		return new NATException((InterpreterException)
596				Symbiosis.symbioticInstanceCreation(jRcvr.getClass(), args)
597				  .asJavaObjectUnderSymbiosis().getWrappedObject());
598	}
599
600	/**
601	 * Pass an AmbientTalk meta-level object into the base-level
602	 */
603	public static final ATObject downObject(ATObject metaObject) throws InterpreterException {
604		return metaObject;
605		/*if (metaObject.meta_isStripedWith(NativeStripes._MIRROR_).asNativeBoolean().javaValue) {
606			return metaObject.meta_select(metaObject, OBJMirrorRoot._BASE_NAME_);
607		} else {
608			return metaObject; // most native objects represent both the object at the base and at the meta-level
609		}*/
610	}
611	
612	/**
613	 * Pass an AmbientTalk base-level object to the meta-level
614	 */
615	public static final ATObject upObject(ATObject baseObject) {
616		if (baseObject instanceof NATMirage) {
617			return ((NATMirage) baseObject).getMirror();
618		} else {
619			return baseObject;
620		}
621	}
622	
623	/**
624	 * Returns, for a given AmbientTalk object atObj, an array of NativeField objects corresponding
625	 * to all non-static methods of that object's Java class, where each method's name is prefixed with 'base_get'
626	 */
627	public static final ATField[] downBaseLevelFields(ATObject atObj) throws InterpreterException {
628		Method[] allBaseGetMethods =
629			JavaInterfaceAdaptor.allMethodsPrefixed(atObj.getClass(), Reflection._BGET_PREFIX_, false);
630		ATField[] fields = new ATField[allBaseGetMethods.length];
631		for (int i = 0; i < allBaseGetMethods.length; i++) {
632			Method m = allBaseGetMethods[i];
633			fields[i] = downBaseLevelField(atObj, downBaseFieldAccessSelector(m.getName()));
634		}
635		return fields;
636	}
637	
638	/**
639	 * Returns, for a given AmbientTalk object atObj, an array of NativeField objects corresponding
640	 * to all non-static methods of that object's Java class, where each method's name is prefixed with 'meta_get'
641	 */
642	public static final ATField[] downMetaLevelFields(ATObject atObj) throws InterpreterException {
643		Method[] allMetaGetMethods =
644			JavaInterfaceAdaptor.allMethodsPrefixed(atObj.getClass(), Reflection._MGET_PREFIX_, false);
645		ATField[] fields = new ATField[allMetaGetMethods.length];
646		for (int i = 0; i < allMetaGetMethods.length; i++) {
647			Method m = allMetaGetMethods[i];
648			fields[i] = downMetaLevelField(atObj, downMetaFieldAccessSelector(m.getName()));
649		}
650		return fields;
651	}
652	
653	/**
654	 * Returns, for a given AmbientTalk object atObj, an array of NativeMethod objects corresponding
655	 * to all non-static methods of that object's class, where each method's name:
656	 *  - is prefixed with 'base_'
657	 *  - is not prefixed with 'base_get'
658	 *  - is not prefixed with 'base_set'
659	 */
660	public static final ATMethod[] downBaseLevelMethods(ATObject atObj) throws InterpreterException {
661		Method[] allBaseMethods =
662			JavaInterfaceAdaptor.allMethodsPrefixed(atObj.getClass(), Reflection._BASE_PREFIX_, false);
663		Vector allNonFieldBaseMethods = new Vector();
664		for (int i = 0; i < allBaseMethods.length; i++) {
665			Method m = allBaseMethods[i];
666			String nam = m.getName();
667			if (!((nam.startsWith(Reflection._BGET_PREFIX_)) ||
668			      (nam.startsWith(Reflection._BSET_PREFIX_)))) {
669				allNonFieldBaseMethods.add(new NativeMethod(m, downBaseLevelSelector(nam)));
670			}
671		}
672		return (ATMethod[]) allNonFieldBaseMethods.toArray(new ATMethod[allNonFieldBaseMethods.size()]);
673	}
674	
675	/**
676	 * Returns, for a given AmbientTalk object natObj, an array of NativeMethod objects corresponding
677	 * to all non-static methods of that object's class, where each method's name:
678	 *  - is prefixed with 'meta_'
679	 *  - is not prefixed with 'meta_get'
680	 *  - is not prefixed with 'meta_set'
681	 */
682	public static final ATMethod[] downMetaLevelMethods(ATObject natObj) throws InterpreterException {
683		Method[] allMetaMethods =
684			JavaInterfaceAdaptor.allMethodsPrefixed(natObj.getClass(), Reflection._META_PREFIX_, false);
685		Vector allNonFieldMetaMethods = new Vector();
686		for (int i = 0; i < allMetaMethods.length; i++) {
687			Method m = allMetaMethods[i];
688			String nam = m.getName();
689			if (!((nam.startsWith(Reflection._MGET_PREFIX_)) ||
690			      (nam.startsWith(Reflection._MSET_PREFIX_)))) {
691				allNonFieldMetaMethods.add(new NativeMethod(m, downMetaLevelSelector(nam)));
692			}
693		}
694		return (ATMethod[]) allNonFieldMetaMethods.toArray(new ATMethod[allNonFieldMetaMethods.size()]);
695	}
696	
697	private static final Pattern oprCode = Pattern.compile("_op(\\w\\w\\w)_"); //'_op', 3 chars, '_'
698	private static final Pattern symbol = Pattern.compile("\\W"); //any non-word character
699	
700	private static String stripPrefix(String input, String prefix) {
701		// \A matches start of input
702	    // Backport from JDK 1.4 to 1.3
703        // return input.replaceFirst("\\A"+prefix, "");
704		return Pattern.compile("\\A"+prefix).matcher(new StringBuffer(input)).replaceFirst("");
705	}
706	
707	private static final String oprCode2Symbol(String code) {
708		switch (code.charAt(0)) {
709		  case 'p': if (code.equals("pls")) { return "+"; } else break;
710		  case 'm': if (code.equals("mns")) { return "-"; } else break;
711		  case 't': if (code.equals("tms")) { return "*"; } else
712			        if (code.equals("til")) { return "~"; } else break;
713		  case 'd': if (code.equals("div")) { return "/"; } else break;
714		  case 'b': if (code.equals("bsl")) { return "\\"; } else break;
715		  case 'a': if (code.equals("and")) { return "&"; } else break;
716		  case 'n': if (code.equals("not")) { return "!"; } else break;
717		  case 'g': if (code.equals("gtx")) { return ">"; } else break;
718		  case 'l': if (code.equals("ltx")) { return "<"; } else break;
719		  case 'e': if (code.equals("eql")) { return "="; } else break;
720		  case 'q': if (code.equals("que")) { return "?"; } else break;
721		  case 'r': if (code.equals("rem")) { return "%"; } else break;
722		}
723		return "_op" + code + "_"; // no match, return original input
724	}
725	
726	private static final String symbol2oprCode(String symbol) {
727		switch (symbol.charAt(0)) {
728		  case '+': return "pls";
729		  case '-': return "mns";
730		  case '*': return "tms";
731		  case '/': return "div";
732		  case '\\': return "bsl";
733		  case '&': return "and";
734		  case '!': return "not";
735		  case '>': return "gtx";
736		  case '<': return "ltx";
737		  case '=': return "eql";
738		  case '~': return "til";
739		  case '?': return "que";
740		  case '%': return "rem";
741		  default: return symbol; // no match, return original input
742		}	
743	}
744	
745	private static final String javaToAmbientTalkSelector(String jSelector) {
746		// _op{code}_ -> operator symbol
747		Matcher m = oprCode.matcher(new StringBuffer(jSelector));
748		StringBuffer sb = new StringBuffer();
749		while (m.find()) {
750             // find every occurence of _op\w\w\w_ and convert it into a symbol
751			m.appendReplacement(sb, oprCode2Symbol(m.group(1)));
752		}
753		m.appendTail(sb);
754		
755		// _ -> :
756        // Backport from JDK 1.4 to 1.3
757		// return sb.toString().replaceAll("_", ":");
758        return Pattern.compile("_").matcher(sb).replaceAll(":");
759	}
760	
761}