Skip to content

Commit

Permalink
Fix: Make Object.toString() spec compliant*
Browse files Browse the repository at this point in the history
Test: Add testing of Object.toString(), need update once
Function.prototype.call is implemented

* not fully because Arguments Exotic Objects are not yet implemented
  • Loading branch information
RageKnify committed Sep 30, 2020
1 parent 0b797d0 commit 5e3db42
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
30 changes: 27 additions & 3 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Value> {
// FIXME: it should not display the object.
Ok("[object Object]".into())
pub fn to_string(this: &Value, _: &[Value], ctx: &mut Context) -> Result<Value> {
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 )`
Expand Down
42 changes: 41 additions & 1 deletion boa/src/builtins/object/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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]\"");
}

0 comments on commit 5e3db42

Please sign in to comment.