Ver Fonte

LibJS: Support spreading of strings and string objects

Linus Groh há 5 anos atrás
pai
commit
30fe1b5d58

+ 23 - 13
Libraries/LibJS/AST.cpp

@@ -39,6 +39,7 @@
 #include <LibJS/Runtime/PrimitiveString.h>
 #include <LibJS/Runtime/Reference.h>
 #include <LibJS/Runtime/ScriptFunction.h>
+#include <LibJS/Runtime/StringObject.h>
 #include <LibJS/Runtime/Value.h>
 #include <stdio.h>
 
@@ -1127,21 +1128,30 @@ Value ArrayExpression::execute(Interpreter& interpreter) const
                 return {};
 
             if (element->is_spread_expression()) {
-                if (!value.is_array()) {
-                    interpreter.throw_exception<TypeError>(String::format("%s is not iterable", value.to_string().characters()));
-                    return {};
-                }
-
-                auto& array_to_spread = static_cast<Array&>(value.as_object());
-                for (auto& it : array_to_spread.elements()) {
-                    if (it.is_empty()) {
-                        array->elements().append(js_undefined());
-                    } else {
-                        array->elements().append(it);
+                // FIXME: Support arbitrary iterables
+                if (value.is_array()) {
+                    auto& array_to_spread = static_cast<Array&>(value.as_object());
+                    for (auto& it : array_to_spread.elements()) {
+                        if (it.is_empty()) {
+                            array->elements().append(js_undefined());
+                        } else {
+                            array->elements().append(it);
+                        }
                     }
+                    continue;
                 }
-
-                continue;
+                if (value.is_string() || (value.is_object() && value.as_object().is_string_object())) {
+                    String string_to_spread;
+                    if (value.is_string())
+                        string_to_spread = value.as_string()->string();
+                    else
+                        string_to_spread = static_cast<StringObject*>(&value.as_object())->primitive_string()->string();
+                    for (size_t i = 0; i < string_to_spread.length(); ++i)
+                        array->elements().append(js_string(interpreter, string_to_spread.substring(i, 1)));
+                    continue;
+                }
+                interpreter.throw_exception<TypeError>(String::format("%s is not iterable", value.to_string().characters()));
+                return {};
             }
         }
         array->elements().append(value);

+ 6 - 6
Libraries/LibJS/Tests/array-spread.js

@@ -24,17 +24,17 @@ try {
     assert(testArray(arr));
 
     assertThrowsError(() => {
-      [...1];
+        [...1];
     }, {
-      error: TypeError,
-      message: "1 is not iterable",
+        error: TypeError,
+        message: "1 is not iterable",
     });
 
     assertThrowsError(() => {
-      [...{}];
+        [...{}];
     }, {
-      error: TypeError,
-      message: "[object Object] is not iterable",
+        error: TypeError,
+        message: "[object Object] is not iterable",
     });
 
     console.log("PASS");

+ 31 - 0
Libraries/LibJS/Tests/string-spread.js

@@ -0,0 +1,31 @@
+load("test-common.js");
+
+function testArray(arr) {
+    return arr.length === 4 &&
+        arr[0] === "a" &&
+        arr[1] === "b" &&
+        arr[2] === "c" &&
+        arr[3] === "d";
+}
+
+try {
+    var arr;
+
+    arr = ["a", ..."bc", "d"];
+    assert(testArray(arr));
+
+    let s = "bc";
+    arr = ["a", ...s, "d"];
+    assert(testArray(arr));
+
+    let obj = { a: "bc" };
+    arr = ["a", ...obj.a, "d"];
+    assert(testArray(arr));
+
+    arr = [..."", ...[...new String("abc")], "d"];
+    assert(testArray(arr));
+
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}