зеркало из https://github.com/mozilla/pjs.git
I've made changes to Rhino such that its default behavior is now only to treat
Iterables or Iterators specially when they are arguments to the new Iterator constructor: js> m = new java.util.HashMap() {} js> m.put("a",1) null js> m.put("b",2) null js> m {a=1.0, b=2.0} js> for (i in m.values()) print(i) notifyAll removeAll containsAll contains empty equals notify class isEmpty add size iterator clear wait retainAll toString hashCode toArray addAll getClass remove js> for (i in Iterator(m.values())) print(i) 1.0 2.0 js> for (i in Iterator(m.values().iterator())) print(i) 1.0 2.0 js> Since Iterator is a new addition for 1.7, there are no issues for backwards compatibility. This still leaves open the possibility of top-level functions to wrap Maps and Lists as JavaScript Objects and Arrays.
This commit is contained in:
Родитель
a1eb01d71b
Коммит
25a7cab519
|
@ -640,20 +640,6 @@ class JavaMembers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For objects that implement java.lang.Iterable, provide a
|
|
||||||
// __iterator__ property
|
|
||||||
if (iterableClass != null && iterableClass.isAssignableFrom(cl) &&
|
|
||||||
members.get(NativeIterator.ITERATOR_PROPERTY_NAME) == null &&
|
|
||||||
staticMembers.get(NativeIterator.ITERATOR_PROPERTY_NAME) == null)
|
|
||||||
{
|
|
||||||
Method m = VMBridge.instance.getIteratorMethod();
|
|
||||||
if (m != null) {
|
|
||||||
members.put(NativeIterator.ITERATOR_PROPERTY_NAME,
|
|
||||||
new FunctionObject(NativeIterator.ITERATOR_PROPERTY_NAME,
|
|
||||||
m, scope));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflect constructors
|
// Reflect constructors
|
||||||
Constructor[] constructors = getAccessibleConstructors();
|
Constructor[] constructors = getAccessibleConstructors();
|
||||||
ctors = new MemberBox[constructors.length];
|
ctors = new MemberBox[constructors.length];
|
||||||
|
@ -874,7 +860,6 @@ class JavaMembers
|
||||||
private Hashtable staticFieldAndMethods;
|
private Hashtable staticFieldAndMethods;
|
||||||
MemberBox[] ctors;
|
MemberBox[] ctors;
|
||||||
private boolean includePrivate;
|
private boolean includePrivate;
|
||||||
private static Class iterableClass = Kit.classOrNull("java.lang.Iterable");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BeanProperty
|
class BeanProperty
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
package org.mozilla.javascript;
|
package org.mozilla.javascript;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements iterator objects. See
|
* This class implements iterator objects. See
|
||||||
* http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Iterators
|
* http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Iterators
|
||||||
|
@ -161,10 +163,24 @@ public final class NativeIterator extends IdScriptableObject {
|
||||||
boolean keyOnly = args.length > 1 && ScriptRuntime.toBoolean(args[1]);
|
boolean keyOnly = args.length > 1 && ScriptRuntime.toBoolean(args[1]);
|
||||||
if (thisObj != null) {
|
if (thisObj != null) {
|
||||||
// Called as a function. Convert to iterator if possible.
|
// Called as a function. Convert to iterator if possible.
|
||||||
Scriptable iterator = ScriptRuntime.toIterator(cx, scope, obj,
|
|
||||||
keyOnly);
|
// For objects that implement java.lang.Iterable or
|
||||||
|
// java.util.Iterator, have JavaScript Iterator call the underlying
|
||||||
|
// iteration methods
|
||||||
|
Iterator iterator =
|
||||||
|
VMBridge.instance.getJavaIterator(cx, scope, obj);
|
||||||
if (iterator != null) {
|
if (iterator != null) {
|
||||||
return iterator;
|
scope = ScriptableObject.getTopLevelScope(scope);
|
||||||
|
return cx.getWrapFactory().wrap(cx, scope,
|
||||||
|
new WrappedJavaIterator(iterator, scope),
|
||||||
|
WrappedJavaIterator.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, just call the runtime routine
|
||||||
|
Scriptable jsIterator = ScriptRuntime.toIterator(cx, scope, obj,
|
||||||
|
keyOnly);
|
||||||
|
if (jsIterator != null) {
|
||||||
|
return jsIterator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +210,30 @@ public final class NativeIterator extends IdScriptableObject {
|
||||||
return cx.newArray(scope, elements);
|
return cx.newArray(scope, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public class WrappedJavaIterator
|
||||||
|
{
|
||||||
|
WrappedJavaIterator(Iterator iterator, Scriptable scope) {
|
||||||
|
this.iterator = iterator;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object next() {
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
// Out of values. Throw StopIteration.
|
||||||
|
throw new JavaScriptException(
|
||||||
|
NativeIterator.getStopIterationObject(scope), null, 0);
|
||||||
|
}
|
||||||
|
return iterator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object __iterator__(boolean b) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator iterator;
|
||||||
|
private Scriptable scope;
|
||||||
|
}
|
||||||
|
|
||||||
// #string_id_map#
|
// #string_id_map#
|
||||||
|
|
||||||
protected int findPrototypeId(String s) {
|
protected int findPrototypeId(String s) {
|
||||||
|
|
|
@ -41,6 +41,7 @@ package org.mozilla.javascript;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
public abstract class VMBridge
|
public abstract class VMBridge
|
||||||
{
|
{
|
||||||
|
@ -165,10 +166,18 @@ public abstract class VMBridge
|
||||||
protected abstract boolean isVarArgs(Member member);
|
protected abstract boolean isVarArgs(Member member);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return method corresponding to __iterator__ for treating a
|
* If "obj" is a java.util.Iterator or a java.lang.Iterable, return a
|
||||||
* java.lang.Iterable as a JavaScript Iterator
|
* wrapping as a JavaScript Iterator. Otherwise, return null.
|
||||||
|
* This method is in VMBridge since Iterable is a JDK 1.5 addition.
|
||||||
*/
|
*/
|
||||||
public Method getIteratorMethod() {
|
public Iterator getJavaIterator(Context cx, Scriptable scope, Object obj) {
|
||||||
|
if (obj instanceof Wrapper) {
|
||||||
|
Object unwrapped = ((Wrapper) obj).unwrap();
|
||||||
|
Iterator iterator = null;
|
||||||
|
if (unwrapped instanceof Iterator)
|
||||||
|
iterator = (Iterator) unwrapped;
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class VMBridge_jdk15 extends org.mozilla.javascript.jdk13.VMBridge_jdk13
|
||||||
// so that we can load a bridge to an older JDK instead.
|
// so that we can load a bridge to an older JDK instead.
|
||||||
Method.class.getMethod("isVarArgs", (Class[]) null);
|
Method.class.getMethod("isVarArgs", (Class[]) null);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
// Throw a fittitng exception that is handled by
|
// Throw a fitting exception that is handled by
|
||||||
// org.mozilla.javascript.Kit.newInstanceOrNull:
|
// org.mozilla.javascript.Kit.newInstanceOrNull:
|
||||||
throw new InstantiationException(e.getMessage());
|
throw new InstantiationException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -67,55 +67,21 @@ public class VMBridge_jdk15 extends org.mozilla.javascript.jdk13.VMBridge_jdk13
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method getIteratorMethod() {
|
/**
|
||||||
try {
|
* If "obj" is a java.util.Iterator or a java.lang.Iterable, return a
|
||||||
Class[] sig = { Context.class, Scriptable.class,
|
* wrapping as a JavaScript Iterator. Otherwise, return null.
|
||||||
ScriptRuntime.emptyArgs.getClass(),
|
* This method is in VMBridge since Iterable is a JDK 1.5 addition.
|
||||||
Function.class };
|
*/
|
||||||
return VMBridge_jdk15.class.getMethod("__iterator__", sig);
|
public Iterator getJavaIterator(Context cx, Scriptable scope, Object obj) {
|
||||||
} catch (NoSuchMethodException e) {
|
if (obj instanceof Wrapper) {
|
||||||
|
Object unwrapped = ((Wrapper) obj).unwrap();
|
||||||
|
Iterator iterator = null;
|
||||||
|
if (unwrapped instanceof Iterator)
|
||||||
|
iterator = (Iterator) unwrapped;
|
||||||
|
if (unwrapped instanceof Iterable)
|
||||||
|
iterator = ((Iterable)unwrapped).iterator();
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object __iterator__(Context cx, Scriptable thisObj,
|
|
||||||
Object[] args, Function funObj)
|
|
||||||
{
|
|
||||||
if (thisObj instanceof Wrapper) {
|
|
||||||
Object obj = ((Wrapper) thisObj).unwrap();
|
|
||||||
if (obj instanceof Iterable) {
|
|
||||||
Scriptable scope = ScriptableObject.getTopLevelScope(funObj);
|
|
||||||
return cx.getWrapFactory().wrap(cx, scope,
|
|
||||||
new WrappedJavaIterator((Iterable) obj, scope),
|
|
||||||
WrappedJavaIterator.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw ScriptRuntime.typeError1("msg.incompat.call",
|
|
||||||
NativeIterator.ITERATOR_PROPERTY_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static public class WrappedJavaIterator
|
|
||||||
{
|
|
||||||
WrappedJavaIterator(Iterable iterable, Scriptable scope) {
|
|
||||||
this.iterator = iterable.iterator();
|
|
||||||
this.scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object next() {
|
|
||||||
if (!iterator.hasNext()) {
|
|
||||||
// Out of values. Throw StopIteration.
|
|
||||||
throw new JavaScriptException(
|
|
||||||
NativeIterator.getStopIterationObject(scope), null, 0);
|
|
||||||
}
|
|
||||||
return iterator.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object __iterator__() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Iterator iterator;
|
|
||||||
private Scriptable scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче