nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
changeset 18885 6b6801c3b81a
parent 18851 bdb92c95f886
child 19088 153f268bfa72
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Jul 16 16:12:26 2013 +0200
+++ b/nashorn/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());
     }
 
     /**