93 /** 94 * ES6 25.1.1.2 The Iterator Interface 95 * 96 * @param arg argument 97 * @return next iterator result 98 */ 99 protected abstract IteratorResult next(final Object arg); 100 101 /** 102 * ES6 25.1.1.3 The IteratorResult Interface 103 * 104 * @param value result value 105 * @param done result status 106 * @param global the global object 107 * @return result object 108 */ 109 protected IteratorResult makeResult(final Object value, final Boolean done, final Global global) { 110 return new IteratorResult(value, done, global); 111 } 112 113 /** 114 * ES6 7.4.1 GetIterator abstract operation 115 * 116 * @param iterable an object 117 * @param global the global object 118 * @return the iterator 119 */ 120 public static Object getIterator(final Object iterable, final Global global) { 121 final Object object = Global.toObject(iterable); 122 123 if (object instanceof ScriptObject) { 124 // TODO we need to implement fast property access for Symbol keys in order to use InvokeByName here. 125 final Object getter = ((ScriptObject) object).get(NativeSymbol.iterator); 126 127 if (Bootstrap.isCallable(getter)) { 128 try { 129 final MethodHandle invoker = global.getDynamicInvoker(ITERATOR_INVOKER_KEY, 130 () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class)); 131 132 final Object value = invoker.invokeExact(getter, iterable); 133 if (JSType.isPrimitive(value)) { 134 throw typeError("not.an.object", ScriptRuntime.safeToString(value)); 135 } 136 return value; 137 138 } catch (final Throwable t) { 139 throw new RuntimeException(t); 140 } 141 } 142 throw typeError("not.a.function", ScriptRuntime.safeToString(getter)); 143 } 144 145 throw typeError("cannot.get.iterator", ScriptRuntime.safeToString(iterable)); 146 } 147 148 /** 149 * Iterate over an iterable object, passing every value to {@code consumer}. 150 * 151 * @param iterable an iterable object 152 * @param global the current global 153 * @param consumer the value consumer 154 */ 155 public static void iterate(final Object iterable, final Global global, final Consumer<Object> consumer) { 156 157 final Object iterator = AbstractIterator.getIterator(Global.toObject(iterable), global); 158 159 final InvokeByName nextInvoker = global.getInvokeByName(AbstractIterator.NEXT_INVOKER_KEY, 160 () -> new InvokeByName("next", Object.class, Object.class, Object.class)); 161 final MethodHandle doneInvoker = global.getDynamicInvoker(AbstractIterator.DONE_INVOKER_KEY, 162 () -> Bootstrap.createDynamicInvoker("done", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 163 final MethodHandle valueInvoker = global.getDynamicInvoker(AbstractIterator.VALUE_INVOKER_KEY, 164 () -> Bootstrap.createDynamicInvoker("value", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 165 166 try { 167 do { 168 final Object next = nextInvoker.getGetter().invokeExact(iterator); 169 if (!Bootstrap.isCallable(next)) { 170 break; 171 } 172 173 final Object result = nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null); 174 if (!(result instanceof ScriptObject)) { 175 break; 176 } 177 178 final Object done = doneInvoker.invokeExact(result); 179 if (JSType.toBoolean(done)) { 180 break; 181 } 182 183 consumer.accept(valueInvoker.invokeExact(result)); 184 | 93 /** 94 * ES6 25.1.1.2 The Iterator Interface 95 * 96 * @param arg argument 97 * @return next iterator result 98 */ 99 protected abstract IteratorResult next(final Object arg); 100 101 /** 102 * ES6 25.1.1.3 The IteratorResult Interface 103 * 104 * @param value result value 105 * @param done result status 106 * @param global the global object 107 * @return result object 108 */ 109 protected IteratorResult makeResult(final Object value, final Boolean done, final Global global) { 110 return new IteratorResult(value, done, global); 111 } 112 113 static MethodHandle getIteratorInvoker(final Global global) { 114 return global.getDynamicInvoker(ITERATOR_INVOKER_KEY, 115 () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class)); 116 } 117 118 /** 119 * Get the invoker for the ES6 iterator {@code next} method. 120 * @param global the global object 121 * @return the next invoker 122 */ 123 public static InvokeByName getNextInvoker(final Global global) { 124 return global.getInvokeByName(AbstractIterator.NEXT_INVOKER_KEY, 125 () -> new InvokeByName("next", Object.class, Object.class, Object.class)); 126 } 127 128 /** 129 * Get the invoker for the ES6 iterator result {@code done} property. 130 * @param global the global object 131 * @return the done invoker 132 */ 133 public static MethodHandle getDoneInvoker(final Global global) { 134 return global.getDynamicInvoker(AbstractIterator.DONE_INVOKER_KEY, 135 () -> Bootstrap.createDynamicInvoker("done", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 136 } 137 138 /** 139 * Get the invoker for the ES6 iterator result {@code value} property. 140 * @param global the global object 141 * @return the value invoker 142 */ 143 public static MethodHandle getValueInvoker(final Global global) { 144 return global.getDynamicInvoker(AbstractIterator.VALUE_INVOKER_KEY, 145 () -> Bootstrap.createDynamicInvoker("value", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 146 } 147 148 /** 149 * ES6 7.4.1 GetIterator abstract operation 150 * 151 * @param iterable an object 152 * @param global the global object 153 * @return the iterator 154 */ 155 public static Object getIterator(final Object iterable, final Global global) { 156 final Object object = Global.toObject(iterable); 157 158 if (object instanceof ScriptObject) { 159 // TODO we need to implement fast property access for Symbol keys in order to use InvokeByName here. 160 final Object getter = ((ScriptObject) object).get(NativeSymbol.iterator); 161 162 if (Bootstrap.isCallable(getter)) { 163 try { 164 final MethodHandle invoker = getIteratorInvoker(global); 165 166 final Object value = invoker.invokeExact(getter, iterable); 167 if (JSType.isPrimitive(value)) { 168 throw typeError("not.an.object", ScriptRuntime.safeToString(value)); 169 } 170 return value; 171 172 } catch (final Throwable t) { 173 throw new RuntimeException(t); 174 } 175 } 176 throw typeError("not.a.function", ScriptRuntime.safeToString(getter)); 177 } 178 179 throw typeError("cannot.get.iterator", ScriptRuntime.safeToString(iterable)); 180 } 181 182 /** 183 * Iterate over an iterable object, passing every value to {@code consumer}. 184 * 185 * @param iterable an iterable object 186 * @param global the current global 187 * @param consumer the value consumer 188 */ 189 public static void iterate(final Object iterable, final Global global, final Consumer<Object> consumer) { 190 191 final Object iterator = AbstractIterator.getIterator(Global.toObject(iterable), global); 192 193 final InvokeByName nextInvoker = getNextInvoker(global); 194 final MethodHandle doneInvoker = getDoneInvoker(global); 195 final MethodHandle valueInvoker = getValueInvoker(global); 196 197 try { 198 do { 199 final Object next = nextInvoker.getGetter().invokeExact(iterator); 200 if (!Bootstrap.isCallable(next)) { 201 break; 202 } 203 204 final Object result = nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null); 205 if (!(result instanceof ScriptObject)) { 206 break; 207 } 208 209 final Object done = doneInvoker.invokeExact(result); 210 if (JSType.toBoolean(done)) { 211 break; 212 } 213 214 consumer.accept(valueInvoker.invokeExact(result)); 215 |