changeset 449:78bdb8a7f1e7

8015356: array concatenation should skip empty elements Reviewed-by: jlaskey, sundar
author attila
date Tue, 16 Jul 2013 17:03:30 +0200
parents 7503f30c1355
children 81cbb18d558a e1d19f9fd5a9
files src/jdk/nashorn/internal/objects/NativeArray.java test/script/basic/JDK-8015356.js test/script/basic/JDK-8015356.js.EXPECTED
diffstat 3 files changed, 86 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Jul 16 16:12:26 2013 +0200
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Jul 16 17:03:30 2013 +0200
@@ -552,35 +552,40 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static Object concat(final Object self, final Object... args) {
         final ArrayList<Object> list = new ArrayList<>();
-        final Object selfToObject = Global.toObject(self);
+        concatToList(list, Global.toObject(self));
+
+        for (final Object obj : args) {
+            concatToList(list, obj);
+        }
+
+        return new NativeArray(list.toArray());
+    }
 
-        if (isArray(selfToObject)) {
-            final Iterator<Object> iter = arrayLikeIterator(selfToObject, true);
-            while (iter.hasNext()) {
-                list.add(iter.next());
+    private static void concatToList(final ArrayList<Object> list, final Object obj) {
+        final boolean isScriptArray = isArray(obj);
+        final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject;
+        if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
+            final Iterator<Object> iter = arrayLikeIterator(obj, true);
+            if (iter.hasNext()) {
+                for(int i = 0; iter.hasNext(); ++i) {
+                    final Object value = iter.next();
+                    if(value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) {
+                        // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling
+                        // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE,
+                        // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it
+                        // into the concatenated array.
+                        list.add(ScriptRuntime.EMPTY);
+                    } else {
+                        list.add(value);
+                    }
+                }
+            } else if (!isScriptArray) {
+                list.add(obj); // add empty object, but not an empty array
             }
         } else {
             // single element, add it
-            list.add(selfToObject);
+            list.add(obj);
         }
-
-        for (final Object obj : args) {
-            if (isArray(obj) || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) {
-                final Iterator<Object> iter = arrayLikeIterator(obj, true);
-                if (iter.hasNext()) {
-                    while (iter.hasNext()) {
-                        list.add(iter.next());
-                    }
-                } else if (!isArray(obj)) {
-                    list.add(obj); // add empty object, but not an empty array
-                }
-            } else {
-                // single element, add it
-                list.add(obj);
-            }
-        }
-
-        return new NativeArray(list.toArray());
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8015356.js	Tue Jul 16 17:03:30 2013 +0200
@@ -0,0 +1,44 @@
+/*
+ * 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-8015355: Array concatenation should ignore empty array elements.
+ * 
+ * @test
+ * @run
+ */
+
+print("***")
+print([].concat([,]).hasOwnProperty("0"))
+
+print("***")
+var x = [].concat([,'a',,'b',,'c'])
+for(var i in x) {
+  print(i + ": " + x[i])
+}
+
+print("***")
+x = x.concat(['d',,'e',,'f',,])
+for(var i in x) {
+  print(i + ": " + x[i])
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8015356.js.EXPECTED	Tue Jul 16 17:03:30 2013 +0200
@@ -0,0 +1,13 @@
+***
+false
+***
+1: a
+3: b
+5: c
+***
+1: a
+3: b
+5: c
+6: d
+8: e
+10: f