1414 *
1515 * @author Norris Boyd
1616 */
17- public final class NativeIterator extends IdScriptableObject {
17+ public final class NativeIterator extends ScriptableObject {
1818 private static final long serialVersionUID = -4136968203581667681L ;
1919 private static final Object ITERATOR_TAG = "Iterator" ;
20+ private static final String CLASS_NAME = "Iterator" ;
21+
22+ private Object objectIterator ;
2023
2124 static void init (Context cx , ScriptableObject scope , boolean sealed ) {
22- // Iterator
23- NativeIterator iterator = new NativeIterator ();
24- iterator .exportAsJSClass (MAX_PROTOTYPE_ID , scope , sealed );
25+ LambdaConstructor constructor =
26+ new LambdaConstructor (
27+ scope ,
28+ CLASS_NAME ,
29+ 2 ,
30+ NativeIterator ::jsConstructorCall ,
31+ NativeIterator ::jsConstructor );
32+ constructor .setPrototypePropertyAttributes (PERMANENT | READONLY | DONTENUM );
33+
34+ NativeIterator proto = new NativeIterator ();
35+ constructor .setPrototypeScriptable (proto );
36+
37+ constructor .definePrototypeMethod (scope , "next" , 0 , NativeIterator ::js_next );
38+ constructor .definePrototypeMethod (
39+ scope , ITERATOR_PROPERTY_NAME , 1 , NativeIterator ::js_iteratorMethod );
40+
41+ ScriptableObject .defineProperty (scope , CLASS_NAME , constructor , ScriptableObject .DONTENUM );
42+ if (sealed ) {
43+ constructor .sealObject ();
44+ ((ScriptableObject ) constructor .getPrototypeProperty ()).sealObject ();
45+ }
2546
2647 // Generator
2748 if (cx .getLanguageVersion () >= Context .VERSION_ES6 ) {
@@ -98,95 +119,59 @@ public boolean hasInstance(Scriptable instance) {
98119
99120 @ Override
100121 public String getClassName () {
101- return "Iterator" ;
122+ return CLASS_NAME ;
102123 }
103124
104- @ Override
105- protected void initPrototypeId (int id ) {
106- String s ;
107- int arity ;
108- switch (id ) {
109- case Id_constructor :
110- arity = 2 ;
111- s = "constructor" ;
112- break ;
113- case Id_next :
114- arity = 0 ;
115- s = "next" ;
116- break ;
117- case Id___iterator__ :
118- arity = 1 ;
119- s = ITERATOR_PROPERTY_NAME ;
120- break ;
121- default :
122- throw new IllegalArgumentException (String .valueOf (id ));
123- }
124- initPrototypeMethod (ITERATOR_TAG , id , s , arity );
125- }
125+ private static Object jsConstructorCall (
126+ Context cx , Scriptable scope , Scriptable thisObj , Object [] args ) {
127+ Scriptable target = requireIteratorTarget (cx , scope , args );
128+ boolean keyOnly = isKeyOnly (args );
126129
127- @ Override
128- public Object execIdCall (
129- IdFunctionObject f , Context cx , Scriptable scope , Scriptable thisObj , Object [] args ) {
130- if (!f .hasTag (ITERATOR_TAG )) {
131- return super .execIdCall (f , cx , scope , thisObj , args );
130+ Iterator <?> iterator = getJavaIterator (target );
131+ if (iterator != null ) {
132+ Scriptable topScope = ScriptableObject .getTopLevelScope (scope );
133+ return cx .getWrapFactory ()
134+ .wrap (
135+ cx ,
136+ topScope ,
137+ new WrappedJavaIterator (iterator , topScope ),
138+ WrappedJavaIterator .class );
132139 }
133- int id = f .methodId ();
134140
135- if (id == Id_constructor ) {
136- return jsConstructor (cx , scope , thisObj , args );
141+ Scriptable jsIterator = ScriptRuntime .toIterator (cx , target , keyOnly );
142+ if (jsIterator != null ) {
143+ return jsIterator ;
137144 }
138145
139- NativeIterator iterator = ensureType (thisObj , NativeIterator .class , f );
140-
141- switch (id ) {
142- case Id_next :
143- return iterator .next (cx , scope );
144-
145- case Id___iterator__ :
146- /// XXX: what about argument? SpiderMonkey apparently ignores it
147- return thisObj ;
146+ return createNativeIterator (cx , scope , target , keyOnly );
147+ }
148148
149- default :
150- throw new IllegalArgumentException (String .valueOf (id ));
151- }
149+ private static Scriptable jsConstructor (Context cx , Scriptable scope , Object [] args ) {
150+ Scriptable target = requireIteratorTarget (cx , scope , args );
151+ boolean keyOnly = isKeyOnly (args );
152+ return createNativeIterator (cx , scope , target , keyOnly );
152153 }
153154
154- /* The JavaScript constructor */
155- private static Object jsConstructor (
156- Context cx , Scriptable scope , Scriptable thisObj , Object [] args ) {
155+ private static Scriptable requireIteratorTarget (Context cx , Scriptable scope , Object [] args ) {
157156 if (args .length == 0 || args [0 ] == null || args [0 ] == Undefined .instance ) {
158157 Object argument = args .length == 0 ? Undefined .instance : args [0 ];
159158 throw ScriptRuntime .typeErrorById (
160159 "msg.no.properties" , ScriptRuntime .toString (argument ));
161160 }
162- Scriptable obj = ScriptRuntime .toObject (cx , scope , args [0 ]);
163- boolean keyOnly = args .length > 1 && ScriptRuntime .toBoolean (args [1 ]);
164- if (thisObj != null ) {
165- // Called as a function. Convert to iterator if possible.
166-
167- // For objects that implement java.lang.Iterable or
168- // java.util.Iterator, have JavaScript Iterator call the underlying
169- // iteration methods
170- Iterator <?> iterator = getJavaIterator (obj );
171- if (iterator != null ) {
172- scope = ScriptableObject .getTopLevelScope (scope );
173- return cx .getWrapFactory ()
174- .wrap (
175- cx ,
176- scope ,
177- new WrappedJavaIterator (iterator , scope ),
178- WrappedJavaIterator .class );
179- }
161+ return ScriptRuntime .toObject (cx , scope , args [0 ]);
162+ }
180163
181- // Otherwise, just call the runtime routine
182- Scriptable jsIterator = ScriptRuntime .toIterator (cx , obj , keyOnly );
183- if (jsIterator != null ) {
184- return jsIterator ;
185- }
186- }
164+ private static boolean isKeyOnly (Object [] args ) {
165+ return args .length > 1 && ScriptRuntime .toBoolean (args [1 ]);
166+ }
167+
168+ private static Object js_next (Context cx , Scriptable scope , Scriptable thisObj , Object [] args ) {
169+ NativeIterator iterator = realThis (thisObj );
170+ return iterator .next (cx , scope );
171+ }
187172
188- // Otherwise, just set up to iterate over the properties of the object.
189- // Do not call __iterator__ method.
173+ private static NativeIterator createNativeIterator (
174+ Context cx , Scriptable scope , Scriptable obj , boolean keyOnly ) {
190175 Object objectIterator =
191176 ScriptRuntime .enumInit (
192177 obj ,
@@ -197,14 +182,23 @@ private static Object jsConstructor(
197182 : ScriptRuntime .ENUMERATE_ARRAY_NO_ITERATOR );
198183 ScriptRuntime .setEnumNumbers (objectIterator , true );
199184 NativeIterator result = new NativeIterator (objectIterator );
200- result .setPrototype (ScriptableObject .getClassPrototype (scope , result . getClassName () ));
185+ result .setPrototype (ScriptableObject .getClassPrototype (scope , CLASS_NAME ));
201186 result .setParentScope (scope );
202187 return result ;
203188 }
204189
190+ private static Object js_iteratorMethod (
191+ Context cx , Scriptable scope , Scriptable thisObj , Object [] args ) {
192+ return realThis (thisObj );
193+ }
194+
195+ private static NativeIterator realThis (Scriptable thisObj ) {
196+ return LambdaConstructor .convertThisObject (thisObj , NativeIterator .class );
197+ }
198+
205199 private Object next (Context cx , Scriptable scope ) {
206200 Boolean b = ScriptRuntime .enumNext (this .objectIterator , cx );
207- if (!b . booleanValue () ) {
201+ if (!b ) {
208202 // Out of values. Throw StopIteration.
209203 throw new JavaScriptException (NativeIterator .getStopIterationObject (scope ), null , 0 );
210204 }
@@ -227,6 +221,9 @@ private static Iterator<?> getJavaIterator(Object obj) {
227221 }
228222
229223 public static class WrappedJavaIterator {
224+ private final Iterator <?> iterator ;
225+ private final Scriptable scope ;
226+
230227 WrappedJavaIterator (Iterator <?> iterator , Scriptable scope ) {
231228 this .iterator = iterator ;
232229 this .scope = scope ;
@@ -244,35 +241,5 @@ public Object next() {
244241 public Object __iterator__ (boolean b ) {
245242 return this ;
246243 }
247-
248- private Iterator <?> iterator ;
249- private Scriptable scope ;
250244 }
251-
252- @ Override
253- protected int findPrototypeId (String s ) {
254- int id ;
255- switch (s ) {
256- case "constructor" :
257- id = Id_constructor ;
258- break ;
259- case "next" :
260- id = Id_next ;
261- break ;
262- case "__iterator__" :
263- id = Id___iterator__ ;
264- break ;
265- default :
266- id = 0 ;
267- break ;
268- }
269- return id ;
270- }
271-
272- private static final int Id_constructor = 1 ,
273- Id_next = 2 ,
274- Id___iterator__ = 3 ,
275- MAX_PROTOTYPE_ID = 3 ;
276-
277- private Object objectIterator ;
278245}
0 commit comments