From 0b797d0d335dbea53f5ada06ec9a0b8f6fa6f7e7 Mon Sep 17 00:00:00 2001 From: RageKnify Date: Tue, 29 Sep 2020 21:03:48 +0100 Subject: [PATCH 1/3] Fix: Fix output of Object.toString(), closes boa-dev/boa#729 --- boa/src/builtins/object/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 7e488e1b26..acb1ffee79 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -115,9 +115,9 @@ impl Object { /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString #[allow(clippy::wrong_self_convention)] - pub fn to_string(this: &Value, _: &[Value], _: &mut Context) -> Result { + pub fn to_string(_: &Value, _: &[Value], _: &mut Context) -> Result { // FIXME: it should not display the object. - Ok(this.display().to_string().into()) + Ok("[object Object]".into()) } /// `Object.prototype.hasOwnPrototype( property )` From 5e3db42e63327ebf9439af55bf8d0a152a8337ba Mon Sep 17 00:00:00 2001 From: RageKnify Date: Thu, 1 Oct 2020 00:43:02 +0100 Subject: [PATCH 2/3] Fix: Make Object.toString() spec compliant* Test: Add testing of Object.toString(), need update once Function.prototype.call is implemented * not fully because Arguments Exotic Objects are not yet implemented --- boa/src/builtins/object/mod.rs | 30 ++++++++++++++++++++--- boa/src/builtins/object/tests.rs | 42 +++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index acb1ffee79..429303797e 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -115,9 +115,33 @@ impl Object { /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString #[allow(clippy::wrong_self_convention)] - pub fn to_string(_: &Value, _: &[Value], _: &mut Context) -> Result { - // FIXME: it should not display the object. - Ok("[object Object]".into()) + pub fn to_string(this: &Value, _: &[Value], ctx: &mut Context) -> Result { + if this.is_undefined() { + Ok("[object Undefined]".into()) + } else if this.is_null() { + Ok("[object Null]".into()) + } else { + let gc_o = this.to_object(ctx)?; + let o = gc_o.borrow(); + let builtin_tag = match &o.data { + ObjectData::Array => "Array", + // TODO: Arguments Exotic Objects are currently not supported + ObjectData::Function(_) => "Function", + ObjectData::Error => "Error", + ObjectData::Boolean(_) => "Boolean", + ObjectData::Number(_) => "Number", + ObjectData::String(_) => "String", + ObjectData::Date(_) => "Date", + ObjectData::RegExp(_) => "RegExp", + _ => "Object", + }; + + let tag = o.get(&ctx.well_known_symbols().to_string_tag_symbol().into()); + + let tag_str = tag.as_string().map(|s| s.as_str()).unwrap_or(builtin_tag); + + Ok(format!("[object {}]", tag_str).into()) + } } /// `Object.prototype.hasOwnPrototype( property )` diff --git a/boa/src/builtins/object/tests.rs b/boa/src/builtins/object/tests.rs index 7ea3f6478b..79a2dcfaf4 100644 --- a/boa/src/builtins/object/tests.rs +++ b/boa/src/builtins/object/tests.rs @@ -55,7 +55,7 @@ fn object_create_with_number() { #[test] #[ignore] -// to test on __proto__ somehow. __proto__ getter is not working as expected currently +// TODO: to test on __proto__ somehow. __proto__ getter is not working as expected currently fn object_create_with_function() { let mut engine = Context::new(); @@ -135,3 +135,43 @@ fn object_property_is_enumerable() { ); assert_eq!(forward(&mut engine, r#"x.propertyIsEnumerable()"#), "false",) } + +#[test] +fn object_to_string() { + let mut ctx = Context::new(); + let init = r#" + let u = undefined; + let n = null; + let a = []; + Array.prototype.toString = Object.prototype.toString; + let f = () => {}; + Function.prototype.toString = Object.prototype.toString; + let b = Boolean(); + Boolean.prototype.toString = Object.prototype.toString; + let i = Number(42); + Number.prototype.toString = Object.prototype.toString; + let s = String('boa'); + String.prototype.toString = Object.prototype.toString; + let d = new Date(Date.now()); + Date.prototype.toString = Object.prototype.toString; + let re = /boa/; + RegExp.prototype.toString = Object.prototype.toString; + "#; + eprintln!("{}", forward(&mut ctx, init)); + // TODO: need Function.prototype.call to be implemented + // assert_eq!( + // forward(&mut ctx, "Object.prototype.toString.call(u)"), + // "\"[object Undefined]\"" + // ); + // assert_eq!( + // forward(&mut ctx, "Object.prototype.toString.call(n)"), + // "\"[object Null]\"" + // ); + assert_eq!(forward(&mut ctx, "a.toString()"), "\"[object Array]\""); + assert_eq!(forward(&mut ctx, "f.toString()"), "\"[object Function]\""); + assert_eq!(forward(&mut ctx, "b.toString()"), "\"[object Boolean]\""); + assert_eq!(forward(&mut ctx, "i.toString()"), "\"[object Number]\""); + assert_eq!(forward(&mut ctx, "s.toString()"), "\"[object String]\""); + assert_eq!(forward(&mut ctx, "d.toString()"), "\"[object Date]\""); + assert_eq!(forward(&mut ctx, "re.toString()"), "\"[object RegExp]\""); +} From 05f076c2eb4237d1b12ec7c487fcc974840ed966 Mon Sep 17 00:00:00 2001 From: RageKnify Date: Thu, 1 Oct 2020 01:07:19 +0100 Subject: [PATCH 3/3] Test: Add test case for [object Object] --- boa/src/builtins/object/tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boa/src/builtins/object/tests.rs b/boa/src/builtins/object/tests.rs index 79a2dcfaf4..5c42f85fc9 100644 --- a/boa/src/builtins/object/tests.rs +++ b/boa/src/builtins/object/tests.rs @@ -156,6 +156,7 @@ fn object_to_string() { Date.prototype.toString = Object.prototype.toString; let re = /boa/; RegExp.prototype.toString = Object.prototype.toString; + let o = Object(); "#; eprintln!("{}", forward(&mut ctx, init)); // TODO: need Function.prototype.call to be implemented @@ -174,4 +175,5 @@ fn object_to_string() { assert_eq!(forward(&mut ctx, "s.toString()"), "\"[object String]\""); assert_eq!(forward(&mut ctx, "d.toString()"), "\"[object Date]\""); assert_eq!(forward(&mut ctx, "re.toString()"), "\"[object RegExp]\""); + assert_eq!(forward(&mut ctx, "o.toString()"), "\"[object Object]\""); }