# HG changeset patch # User attila # Date 1377085180 -7200 # Node ID 6b73157185e05f5b178d1c38885db01c8a5e1950 # Parent 310246d552b736e0b13ad011fbaed3d2cb0fb83e 8022903: Enhance for-in and for-each for Lists and Maps Reviewed-by: lagergren, sundar diff -r 310246d552b7 -r 6b73157185e0 nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Aug 21 13:39:09 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Aug 21 13:39:40 2013 +0200 @@ -37,7 +37,9 @@ import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import jdk.internal.dynalink.beans.StaticClass; @@ -221,49 +223,71 @@ } /** - * Used to determine property iterator used in for in. - * @param obj Object to iterate on. - * @return Iterator. + * Returns an iterator over property identifiers used in the {@code for...in} statement. Note that the ECMAScript + * 5.1 specification, chapter 12.6.4. uses the terminology "property names", which seems to imply that the property + * identifiers are expected to be strings, but this is not actually spelled out anywhere, and Nashorn will in some + * cases deviate from this. Namely, we guarantee to always return an iterator over {@link String} values for any + * built-in JavaScript object. We will however return an iterator over {@link Integer} objects for native Java + * arrays and {@link List} objects, as well as arbitrary objects representing keys of a {@link Map}. Therefore, the + * expression {@code typeof i} within a {@code for(i in obj)} statement can return something other than + * {@code string} when iterating over native Java arrays, {@code List}, and {@code Map} objects. + * @param obj object to iterate on. + * @return iterator over the object's property names. */ - public static Iterator toPropertyIterator(final Object obj) { + public static Iterator toPropertyIterator(final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).propertyIterator(); } if (obj != null && obj.getClass().isArray()) { - final int length = Array.getLength(obj); - - return new Iterator() { - private int index = 0; - - @Override - public boolean hasNext() { - return index < length; - } - - @Override - public String next() { - return "" + index++; //TODO numeric property iterator? - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; + return new RangeIterator(Array.getLength(obj)); } if (obj instanceof ScriptObjectMirror) { return ((ScriptObjectMirror)obj).keySet().iterator(); } + if (obj instanceof List) { + return new RangeIterator(((List)obj).size()); + } + + if (obj instanceof Map) { + return ((Map)obj).keySet().iterator(); + } + return Collections.emptyIterator(); } + private static final class RangeIterator implements Iterator { + private final int length; + private int index; + + RangeIterator(int length) { + this.length = length; + } + + @Override + public boolean hasNext() { + return index < length; + } + + @Override + public Integer next() { + return index++; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + /** - * Used to determine property value iterator used in for each in. - * @param obj Object to iterate on. - * @return Iterator. + * Returns an iterator over property values used in the {@code for each...in} statement. Aside from built-in JS + * objects, it also operates on Java arrays, any {@link Iterable}, as well as on {@link Map} objects, iterating over + * map values. + * @param obj object to iterate on. + * @return iterator over the object's property values. */ public static Iterator toValueIterator(final Object obj) { if (obj instanceof ScriptObject) { @@ -301,6 +325,10 @@ return ((ScriptObjectMirror)obj).values().iterator(); } + if (obj instanceof Map) { + return ((Map)obj).values().iterator(); + } + if (obj instanceof Iterable) { return ((Iterable)obj).iterator(); } diff -r 310246d552b7 -r 6b73157185e0 nashorn/test/script/basic/JDK-8022903.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8022903.js Wed Aug 21 13:39:40 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8022903: Enhance for-in and for-each for Lists and Maps + * + * @test + * @run + */ + +var colors = new java.util.ArrayList() +colors.add("red") +colors.add("purple") +colors.add("pink") + +for(var index in colors) { + print("colors[" + index + "]=" + colors[index]) +} + +for each(var color in colors) { + print(color) +} + +var capitals = new java.util.LinkedHashMap() +capitals.Sweden = "Stockholm" +capitals.Hungary = "Budapet" +capitals.Croatia = "Zagreb" + +for(var key in capitals) { + print("capital of " + key + " is " + capitals[key]) +} + +for each(var capital in capitals) { + print(capital) +} diff -r 310246d552b7 -r 6b73157185e0 nashorn/test/script/basic/JDK-8022903.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8022903.js.EXPECTED Wed Aug 21 13:39:40 2013 +0200 @@ -0,0 +1,12 @@ +colors[0]=red +colors[1]=purple +colors[2]=pink +red +purple +pink +capital of Sweden is Stockholm +capital of Hungary is Budapet +capital of Croatia is Zagreb +Stockholm +Budapet +Zagreb