AbstractIterator.java revision 1626:d99fa86747ee
1221828Sgrehan/* 2221828Sgrehan * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3221828Sgrehan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4221828Sgrehan * 5221828Sgrehan * This code is free software; you can redistribute it and/or modify it 6221828Sgrehan * under the terms of the GNU General Public License version 2 only, as 7221828Sgrehan * published by the Free Software Foundation. Oracle designates this 8221828Sgrehan * particular file as subject to the "Classpath" exception as provided 9221828Sgrehan * by Oracle in the LICENSE file that accompanied this code. 10221828Sgrehan * 11221828Sgrehan * This code is distributed in the hope that it will be useful, but WITHOUT 12221828Sgrehan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13221828Sgrehan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14221828Sgrehan * version 2 for more details (a copy is included in the LICENSE file that 15221828Sgrehan * accompanied this code). 16221828Sgrehan * 17221828Sgrehan * You should have received a copy of the GNU General Public License version 18221828Sgrehan * 2 along with this work; if not, write to the Free Software Foundation, 19221828Sgrehan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20221828Sgrehan * 21221828Sgrehan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22221828Sgrehan * or visit www.oracle.com if you need additional information or have any 23221828Sgrehan * questions. 24221828Sgrehan */ 25221828Sgrehan 26221828Sgrehanpackage jdk.nashorn.internal.objects; 27221828Sgrehan 28221828Sgrehanimport java.lang.invoke.MethodHandle; 29221828Sgrehanimport java.util.function.Consumer; 30221828Sgrehanimport jdk.nashorn.internal.objects.annotations.Attribute; 31221828Sgrehanimport jdk.nashorn.internal.objects.annotations.Function; 32221828Sgrehanimport jdk.nashorn.internal.objects.annotations.ScriptClass; 33221828Sgrehanimport jdk.nashorn.internal.runtime.JSType; 34221828Sgrehanimport jdk.nashorn.internal.runtime.PropertyMap; 35221828Sgrehanimport jdk.nashorn.internal.runtime.ScriptObject; 36221828Sgrehanimport jdk.nashorn.internal.runtime.ScriptRuntime; 37221828Sgrehanimport jdk.nashorn.internal.runtime.linker.Bootstrap; 38221828Sgrehanimport jdk.nashorn.internal.runtime.linker.InvokeByName; 39221828Sgrehanimport jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 40221828Sgrehan 41221828Sgrehanimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 42221828Sgrehan 43221828Sgrehan/** 44221828Sgrehan * ECMA6 25.1.2 The %IteratorPrototype% Object 45221828Sgrehan */ 46221828Sgrehan@ScriptClass("Iterator") 47221828Sgrehanpublic abstract class AbstractIterator extends ScriptObject { 48221828Sgrehan 49221828Sgrehan // initialized by nasgen 50221828Sgrehan private static PropertyMap $nasgenmap$; 51221828Sgrehan 52221828Sgrehan private final static Object ITERATOR_INVOKER_KEY = new Object(); 53221828Sgrehan private final static Object NEXT_INVOKER_KEY = new Object(); 54221828Sgrehan private final static Object DONE_INVOKER_KEY = new Object(); 55221828Sgrehan private final static Object VALUE_INVOKER_KEY = new Object(); 56221828Sgrehan 57221828Sgrehan /** ECMA6 iteration kinds */ 58221828Sgrehan enum IterationKind { 59221828Sgrehan /** key iteration */ 60221828Sgrehan KEY, 61221828Sgrehan /** value iteration */ 62221828Sgrehan VALUE, 63221828Sgrehan /** key+value iteration */ 64221828Sgrehan KEY_VALUE 65221828Sgrehan } 66221828Sgrehan 67221828Sgrehan /** 68221828Sgrehan * Create an abstract iterator object with the given prototype and property map. 69221828Sgrehan * 70221828Sgrehan * @param prototype the prototype 71221828Sgrehan * @param map the property map 72221828Sgrehan */ 73221828Sgrehan protected AbstractIterator(final ScriptObject prototype, final PropertyMap map) { 74221828Sgrehan super(prototype, map); 75221828Sgrehan } 76221828Sgrehan 77221828Sgrehan /** 78221828Sgrehan * 25.1.2.1 %IteratorPrototype% [ @@iterator ] ( ) 79221828Sgrehan * 80221828Sgrehan * @param self the self object 81221828Sgrehan * @return this iterator 82221828Sgrehan */ 83221828Sgrehan @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator") 84221828Sgrehan public static Object getIterator(final Object self) { 85221828Sgrehan return self; 86221828Sgrehan } 87221828Sgrehan 88221828Sgrehan @Override 89221828Sgrehan public String getClassName() { 90221828Sgrehan return "Iterator"; 91221828Sgrehan } 92221828Sgrehan 93221828Sgrehan /** 94221828Sgrehan * ES6 25.1.1.2 The Iterator Interface 95221828Sgrehan * 96221828Sgrehan * @param arg argument 97221828Sgrehan * @return next iterator result 98221828Sgrehan */ 99221828Sgrehan protected abstract IteratorResult next(final Object arg); 100221828Sgrehan 101221828Sgrehan /** 102221828Sgrehan * ES6 25.1.1.3 The IteratorResult Interface 103221828Sgrehan * 104221828Sgrehan * @param value result value 105221828Sgrehan * @param done result status 106221828Sgrehan * @param global the global object 107221828Sgrehan * @return result object 108221828Sgrehan */ 109221828Sgrehan protected IteratorResult makeResult(final Object value, final Boolean done, final Global global) { 110221828Sgrehan return new IteratorResult(value, done, global); 111221828Sgrehan } 112221828Sgrehan 113221828Sgrehan /** 114221828Sgrehan * ES6 7.4.1 GetIterator abstract operation 115221828Sgrehan * 116221828Sgrehan * @param iterable an object 117221828Sgrehan * @param global the global object 118221828Sgrehan * @return the iterator 119221828Sgrehan */ 120221828Sgrehan public static Object getIterator(final Object iterable, final Global global) { 121221828Sgrehan final Object object = Global.toObject(iterable); 122221828Sgrehan 123221828Sgrehan if (object instanceof ScriptObject) { 124221828Sgrehan // TODO we need to implement fast property access for Symbol keys in order to use InvokeByName here. 125221828Sgrehan final Object getter = ((ScriptObject) object).get(NativeSymbol.iterator); 126221828Sgrehan 127221828Sgrehan if (Bootstrap.isCallable(getter)) { 128221828Sgrehan try { 129221828Sgrehan final MethodHandle invoker = global.getDynamicInvoker(ITERATOR_INVOKER_KEY, 130221828Sgrehan () -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class)); 131221828Sgrehan 132221828Sgrehan final Object value = invoker.invokeExact(getter, iterable); 133221828Sgrehan if (JSType.isPrimitive(value)) { 134221828Sgrehan throw typeError("not.an.object", ScriptRuntime.safeToString(value)); 135221828Sgrehan } 136221828Sgrehan return value; 137221828Sgrehan 138221828Sgrehan } catch (final Throwable t) { 139221828Sgrehan throw new RuntimeException(t); 140221828Sgrehan } 141221828Sgrehan } 142221828Sgrehan throw typeError("not.a.function", ScriptRuntime.safeToString(getter)); 143221828Sgrehan } 144221828Sgrehan 145221828Sgrehan throw typeError("cannot.get.iterator", ScriptRuntime.safeToString(iterable)); 146221828Sgrehan } 147221828Sgrehan 148221828Sgrehan /** 149221828Sgrehan * Iterate over an iterable object, passing every value to {@code consumer}. 150221828Sgrehan * 151221828Sgrehan * @param iterable an iterable object 152221828Sgrehan * @param global the current global 153221828Sgrehan * @param consumer the value consumer 154221828Sgrehan */ 155221828Sgrehan public static void iterate(final Object iterable, final Global global, final Consumer<Object> consumer) { 156221828Sgrehan 157221828Sgrehan final Object iterator = AbstractIterator.getIterator(Global.toObject(iterable), global); 158221828Sgrehan 159221828Sgrehan final InvokeByName nextInvoker = global.getInvokeByName(AbstractIterator.NEXT_INVOKER_KEY, 160221828Sgrehan () -> new InvokeByName("next", Object.class, Object.class, Object.class)); 161221828Sgrehan final MethodHandle doneInvoker = global.getDynamicInvoker(AbstractIterator.DONE_INVOKER_KEY, 162221828Sgrehan () -> Bootstrap.createDynamicInvoker("done", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 163221828Sgrehan final MethodHandle valueInvoker = global.getDynamicInvoker(AbstractIterator.VALUE_INVOKER_KEY, 164221828Sgrehan () -> Bootstrap.createDynamicInvoker("value", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class)); 165221828Sgrehan 166221828Sgrehan try { 167221828Sgrehan do { 168221828Sgrehan final Object next = nextInvoker.getGetter().invokeExact(iterator); 169221828Sgrehan if (!Bootstrap.isCallable(next)) { 170221828Sgrehan break; 171221828Sgrehan } 172221828Sgrehan 173221828Sgrehan final Object result = nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null); 174221828Sgrehan if (!(result instanceof ScriptObject)) { 175221828Sgrehan break; 176221828Sgrehan } 177221828Sgrehan 178221828Sgrehan final Object done = doneInvoker.invokeExact(result); 179221828Sgrehan if (JSType.toBoolean(done)) { 180221828Sgrehan break; 181221828Sgrehan } 182221828Sgrehan 183221828Sgrehan consumer.accept(valueInvoker.invokeExact(result)); 184221828Sgrehan 185221828Sgrehan } while (true); 186221828Sgrehan 187221828Sgrehan } catch (final RuntimeException r) { 188221828Sgrehan throw r; 189221828Sgrehan } catch (final Throwable t) { 190221828Sgrehan throw new RuntimeException(t); 191221828Sgrehan } 192221828Sgrehan 193221828Sgrehan } 194221828Sgrehan} 195221828Sgrehan 196221828Sgrehan 197221828Sgrehan