summaryrefslogtreecommitdiff
path: root/Libraries/LibJS
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-05-22 13:20:53 +0100
committerAndreas Kling <kling@serenityos.org>2020-05-22 17:43:44 +0200
commit4334a1b20864bd66148b11e684963868bfbbd1cf (patch)
tree771f6279c0021f14fb39e8f673d90fa25828ddf3 /Libraries/LibJS
parent9f7a6e116ac40e725644b78bb265fc041cc1ef16 (diff)
downloadserenity-4334a1b20864bd66148b11e684963868bfbbd1cf.zip
LibJS: Make Array.prototype.push() generic
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r--Libraries/LibJS/Runtime/ArrayPrototype.cpp27
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp5
-rw-r--r--Libraries/LibJS/Runtime/Value.h3
-rw-r--r--Libraries/LibJS/Tests/Array.prototype-generic-functions.js19
4 files changed, 42 insertions, 12 deletions
diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp
index b9ff84a0ab..569463d537 100644
--- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp
+++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp
@@ -168,12 +168,29 @@ Value ArrayPrototype::map(Interpreter& interpreter)
Value ArrayPrototype::push(Interpreter& interpreter)
{
- auto* array = array_from(interpreter);
- if (!array)
+ auto* this_object = interpreter.this_value().to_object(interpreter);
+ if (!this_object)
return {};
- for (size_t i = 0; i < interpreter.argument_count(); ++i)
- array->elements().append(interpreter.argument(i));
- return Value(array->length());
+ if (this_object->is_array()) {
+ auto* array = static_cast<Array*>(this_object);
+ for (size_t i = 0; i < interpreter.argument_count(); ++i)
+ array->elements().append(interpreter.argument(i));
+ return Value(array->length());
+ }
+ auto length = get_length(interpreter, *this_object);
+ if (interpreter.exception())
+ return {};
+ auto argument_count = interpreter.argument_count();
+ auto new_length = length + argument_count;
+ if (new_length > MAX_ARRAY_LIKE_INDEX)
+ return interpreter.throw_exception<TypeError>("Maximum array size exceeded");
+ for (size_t i = 0; i < argument_count; ++i)
+ this_object->put_by_index(length + i, interpreter.argument(i));
+ auto new_length_value = Value((i32)new_length);
+ this_object->put("length", new_length_value);
+ if (interpreter.exception())
+ return {};
+ return new_length_value;
}
Value ArrayPrototype::unshift(Interpreter& interpreter)
diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp
index dc45ea589b..80917df5d5 100644
--- a/Libraries/LibJS/Runtime/Value.cpp
+++ b/Libraries/LibJS/Runtime/Value.cpp
@@ -43,9 +43,6 @@
#include <LibJS/Runtime/Value.h>
#include <math.h>
-// 2 ** 53 - 1
-#define MAX_ARRAY_LIKE_INDEX 9007199254740991.0
-
namespace JS {
bool Value::is_array() const
@@ -261,7 +258,7 @@ i32 Value::as_i32() const
size_t Value::as_size_t() const
{
ASSERT(as_double() >= 0);
- return min((double)(i32)as_double(), MAX_ARRAY_LIKE_INDEX);
+ return min((double)as_i32(), MAX_ARRAY_LIKE_INDEX);
}
double Value::to_double(Interpreter& interpreter) const
diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h
index aa6f690a49..887a11ebcf 100644
--- a/Libraries/LibJS/Runtime/Value.h
+++ b/Libraries/LibJS/Runtime/Value.h
@@ -32,6 +32,9 @@
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Symbol.h>
+// 2 ** 53 - 1
+static constexpr double MAX_ARRAY_LIKE_INDEX = 9007199254740991.0;
+
namespace JS {
class Value {
diff --git a/Libraries/LibJS/Tests/Array.prototype-generic-functions.js b/Libraries/LibJS/Tests/Array.prototype-generic-functions.js
index 63d19532eb..d906d2be3b 100644
--- a/Libraries/LibJS/Tests/Array.prototype-generic-functions.js
+++ b/Libraries/LibJS/Tests/Array.prototype-generic-functions.js
@@ -1,11 +1,24 @@
load("test-common.js");
try {
+ [undefined, "foo", -42, 0].forEach(length => {
+ const o = { length };
+
+ assert(Array.prototype.push.call(o, "foo") === 1);
+ assert(o.length === 1);
+ assert(o[0] === "foo");
+ assert(Array.prototype.push.call(o, "bar", "baz") === 3);
+ assert(o.length === 3);
+ assert(o[0] === "foo");
+ assert(o[1] === "bar");
+ assert(o[2] === "baz");
+ });
+
const o = { length: 5, 0: "foo", 1: "bar", 3: "baz" };
- ["every"].forEach(name => {
+ {
const visited = [];
- Array.prototype[name].call(o, function (value) {
+ Array.prototype.every.call(o, function (value) {
visited.push(value);
return true;
});
@@ -13,7 +26,7 @@ try {
assert(visited[0] === "foo");
assert(visited[1] === "bar");
assert(visited[2] === "baz");
- });
+ }
["find", "findIndex"].forEach(name => {
const visited = [];