diff options
author | Linus Groh <mail@linusgroh.de> | 2020-05-22 15:04:52 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-22 17:43:44 +0200 |
commit | 040c75a3cc8ae4ac87bcc03bf741b47bc688d2a0 (patch) | |
tree | b9caf3c7ac84e5f6a2444f63fd7678a0285e43fc /Libraries/LibJS | |
parent | e9ee06b19e78a44b2715967579ab7584672eeb63 (diff) | |
download | serenity-040c75a3cc8ae4ac87bcc03bf741b47bc688d2a0.zip |
LibJS: Make Array.prototype.{join,toString}() generic
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r-- | Libraries/LibJS/Runtime/ArrayPrototype.cpp | 55 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ObjectPrototype.h | 4 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Array.prototype-generic-functions.js | 16 |
3 files changed, 48 insertions, 27 deletions
diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index 83be93ba4c..ecd14217c1 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -35,6 +35,7 @@ #include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/MarkedValueList.h> +#include <LibJS/Runtime/ObjectPrototype.h> #include <LibJS/Runtime/Value.h> namespace JS { @@ -240,46 +241,48 @@ Value ArrayPrototype::shift(Interpreter& interpreter) return array->elements().take_first().value_or(js_undefined()); } -static Value join_array_with_separator(Interpreter& interpreter, const Array& array, StringView separator) -{ - StringBuilder builder; - for (size_t i = 0; i < array.elements().size(); ++i) { - if (i != 0) - builder.append(separator); - auto value = array.elements()[i]; - if (!value.is_empty() && !value.is_undefined() && !value.is_null()) { - auto string = value.to_string(interpreter); - if (interpreter.exception()) - return {}; - builder.append(string); - } - } - return js_string(interpreter, builder.to_string()); -} - Value ArrayPrototype::to_string(Interpreter& interpreter) { - auto* array = array_from(interpreter); - if (!array) + auto* this_object = interpreter.this_value().to_object(interpreter); + if (!this_object) return {}; - - return join_array_with_separator(interpreter, *array, ","); + auto join_function = this_object->get("join"); + if (interpreter.exception()) + return {}; + if (!join_function.is_function()) + return ObjectPrototype::to_string(interpreter); + return interpreter.call(join_function.as_function(), this_object); } Value ArrayPrototype::join(Interpreter& interpreter) { - auto* array = array_from(interpreter); - if (!array) + auto* this_object = interpreter.this_value().to_object(interpreter); + if (!this_object) return {}; - String separator = ","; if (interpreter.argument_count()) { separator = interpreter.argument(0).to_string(interpreter); if (interpreter.exception()) return {}; } - - return join_array_with_separator(interpreter, *array, separator); + auto length = get_length(interpreter, *this_object); + if (interpreter.exception()) + return {}; + StringBuilder builder; + for (size_t i = 0; i < length; ++i) { + if (i > 0) + builder.append(separator); + auto value = this_object->get_by_index(i).value_or(js_undefined()); + if (interpreter.exception()) + return {}; + if (value.is_undefined() || value.is_null()) + continue; + auto string = value.to_string(interpreter); + if (interpreter.exception()) + return {}; + builder.append(string); + } + return js_string(interpreter, builder.to_string()); } Value ArrayPrototype::concat(Interpreter& interpreter) diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.h b/Libraries/LibJS/Runtime/ObjectPrototype.h index 737dadab8c..8e18b5bd3b 100644 --- a/Libraries/LibJS/Runtime/ObjectPrototype.h +++ b/Libraries/LibJS/Runtime/ObjectPrototype.h @@ -37,12 +37,14 @@ public: virtual ~ObjectPrototype() override; + // public to serve as intrinsic function %Object.prototype.toString% + static Value to_string(Interpreter&); + private: virtual const char* class_name() const override { return "ObjectPrototype"; } static Value has_own_property(Interpreter&); static Value value_of(Interpreter&); - static Value to_string(Interpreter&); }; } diff --git a/Libraries/LibJS/Tests/Array.prototype-generic-functions.js b/Libraries/LibJS/Tests/Array.prototype-generic-functions.js index aed23c4ad3..1b9848cf16 100644 --- a/Libraries/LibJS/Tests/Array.prototype-generic-functions.js +++ b/Libraries/LibJS/Tests/Array.prototype-generic-functions.js @@ -27,6 +27,22 @@ try { assert(o.length === 0); }); + { + assert(Array.prototype.join.call({}) === ""); + assert(Array.prototype.join.call({ length: "foo" }) === ""); + assert(Array.prototype.join.call({ length: 3 }) === ",,"); + assert(Array.prototype.join.call({ length: 2, 0: "foo", 1: "bar" }) === "foo,bar"); + assert(Array.prototype.join.call({ length: 2, 0: "foo", 1: "bar", 2: "baz" }) === "foo,bar"); + assert(Array.prototype.join.call({ length: 3, 1: "bar" }, "~") === "~bar~"); + assert(Array.prototype.join.call({ length: 3, 0: "foo", 1: "bar", 2: "baz" }, "~") === "foo~bar~baz"); + } + + { + assert(Array.prototype.toString.call({}) === "[object Object]"); + assert(Array.prototype.toString.call({ join: "foo" }) === "[object Object]"); + assert(Array.prototype.toString.call({ join: () => "foo" }) === "foo"); + } + const o = { length: 5, 0: "foo", 1: "bar", 3: "baz" }; { |