summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2020-07-11 10:11:37 -0700
committerAndreas Kling <kling@serenityos.org>2020-07-11 23:13:29 +0200
commit5ecd504f4e158b1c95b10c88b019b5a2ad232c10 (patch)
tree6ca1a71a1d7cff5170a0b6ea5d1f83d6de932845 /Libraries
parentcaa11503b1df4abde41c16a5435a49be8222ba5d (diff)
downloadserenity-5ecd504f4e158b1c95b10c88b019b5a2ad232c10.zip
LibJS: Implement spec-compliant Object.prototype.toString
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/Runtime/ObjectPrototype.cpp37
-rw-r--r--Libraries/LibJS/Runtime/ProxyObject.h2
-rw-r--r--Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js4
-rw-r--r--Libraries/LibJS/Tests/builtins/Object/Object.prototype.toString.js22
4 files changed, 53 insertions, 12 deletions
diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Libraries/LibJS/Runtime/ObjectPrototype.cpp
index 2d49372eb4..051af847ec 100644
--- a/Libraries/LibJS/Runtime/ObjectPrototype.cpp
+++ b/Libraries/LibJS/Runtime/ObjectPrototype.cpp
@@ -68,10 +68,43 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
{
- auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
+ auto this_value = interpreter.this_value(global_object);
+
+ if (this_value.is_undefined())
+ return js_string(interpreter, "[object Undefined]");
+ if (this_value.is_null())
+ return js_string(interpreter, "[object Null]");
+
+ auto* this_object = this_value.to_object(interpreter, global_object);
if (!this_object)
return {};
- return js_string(interpreter, String::format("[object %s]", this_object->class_name()));
+
+ String tag;
+ auto to_string_tag = this_object->get(interpreter.well_known_symbol_to_string_tag());
+
+ if (to_string_tag.is_string()) {
+ tag = to_string_tag.as_string().string();
+ } else if (this_object->is_array()) {
+ tag = "Array";
+ } else if (this_object->is_function()) {
+ tag = "Function";
+ } else if (this_object->is_error()) {
+ tag = "Error";
+ } else if (this_object->is_boolean_object()) {
+ tag = "Boolean";
+ } else if (this_object->is_number_object()) {
+ tag = "Number";
+ } else if (this_object->is_string_object()) {
+ tag = "String";
+ } else if (this_object->is_date()) {
+ tag = "Date";
+ } else if (this_object->is_regexp_object()) {
+ tag = "RegExp";
+ } else {
+ tag = "Object";
+ }
+
+ return js_string(interpreter, String::format("[object %s]", tag.characters()));
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string)
diff --git a/Libraries/LibJS/Runtime/ProxyObject.h b/Libraries/LibJS/Runtime/ProxyObject.h
index 83451712eb..04fb8178b0 100644
--- a/Libraries/LibJS/Runtime/ProxyObject.h
+++ b/Libraries/LibJS/Runtime/ProxyObject.h
@@ -64,8 +64,8 @@ public:
private:
virtual void visit_children(Visitor&) override;
virtual bool is_proxy_object() const override { return true; }
- virtual bool is_function() const override { return m_target.is_function(); }
+ virtual bool is_function() const override { return m_target.is_function(); }
virtual bool is_array() const override { return m_target.is_array(); };
Object& m_target;
diff --git a/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js b/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
index a08a33601d..e951dbbe8f 100644
--- a/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
+++ b/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
@@ -16,9 +16,7 @@ describe("normal behavior", () => {
});
test("number stringification differs from regular toString, for now", () => {
- expect([1, 2, 3].toLocaleString()).toBe(
- "[object NumberObject],[object NumberObject],[object NumberObject]"
- );
+ expect([1, 2, 3].toLocaleString()).toBe("[object Number],[object Number],[object Number]");
});
test("null and undefined result in empty strings", () => {
diff --git a/Libraries/LibJS/Tests/builtins/Object/Object.prototype.toString.js b/Libraries/LibJS/Tests/builtins/Object/Object.prototype.toString.js
index 95001ed3f6..c5d6d77b0e 100644
--- a/Libraries/LibJS/Tests/builtins/Object/Object.prototype.toString.js
+++ b/Libraries/LibJS/Tests/builtins/Object/Object.prototype.toString.js
@@ -1,8 +1,18 @@
-test("basic functionality", () => {
+test("length", () => {
expect(Object.prototype.toString).toHaveLength(0);
- // FIXME: The tag is ObjectPrototype, but should be Object
- // expect(Object.prototype.toString()).toBe("[object Object]");
- expect({ foo: 1 }.toString()).toBe("[object Object]");
- expect([].toString()).toBe("");
- expect(Object.prototype.toString.call([])).toBe("[object Array]");
+});
+
+test("result for various object types", () => {
+ const oToString = o => Object.prototype.toString.call(o);
+
+ expect(oToString(undefined)).toBe("[object Undefined]");
+ expect(oToString(null)).toBe("[object Null]");
+ expect(oToString([])).toBe("[object Array]");
+ expect(oToString(function () {})).toBe("[object Function]");
+ expect(oToString(new Error())).toBe("[object Error]");
+ expect(oToString(new Boolean())).toBe("[object Boolean]");
+ expect(oToString(new Number())).toBe("[object Number]");
+ expect(oToString(new Date())).toBe("[object Date]");
+ expect(oToString(new RegExp())).toBe("[object RegExp]");
+ expect(oToString({})).toBe("[object Object]");
});