From 84bedd74fd7ab4acb1039867ccf54816add9a739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Wed, 6 May 2020 11:57:05 +0100 Subject: [PATCH 01/16] Fix #172, quotes around value in fmt for ValueData::String --- boa/src/builtins/value/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 8e8bdadd5ba..6f4a981c6f8 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -838,7 +838,7 @@ impl Display for ValueData { Self::String(ref v) => write!(f, "{}", format!("Symbol({})", v)), _ => write!(f, "Symbol()"), }, - Self::String(ref v) => write!(f, "{}", v), + Self::String(ref v) => write!(f, "\"{}\"", v), Self::Rational(v) => write!( f, "{}", From 97bef40b46f6b71a4b510b7079a1d21ff5c6e496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Thu, 28 May 2020 23:59:36 +0100 Subject: [PATCH 02/16] Revert "Fix #172, quotes around value in fmt for ValueData::String" This reverts commit 84bedd74fd7ab4acb1039867ccf54816add9a739. --- boa/src/builtins/value/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 71fae1707ac..0d3f86672cb 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -965,7 +965,7 @@ impl Display for ValueData { Self::String(ref v) => write!(f, "{}", format!("Symbol({})", v)), _ => write!(f, "Symbol()"), }, - Self::String(ref v) => write!(f, "\"{}\"", v), + Self::String(ref v) => write!(f, "{}", v), Self::Rational(v) => write!( f, "{}", From 54e5c600b00e6a9c4109e88425c47c32dddf6bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Fri, 29 May 2020 00:13:54 +0100 Subject: [PATCH 03/16] Implement DisplayValueData as discussed in #373 Allow separation of internal representation from REPL representation --- boa/src/builtins/value/mod.rs | 36 +++++++++++++++++++++++++++++++++-- boa_cli/src/main.rs | 8 ++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 0d3f86672cb..10a9b93a86b 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -145,6 +145,13 @@ impl Value { } } +impl<'vd> Value { + /// Returns a REPL representation of the contained `ValueData` + pub fn display(&'vd self) -> DisplayValueData<'vd> { + self.data().display() + } +} + impl Deref for Value { type Target = ValueData; @@ -763,6 +770,13 @@ impl ValueData { } } +impl<'vd> ValueData { + /// Returns a REPL representation of the `ValueData` + fn display(&'vd self) -> DisplayValueData<'vd> { + DisplayValueData::new(self) + } +} + impl Default for ValueData { fn default() -> Self { Self::Undefined @@ -894,7 +908,7 @@ pub(crate) fn log_string_from(x: &ValueData, print_internals: bool) -> String { } } - _ => format!("{}", x), + _ => format!("{}", x.display()), } } @@ -947,7 +961,7 @@ pub(crate) fn display_obj(v: &ValueData, print_internals: bool) -> String { format!("{{\n{}\n{}}}", result, closing_indent) } else { // Every other type of data is printed as is - format!("{}", data) + format!("{}", data.display()) } } @@ -982,3 +996,21 @@ impl Display for ValueData { } } } + +#[derive(Debug, Clone)] +pub struct DisplayValueData<'vd>(pub(crate) &'vd ValueData); + +impl<'vd> DisplayValueData<'vd> { + fn new(vd: &'vd ValueData) -> Self { + DisplayValueData(vd) + } +} + +impl<'vd> Display for DisplayValueData<'vd> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 { + ValueData::String(ref v) => write!(f, "\"{}\"", v), + _ => self.0.fmt(f), + } + } +} diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index a24c941a39c..9ec6d581265 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -189,8 +189,8 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match forward_val(&mut engine, &buffer) { - Ok(v) => print!("{}", v.to_string()), - Err(v) => eprint!("{}", v.to_string()), + Ok(v) => print!("{}", v.display()), + Err(v) => eprint!("{}", v.display()), } } } @@ -208,8 +208,8 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match forward_val(&mut engine, buffer.trim_end()) { - Ok(v) => println!("{}", v.to_string()), - Err(v) => eprintln!("{}", v.to_string()), + Ok(v) => println!("{}", v.display()), + Err(v) => eprintln!("{}", v.display()), } } From 5adb7af82ebc4d6144542538a669340be6538a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Fri, 29 May 2020 15:04:49 +0100 Subject: [PATCH 04/16] Change DisplayValueData to ValueDisplay, as requested by @HalidOdat --- boa/src/builtins/value/mod.rs | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 10a9b93a86b..5003819aec9 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -145,10 +145,10 @@ impl Value { } } -impl<'vd> Value { +impl<'value> Value { /// Returns a REPL representation of the contained `ValueData` - pub fn display(&'vd self) -> DisplayValueData<'vd> { - self.data().display() + pub fn display(&'value self) -> ValueDisplay<'value> { + ValueDisplay::new(self) } } @@ -770,13 +770,6 @@ impl ValueData { } } -impl<'vd> ValueData { - /// Returns a REPL representation of the `ValueData` - fn display(&'vd self) -> DisplayValueData<'vd> { - DisplayValueData::new(self) - } -} - impl Default for ValueData { fn default() -> Self { Self::Undefined @@ -908,7 +901,7 @@ pub(crate) fn log_string_from(x: &ValueData, print_internals: bool) -> String { } } - _ => format!("{}", x.display()), + _ => format!("{}", x), } } @@ -961,7 +954,7 @@ pub(crate) fn display_obj(v: &ValueData, print_internals: bool) -> String { format!("{{\n{}\n{}}}", result, closing_indent) } else { // Every other type of data is printed as is - format!("{}", data.display()) + format!("{}", data) } } @@ -998,17 +991,17 @@ impl Display for ValueData { } #[derive(Debug, Clone)] -pub struct DisplayValueData<'vd>(pub(crate) &'vd ValueData); +pub struct ValueDisplay<'value>(&'value Value); -impl<'vd> DisplayValueData<'vd> { - fn new(vd: &'vd ValueData) -> Self { - DisplayValueData(vd) +impl<'value> ValueDisplay<'value> { + fn new(vd: &'value Value) -> Self { + ValueDisplay(vd) } } -impl<'vd> Display for DisplayValueData<'vd> { +impl<'value> Display for ValueDisplay<'value> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { + match self.0.data() { ValueData::String(ref v) => write!(f, "\"{}\"", v), _ => self.0.fmt(f), } From 9e44b5cf65a71971f6e3a1d06f401b4b48ae354b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Fri, 26 Jun 2020 04:11:34 +0100 Subject: [PATCH 05/16] Change display_obj so that it calls data.display() --- boa/src/builtins/value/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/builtins/value/display.rs b/boa/src/builtins/value/display.rs index 9176431564d..30c045dcd6f 100644 --- a/boa/src/builtins/value/display.rs +++ b/boa/src/builtins/value/display.rs @@ -165,8 +165,8 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { format!("{{\n{}\n{}}}", result, closing_indent) } else { - // Every other type of data is printed as is - format!("{}", data) + // Every other type of data is printed with the display method + format!("{}", data.display()) } } From 830773eda279272e1b33829288c9f73f16724711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Fri, 26 Jun 2020 04:45:31 +0100 Subject: [PATCH 06/16] Change log_string_from so that it calls x.display() --- boa/src/builtins/value/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/builtins/value/display.rs b/boa/src/builtins/value/display.rs index 30c045dcd6f..972f533ff9e 100644 --- a/boa/src/builtins/value/display.rs +++ b/boa/src/builtins/value/display.rs @@ -113,7 +113,7 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool) -> String { } } Value::Symbol(ref symbol) => symbol.to_string(), - _ => format!("{}", x), + _ => format!("{}", x.display()), } } From a3b4355b1d375ee54e45cfe5e142657f79141165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Sun, 28 Jun 2020 16:26:38 +0100 Subject: [PATCH 07/16] Add tests for displaying String values --- boa/src/builtins/value/tests.rs | 69 ++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index c3bd570ca27..12cd3527361 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{forward, forward_val, Interpreter, Realm}; +use crate::{exec, forward, forward_val, Interpreter, Realm}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -213,3 +213,70 @@ fn get_types() { Type::Symbol ); } + +#[test] +fn display_string() { + let s = String::from("Hello"); + let v = Value::from(s); + assert_eq!(v.display().to_string(), "\"Hello\""); +} + +#[test] +fn display_array_string() { + let d_arr = r#" + let a = ["Hello"]; + a + "#; + assert_eq!(&exec(d_arr), "[ \"Hello\" ]"); +} + +#[test] +fn display_object() { + let d_obj = r#" + let o = {a: 'a'}; + o + "#; + assert_eq!( + &exec(d_obj), + r#"{ + a: "a", +__proto__: { +constructor: { +setPrototypeOf: { + length: 2 + }, + prototype: [Cycle], + name: "Object", + length: 1, +defineProperty: { + length: 3 + }, +getPrototypeOf: { + length: 1 + }, + is: { + length: 2 + }, + __proto__: { + constructor: { + name: "Function", + prototype: [Cycle], + length: 1, + __proto__: undefined + }, + __proto__: undefined + } + }, +hasOwnProperty: { + length: 0 + }, +propertyIsEnumerable: { + length: 0 + }, +toString: { + length: 0 + } + } +}"# + ); +} From 3d81f49063d4740901c78e3a98fbf0e4565376e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Mon, 29 Jun 2020 14:11:30 +0100 Subject: [PATCH 08/16] Ignore display_object test, waiting for #507 --- boa/src/builtins/value/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index 12cd3527361..86c9cfc6c1e 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -231,6 +231,7 @@ fn display_array_string() { } #[test] +#[ignore] // TODO: Once #507 is fixed this test can be simplified and used fn display_object() { let d_obj = r#" let o = {a: 'a'}; From f8ae2b0d75e64c59874c119454279b461ed905bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Fri, 24 Jul 2020 18:19:15 +0100 Subject: [PATCH 09/16] Feat: Introduce set_str_field and PropertyKey, discussed on #373 --- boa/src/builtins/array/mod.rs | 42 +++++------ boa/src/builtins/error/mod.rs | 4 +- boa/src/builtins/error/range.rs | 6 +- boa/src/builtins/error/reference.rs | 6 +- boa/src/builtins/error/syntax.rs | 6 +- boa/src/builtins/error/type.rs | 6 +- boa/src/builtins/function/mod.rs | 4 +- boa/src/builtins/json/mod.rs | 4 +- boa/src/builtins/object/internal_methods.rs | 83 ++++++++++----------- boa/src/builtins/object/mod.rs | 2 +- boa/src/builtins/property/mod.rs | 63 ++++++++++++---- boa/src/builtins/property/tests.rs | 10 --- boa/src/builtins/regexp/mod.rs | 6 +- boa/src/builtins/string/mod.rs | 2 +- boa/src/builtins/value/display.rs | 33 +------- boa/src/builtins/value/mod.rs | 50 ++++++++++--- boa/src/builtins/value/tests.rs | 21 +++--- boa/src/exec/declaration/mod.rs | 4 +- boa/src/exec/mod.rs | 38 +++++----- boa/src/exec/object/mod.rs | 6 +- boa/src/exec/operator/mod.rs | 6 +- boa/src/realm.rs | 2 +- boa_cli/src/main.rs | 8 +- 23 files changed, 219 insertions(+), 193 deletions(-) delete mode 100644 boa/src/builtins/property/tests.rs diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 0e9bf0aa41b..92882355d8f 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -58,7 +58,7 @@ impl Array { .borrow() .get_field(PROTOTYPE), ); - array.borrow().set_field("length", Value::from(0)); + array.borrow().set_str_field("length", Value::from(0)); Ok(array) } @@ -85,7 +85,7 @@ impl Array { array_obj_ptr.set_property("length".to_string(), length); for (n, value) in array_contents.iter().enumerate() { - array_obj_ptr.set_field(n.to_string(), value); + array_obj_ptr.set_str_field(&n.to_string(), value); } Ok(array_obj_ptr) } @@ -97,10 +97,10 @@ impl Array { for (n, value) in add_values.iter().enumerate() { let new_index = orig_length.wrapping_add(n as i32); - array_ptr.set_field(new_index.to_string(), value); + array_ptr.set_str_field(&new_index.to_string(), value); } - array_ptr.set_field( + array_ptr.set_str_field( "length", Value::from(orig_length.wrapping_add(add_values.len() as i32)), ); @@ -128,7 +128,7 @@ impl Array { length = i32::from(&args[0]); // TODO: It should not create an array of undefineds, but an empty array ("holy" array in V8) with length `n`. for n in 0..length { - this.set_field(n.to_string(), Value::undefined()); + this.set_str_field(&n.to_string(), Value::undefined()); } } 1 if args[0].is_double() => { @@ -136,7 +136,7 @@ impl Array { } _ => { for (n, value) in args.iter().enumerate() { - this.set_field(n.to_string(), value.clone()); + this.set_str_field(&n.to_string(), value.clone()); } } } @@ -247,7 +247,7 @@ impl Array { let pop_index = curr_length.wrapping_sub(1); let pop_value: Value = this.get_field(pop_index.to_string()); this.remove_property(&pop_index.to_string()); - this.set_field("length", Value::from(pop_index)); + this.set_str_field("length", Value::from(pop_index)); Ok(pop_value) } @@ -382,13 +382,13 @@ impl Array { let lower_value = this.get_field(lower.to_string()); if upper_exists && lower_exists { - this.set_field(upper.to_string(), lower_value); - this.set_field(lower.to_string(), upper_value); + this.set_str_field(&upper.to_string(), lower_value); + this.set_str_field(&lower.to_string(), upper_value); } else if upper_exists { - this.set_field(lower.to_string(), upper_value); + this.set_str_field(&lower.to_string(), upper_value); this.remove_property(&upper.to_string()); } else if lower_exists { - this.set_field(upper.to_string(), lower_value); + this.set_str_field(&upper.to_string(), lower_value); this.remove_property(&lower.to_string()); } } @@ -410,7 +410,7 @@ impl Array { let len = i32::from(&this.get_field("length")); if len == 0 { - this.set_field("length", Value::from(0)); + this.set_str_field("length", 0); // Since length is 0, this will be an Undefined value return Ok(this.get_field(0.to_string())); } @@ -425,13 +425,13 @@ impl Array { if from_value.is_undefined() { this.remove_property(&to); } else { - this.set_field(to, from_value); + this.set_str_field(&to, from_value); } } let final_index = len.wrapping_sub(1); this.remove_property(&(final_index).to_string()); - this.set_field("length", Value::from(final_index)); + this.set_str_field("length", Value::from(final_index)); Ok(first) } @@ -461,12 +461,12 @@ impl Array { if from_value.is_undefined() { this.remove_property(&to); } else { - this.set_field(to, from_value); + this.set_str_field(&to, from_value); } } for j in 0..arg_c { - this.set_field( - j.to_string(), + this.set_str_field( + &j.to_string(), args.get(j as usize) .expect("Could not get argument") .clone(), @@ -475,7 +475,7 @@ impl Array { } let temp = len.wrapping_add(arg_c); - this.set_field("length", Value::from(temp)); + this.set_str_field("length", Value::from(temp)); Ok(Value::from(temp)) } @@ -779,7 +779,7 @@ impl Array { }; for i in start..fin { - this.set_field(i.to_string(), value.clone()); + this.set_str_field(&i.to_string(), value.clone()); } Ok(this.clone()) @@ -856,10 +856,10 @@ impl Array { let span = max(to.wrapping_sub(from), 0); let mut new_array_len: i32 = 0; for i in from..from.wrapping_add(span) { - new_array.set_field(new_array_len.to_string(), this.get_field(i.to_string())); + new_array.set_str_field(&new_array_len.to_string(), this.get_field(i.to_string())); new_array_len = new_array_len.wrapping_add(1); } - new_array.set_field("length", Value::from(new_array_len)); + new_array.set_str_field("length", Value::from(new_array_len)); Ok(new_array) } diff --git a/boa/src/builtins/error/mod.rs b/boa/src/builtins/error/mod.rs index f19f0fcf679..91b67310a8f 100644 --- a/boa/src/builtins/error/mod.rs +++ b/boa/src/builtins/error/mod.rs @@ -48,7 +48,7 @@ impl Error { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_field("message", ctx.to_string(message)?); + this.set_str_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -77,7 +77,7 @@ impl Error { /// Create a new `Error` object. pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_field("message", Value::from("")); + prototype.set_str_field("message", Value::from("")); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/range.rs b/boa/src/builtins/error/range.rs index 04276281f75..b8900174f61 100644 --- a/boa/src/builtins/error/range.rs +++ b/boa/src/builtins/error/range.rs @@ -34,7 +34,7 @@ impl RangeError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_field("message", ctx.to_string(message)?); + this.set_str_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -63,8 +63,8 @@ impl RangeError { /// Create a new `RangeError` object. pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_field("name", Self::NAME); - prototype.set_field("message", ""); + prototype.set_str_field("name", Self::NAME); + prototype.set_str_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/reference.rs b/boa/src/builtins/error/reference.rs index 6c2edef05ef..460043b7d0f 100644 --- a/boa/src/builtins/error/reference.rs +++ b/boa/src/builtins/error/reference.rs @@ -33,7 +33,7 @@ impl ReferenceError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_field("message", ctx.to_string(message)?); + this.set_str_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -62,8 +62,8 @@ impl ReferenceError { /// Create a new `ReferenceError` object. pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_field("name", Self::NAME); - prototype.set_field("message", ""); + prototype.set_str_field("name", Self::NAME); + prototype.set_str_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/syntax.rs b/boa/src/builtins/error/syntax.rs index d7f954189ad..56d0f5ff418 100644 --- a/boa/src/builtins/error/syntax.rs +++ b/boa/src/builtins/error/syntax.rs @@ -35,7 +35,7 @@ impl SyntaxError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_field("message", ctx.to_string(message)?); + this.set_str_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -64,8 +64,8 @@ impl SyntaxError { /// Create a new `SyntaxError` object. pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_field("name", Self::NAME); - prototype.set_field("message", ""); + prototype.set_str_field("name", Self::NAME); + prototype.set_str_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/type.rs b/boa/src/builtins/error/type.rs index 23fe45b6637..c73a8901d88 100644 --- a/boa/src/builtins/error/type.rs +++ b/boa/src/builtins/error/type.rs @@ -40,7 +40,7 @@ impl TypeError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_field("message", ctx.to_string(message)?); + this.set_str_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -69,8 +69,8 @@ impl TypeError { /// Create a new `RangeError` object. pub(crate) fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - prototype.set_field("name", Self::NAME); - prototype.set_field("message", ""); + prototype.set_str_field("name", Self::NAME); + prototype.set_str_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index d98c99ad8f3..1f59323db3e 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -15,7 +15,7 @@ use crate::{ builtins::{ array::Array, object::{Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE}, - property::Property, + property::{Property, PropertyKey}, value::{RcString, ResultValue, Value}, }, environment::function_environment_record::BindingStatus, @@ -379,7 +379,7 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { let mut length = Property::default(); length = length.writable(true).value(Value::from(len)); // Define length as a property - obj.define_own_property("length".to_string(), length); + obj.define_own_property(&PropertyKey::from(RcString::from("length")), length); let mut index: usize = 0; while index < len { let val = arguments_list.get(index).expect("Could not get argument"); diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index d266c3019f0..e7b1c44fa1f 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -53,7 +53,7 @@ impl Json { match args.get(1) { Some(reviver) if reviver.is_function() => { let mut holder = Value::new_object(None); - holder.set_field(Value::from(""), j); + holder.set_str_field("", j); Self::walk(reviver, ctx, &mut holder, Value::from("")) } _ => Ok(j), @@ -78,7 +78,7 @@ impl Json { let v = Self::walk(reviver, ctx, &mut value, Value::from(key.as_str())); match v { Ok(v) if !v.is_undefined() => { - value.set_field(Value::from(key.as_str()), v); + value.set_str_field(key.as_str(), v); } Ok(_) => { value.remove_property(key.as_str()); diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index 7b79c0c0544..c9839f3ac9c 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -7,7 +7,7 @@ use crate::builtins::{ object::{Object, INSTANCE_PROTOTYPE, PROTOTYPE}, - property::Property, + property::{Property, PropertyKey}, value::{same_value, RcString, Value}, }; use crate::BoaProfiler; @@ -19,16 +19,15 @@ impl Object { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p - pub fn has_property(&self, val: &Value) -> bool { - debug_assert!(Property::is_property_key(val)); - let prop = self.get_own_property(val); + pub fn has_property(&self, property_key: &PropertyKey) -> bool { + let prop = self.get_own_property(&property_key); if prop.value.is_none() { let parent: Value = self.get_prototype_of(); if !parent.is_null() { // the parent value variant should be an object // In the unlikely event it isn't return false return match parent { - Value::Object(ref obj) => obj.borrow().has_property(val), + Value::Object(ref obj) => obj.borrow().has_property(&property_key), _ => false, }; } @@ -62,9 +61,8 @@ impl Object { } /// Delete property. - pub fn delete(&mut self, prop_key: &Value) -> bool { - debug_assert!(Property::is_property_key(prop_key)); - let desc = self.get_own_property(prop_key); + pub fn delete(&mut self, property_key: &PropertyKey) -> bool { + let desc = self.get_own_property(&property_key); if desc .value .clone() @@ -74,17 +72,17 @@ impl Object { return true; } if desc.configurable.expect("unable to get value") { - self.remove_property(&prop_key.to_string()); + self.remove_property(&property_key.to_string()); return true; } false } - // [[Get]] - pub fn get(&self, val: &Value) -> Value { - debug_assert!(Property::is_property_key(val)); - let desc = self.get_own_property(val); + /// [[Get]] + /// https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver + pub fn get(&self, property_key: &PropertyKey) -> Value { + let desc = self.get_own_property(property_key); if desc.value.clone().is_none() || desc .value @@ -100,7 +98,7 @@ impl Object { let parent_obj = Object::from(&parent).expect("Failed to get object"); - return parent_obj.get(val); + return parent_obj.get(property_key); } if desc.is_data_descriptor() { @@ -118,13 +116,11 @@ impl Object { /// [[Set]] /// - pub fn set(&mut self, field: Value, val: Value) -> bool { + pub fn set(&mut self, property_key: PropertyKey, val: Value) -> bool { let _timer = BoaProfiler::global().start_event("Object::set", "object"); - // [1] - debug_assert!(Property::is_property_key(&field)); // Fetch property key - let mut own_desc = self.get_own_property(&field); + let mut own_desc = self.get_own_property(&property_key); // [2] if own_desc.is_none() { let parent = self.get_prototype_of(); @@ -144,7 +140,7 @@ impl Object { // Change value on the current descriptor own_desc = own_desc.value(val); - return self.define_own_property(field.to_string(), own_desc); + return self.define_own_property(&property_key, own_desc); } // [4] debug_assert!(own_desc.is_accessor_descriptor()); @@ -162,10 +158,10 @@ impl Object { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-defineownproperty-p-desc - pub fn define_own_property(&mut self, property_key: String, desc: Property) -> bool { + pub fn define_own_property(&mut self, property_key: &PropertyKey, desc: Property) -> bool { let _timer = BoaProfiler::global().start_event("Object::define_own_property", "object"); - let mut current = self.get_own_property(&Value::from(property_key.to_string())); + let mut current = self.get_own_property(property_key); let extensible = self.is_extensible(); // https://tc39.es/ecma262/#sec-validateandapplypropertydescriptor @@ -220,7 +216,7 @@ impl Object { current.set = None; } - self.insert_property(property_key.clone(), current); + self.insert_property(property_key, current); // 7 } else if current.is_data_descriptor() && desc.is_data_descriptor() { // a @@ -273,13 +269,12 @@ impl Object { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p - pub fn get_own_property(&self, prop: &Value) -> Property { + pub fn get_own_property(&self, property_key: &PropertyKey) -> Property { let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object"); - debug_assert!(Property::is_property_key(prop)); // Prop could either be a String or Symbol - match *prop { - Value::String(ref st) => { + match property_key { + PropertyKey::String(ref st) => { self.properties() .get(st) .map_or_else(Property::default, |v| { @@ -297,25 +292,23 @@ impl Object { d }) } - Value::Symbol(ref symbol) => { - self.symbol_properties() - .get(&symbol.hash()) - .map_or_else(Property::default, |v| { - let mut d = Property::default(); - if v.is_data_descriptor() { - d.value = v.value.clone(); - d.writable = v.writable; - } else { - debug_assert!(v.is_accessor_descriptor()); - d.get = v.get.clone(); - d.set = v.set.clone(); - } - d.enumerable = v.enumerable; - d.configurable = v.configurable; - d - }) - } - _ => Property::default(), + PropertyKey::Symbol(ref symbol) => self + .symbol_properties() + .get(&symbol.hash()) + .map_or_else(Property::default, |v| { + let mut d = Property::default(); + if v.is_data_descriptor() { + d.value = v.value.clone(); + d.writable = v.writable; + } else { + debug_assert!(v.is_accessor_descriptor()); + d.get = v.get.clone(); + d.set = v.set.clone(); + } + d.enumerable = v.enumerable; + d.configurable = v.configurable; + d + }), } } diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 58c2aeedaa1..d6464ae64db 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -476,7 +476,7 @@ pub fn has_own_property(this: &Value, args: &[Value], ctx: &mut Interpreter) -> .as_object() .as_deref() .expect("Cannot get THIS object") - .get_own_property(&Value::string(prop.expect("cannot get prop"))); + .get_own_property(&prop.expect("cannot get prop").into()); if own_property.is_none() { Ok(Value::from(false)) } else { diff --git a/boa/src/builtins/property/mod.rs b/boa/src/builtins/property/mod.rs index 5496e6256c2..8d8113f595c 100644 --- a/boa/src/builtins/property/mod.rs +++ b/boa/src/builtins/property/mod.rs @@ -14,8 +14,11 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty //! [section]: https://tc39.es/ecma262/#sec-property-attributes +use crate::builtins::value::rcstring::RcString; +use crate::builtins::value::rcsymbol::RcSymbol; use crate::builtins::value::Value; use gc::{Finalize, Trace}; +use std::fmt; /// This represents a Javascript Property AKA The Property Descriptor. /// @@ -52,11 +55,6 @@ pub struct Property { } impl Property { - /// Checks if the provided Value can be used as a property key. - pub fn is_property_key(value: &Value) -> bool { - value.is_string() || value.is_symbol() // Uncomment this when we are handeling symbols. - } - /// Make a new property with the given value /// The difference between New and Default: /// @@ -173,12 +171,12 @@ impl Default for Property { impl From<&Property> for Value { fn from(value: &Property) -> Value { let property = Value::new_object(None); - property.set_field("configurable", Value::from(value.configurable)); - property.set_field("enumerable", Value::from(value.enumerable)); - property.set_field("writable", Value::from(value.writable)); - property.set_field("value", value.value.clone().unwrap_or_else(Value::null)); - property.set_field("get", value.get.clone().unwrap_or_else(Value::null)); - property.set_field("set", value.set.clone().unwrap_or_else(Value::null)); + property.set_str_field("configurable", Value::from(value.configurable)); + property.set_str_field("enumerable", Value::from(value.enumerable)); + property.set_str_field("writable", Value::from(value.writable)); + property.set_str_field("value", value.value.clone().unwrap_or_else(Value::null)); + property.set_str_field("get", value.get.clone().unwrap_or_else(Value::null)); + property.set_str_field("set", value.set.clone().unwrap_or_else(Value::null)); property } } @@ -198,5 +196,44 @@ impl<'a> From<&'a Value> for Property { } } -#[cfg(test)] -mod tests; +#[derive(Trace, Finalize, Debug, Clone)] +pub enum PropertyKey { + String(RcString), + Symbol(RcSymbol), +} + +impl From for PropertyKey { + fn from(string: RcString) -> PropertyKey { + PropertyKey::String(string.clone()) + } +} + +impl From<&str> for PropertyKey { + fn from(string: &str) -> PropertyKey { + PropertyKey::String(string.into()) + } +} + +impl From for PropertyKey { + fn from(symbol: RcSymbol) -> PropertyKey { + PropertyKey::Symbol(symbol.clone()) + } +} + +impl fmt::Display for PropertyKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PropertyKey::String(ref string) => string.fmt(f), + PropertyKey::Symbol(ref symbol) => symbol.fmt(f), + } + } +} + +impl From<&PropertyKey> for RcString { + fn from(property_key: &PropertyKey) -> RcString { + match property_key { + PropertyKey::String(ref string) => string.clone(), + PropertyKey::Symbol(ref symbol) => symbol.to_string().into(), + } + } +} diff --git a/boa/src/builtins/property/tests.rs b/boa/src/builtins/property/tests.rs deleted file mode 100644 index 09189e82a37..00000000000 --- a/boa/src/builtins/property/tests.rs +++ /dev/null @@ -1,10 +0,0 @@ -use super::*; - -#[test] -fn is_property_key_test() { - let v = Value::string("Boop"); - assert!(Property::is_property_key(&v)); - - let v = Value::boolean(true); - assert!(!Property::is_property_key(&v)); -} diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index fb6eca2e7b7..d2d39cbe4f4 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -306,7 +306,7 @@ impl RegExp { }; Ok(Value::boolean(result)) }); - this.set_field("lastIndex", Value::from(last_index)); + this.set_str_field("lastIndex", Value::from(last_index)); result } @@ -358,7 +358,7 @@ impl RegExp { }; Ok(result) }); - this.set_field("lastIndex", Value::from(last_index)); + this.set_str_field("lastIndex", Value::from(last_index)); result } @@ -452,7 +452,7 @@ impl RegExp { let length = matches.len(); let result = Value::from(matches); - result.set_field("length", Value::from(length)); + result.set_str_field("length", Value::from(length)); result.set_data(ObjectData::Array); Ok(result) diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 6ff42c903cc..64077fee891 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -70,7 +70,7 @@ impl String { let length = string.chars().count(); - this.set_field("length", Value::from(length as i32)); + this.set_str_field("length", Value::from(length as i32)); this.set_data(ObjectData::String(string.clone())); diff --git a/boa/src/builtins/value/display.rs b/boa/src/builtins/value/display.rs index 4c6a1cc1b0a..e4199e52feb 100644 --- a/boa/src/builtins/value/display.rs +++ b/boa/src/builtins/value/display.rs @@ -1,12 +1,5 @@ use super::*; -impl<'value> Value { - /// Returns a REPL representation of the `Value` - pub fn display(&'value self) -> ValueDisplay<'value> { - ValueDisplay::new(self) - } -} - /// A helper macro for printing objects /// Can be used to print both properties and internal slots /// All of the overloads take: @@ -79,7 +72,7 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool) -> String { &v.borrow() .properties() .get("length") - .unwrap() + .expect("Could not get Array's length property") .value .clone() .expect("Could not borrow value"), @@ -113,7 +106,7 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool) -> String { } } Value::Symbol(ref symbol) => symbol.to_string(), - _ => format!("{}", x.display()), + _ => format!("{}", x), } } @@ -166,7 +159,7 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { format!("{{\n{}\n{}}}", result, closing_indent) } else { // Every other type of data is printed with the display method - format!("{}", data.display()) + format!("{}", data) } } @@ -183,7 +176,7 @@ impl Display for Value { Some(description) => write!(f, "Symbol({})", description), None => write!(f, "Symbol()"), }, - Self::String(ref v) => write!(f, "{}", v), + Self::String(ref v) => write!(f, "\"{}\"", v), Self::Rational(v) => write!( f, "{}", @@ -200,21 +193,3 @@ impl Display for Value { } } } - -#[derive(Debug, Clone)] -pub struct ValueDisplay<'value>(&'value Value); - -impl<'value> ValueDisplay<'value> { - fn new(vd: &'value Value) -> Self { - ValueDisplay(vd) - } -} - -impl<'value> Display for ValueDisplay<'value> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Value::String(ref v) => write!(f, "\"{}\"", v), - _ => self.0.fmt(f), - } - } -} diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 8d5447dfe15..90c88c602ff 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -15,7 +15,7 @@ use crate::builtins::{ GcObject, InternalState, InternalStateCell, Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE, }, - property::Property, + property::{Property, PropertyKey}, BigInt, Symbol, }; use crate::exec::Interpreter; @@ -644,9 +644,36 @@ impl Value { self.get_property(field).is_some() } + /// Set the string field in the value + /// Alternative to set_field, strictly for &str fields + pub fn set_str_field(&self, field: &str, val: V) -> Value + where + V: Into, + { + let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); + let val = val.into(); + + if let Self::Object(ref obj) = *self { + if obj.borrow().is_array() { + if let Ok(num) = field.parse::() { + if num > 0 { + let len = i32::from(&self.get_field("length")); + if len < (num + 1) as i32 { + self.set_str_field("length", Value::from(num + 1)); + } + } + } + } + + obj.borrow_mut().set(field.into(), val.clone()); + } + + val + } + /// Set the field in the value /// Field could be a Symbol, so we need to accept a Value (not a string) - pub fn set_field(&self, field: F, val: V) -> Value + pub fn set_field(&self, field: F, val: V, interpreter: &mut Interpreter) -> Value where F: Into, V: Into, @@ -661,19 +688,22 @@ impl Value { if num > 0 { let len = i32::from(&self.get_field("length")); if len < (num + 1) as i32 { - self.set_field("length", Value::from(num + 1)); + self.set_str_field("length", Value::from(num + 1)); } } } } // Symbols get saved into a different bucket to general properties - if field.is_symbol() { - obj.borrow_mut().set(field, val.clone()); - } else { - obj.borrow_mut() - .set(Value::from(field.to_string()), val.clone()); - } + match field { + Value::Symbol(ref symbol) => obj + .borrow_mut() + .set(PropertyKey::from(symbol.clone()), val.clone()), + _ => obj.borrow_mut().set( + PropertyKey::from(interpreter.to_string(&field).unwrap()), + val.clone(), + ), + }; } val @@ -727,7 +757,7 @@ impl Value { // Wrap Object in GC'd Value let new_func_val = Value::from(new_func); // Set length to parameters - new_func_val.set_field("length", Value::from(length)); + new_func_val.set_str_field("length", Value::from(length)); new_func_val } } diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index 222ff8d82d0..8d6b8c01d85 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{exec, forward, forward_val, Interpreter, Realm}; +use crate::{forward, forward_val, Interpreter, Realm}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -30,7 +30,7 @@ fn get_set_field() { let obj = Value::new_object(None); // Create string and convert it to a Value let s = Value::from("bar"); - obj.set_field("foo", s); + obj.set_str_field("foo", s); assert_eq!(obj.get_field("foo").to_string(), "bar"); } @@ -328,27 +328,30 @@ fn bitand_rational_and_rational() { fn display_string() { let s = String::from("Hello"); let v = Value::from(s); - assert_eq!(v.display().to_string(), "\"Hello\""); + assert_eq!(v.to_string(), "\"Hello\""); } #[test] fn display_array_string() { - let d_arr = r#" - let a = ["Hello"]; - a - "#; - assert_eq!(&exec(d_arr), "[ \"Hello\" ]"); + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + + let value = forward_val(&mut engine, "[\"Hello\"]").unwrap(); + assert_eq!(value.to_string(), "[ \"Hello\" ]"); } #[test] #[ignore] // TODO: Once #507 is fixed this test can be simplified and used fn display_object() { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); let d_obj = r#" let o = {a: 'a'}; o "#; + let value = forward_val(&mut engine, d_obj).unwrap(); assert_eq!( - &exec(d_obj), + value.to_string(), r#"{ a: "a", __proto__: { diff --git a/boa/src/exec/declaration/mod.rs b/boa/src/exec/declaration/mod.rs index 37f199003a4..4eb273763f1 100644 --- a/boa/src/exec/declaration/mod.rs +++ b/boa/src/exec/declaration/mod.rs @@ -25,7 +25,7 @@ impl Executable for FunctionDecl { ); // Set the name and assign it in the current environment - val.set_field("name", self.name()); + val.set_str_field("name", self.name()); interpreter.realm_mut().environment.create_mutable_binding( self.name().to_owned(), false, @@ -52,7 +52,7 @@ impl Executable for FunctionExpr { ); if let Some(name) = self.name() { - val.set_field("name", Value::from(name)); + val.set_str_field("name", Value::from(name)); } Ok(val) diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 8999040ff91..121dc46f2f4 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -26,7 +26,7 @@ use crate::{ function::{Function as FunctionObject, FunctionBody, ThisMode}, number::{f64_to_int32, f64_to_uint32}, object::{Object, ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE}, - property::Property, + property::PropertyKey, value::{RcBigInt, RcString, ResultValue, Type, Value}, BigInt, Number, }, @@ -147,8 +147,8 @@ impl Interpreter { let val = Value::from(new_func); val.set_internal_slot(INSTANCE_PROTOTYPE, function_prototype.clone()); - val.set_field(PROTOTYPE, proto); - val.set_field("length", Value::from(params_len)); + val.set_str_field(PROTOTYPE, proto); + val.set_str_field("length", Value::from(params_len)); val } @@ -453,23 +453,21 @@ impl Interpreter { /// /// https://tc39.es/ecma262/#sec-topropertykey #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_property_key(&mut self, value: &Value) -> ResultValue { + pub(crate) fn to_property_key(&mut self, value: &Value) -> Result { let key = self.to_primitive(value, PreferredType::String)?; - if key.is_symbol() { - Ok(key) - } else { - self.to_string(&key).map(Value::from) + match key { + Value::Symbol(ref symbol) => Ok(PropertyKey::from(symbol.clone())), + _ => { + let string = self.to_string(&key)?; + return Ok(PropertyKey::from(string)); + } } } /// https://tc39.es/ecma262/#sec-hasproperty - pub(crate) fn has_property(&self, obj: &Value, key: &Value) -> bool { + pub(crate) fn has_property(&self, obj: &Value, key: &PropertyKey) -> bool { if let Some(obj) = obj.as_object() { - if !Property::is_property_key(key) { - false - } else { - obj.has_property(key) - } + obj.has_property(key) } else { false } @@ -573,11 +571,13 @@ impl Interpreter { Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node .obj() .run(self)? - .set_field(get_const_field_node.field(), value)), - Node::GetField(ref get_field) => Ok(get_field - .obj() - .run(self)? - .set_field(get_field.field().run(self)?, value)), + .set_str_field(get_const_field_node.field(), value)), + Node::GetField(ref get_field) => { + Ok(get_field + .obj() + .run(self)? + .set_field(get_field.field().run(self)?, value, self)) + } _ => panic!("TypeError: invalid assignment to {}", node), } } diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs index 5b9acd8ec3c..0040934a8e4 100644 --- a/boa/src/exec/object/mod.rs +++ b/boa/src/exec/object/mod.rs @@ -22,13 +22,11 @@ impl Executable for Object { for property in self.properties().iter() { match property { PropertyDefinition::Property(key, value) => { - obj.borrow() - .set_field(&key.clone(), value.run(interpreter)?); + obj.borrow().set_str_field(key, value.run(interpreter)?); } PropertyDefinition::MethodDefinition(kind, name, func) => { if let MethodDefinitionKind::Ordinary = kind { - obj.borrow() - .set_field(&name.clone(), func.run(interpreter)?); + obj.borrow().set_str_field(name, func.run(interpreter)?); } else { // TODO: Implement other types of MethodDefinitionKinds. unimplemented!("other types of property method definitions."); diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index 1c9fe4623ed..159fd6c8c46 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -35,12 +35,12 @@ impl Executable for Assign { } Node::GetConstField(ref get_const_field) => { let val_obj = get_const_field.obj().run(interpreter)?; - val_obj.set_field(get_const_field.field(), val.clone()); + val_obj.set_str_field(get_const_field.field(), val.clone()); } Node::GetField(ref get_field) => { let val_obj = get_field.obj().run(interpreter)?; let val_field = get_field.field().run(interpreter)?; - val_obj.set_field(val_field, val.clone()); + val_obj.set_field(val_field, val.clone(), interpreter); } _ => (), } @@ -134,7 +134,7 @@ impl Executable for BinOp { let v_a = v_r_a.get_field(get_const_field.field()); let v_b = self.rhs().run(interpreter)?; let value = Self::run_assign(op, v_a, v_b, interpreter)?; - v_r_a.set_field(get_const_field.field(), value.clone()); + v_r_a.set_str_field(get_const_field.field(), value.clone()); Ok(value) } _ => Ok(Value::undefined()), diff --git a/boa/src/realm.rs b/boa/src/realm.rs index 1119ef7bca1..9879bbd7123 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -65,7 +65,7 @@ impl Realm { pub fn register_global_func(self, func_name: &str, func: NativeFunctionData) -> Self { let func = Function::builtin(Vec::new(), func); self.global_obj - .set_field(Value::from(func_name), Value::from_func(func)); + .set_str_field(func_name, Value::from_func(func)); self } diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 9ec6d581265..7f86e667dd2 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -189,8 +189,8 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match forward_val(&mut engine, &buffer) { - Ok(v) => print!("{}", v.display()), - Err(v) => eprint!("{}", v.display()), + Ok(v) => print!("{}", v), + Err(v) => eprint!("{}", v), } } } @@ -208,8 +208,8 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match forward_val(&mut engine, buffer.trim_end()) { - Ok(v) => println!("{}", v.display()), - Err(v) => eprintln!("{}", v.display()), + Ok(v) => println!("{}", v), + Err(v) => eprintln!("{}", v), } } From 9a2c016d65cc17bbe256f490ebe182e263809401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Sat, 25 Jul 2020 01:17:16 +0100 Subject: [PATCH 10/16] Test: Update tests to work with new Value::String formatting - There were some parts of code that needed to be updated to use Interpreter::to_string instead of Value::to_string - Most tests only required adding `\"` at the start and end - In a few tests I took the Liberty to remove unnecessary conversions to String before comparing --- boa/src/builtins/array/tests.rs | 86 +++++++------ boa/src/builtins/bigint/tests.rs | 14 +- boa/src/builtins/console/mod.rs | 2 +- boa/src/builtins/error/reference.rs | 6 +- boa/src/builtins/error/type.rs | 6 +- boa/src/builtins/global_this/tests.rs | 2 +- boa/src/builtins/json/mod.rs | 2 +- boa/src/builtins/json/tests.rs | 8 +- boa/src/builtins/number/tests.rs | 141 +++++++++++---------- boa/src/builtins/object/tests.rs | 4 +- boa/src/builtins/regexp/tests.rs | 19 +-- boa/src/builtins/string/tests.rs | 77 +++++------ boa/src/builtins/symbol/tests.rs | 2 +- boa/src/builtins/value/tests.rs | 2 +- boa/src/environment/lexical_environment.rs | 4 +- boa/src/exec/field/mod.rs | 2 +- boa/src/exec/operator/mod.rs | 12 +- boa/src/exec/operator/tests.rs | 4 +- boa/src/exec/switch/tests.rs | 12 +- boa/src/exec/tests.rs | 128 ++++++++++--------- 20 files changed, 285 insertions(+), 248 deletions(-) diff --git a/boa/src/builtins/array/tests.rs b/boa/src/builtins/array/tests.rs index 26dc512c1c8..1f0c111861f 100644 --- a/boa/src/builtins/array/tests.rs +++ b/boa/src/builtins/array/tests.rs @@ -76,13 +76,13 @@ fn join() { eprintln!("{}", forward(&mut engine, init)); // Empty let empty = forward(&mut engine, "empty.join('.')"); - assert_eq!(empty, String::from("")); + assert_eq!(empty, String::from("\"\"")); // One let one = forward(&mut engine, "one.join('.')"); - assert_eq!(one, String::from("a")); + assert_eq!(one, String::from("\"a\"")); // Many let many = forward(&mut engine, "many.join('.')"); - assert_eq!(many, String::from("a.b.c")); + assert_eq!(many, String::from("\"a.b.c\"")); } #[test] @@ -97,13 +97,13 @@ fn to_string() { eprintln!("{}", forward(&mut engine, init)); // Empty let empty = forward(&mut engine, "empty.toString()"); - assert_eq!(empty, String::from("")); + assert_eq!(empty, String::from("\"\"")); // One let one = forward(&mut engine, "one.toString()"); - assert_eq!(one, String::from("a")); + assert_eq!(one, String::from("\"a\"")); // Many let many = forward(&mut engine, "many.toString()"); - assert_eq!(many, String::from("a,b,c")); + assert_eq!(many, String::from("\"a,b,c\"")); } #[test] @@ -163,7 +163,7 @@ fn find() { "#; eprintln!("{}", forward(&mut engine, init)); let found = forward(&mut engine, "many.find(comp)"); - assert_eq!(found, String::from("a")); + assert_eq!(found, String::from("\"a\"")); } #[test] @@ -417,92 +417,92 @@ fn fill() { forward(&mut engine, "var a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4).join()"), - String::from("4,4,4") + String::from("\"4,4,4\"") ); // make sure the array is modified - assert_eq!(forward(&mut engine, "a.join()"), String::from("4,4,4")); + assert_eq!(forward(&mut engine, "a.join()"), String::from("\"4,4,4\"")); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, '1').join()"), - String::from("1,4,4") + String::from("\"1,4,4\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 1, 2).join()"), - String::from("1,4,3") + String::from("\"1,4,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 1, 1).join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 3, 3).join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, -3, -2).join()"), - String::from("4,2,3") + String::from("\"4,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, NaN, NaN).join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 3, 5).join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, '1.2', '2.5').join()"), - String::from("1,4,3") + String::from("\"1,4,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 'str').join()"), - String::from("4,4,4") + String::from("\"4,4,4\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, 'str', 'str').join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, undefined, null).join()"), - String::from("1,2,3") + String::from("\"1,2,3\"") ); forward(&mut engine, "a = [1, 2, 3];"); assert_eq!( forward(&mut engine, "a.fill(4, undefined, undefined).join()"), - String::from("4,4,4") + String::from("\"4,4,4\"") ); assert_eq!( forward(&mut engine, "a.fill().join()"), - String::from("undefined,undefined,undefined") + String::from("\"undefined,undefined,undefined\"") ); // test object reference forward(&mut engine, "a = (new Array(3)).fill({});"); forward(&mut engine, "a[0].hi = 'hi';"); - assert_eq!(forward(&mut engine, "a[0].hi"), String::from("hi")); + assert_eq!(forward(&mut engine, "a[0].hi"), String::from("\"hi\"")); } #[test] @@ -569,10 +569,10 @@ fn map() { forward(&mut engine, js); // assert the old arrays have not been modified - assert_eq!(forward(&mut engine, "one[0]"), String::from("x")); + assert_eq!(forward(&mut engine, "one[0]"), String::from("\"x\"")); assert_eq!( forward(&mut engine, "many[2] + many[1] + many[0]"), - String::from("zyx") + String::from("\"zyx\"") ); // NB: These tests need to be rewritten once `Display` has been implemented for `Array` @@ -584,7 +584,10 @@ fn map() { // One assert_eq!(forward(&mut engine, "one_mapped.length"), String::from("1")); - assert_eq!(forward(&mut engine, "one_mapped[0]"), String::from("_x")); + assert_eq!( + forward(&mut engine, "one_mapped[0]"), + String::from("\"_x\"") + ); // Many assert_eq!( @@ -596,7 +599,7 @@ fn map() { &mut engine, "many_mapped[0] + many_mapped[1] + many_mapped[2]" ), - String::from("_x__y__z_") + String::from("\"_x__y__z_\"") ); // TODO: uncomment when `this` has been implemented @@ -619,12 +622,12 @@ fn slice() { eprintln!("{}", forward(&mut engine, init)); assert_eq!(forward(&mut engine, "empty.length"), "0"); - assert_eq!(forward(&mut engine, "one[0]"), "a"); - assert_eq!(forward(&mut engine, "many1[0]"), "b"); - assert_eq!(forward(&mut engine, "many1[1]"), "c"); - assert_eq!(forward(&mut engine, "many1[2]"), "d"); + assert_eq!(forward(&mut engine, "one[0]"), "\"a\""); + assert_eq!(forward(&mut engine, "many1[0]"), "\"b\""); + assert_eq!(forward(&mut engine, "many1[1]"), "\"c\""); + assert_eq!(forward(&mut engine, "many1[2]"), "\"d\""); assert_eq!(forward(&mut engine, "many1.length"), "3"); - assert_eq!(forward(&mut engine, "many2[0]"), "c"); + assert_eq!(forward(&mut engine, "many2[0]"), "\"c\""); assert_eq!(forward(&mut engine, "many2.length"), "1"); assert_eq!(forward(&mut engine, "many3.length"), "0"); } @@ -693,10 +696,10 @@ fn filter() { forward(&mut engine, js); // assert the old arrays have not been modified - assert_eq!(forward(&mut engine, "one[0]"), String::from("1")); + assert_eq!(forward(&mut engine, "one[0]"), String::from("\"1\"")); assert_eq!( forward(&mut engine, "many[2] + many[1] + many[0]"), - String::from("101") + String::from("\"101\"") ); // NB: These tests need to be rewritten once `Display` has been implemented for `Array` @@ -711,7 +714,10 @@ fn filter() { forward(&mut engine, "one_filtered.length"), String::from("1") ); - assert_eq!(forward(&mut engine, "one_filtered[0]"), String::from("1")); + assert_eq!( + forward(&mut engine, "one_filtered[0]"), + String::from("\"1\"") + ); // One filtered on "0" assert_eq!( @@ -726,7 +732,7 @@ fn filter() { ); assert_eq!( forward(&mut engine, "many_one_filtered[0] + many_one_filtered[1]"), - String::from("11") + String::from("\"11\"") ); // Many filtered on "0" @@ -736,7 +742,7 @@ fn filter() { ); assert_eq!( forward(&mut engine, "many_zero_filtered[0]"), - String::from("0") + String::from("\"0\"") ); } @@ -863,7 +869,7 @@ fn reduce() { ); assert_eq!( result, - "Reduce was called on an empty array and with no initial value" + "\"Reduce was called on an empty array and with no initial value\"" ); // Array with no defined elements @@ -882,7 +888,7 @@ fn reduce() { ); assert_eq!( result, - "Reduce was called on an empty array and with no initial value" + "\"Reduce was called on an empty array and with no initial value\"" ); // No callback @@ -896,7 +902,7 @@ fn reduce() { } "#, ); - assert_eq!(result, "Reduce was called without a callback"); + assert_eq!(result, "\"Reduce was called without a callback\""); } #[test] diff --git a/boa/src/builtins/bigint/tests.rs b/boa/src/builtins/bigint/tests.rs index c1c37b8fa1a..d816fac806b 100644 --- a/boa/src/builtins/bigint/tests.rs +++ b/boa/src/builtins/bigint/tests.rs @@ -94,7 +94,7 @@ fn bigint_function_conversion_from_rational_with_fractional_part() { "#; assert_eq!( forward(&mut engine, scenario), - "TypeError: The number 0.1 cannot be converted to a BigInt because it is not an integer" + "\"TypeError: The number 0.1 cannot be converted to a BigInt because it is not an integer\"" ); } @@ -112,7 +112,7 @@ fn bigint_function_conversion_from_null() { "#; assert_eq!( forward(&mut engine, scenario), - "TypeError: cannot convert null to a BigInt" + "\"TypeError: cannot convert null to a BigInt\"" ); } @@ -130,7 +130,7 @@ fn bigint_function_conversion_from_undefined() { "#; assert_eq!( forward(&mut engine, scenario), - "TypeError: cannot convert undefined to a BigInt" + "\"TypeError: cannot convert undefined to a BigInt\"" ); } @@ -217,10 +217,10 @@ fn to_string() { let realm = Realm::create(); let mut engine = Interpreter::new(realm); - assert_eq!(forward(&mut engine, "1000n.toString()"), "1000"); - assert_eq!(forward(&mut engine, "1000n.toString(2)"), "1111101000"); - assert_eq!(forward(&mut engine, "255n.toString(16)"), "ff"); - assert_eq!(forward(&mut engine, "1000n.toString(36)"), "rs"); + assert_eq!(forward(&mut engine, "1000n.toString()"), "\"1000\""); + assert_eq!(forward(&mut engine, "1000n.toString(2)"), "\"1111101000\""); + assert_eq!(forward(&mut engine, "255n.toString(16)"), "\"ff\""); + assert_eq!(forward(&mut engine, "1000n.toString(36)"), "\"rs\""); } #[test] diff --git a/boa/src/builtins/console/mod.rs b/boa/src/builtins/console/mod.rs index 7b7c68c7833..68ff83c47fd 100644 --- a/boa/src/builtins/console/mod.rs +++ b/boa/src/builtins/console/mod.rs @@ -111,7 +111,7 @@ pub fn formatter(data: &[Value], ctx: &mut Interpreter) -> Result /* unformatted data */ for rest in data.iter().skip(arg_index) { - formatted.push_str(&format!(" {}", rest)) + formatted.push_str(&format!(" {}", ctx.to_string(rest)?)) } Ok(formatted) diff --git a/boa/src/builtins/error/reference.rs b/boa/src/builtins/error/reference.rs index c143244e248..3d075f44f4b 100644 --- a/boa/src/builtins/error/reference.rs +++ b/boa/src/builtins/error/reference.rs @@ -53,9 +53,9 @@ impl ReferenceError { /// [spec]: https://tc39.es/ecma262/#sec-error.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - let name = this.get_field("name"); - let message = this.get_field("message"); + pub(crate) fn to_string(this: &Value, _: &[Value], ctx: &mut Interpreter) -> ResultValue { + let name = ctx.to_string(&this.get_field("name"))?; + let message = ctx.to_string(&this.get_field("message"))?; Ok(Value::from(format!("{}: {}", name, message))) } diff --git a/boa/src/builtins/error/type.rs b/boa/src/builtins/error/type.rs index 8664695b08b..a40f84d966e 100644 --- a/boa/src/builtins/error/type.rs +++ b/boa/src/builtins/error/type.rs @@ -60,9 +60,9 @@ impl TypeError { /// [spec]: https://tc39.es/ecma262/#sec-error.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { - let name = this.get_field("name"); - let message = this.get_field("message"); + pub(crate) fn to_string(this: &Value, _: &[Value], ctx: &mut Interpreter) -> ResultValue { + let name = ctx.to_string(&this.get_field("name"))?; + let message = ctx.to_string(&this.get_field("message"))?; Ok(Value::from(format!("{}: {}", name, message))) } diff --git a/boa/src/builtins/global_this/tests.rs b/boa/src/builtins/global_this/tests.rs index 7dbac74d0c1..719ef5124b0 100644 --- a/boa/src/builtins/global_this/tests.rs +++ b/boa/src/builtins/global_this/tests.rs @@ -6,5 +6,5 @@ fn global_this_exists_on_global_object_and_evaluates_to_an_object() { typeof globalThis; "#; - assert_eq!(&exec(scenario), "object"); + assert_eq!(&exec(scenario), "\"object\""); } diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 39ce1d8e2f5..722cc5d0245 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -161,7 +161,7 @@ impl Json { .and_then(|prop| prop.value.as_ref().map(|v| v.to_json(ctx))) .transpose()? { - obj_to_return.insert(field.to_string(), value); + obj_to_return.insert(ctx.to_string(&field)?.to_string(), value); } } Ok(Value::from(JSONValue::Object(obj_to_return).to_string())) diff --git a/boa/src/builtins/json/tests.rs b/boa/src/builtins/json/tests.rs index 87033013e6d..07974fb5615 100644 --- a/boa/src/builtins/json/tests.rs +++ b/boa/src/builtins/json/tests.rs @@ -34,7 +34,7 @@ fn json_stringify_remove_undefined_values_from_objects() { &mut engine, r#"JSON.stringify({ aaa: undefined, bbb: 'ccc' })"#, ); - let expected = r#"{"bbb":"ccc"}"#; + let expected = r#""{"bbb":"ccc"}""#; assert_eq!(actual, expected); } @@ -48,7 +48,7 @@ fn json_stringify_remove_function_values_from_objects() { &mut engine, r#"JSON.stringify({ aaa: () => {}, bbb: 'ccc' })"#, ); - let expected = r#"{"bbb":"ccc"}"#; + let expected = r#""{"bbb":"ccc"}""#; assert_eq!(actual, expected); } @@ -62,7 +62,7 @@ fn json_stringify_remove_symbols_from_objects() { &mut engine, r#"JSON.stringify({ aaa: Symbol(), bbb: 'ccc' })"#, ); - let expected = r#"{"bbb":"ccc"}"#; + let expected = r#""{"bbb":"ccc"}""#; assert_eq!(actual, expected); } @@ -267,7 +267,7 @@ fn json_parse_object_with_reviver() { JSON.stringify(jsonObj);"#, ); - assert_eq!(result, r#"{"firstname":"boa","lastname":"interpreter"}"#); + assert_eq!(result, r#""{"firstname":"boa","lastname":"interpreter"}""#); } #[test] diff --git a/boa/src/builtins/number/tests.rs b/boa/src/builtins/number/tests.rs index 4e7baf1cf86..adf2d386158 100644 --- a/boa/src/builtins/number/tests.rs +++ b/boa/src/builtins/number/tests.rs @@ -70,12 +70,12 @@ fn to_exponential() { let nan_exp = forward(&mut engine, "nan_exp"); let noop_exp = forward(&mut engine, "noop_exp"); - assert_eq!(default_exp, "0e+0"); - assert_eq!(int_exp, "5e+0"); - assert_eq!(float_exp, "1.234e+0"); - assert_eq!(big_exp, "1.234e+3"); - assert_eq!(nan_exp, "NaN"); - assert_eq!(noop_exp, "1.23e+2"); + assert_eq!(default_exp, "\"0e+0\""); + assert_eq!(int_exp, "\"5e+0\""); + assert_eq!(float_exp, "\"1.234e+0\""); + assert_eq!(big_exp, "\"1.234e+3\""); + assert_eq!(nan_exp, "\"NaN\""); + assert_eq!(noop_exp, "\"1.23e+2\""); } #[test] @@ -97,11 +97,11 @@ fn to_fixed() { let noop_fixed = forward(&mut engine, "noop_fixed"); let nan_fixed = forward(&mut engine, "nan_fixed"); - assert_eq!(default_fixed, String::from("0")); - assert_eq!(pos_fixed, String::from("34560")); - assert_eq!(neg_fixed, String::from("0")); - assert_eq!(noop_fixed, String::from("5")); - assert_eq!(nan_fixed, String::from("NaN")); + assert_eq!(default_fixed, "\"0\""); + assert_eq!(pos_fixed, "\"34560\""); + assert_eq!(neg_fixed, "\"0\""); + assert_eq!(noop_fixed, "\"5\""); + assert_eq!(nan_fixed, "\"NaN\""); } #[test] @@ -124,10 +124,10 @@ fn to_locale_string() { let big_locale = forward(&mut engine, "big_locale"); let neg_locale = forward(&mut engine, "neg_locale"); - assert_eq!(default_locale, String::from("0")); - assert_eq!(small_locale, String::from("5")); - assert_eq!(big_locale, String::from("345600")); - assert_eq!(neg_locale, String::from("-25")); + assert_eq!(default_locale, "\"0\""); + assert_eq!(small_locale, "\"5\""); + assert_eq!(big_locale, "\"345600\""); + assert_eq!(neg_locale, "\"-25\""); } #[test] @@ -168,161 +168,170 @@ fn to_string() { let realm = Realm::create(); let mut engine = Interpreter::new(realm); - assert_eq!("NaN", &forward(&mut engine, "Number(NaN).toString()")); - assert_eq!("Infinity", &forward(&mut engine, "Number(1/0).toString()")); + assert_eq!("\"NaN\"", &forward(&mut engine, "Number(NaN).toString()")); assert_eq!( - "-Infinity", + "\"Infinity\"", + &forward(&mut engine, "Number(1/0).toString()") + ); + assert_eq!( + "\"-Infinity\"", &forward(&mut engine, "Number(-1/0).toString()") ); - assert_eq!("0", &forward(&mut engine, "Number(0).toString()")); - assert_eq!("9", &forward(&mut engine, "Number(9).toString()")); - assert_eq!("90", &forward(&mut engine, "Number(90).toString()")); - assert_eq!("90.12", &forward(&mut engine, "Number(90.12).toString()")); - assert_eq!("0.1", &forward(&mut engine, "Number(0.1).toString()")); - assert_eq!("0.01", &forward(&mut engine, "Number(0.01).toString()")); - assert_eq!("0.0123", &forward(&mut engine, "Number(0.0123).toString()")); + assert_eq!("\"0\"", &forward(&mut engine, "Number(0).toString()")); + assert_eq!("\"9\"", &forward(&mut engine, "Number(9).toString()")); + assert_eq!("\"90\"", &forward(&mut engine, "Number(90).toString()")); + assert_eq!( + "\"90.12\"", + &forward(&mut engine, "Number(90.12).toString()") + ); + assert_eq!("\"0.1\"", &forward(&mut engine, "Number(0.1).toString()")); + assert_eq!("\"0.01\"", &forward(&mut engine, "Number(0.01).toString()")); + assert_eq!( + "\"0.0123\"", + &forward(&mut engine, "Number(0.0123).toString()") + ); assert_eq!( - "0.00001", + "\"0.00001\"", &forward(&mut engine, "Number(0.00001).toString()") ); assert_eq!( - "0.000001", + "\"0.000001\"", &forward(&mut engine, "Number(0.000001).toString()") ); - assert_eq!("NaN", &forward(&mut engine, "Number(NaN).toString(16)")); + assert_eq!("\"NaN\"", &forward(&mut engine, "Number(NaN).toString(16)")); assert_eq!( - "Infinity", + "\"Infinity\"", &forward(&mut engine, "Number(1/0).toString(16)") ); assert_eq!( - "-Infinity", + "\"-Infinity\"", &forward(&mut engine, "Number(-1/0).toString(16)") ); - assert_eq!("0", &forward(&mut engine, "Number(0).toString(16)")); - assert_eq!("9", &forward(&mut engine, "Number(9).toString(16)")); - assert_eq!("5a", &forward(&mut engine, "Number(90).toString(16)")); + assert_eq!("\"0\"", &forward(&mut engine, "Number(0).toString(16)")); + assert_eq!("\"9\"", &forward(&mut engine, "Number(9).toString(16)")); + assert_eq!("\"5a\"", &forward(&mut engine, "Number(90).toString(16)")); assert_eq!( - "5a.1eb851eb852", + "\"5a.1eb851eb852\"", &forward(&mut engine, "Number(90.12).toString(16)") ); assert_eq!( - "0.1999999999999a", + "\"0.1999999999999a\"", &forward(&mut engine, "Number(0.1).toString(16)") ); assert_eq!( - "0.028f5c28f5c28f6", + "\"0.028f5c28f5c28f6\"", &forward(&mut engine, "Number(0.01).toString(16)") ); assert_eq!( - "0.032617c1bda511a", + "\"0.032617c1bda511a\"", &forward(&mut engine, "Number(0.0123).toString(16)") ); assert_eq!( - "605f9f6dd18bc8000", + "\"605f9f6dd18bc8000\"", &forward(&mut engine, "Number(111111111111111111111).toString(16)") ); assert_eq!( - "3c3bc3a4a2f75c0000", + "\"3c3bc3a4a2f75c0000\"", &forward(&mut engine, "Number(1111111111111111111111).toString(16)") ); assert_eq!( - "25a55a46e5da9a00000", + "\"25a55a46e5da9a00000\"", &forward(&mut engine, "Number(11111111111111111111111).toString(16)") ); assert_eq!( - "0.0000a7c5ac471b4788", + "\"0.0000a7c5ac471b4788\"", &forward(&mut engine, "Number(0.00001).toString(16)") ); assert_eq!( - "0.000010c6f7a0b5ed8d", + "\"0.000010c6f7a0b5ed8d\"", &forward(&mut engine, "Number(0.000001).toString(16)") ); assert_eq!( - "0.000001ad7f29abcaf48", + "\"0.000001ad7f29abcaf48\"", &forward(&mut engine, "Number(0.0000001).toString(16)") ); assert_eq!( - "0.000002036565348d256", + "\"0.000002036565348d256\"", &forward(&mut engine, "Number(0.00000012).toString(16)") ); assert_eq!( - "0.0000021047ee22aa466", + "\"0.0000021047ee22aa466\"", &forward(&mut engine, "Number(0.000000123).toString(16)") ); assert_eq!( - "0.0000002af31dc4611874", + "\"0.0000002af31dc4611874\"", &forward(&mut engine, "Number(0.00000001).toString(16)") ); assert_eq!( - "0.000000338a23b87483be", + "\"0.000000338a23b87483be\"", &forward(&mut engine, "Number(0.000000012).toString(16)") ); assert_eq!( - "0.00000034d3fe36aaa0a2", + "\"0.00000034d3fe36aaa0a2\"", &forward(&mut engine, "Number(0.0000000123).toString(16)") ); - assert_eq!("0", &forward(&mut engine, "Number(-0).toString(16)")); - assert_eq!("-9", &forward(&mut engine, "Number(-9).toString(16)")); - assert_eq!("-5a", &forward(&mut engine, "Number(-90).toString(16)")); + assert_eq!("\"0\"", &forward(&mut engine, "Number(-0).toString(16)")); + assert_eq!("\"-9\"", &forward(&mut engine, "Number(-9).toString(16)")); + assert_eq!("\"-5a\"", &forward(&mut engine, "Number(-90).toString(16)")); assert_eq!( - "-5a.1eb851eb852", + "\"-5a.1eb851eb852\"", &forward(&mut engine, "Number(-90.12).toString(16)") ); assert_eq!( - "-0.1999999999999a", + "\"-0.1999999999999a\"", &forward(&mut engine, "Number(-0.1).toString(16)") ); assert_eq!( - "-0.028f5c28f5c28f6", + "\"-0.028f5c28f5c28f6\"", &forward(&mut engine, "Number(-0.01).toString(16)") ); assert_eq!( - "-0.032617c1bda511a", + "\"-0.032617c1bda511a\"", &forward(&mut engine, "Number(-0.0123).toString(16)") ); assert_eq!( - "-605f9f6dd18bc8000", + "\"-605f9f6dd18bc8000\"", &forward(&mut engine, "Number(-111111111111111111111).toString(16)") ); assert_eq!( - "-3c3bc3a4a2f75c0000", + "\"-3c3bc3a4a2f75c0000\"", &forward(&mut engine, "Number(-1111111111111111111111).toString(16)") ); assert_eq!( - "-25a55a46e5da9a00000", + "\"-25a55a46e5da9a00000\"", &forward(&mut engine, "Number(-11111111111111111111111).toString(16)") ); assert_eq!( - "-0.0000a7c5ac471b4788", + "\"-0.0000a7c5ac471b4788\"", &forward(&mut engine, "Number(-0.00001).toString(16)") ); assert_eq!( - "-0.000010c6f7a0b5ed8d", + "\"-0.000010c6f7a0b5ed8d\"", &forward(&mut engine, "Number(-0.000001).toString(16)") ); assert_eq!( - "-0.000001ad7f29abcaf48", + "\"-0.000001ad7f29abcaf48\"", &forward(&mut engine, "Number(-0.0000001).toString(16)") ); assert_eq!( - "-0.000002036565348d256", + "\"-0.000002036565348d256\"", &forward(&mut engine, "Number(-0.00000012).toString(16)") ); assert_eq!( - "-0.0000021047ee22aa466", + "\"-0.0000021047ee22aa466\"", &forward(&mut engine, "Number(-0.000000123).toString(16)") ); assert_eq!( - "-0.0000002af31dc4611874", + "\"-0.0000002af31dc4611874\"", &forward(&mut engine, "Number(-0.00000001).toString(16)") ); assert_eq!( - "-0.000000338a23b87483be", + "\"-0.000000338a23b87483be\"", &forward(&mut engine, "Number(-0.000000012).toString(16)") ); assert_eq!( - "-0.00000034d3fe36aaa0a2", + "\"-0.00000034d3fe36aaa0a2\"", &forward(&mut engine, "Number(-0.0000000123).toString(16)") ); } diff --git a/boa/src/builtins/object/tests.rs b/boa/src/builtins/object/tests.rs index 68b30642bde..9ed1156f31c 100644 --- a/boa/src/builtins/object/tests.rs +++ b/boa/src/builtins/object/tests.rs @@ -32,7 +32,7 @@ fn object_create_with_undefined() { let result = forward(&mut engine, init); assert_eq!( result, - "TypeError: Object prototype may only be an Object or null: undefined" + "\"TypeError: Object prototype may only be an Object or null: undefined\"" ); } @@ -52,7 +52,7 @@ fn object_create_with_number() { let result = forward(&mut engine, init); assert_eq!( result, - "TypeError: Object prototype may only be an Object or null: 5" + "\"TypeError: Object prototype may only be an Object or null: 5\"" ); } diff --git a/boa/src/builtins/regexp/tests.rs b/boa/src/builtins/regexp/tests.rs index 984a392a231..31f7bdbbdc0 100644 --- a/boa/src/builtins/regexp/tests.rs +++ b/boa/src/builtins/regexp/tests.rs @@ -78,13 +78,16 @@ fn exec() { "#; eprintln!("{}", forward(&mut engine, init)); - assert_eq!(forward(&mut engine, "result[0]"), "Quick Brown Fox Jumps"); - assert_eq!(forward(&mut engine, "result[1]"), "Brown"); - assert_eq!(forward(&mut engine, "result[2]"), "Jumps"); + assert_eq!( + forward(&mut engine, "result[0]"), + "\"Quick Brown Fox Jumps\"" + ); + assert_eq!(forward(&mut engine, "result[1]"), "\"Brown\""); + assert_eq!(forward(&mut engine, "result[2]"), "\"Jumps\""); assert_eq!(forward(&mut engine, "result.index"), "4"); assert_eq!( forward(&mut engine, "result.input"), - "The Quick Brown Fox Jumps Over The Lazy Dog" + "\"The Quick Brown Fox Jumps Over The Lazy Dog\"" ); } @@ -95,15 +98,15 @@ fn to_string() { assert_eq!( forward(&mut engine, "(new RegExp('a+b+c')).toString()"), - "/a+b+c/" + "\"/a+b+c/\"" ); assert_eq!( forward(&mut engine, "(new RegExp('bar', 'g')).toString()"), - "/bar/g" + "\"/bar/g\"" ); assert_eq!( forward(&mut engine, "(new RegExp('\\\\n', 'g')).toString()"), - "/\\n/g" + "\"/\\n/g\"" ); - assert_eq!(forward(&mut engine, "/\\n/g.toString()"), "/\\n/g"); + assert_eq!(forward(&mut engine, "/\\n/g.toString()"), "\"/\\n/g\""); } diff --git a/boa/src/builtins/string/tests.rs b/boa/src/builtins/string/tests.rs index ce4673de07c..1f80a552bdd 100644 --- a/boa/src/builtins/string/tests.rs +++ b/boa/src/builtins/string/tests.rs @@ -66,10 +66,10 @@ fn concat() { eprintln!("{}", forward(&mut engine, init)); let a = forward(&mut engine, "hello.concat(world, nice)"); - assert_eq!(a, "Hello, world! Have a nice day."); + assert_eq!(a, "\"Hello, world! Have a nice day.\""); let b = forward(&mut engine, "hello + world + nice"); - assert_eq!(b, "Hello, world! Have a nice day."); + assert_eq!(b, "\"Hello, world! Have a nice day.\""); } #[test] @@ -83,7 +83,7 @@ fn generic_concat() { eprintln!("{}", forward(&mut engine, init)); let a = forward(&mut engine, "number.concat(' - 50', ' = 50')"); - assert_eq!(a, "100 - 50 = 50"); + assert_eq!(a, "\"100 - 50 = 50\""); } #[allow(clippy::result_unwrap_used)] @@ -118,14 +118,14 @@ fn repeat() { forward(&mut engine, init); - assert_eq!(forward(&mut engine, "empty.repeat(0)"), ""); - assert_eq!(forward(&mut engine, "empty.repeat(1)"), ""); + assert_eq!(forward(&mut engine, "empty.repeat(0)"), "\"\""); + assert_eq!(forward(&mut engine, "empty.repeat(1)"), "\"\""); - assert_eq!(forward(&mut engine, "en.repeat(0)"), ""); - assert_eq!(forward(&mut engine, "zh.repeat(0)"), ""); + assert_eq!(forward(&mut engine, "en.repeat(0)"), "\"\""); + assert_eq!(forward(&mut engine, "zh.repeat(0)"), "\"\""); - assert_eq!(forward(&mut engine, "en.repeat(1)"), "english"); - assert_eq!(forward(&mut engine, "zh.repeat(2)"), "中文中文"); + assert_eq!(forward(&mut engine, "en.repeat(1)"), "\"english\""); + assert_eq!(forward(&mut engine, "zh.repeat(2)"), "\"中文中文\""); } #[test] @@ -140,7 +140,7 @@ fn replace() { forward(&mut engine, init); - assert_eq!(forward(&mut engine, "a"), "2bc"); + assert_eq!(forward(&mut engine, "a"), "\"2bc\""); } #[test] @@ -163,11 +163,11 @@ fn replace_with_function() { forward(&mut engine, init); - assert_eq!(forward(&mut engine, "a"), "ecmascript is awesome!"); + assert_eq!(forward(&mut engine, "a"), "\"ecmascript is awesome!\""); - assert_eq!(forward(&mut engine, "p1"), "o"); - assert_eq!(forward(&mut engine, "p2"), "o"); - assert_eq!(forward(&mut engine, "p3"), "l"); + assert_eq!(forward(&mut engine, "p1"), "\"o\""); + assert_eq!(forward(&mut engine, "p2"), "\"o\""); + assert_eq!(forward(&mut engine, "p3"), "\"l\""); } #[test] @@ -236,10 +236,10 @@ fn match_all() { ); assert_eq!(forward(&mut engine, "groupMatches.length"), "2"); - assert_eq!(forward(&mut engine, "groupMatches[0][1]"), "e"); - assert_eq!(forward(&mut engine, "groupMatches[0][2]"), "st1"); - assert_eq!(forward(&mut engine, "groupMatches[0][3]"), "1"); - assert_eq!(forward(&mut engine, "groupMatches[1][3]"), "2"); + assert_eq!(forward(&mut engine, "groupMatches[0][1]"), "\"e\""); + assert_eq!(forward(&mut engine, "groupMatches[0][2]"), "\"st1\""); + assert_eq!(forward(&mut engine, "groupMatches[0][3]"), "\"1\""); + assert_eq!(forward(&mut engine, "groupMatches[1][3]"), "\"2\""); assert_eq!( forward( @@ -257,9 +257,9 @@ fn match_all() { forward(&mut engine, init); - assert_eq!(forward(&mut engine, "matches[0][0]"), "football"); + assert_eq!(forward(&mut engine, "matches[0][0]"), "\"football\""); assert_eq!(forward(&mut engine, "matches[0].index"), "6"); - assert_eq!(forward(&mut engine, "matches[1][0]"), "foosball"); + assert_eq!(forward(&mut engine, "matches[1][0]"), "\"foosball\""); assert_eq!(forward(&mut engine, "matches[1].index"), "16"); } @@ -277,30 +277,33 @@ fn test_match() { forward(&mut engine, init); - assert_eq!(forward(&mut engine, "result1[0]"), "Quick Brown Fox Jumps"); - assert_eq!(forward(&mut engine, "result1[1]"), "Brown"); - assert_eq!(forward(&mut engine, "result1[2]"), "Jumps"); + assert_eq!( + forward(&mut engine, "result1[0]"), + "\"Quick Brown Fox Jumps\"" + ); + assert_eq!(forward(&mut engine, "result1[1]"), "\"Brown\""); + assert_eq!(forward(&mut engine, "result1[2]"), "\"Jumps\""); assert_eq!(forward(&mut engine, "result1.index"), "4"); assert_eq!( forward(&mut engine, "result1.input"), - "The Quick Brown Fox Jumps Over The Lazy Dog" + "\"The Quick Brown Fox Jumps Over The Lazy Dog\"" ); - assert_eq!(forward(&mut engine, "result2[0]"), "T"); - assert_eq!(forward(&mut engine, "result2[1]"), "Q"); - assert_eq!(forward(&mut engine, "result2[2]"), "B"); - assert_eq!(forward(&mut engine, "result2[3]"), "F"); - assert_eq!(forward(&mut engine, "result2[4]"), "J"); - assert_eq!(forward(&mut engine, "result2[5]"), "O"); - assert_eq!(forward(&mut engine, "result2[6]"), "T"); - assert_eq!(forward(&mut engine, "result2[7]"), "L"); - assert_eq!(forward(&mut engine, "result2[8]"), "D"); - - assert_eq!(forward(&mut engine, "result3[0]"), "T"); + assert_eq!(forward(&mut engine, "result2[0]"), "\"T\""); + assert_eq!(forward(&mut engine, "result2[1]"), "\"Q\""); + assert_eq!(forward(&mut engine, "result2[2]"), "\"B\""); + assert_eq!(forward(&mut engine, "result2[3]"), "\"F\""); + assert_eq!(forward(&mut engine, "result2[4]"), "\"J\""); + assert_eq!(forward(&mut engine, "result2[5]"), "\"O\""); + assert_eq!(forward(&mut engine, "result2[6]"), "\"T\""); + assert_eq!(forward(&mut engine, "result2[7]"), "\"L\""); + assert_eq!(forward(&mut engine, "result2[8]"), "\"D\""); + + assert_eq!(forward(&mut engine, "result3[0]"), "\"T\""); assert_eq!(forward(&mut engine, "result3.index"), "0"); assert_eq!( forward(&mut engine, "result3.input"), - "The Quick Brown Fox Jumps Over The Lazy Dog" + "\"The Quick Brown Fox Jumps Over The Lazy Dog\"" ); - assert_eq!(forward(&mut engine, "result4[0]"), "B"); + assert_eq!(forward(&mut engine, "result4[0]"), "\"B\""); } diff --git a/boa/src/builtins/symbol/tests.rs b/boa/src/builtins/symbol/tests.rs index 4dd2b462d82..518632a4ef9 100644 --- a/boa/src/builtins/symbol/tests.rs +++ b/boa/src/builtins/symbol/tests.rs @@ -21,5 +21,5 @@ fn print_symbol_expect_description() { "#; eprintln!("{}", forward(&mut engine, init)); let sym = forward_val(&mut engine, "sym.toString()").unwrap(); - assert_eq!(sym.to_string(), "Symbol(Hello)"); + assert_eq!(sym.to_string(), "\"Symbol(Hello)\""); } diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index 37337c21d5a..0f7afcea27d 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -31,7 +31,7 @@ fn get_set_field() { // Create string and convert it to a Value let s = Value::from("bar"); obj.set_str_field("foo", s); - assert_eq!(obj.get_field("foo").to_string(), "bar"); + assert_eq!(obj.get_field("foo").to_string(), "\"bar\""); } #[test] diff --git a/boa/src/environment/lexical_environment.rs b/boa/src/environment/lexical_environment.rs index ad7e0dde190..66bf668d771 100644 --- a/boa/src/environment/lexical_environment.rs +++ b/boa/src/environment/lexical_environment.rs @@ -307,7 +307,7 @@ mod tests { } "#; - assert_eq!(&exec(scenario), "bar is not defined"); + assert_eq!(&exec(scenario), "\"bar is not defined\""); } #[test] @@ -324,7 +324,7 @@ mod tests { } "#; - assert_eq!(&exec(scenario), "bar is not defined"); + assert_eq!(&exec(scenario), "\"bar is not defined\""); } #[test] diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs index 9e3344c9265..45e0a2ab424 100644 --- a/boa/src/exec/field/mod.rs +++ b/boa/src/exec/field/mod.rs @@ -23,6 +23,6 @@ impl Executable for GetField { } let field = self.field().run(interpreter)?; - Ok(obj.get_field(field.to_string())) + Ok(obj.get_field(interpreter.to_string(&field)?)) } } diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index 159fd6c8c46..6f1daf240e7 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -203,12 +203,12 @@ impl Executable for UnaryOp { .run(interpreter)? .remove_property(get_const_field.field()), ), - Node::GetField(ref get_field) => Value::boolean( - get_field - .obj() - .run(interpreter)? - .remove_property(&get_field.field().run(interpreter)?.to_string()), - ), + Node::GetField(ref get_field) => { + let obj = get_field.obj().run(interpreter)?; + let field = &get_field.field().run(interpreter)?; + let res = obj.remove_property(interpreter.to_string(field)?.as_str()); + return Ok(Value::boolean(res)); + } Node::Identifier(_) => Value::boolean(false), Node::ArrayDecl(_) | Node::Block(_) diff --git a/boa/src/exec/operator/tests.rs b/boa/src/exec/operator/tests.rs index acabf87fe54..f567b795713 100644 --- a/boa/src/exec/operator/tests.rs +++ b/boa/src/exec/operator/tests.rs @@ -10,7 +10,7 @@ fn assignmentoperator_lhs_not_defined() { } "#; - assert_eq!(&exec(scenario), "ReferenceError: a is not defined"); + assert_eq!(&exec(scenario), "\"ReferenceError: a is not defined\""); } #[test] @@ -24,5 +24,5 @@ fn assignmentoperator_rhs_throws_error() { } "#; - assert_eq!(&exec(scenario), "ReferenceError: b is not defined"); + assert_eq!(&exec(scenario), "\"ReferenceError: b is not defined\""); } diff --git a/boa/src/exec/switch/tests.rs b/boa/src/exec/switch/tests.rs index 2c6f0ad3b1b..ead275bc836 100644 --- a/boa/src/exec/switch/tests.rs +++ b/boa/src/exec/switch/tests.rs @@ -152,12 +152,20 @@ fn string_switch() { a; "#; - assert_eq!(&exec(scenario), "world"); + assert_eq!(&exec(scenario), "\"world\""); } #[test] fn bigger_switch_example() { - let expected = ["Mon", "Tue", "Wed", "Thurs", "Fri", "Sat", "Sun"]; + let expected = [ + "\"Mon\"", + "\"Tue\"", + "\"Wed\"", + "\"Thurs\"", + "\"Fri\"", + "\"Sat\"", + "\"Sun\"", + ]; for (i, val) in expected.iter().enumerate() { let scenario = format!( diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 68cdaa39f6c..0bded320007 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -21,7 +21,7 @@ fn property_accessor_member_expression_dot_notation_on_string_literal() { typeof 'asd'.matchAll; "#; - assert_eq!(&exec(scenario), "function"); + assert_eq!(&exec(scenario), "\"function\""); } #[test] @@ -30,7 +30,7 @@ fn property_accessor_member_expression_bracket_notation_on_string_literal() { typeof 'asd'['matchAll']; "#; - assert_eq!(&exec(scenario), "function"); + assert_eq!(&exec(scenario), "\"function\""); } #[test] @@ -40,7 +40,7 @@ fn property_accessor_member_expression_dot_notation_on_function() { asd.name; "#; - assert_eq!(&exec(scenario), "asd"); + assert_eq!(&exec(scenario), "\"asd\""); } #[test] @@ -50,7 +50,7 @@ fn property_accessor_member_expression_bracket_notation_on_function() { asd['name']; "#; - assert_eq!(&exec(scenario), "asd"); + assert_eq!(&exec(scenario), "\"asd\""); } #[test] @@ -94,7 +94,7 @@ fn identifier_on_global_object_undefined() { } "#; - assert_eq!(&exec(scenario), "bar is not defined"); + assert_eq!(&exec(scenario), "\"bar is not defined\""); } #[test] @@ -125,7 +125,7 @@ fn spread_with_arguments() { assert_eq!(one, String::from("1")); let two = forward(&mut engine, "result[1]"); - assert_eq!(two, String::from("test")); + assert_eq!(two, String::from("\"test\"")); let three = forward(&mut engine, "result[2]"); assert_eq!(three, String::from("3")); @@ -140,9 +140,9 @@ fn array_rest_with_arguments() { let mut engine = Interpreter::new(realm); let scenario = r#" - var b = [4, 5, 6] - var a = [1, 2, 3, ...b]; - "#; + var b = [4, 5, 6] + var a = [1, 2, 3, ...b]; + "#; forward(&mut engine, scenario); let one = forward(&mut engine, "a"); assert_eq!(one, String::from("[ 1, 2, 3, 4, 5, 6 ]")); @@ -151,54 +151,53 @@ fn array_rest_with_arguments() { #[test] fn array_field_set() { let element_changes = r#" - let m = [1, 2, 3]; - m[1] = 5; - m[1] - "#; + let m = [1, 2, 3]; + m[1] = 5; + m[1] + "#; assert_eq!(&exec(element_changes), "5"); let length_changes = r#" - let m = [1, 2, 3]; - m[10] = 52; - m.length - "#; + let m = [1, 2, 3]; + m[10] = 52; + m.length + "#; assert_eq!(&exec(length_changes), "11"); let negative_index_wont_affect_length = r#" - let m = [1, 2, 3]; - m[-11] = 5; - m.length - "#; + let m = [1, 2, 3]; + m[-11] = 5; + m.length + "#; assert_eq!(&exec(negative_index_wont_affect_length), "3"); let non_num_key_wont_affect_length = r#" - let m = [1, 2, 3]; - m["magic"] = 5; - m.length - "#; + let m = [1, 2, 3]; + m["magic"] = 5; + m.length + "#; assert_eq!(&exec(non_num_key_wont_affect_length), "3"); } #[test] fn tilde_operator() { let float = r#" - let f = -1.2; - ~f - "#; + let f = -1.2; + ~f + "#; assert_eq!(&exec(float), "0"); let numeric = r#" - let f = 1789; - ~f - "#; + let f = 1789; + ~f + "#; assert_eq!(&exec(numeric), "-1790"); - // TODO: enable test after we have NaN - // let nan = r#" - // var m = NaN; - // ~m - // "#; - // assert_eq!(&exec(nan), "-1"); + let nan = r#" + var m = NaN; + ~m + "#; + assert_eq!(&exec(nan), "-1"); let object = r#" let m = {}; @@ -240,7 +239,7 @@ fn early_return() { } outer_fnct() "#; - assert_eq!(&exec(early_return), "outer"); + assert_eq!(&exec(early_return), "\"outer\""); } #[test] @@ -370,7 +369,7 @@ fn for_loop() { } b "#; - assert_eq!(&exec(simple), "hello"); + assert_eq!(&exec(simple), "\"hello\""); let without_init_and_inc_step = r#" let a = 0; @@ -407,7 +406,7 @@ fn for_loop_iteration_variable_does_not_leak() { } "#; - assert_eq!(&exec(inner_scope), "i is not defined"); + assert_eq!(&exec(inner_scope), "\"i is not defined\""); } #[test] @@ -459,7 +458,7 @@ fn typeof_string() { const a = String(); typeof a; "#; - assert_eq!(&exec(typeof_string), "string"); + assert_eq!(&exec(typeof_string), "\"string\""); } #[test] @@ -468,7 +467,7 @@ fn typeof_int() { let a = 5; typeof a; "#; - assert_eq!(&exec(typeof_int), "number"); + assert_eq!(&exec(typeof_int), "\"number\""); } #[test] @@ -477,7 +476,7 @@ fn typeof_rational() { let a = 0.5; typeof a; "#; - assert_eq!(&exec(typeof_rational), "number"); + assert_eq!(&exec(typeof_rational), "\"number\""); } #[test] @@ -486,7 +485,7 @@ fn typeof_undefined() { let a = undefined; typeof a; "#; - assert_eq!(&exec(typeof_undefined), "undefined"); + assert_eq!(&exec(typeof_undefined), "\"undefined\""); } #[test] @@ -494,7 +493,7 @@ fn typeof_undefined_directly() { let typeof_undefined = r#" typeof undefined; "#; - assert_eq!(&exec(typeof_undefined), "undefined"); + assert_eq!(&exec(typeof_undefined), "\"undefined\""); } #[test] @@ -503,7 +502,7 @@ fn typeof_boolean() { let a = true; typeof a; "#; - assert_eq!(&exec(typeof_boolean), "boolean"); + assert_eq!(&exec(typeof_boolean), "\"boolean\""); } #[test] @@ -512,7 +511,7 @@ fn typeof_null() { let a = null; typeof a; "#; - assert_eq!(&exec(typeof_null), "object"); + assert_eq!(&exec(typeof_null), "\"object\""); } #[test] @@ -521,7 +520,7 @@ fn typeof_object() { let a = {}; typeof a; "#; - assert_eq!(&exec(typeof_object), "object"); + assert_eq!(&exec(typeof_object), "\"object\""); } #[test] @@ -530,7 +529,7 @@ fn typeof_symbol() { let a = Symbol(); typeof a; "#; - assert_eq!(&exec(typeof_symbol), "symbol"); + assert_eq!(&exec(typeof_symbol), "\"symbol\""); } #[test] @@ -539,7 +538,7 @@ fn typeof_function() { let a = function(){}; typeof a; "#; - assert_eq!(&exec(typeof_function), "function"); + assert_eq!(&exec(typeof_function), "\"function\""); } #[test] @@ -599,7 +598,7 @@ fn unary_void() { const b = void test() + ''; a + b "#; - assert_eq!(&exec(void_invocation), "42undefined"); + assert_eq!(&exec(void_invocation), "\"42undefined\""); } #[test] @@ -609,28 +608,28 @@ fn unary_delete() { const b = delete a + ''; a + b "#; - assert_eq!(&exec(delete_var), "5false"); + assert_eq!(&exec(delete_var), "\"5false\""); let delete_prop = r#" const a = { b: 5 }; const c = delete a.b + ''; a.b + c "#; - assert_eq!(&exec(delete_prop), "undefinedtrue"); + assert_eq!(&exec(delete_prop), "\"undefinedtrue\""); let delete_not_existing_prop = r#" const a = { b: 5 }; const c = delete a.c + ''; a.b + c "#; - assert_eq!(&exec(delete_not_existing_prop), "5false"); + assert_eq!(&exec(delete_not_existing_prop), "\"5false\""); let delete_field = r#" const a = { b: 5 }; const c = delete a['b'] + ''; a.b + c "#; - assert_eq!(&exec(delete_field), "undefinedtrue"); + assert_eq!(&exec(delete_field), "\"undefinedtrue\""); let delete_object = r#" const a = { b: 5 }; @@ -746,8 +745,8 @@ mod in_operator { var bar = new Foo(); "#; forward(&mut engine, scenario); - assert_eq!(forward(&mut engine, "bar.a"), "a"); - assert_eq!(forward(&mut engine, "bar.b"), "b"); + assert_eq!(forward(&mut engine, "bar.a"), "\"a\""); + assert_eq!(forward(&mut engine, "bar.b"), "\"b\""); } #[test] @@ -1145,7 +1144,10 @@ fn not_a_function() { e.toString() } "#; - assert_eq!(forward(&mut engine, scenario), "TypeError: not a function"); + assert_eq!( + forward(&mut engine, scenario), + "\"TypeError: not a function\"" + ); let scenario = r#" try { a.a(); @@ -1153,7 +1155,10 @@ fn not_a_function() { e.toString() } "#; - assert_eq!(forward(&mut engine, scenario), "TypeError: not a function"); + assert_eq!( + forward(&mut engine, scenario), + "\"TypeError: not a function\"" + ); let scenario = r#" try { b(); @@ -1161,5 +1166,8 @@ fn not_a_function() { e.toString() } "#; - assert_eq!(forward(&mut engine, scenario), "TypeError: not a function"); + assert_eq!( + forward(&mut engine, scenario), + "\"TypeError: not a function\"" + ); } From 0e897c8a228f364241e09964850e0618c78cc0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Sat, 25 Jul 2020 02:26:29 +0100 Subject: [PATCH 11/16] Style: Fix not respecting clippy --- boa/src/builtins/property/mod.rs | 4 ++-- boa/src/exec/mod.rs | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/boa/src/builtins/property/mod.rs b/boa/src/builtins/property/mod.rs index ae6ac2ac059..2ac3328443c 100644 --- a/boa/src/builtins/property/mod.rs +++ b/boa/src/builtins/property/mod.rs @@ -287,7 +287,7 @@ pub enum PropertyKey { impl From for PropertyKey { fn from(string: RcString) -> PropertyKey { - PropertyKey::String(string.clone()) + PropertyKey::String(string) } } @@ -299,7 +299,7 @@ impl From<&str> for PropertyKey { impl From for PropertyKey { fn from(symbol: RcSymbol) -> PropertyKey { - PropertyKey::Symbol(symbol.clone()) + PropertyKey::Symbol(symbol) } } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 004fa701c58..a5a0e84d808 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -491,12 +491,11 @@ impl Interpreter { #[allow(clippy::wrong_self_convention)] pub(crate) fn to_property_key(&mut self, value: &Value) -> Result { let key = self.to_primitive(value, PreferredType::String)?; - match key { - Value::Symbol(ref symbol) => Ok(PropertyKey::from(symbol.clone())), - _ => { - let string = self.to_string(&key)?; - return Ok(PropertyKey::from(string)); - } + if let Value::Symbol(ref symbol) = key { + Ok(PropertyKey::from(symbol.clone())) + } else { + let string = self.to_string(&key)?; + Ok(PropertyKey::from(string)) } } From 50cff2cda2f59aad849f8dd5944e723dd2ff1d07 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sun, 26 Jul 2020 08:13:19 +0200 Subject: [PATCH 12/16] Removed `set_str_field` --- boa/src/builtins/array/mod.rs | 44 +++++++++--------- boa/src/builtins/error/mod.rs | 6 +-- boa/src/builtins/error/range.rs | 6 +-- boa/src/builtins/error/reference.rs | 6 +-- boa/src/builtins/error/syntax.rs | 6 +-- boa/src/builtins/error/type.rs | 6 +-- boa/src/builtins/json/mod.rs | 4 +- boa/src/builtins/property/mod.rs | 42 ++++++++++++++--- boa/src/builtins/regexp/mod.rs | 6 +-- boa/src/builtins/string/mod.rs | 2 +- boa/src/builtins/value/conversions.rs | 6 +++ boa/src/builtins/value/mod.rs | 65 +++++++-------------------- boa/src/builtins/value/rcstring.rs | 7 +++ boa/src/builtins/value/tests.rs | 2 +- boa/src/exec/declaration/mod.rs | 4 +- boa/src/exec/mod.rs | 19 ++++---- boa/src/exec/object/mod.rs | 4 +- boa/src/exec/operator/mod.rs | 11 ++--- boa/src/realm.rs | 3 +- 19 files changed, 128 insertions(+), 121 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 9e6ad6035f5..2a9ab4fb16e 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -57,7 +57,7 @@ impl Array { .borrow() .get_field(PROTOTYPE), ); - array.borrow().set_str_field("length", Value::from(0)); + array.borrow().set_field("length", Value::from(0)); Ok(array) } @@ -82,7 +82,7 @@ impl Array { array_obj_ptr.set_property("length".to_string(), length); for (n, value) in array_contents.iter().enumerate() { - array_obj_ptr.set_str_field(&n.to_string(), value); + array_obj_ptr.set_field(n.to_string(), value); } Ok(array_obj_ptr) } @@ -94,10 +94,10 @@ impl Array { for (n, value) in add_values.iter().enumerate() { let new_index = orig_length.wrapping_add(n as i32); - array_ptr.set_str_field(&new_index.to_string(), value); + array_ptr.set_field(new_index.to_string(), value); } - array_ptr.set_str_field( + array_ptr.set_field( "length", Value::from(orig_length.wrapping_add(add_values.len() as i32)), ); @@ -127,7 +127,7 @@ impl Array { length = i32::from(&args[0]); // TODO: It should not create an array of undefineds, but an empty array ("holy" array in V8) with length `n`. for n in 0..length { - this.set_str_field(&n.to_string(), Value::undefined()); + this.set_field(n.to_string(), Value::undefined()); } } 1 if args[0].is_double() => { @@ -135,7 +135,7 @@ impl Array { } _ => { for (n, value) in args.iter().enumerate() { - this.set_str_field(&n.to_string(), value.clone()); + this.set_field(n.to_string(), value.clone()); } } } @@ -245,7 +245,7 @@ impl Array { let pop_index = curr_length.wrapping_sub(1); let pop_value: Value = this.get_field(pop_index.to_string()); this.remove_property(&pop_index.to_string()); - this.set_str_field("length", Value::from(pop_index)); + this.set_field("length", Value::from(pop_index)); Ok(pop_value) } @@ -380,13 +380,13 @@ impl Array { let lower_value = this.get_field(lower.to_string()); if upper_exists && lower_exists { - this.set_str_field(&upper.to_string(), lower_value); - this.set_str_field(&lower.to_string(), upper_value); + this.set_field(upper.to_string(), lower_value); + this.set_field(lower.to_string(), upper_value); } else if upper_exists { - this.set_str_field(&lower.to_string(), upper_value); + this.set_field(lower.to_string(), upper_value); this.remove_property(&upper.to_string()); } else if lower_exists { - this.set_str_field(&upper.to_string(), lower_value); + this.set_field(upper.to_string(), lower_value); this.remove_property(&lower.to_string()); } } @@ -408,7 +408,7 @@ impl Array { let len = i32::from(&this.get_field("length")); if len == 0 { - this.set_str_field("length", 0); + this.set_field("length", 0); // Since length is 0, this will be an Undefined value return Ok(this.get_field(0.to_string())); } @@ -423,13 +423,13 @@ impl Array { if from_value.is_undefined() { this.remove_property(&to); } else { - this.set_str_field(&to, from_value); + this.set_field(to, from_value); } } let final_index = len.wrapping_sub(1); this.remove_property(&(final_index).to_string()); - this.set_str_field("length", Value::from(final_index)); + this.set_field("length", Value::from(final_index)); Ok(first) } @@ -459,12 +459,12 @@ impl Array { if from_value.is_undefined() { this.remove_property(&to); } else { - this.set_str_field(&to, from_value); + this.set_field(to, from_value); } } for j in 0..arg_c { - this.set_str_field( - &j.to_string(), + this.set_field( + j.to_string(), args.get(j as usize) .expect("Could not get argument") .clone(), @@ -473,7 +473,7 @@ impl Array { } let temp = len.wrapping_add(arg_c); - this.set_str_field("length", Value::from(temp)); + this.set_field("length", Value::from(temp)); Ok(Value::from(temp)) } @@ -777,7 +777,7 @@ impl Array { }; for i in start..fin { - this.set_str_field(&i.to_string(), value.clone()); + this.set_field(i.to_string(), value.clone()); } Ok(this.clone()) @@ -854,10 +854,10 @@ impl Array { let span = max(to.wrapping_sub(from), 0); let mut new_array_len: i32 = 0; for i in from..from.wrapping_add(span) { - new_array.set_str_field(&new_array_len.to_string(), this.get_field(i.to_string())); + new_array.set_field(new_array_len.to_string(), this.get_field(i.to_string())); new_array_len = new_array_len.wrapping_add(1); } - new_array.set_str_field("length", Value::from(new_array_len)); + new_array.set_field("length", Value::from(new_array_len)); Ok(new_array) } @@ -1026,7 +1026,7 @@ impl Array { /// /// The reduceRight method traverses right to left starting from the last defined value in the array, /// accumulating a value using a given callback function. It returns the accumulated value. - /// + /// /// More information: /// - [ECMAScript reference][spec] /// - [MDN documentation][mdn] diff --git a/boa/src/builtins/error/mod.rs b/boa/src/builtins/error/mod.rs index 95f7a667428..828ab554cee 100644 --- a/boa/src/builtins/error/mod.rs +++ b/boa/src/builtins/error/mod.rs @@ -48,7 +48,7 @@ impl Error { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_str_field("message", ctx.to_string(message)?); + this.set_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -80,8 +80,8 @@ impl Error { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let prototype = Value::new_object(Some(global)); - prototype.set_str_field("name", Self::NAME); - prototype.set_str_field("message", ""); + prototype.set_field("name", Self::NAME); + prototype.set_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/range.rs b/boa/src/builtins/error/range.rs index 9dbd1550ed1..91d1f1a1c1f 100644 --- a/boa/src/builtins/error/range.rs +++ b/boa/src/builtins/error/range.rs @@ -34,7 +34,7 @@ impl RangeError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_str_field("message", ctx.to_string(message)?); + this.set_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -66,8 +66,8 @@ impl RangeError { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let prototype = Value::new_object(Some(global)); - prototype.set_str_field("name", Self::NAME); - prototype.set_str_field("message", ""); + prototype.set_field("name", Self::NAME); + prototype.set_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/reference.rs b/boa/src/builtins/error/reference.rs index a7baaf7a6ac..b757fcccbeb 100644 --- a/boa/src/builtins/error/reference.rs +++ b/boa/src/builtins/error/reference.rs @@ -33,7 +33,7 @@ impl ReferenceError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_str_field("message", ctx.to_string(message)?); + this.set_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -64,8 +64,8 @@ impl ReferenceError { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let prototype = Value::new_object(Some(global)); - prototype.set_str_field("name", Self::NAME); - prototype.set_str_field("message", ""); + prototype.set_field("name", Self::NAME); + prototype.set_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/syntax.rs b/boa/src/builtins/error/syntax.rs index 4db99614d7d..783551651a5 100644 --- a/boa/src/builtins/error/syntax.rs +++ b/boa/src/builtins/error/syntax.rs @@ -36,7 +36,7 @@ impl SyntaxError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_str_field("message", ctx.to_string(message)?); + this.set_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -68,8 +68,8 @@ impl SyntaxError { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let prototype = Value::new_object(Some(global)); - prototype.set_str_field("name", Self::NAME); - prototype.set_str_field("message", ""); + prototype.set_field("name", Self::NAME); + prototype.set_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/error/type.rs b/boa/src/builtins/error/type.rs index 8659ee3f80d..0fef65222fe 100644 --- a/boa/src/builtins/error/type.rs +++ b/boa/src/builtins/error/type.rs @@ -40,7 +40,7 @@ impl TypeError { /// Create a new error object. pub(crate) fn make_error(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { if let Some(message) = args.get(0) { - this.set_str_field("message", ctx.to_string(message)?); + this.set_field("message", ctx.to_string(message)?); } // This value is used by console.log and other routines to match Object type @@ -72,8 +72,8 @@ impl TypeError { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let prototype = Value::new_object(Some(global)); - prototype.set_str_field("name", Self::NAME); - prototype.set_str_field("message", ""); + prototype.set_field("name", Self::NAME); + prototype.set_field("message", ""); make_builtin_fn(Self::to_string, "toString", &prototype, 0); diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 722cc5d0245..e01c46f9e38 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -53,7 +53,7 @@ impl Json { match args.get(1) { Some(reviver) if reviver.is_function() => { let mut holder = Value::new_object(None); - holder.set_str_field("", j); + holder.set_field("", j); Self::walk(reviver, ctx, &mut holder, Value::from("")) } _ => Ok(j), @@ -78,7 +78,7 @@ impl Json { let v = Self::walk(reviver, ctx, &mut value, Value::from(key.as_str())); match v { Ok(v) if !v.is_undefined() => { - value.set_str_field(key.as_str(), v); + value.set_field(key.as_str(), v); } Ok(_) => { value.remove_property(key.as_str()); diff --git a/boa/src/builtins/property/mod.rs b/boa/src/builtins/property/mod.rs index 2ac3328443c..d215c58f135 100644 --- a/boa/src/builtins/property/mod.rs +++ b/boa/src/builtins/property/mod.rs @@ -231,20 +231,20 @@ impl From<&Property> for Value { fn from(value: &Property) -> Value { let property = Value::new_object(None); if value.attribute.has_writable() { - property.set_str_field("writable", value.attribute.writable()); + property.set_field("writable", value.attribute.writable()); } if value.attribute.has_enumerable() { - property.set_str_field("enumerable", value.attribute.enumerable()); + property.set_field("enumerable", value.attribute.enumerable()); } if value.attribute.has_configurable() { - property.set_str_field("configurable", value.attribute.configurable()); + property.set_field("configurable", value.attribute.configurable()); } - property.set_str_field("value", value.value.clone().unwrap_or_else(Value::null)); - property.set_str_field("get", value.get.clone().unwrap_or_else(Value::null)); - property.set_str_field("set", value.set.clone().unwrap_or_else(Value::null)); + property.set_field("value", value.value.clone().unwrap_or_else(Value::null)); + property.set_field("get", value.get.clone().unwrap_or_else(Value::null)); + property.set_field("set", value.set.clone().unwrap_or_else(Value::null)); property } } @@ -297,6 +297,18 @@ impl From<&str> for PropertyKey { } } +impl From for PropertyKey { + fn from(string: String) -> PropertyKey { + PropertyKey::String(string.into()) + } +} + +impl From> for PropertyKey { + fn from(string: Box) -> PropertyKey { + PropertyKey::String(string.into()) + } +} + impl From for PropertyKey { fn from(symbol: RcSymbol) -> PropertyKey { PropertyKey::Symbol(symbol) @@ -320,3 +332,21 @@ impl From<&PropertyKey> for RcString { } } } + +impl From<&PropertyKey> for Value { + fn from(property_key: &PropertyKey) -> Value { + match property_key { + PropertyKey::String(ref string) => string.clone().into(), + PropertyKey::Symbol(ref symbol) => symbol.clone().into(), + } + } +} + +impl From for Value { + fn from(property_key: PropertyKey) -> Value { + match property_key { + PropertyKey::String(ref string) => string.clone().into(), + PropertyKey::Symbol(ref symbol) => symbol.clone().into(), + } + } +} diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index c38c0491cdc..cf96bfb96e8 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -306,7 +306,7 @@ impl RegExp { }; Ok(Value::boolean(result)) }); - this.set_str_field("lastIndex", Value::from(last_index)); + this.set_field("lastIndex", Value::from(last_index)); result } @@ -358,7 +358,7 @@ impl RegExp { }; Ok(result) }); - this.set_str_field("lastIndex", Value::from(last_index)); + this.set_field("lastIndex", Value::from(last_index)); result } @@ -452,7 +452,7 @@ impl RegExp { let length = matches.len(); let result = Value::from(matches); - result.set_str_field("length", Value::from(length)); + result.set_field("length", Value::from(length)); result.set_data(ObjectData::Array); Ok(result) diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 9bf7e6a4710..c6576917514 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -77,7 +77,7 @@ impl String { let length = string.chars().count(); - this.set_str_field("length", Value::from(length as i32)); + this.set_field("length", Value::from(length as i32)); this.set_data(ObjectData::String(string.clone())); diff --git a/boa/src/builtins/value/conversions.rs b/boa/src/builtins/value/conversions.rs index dafe62fc74f..9f982998c34 100644 --- a/boa/src/builtins/value/conversions.rs +++ b/boa/src/builtins/value/conversions.rs @@ -44,6 +44,12 @@ impl From for Value { } } +impl From for Value { + fn from(value: RcSymbol) -> Self { + Value::Symbol(value) + } +} + #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct TryFromCharError; diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 6843fb92a05..70e2b1cb437 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -623,69 +623,34 @@ impl Value { self.get_property(field).is_some() } - /// Set the string field in the value - /// Alternative to set_field, strictly for &str fields - pub fn set_str_field(&self, field: &str, val: V) -> Value - where - V: Into, - { - let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); - let val = val.into(); - - if let Self::Object(ref obj) = *self { - if obj.borrow().is_array() { - if let Ok(num) = field.parse::() { - if num > 0 { - let len = i32::from(&self.get_field("length")); - if len < (num + 1) as i32 { - self.set_str_field("length", Value::from(num + 1)); - } - } - } - } - - obj.borrow_mut().set(field.into(), val.clone()); - } - - val - } - /// Set the field in the value /// Field could be a Symbol, so we need to accept a Value (not a string) - pub fn set_field(&self, field: F, val: V, interpreter: &mut Interpreter) -> Value + #[inline] + pub fn set_field(&self, field: F, value: V) -> Value where - F: Into, + F: Into, V: Into, { - let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); let field = field.into(); - let val = val.into(); - + let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); if let Self::Object(ref obj) = *self { - if obj.borrow().is_array() { - if let Ok(num) = field.to_string().parse::() { - if num > 0 { - let len = i32::from(&self.get_field("length")); - if len < (num + 1) as i32 { - self.set_str_field("length", Value::from(num + 1)); + if let PropertyKey::String(ref string) = field { + if obj.borrow().is_array() { + if let Ok(num) = string.parse::() { + if num > 0 { + let len = i32::from(&self.get_field("length")); + if len < (num + 1) as i32 { + self.set_field("length", num + 1); + } } } } } // Symbols get saved into a different bucket to general properties - match field { - Value::Symbol(ref symbol) => obj - .borrow_mut() - .set(PropertyKey::from(symbol.clone()), val.clone()), - _ => obj.borrow_mut().set( - PropertyKey::from(interpreter.to_string(&field).unwrap()), - val.clone(), - ), - }; + obj.borrow_mut().set(field.clone(), value.into()); } - - val + field.into() } /// Set the private field in the value @@ -737,7 +702,7 @@ impl Value { // Wrap Object in GC'd Value let new_func_val = Value::from(new_func); // Set length to parameters - new_func_val.set_str_field("length", Value::from(length)); + new_func_val.set_field("length", Value::from(length)); new_func_val } } diff --git a/boa/src/builtins/value/rcstring.rs b/boa/src/builtins/value/rcstring.rs index f5fab547320..d5a58552390 100644 --- a/boa/src/builtins/value/rcstring.rs +++ b/boa/src/builtins/value/rcstring.rs @@ -79,6 +79,13 @@ impl From for RcString { } } +impl From> for RcString { + #[inline] + fn from(string: Box) -> Self { + Self(Rc::from(string)) + } +} + impl From<&str> for RcString { #[inline] fn from(string: &str) -> Self { diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index 0f7afcea27d..faa810bdbcd 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -30,7 +30,7 @@ fn get_set_field() { let obj = Value::new_object(None); // Create string and convert it to a Value let s = Value::from("bar"); - obj.set_str_field("foo", s); + obj.set_field("foo", s); assert_eq!(obj.get_field("foo").to_string(), "\"bar\""); } diff --git a/boa/src/exec/declaration/mod.rs b/boa/src/exec/declaration/mod.rs index 4eb273763f1..37f199003a4 100644 --- a/boa/src/exec/declaration/mod.rs +++ b/boa/src/exec/declaration/mod.rs @@ -25,7 +25,7 @@ impl Executable for FunctionDecl { ); // Set the name and assign it in the current environment - val.set_str_field("name", self.name()); + val.set_field("name", self.name()); interpreter.realm_mut().environment.create_mutable_binding( self.name().to_owned(), false, @@ -52,7 +52,7 @@ impl Executable for FunctionExpr { ); if let Some(name) = self.name() { - val.set_str_field("name", Value::from(name)); + val.set_field("name", Value::from(name)); } Ok(val) diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index a5a0e84d808..5d2cc1b2920 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -152,8 +152,8 @@ impl Interpreter { let new_func = Object::function(func, function_prototype); let val = Value::from(new_func); - val.set_str_field(PROTOTYPE, proto); - val.set_str_field("length", Value::from(params_len)); + val.set_field(PROTOTYPE, proto); + val.set_field("length", Value::from(params_len)); val } @@ -400,9 +400,9 @@ impl Interpreter { .borrow() .get_field(PROTOTYPE), ); - array.set_str_field("0", key); - array.set_str_field("1", value); - array.set_str_field("length", Value::from(2)); + array.set_field("0", key); + array.set_field("1", value); + array.set_field("length", Value::from(2)); array }) .collect(); @@ -606,12 +606,11 @@ impl Interpreter { Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node .obj() .run(self)? - .set_str_field(get_const_field_node.field(), value)), + .set_field(get_const_field_node.field(), value)), Node::GetField(ref get_field) => { - Ok(get_field - .obj() - .run(self)? - .set_field(get_field.field().run(self)?, value, self)) + let field = get_field.field().run(self)?; + let key = self.to_property_key(&field)?; + Ok(get_field.obj().run(self)?.set_field(key, value)) } _ => panic!("TypeError: invalid assignment to {}", node), } diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs index 0040934a8e4..8b0fce3de8e 100644 --- a/boa/src/exec/object/mod.rs +++ b/boa/src/exec/object/mod.rs @@ -22,11 +22,11 @@ impl Executable for Object { for property in self.properties().iter() { match property { PropertyDefinition::Property(key, value) => { - obj.borrow().set_str_field(key, value.run(interpreter)?); + obj.borrow().set_field(key.clone(), value.run(interpreter)?); } PropertyDefinition::MethodDefinition(kind, name, func) => { if let MethodDefinitionKind::Ordinary = kind { - obj.borrow().set_str_field(name, func.run(interpreter)?); + obj.borrow().set_field(name.clone(), func.run(interpreter)?); } else { // TODO: Implement other types of MethodDefinitionKinds. unimplemented!("other types of property method definitions."); diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index 6f1daf240e7..3274f15383c 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -35,12 +35,13 @@ impl Executable for Assign { } Node::GetConstField(ref get_const_field) => { let val_obj = get_const_field.obj().run(interpreter)?; - val_obj.set_str_field(get_const_field.field(), val.clone()); + val_obj.set_field(get_const_field.field(), val.clone()); } Node::GetField(ref get_field) => { - let val_obj = get_field.obj().run(interpreter)?; - let val_field = get_field.field().run(interpreter)?; - val_obj.set_field(val_field, val.clone(), interpreter); + let object = get_field.obj().run(interpreter)?; + let field = get_field.field().run(interpreter)?; + let key = interpreter.to_property_key(&field)?; + object.set_field(key, val.clone()); } _ => (), } @@ -134,7 +135,7 @@ impl Executable for BinOp { let v_a = v_r_a.get_field(get_const_field.field()); let v_b = self.rhs().run(interpreter)?; let value = Self::run_assign(op, v_a, v_b, interpreter)?; - v_r_a.set_str_field(get_const_field.field(), value.clone()); + v_r_a.set_field(get_const_field.field(), value.clone()); Ok(value) } _ => Ok(Value::undefined()), diff --git a/boa/src/realm.rs b/boa/src/realm.rs index 9879bbd7123..f7df95a5a6a 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -64,8 +64,7 @@ impl Realm { /// Utility to add a function to the global object pub fn register_global_func(self, func_name: &str, func: NativeFunctionData) -> Self { let func = Function::builtin(Vec::new(), func); - self.global_obj - .set_str_field(func_name, Value::from_func(func)); + self.global_obj.set_field(func_name, Value::from_func(func)); self } From d54d90881840cfb9b4c1bfd454e952b2bff731bd Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sun, 26 Jul 2020 08:25:39 +0200 Subject: [PATCH 13/16] Fixed `String.prototype.replace` test --- boa/src/builtins/string/mod.rs | 7 ++++++- boa/src/builtins/value/mod.rs | 9 +++++++++ boa/src/builtins/value/rcstring.rs | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index c6576917514..5d48b5c8837 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -418,7 +418,10 @@ impl String { if obj.internal_slots().get("RegExpMatcher").is_some() { // first argument is another `RegExp` object, so copy its pattern and flags if let Some(body) = obj.internal_slots().get("OriginalSource") { - return body.to_string(); + return body + .as_string() + .expect("OriginalSource should be a string") + .into(); } } "undefined".to_string() @@ -451,6 +454,8 @@ impl String { let regex_body = Self::get_regex_string(args.get(0).expect("Value needed")); let re = Regex::new(®ex_body).expect("unable to convert regex to regex object"); + dbg!(&primitive_val); + dbg!(®ex_body); let mat = re.find(&primitive_val).expect("unable to find value"); let caps = re .captures(&primitive_val) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 70e2b1cb437..631618d9a4f 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -374,6 +374,15 @@ impl Value { matches!(self, Self::String(_)) } + /// Returns the a string if the values is a string, otherwise `None`. + #[inline] + pub fn as_string(&self) -> Option<&RcString> { + match self { + Self::String(ref string) => Some(string), + _ => None, + } + } + /// Returns true if the value is a boolean. #[inline] pub fn is_boolean(&self) -> bool { diff --git a/boa/src/builtins/value/rcstring.rs b/boa/src/builtins/value/rcstring.rs index d5a58552390..5d8c427d2b5 100644 --- a/boa/src/builtins/value/rcstring.rs +++ b/boa/src/builtins/value/rcstring.rs @@ -79,6 +79,13 @@ impl From for RcString { } } +impl From<&RcString> for String { + #[inline] + fn from(string: &RcString) -> Self { + string.to_string() + } +} + impl From> for RcString { #[inline] fn from(string: Box) -> Self { From 7b689900b0a3233899da9ea1797e5e6b322bca68 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sun, 26 Jul 2020 14:32:04 +0200 Subject: [PATCH 14/16] Removed debug code --- boa/src/builtins/string/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 5d48b5c8837..5bad6de4b0a 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -454,8 +454,6 @@ impl String { let regex_body = Self::get_regex_string(args.get(0).expect("Value needed")); let re = Regex::new(®ex_body).expect("unable to convert regex to regex object"); - dbg!(&primitive_val); - dbg!(®ex_body); let mat = re.find(&primitive_val).expect("unable to find value"); let caps = re .captures(&primitive_val) From cfef90d59dd5dd7dc9f855521007807ed89169f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Mon, 27 Jul 2020 00:02:04 +0100 Subject: [PATCH 15/16] Refactor: cleanup #373 Test: Add tests for Number and Boolean Fix: Fix return and remove old comments in Value::set_field Refactor: Change Object::set to receive &PropertyKey like its other methods, remove unnecessary &s --- boa/src/builtins/object/internal_methods.rs | 12 +++---- boa/src/builtins/value/mod.rs | 8 ++--- boa/src/builtins/value/tests.rs | 38 ++++++++++++++++++++- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index 44b2449ddaf..be4269da47d 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -20,14 +20,14 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p pub fn has_property(&self, property_key: &PropertyKey) -> bool { - let prop = self.get_own_property(&property_key); + let prop = self.get_own_property(property_key); if prop.value.is_none() { let parent: Value = self.get_prototype_of(); if !parent.is_null() { // the parent value variant should be an object // In the unlikely event it isn't return false return match parent { - Value::Object(ref obj) => obj.borrow().has_property(&property_key), + Value::Object(ref obj) => obj.borrow().has_property(property_key), _ => false, }; } @@ -62,7 +62,7 @@ impl Object { /// Delete property. pub fn delete(&mut self, property_key: &PropertyKey) -> bool { - let desc = self.get_own_property(&property_key); + let desc = self.get_own_property(property_key); if desc .value .clone() @@ -116,11 +116,11 @@ impl Object { /// [[Set]] /// - pub fn set(&mut self, property_key: PropertyKey, val: Value) -> bool { + pub fn set(&mut self, property_key: &PropertyKey, val: Value) -> bool { let _timer = BoaProfiler::global().start_event("Object::set", "object"); // Fetch property key - let mut own_desc = self.get_own_property(&property_key); + let mut own_desc = self.get_own_property(property_key); // [2] if own_desc.is_none() { let parent = self.get_prototype_of(); @@ -140,7 +140,7 @@ impl Object { // Change value on the current descriptor own_desc = own_desc.value(val); - return self.define_own_property(&property_key, own_desc); + return self.define_own_property(property_key, own_desc); } // [4] debug_assert!(own_desc.is_accessor_descriptor()); diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 631618d9a4f..9db19eeab35 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -633,7 +633,6 @@ impl Value { } /// Set the field in the value - /// Field could be a Symbol, so we need to accept a Value (not a string) #[inline] pub fn set_field(&self, field: F, value: V) -> Value where @@ -641,6 +640,7 @@ impl Value { V: Into, { let field = field.into(); + let value = value.into(); let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); if let Self::Object(ref obj) = *self { if let PropertyKey::String(ref string) = field { @@ -655,11 +655,9 @@ impl Value { } } } - - // Symbols get saved into a different bucket to general properties - obj.borrow_mut().set(field.clone(), value.into()); + obj.borrow_mut().set(&field, value.clone()); } - field.into() + value } /// Set the private field in the value diff --git a/boa/src/builtins/value/tests.rs b/boa/src/builtins/value/tests.rs index faa810bdbcd..8a55700d21c 100644 --- a/boa/src/builtins/value/tests.rs +++ b/boa/src/builtins/value/tests.rs @@ -375,7 +375,43 @@ fn display_array_string() { } #[test] -#[ignore] // TODO: Once #507 is fixed this test can be simplified and used +fn display_boolean_object() { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + let d_obj = r#" + let bool = new Boolean(0); + bool + "#; + let value = forward_val(&mut engine, d_obj).unwrap(); + assert_eq!(value.to_string(), "Boolean { false }") +} + +#[test] +fn display_number_object() { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + let d_obj = r#" + let num = new Number(3.14); + num + "#; + let value = forward_val(&mut engine, d_obj).unwrap(); + assert_eq!(value.to_string(), "Number { 3.14 }") +} + +#[test] +fn display_negative_zero_object() { + let realm = Realm::create(); + let mut engine = Interpreter::new(realm); + let d_obj = r#" + let num = new Number(-0); + num + "#; + let value = forward_val(&mut engine, d_obj).unwrap(); + assert_eq!(value.to_string(), "Number { -0 }") +} + +#[test] +#[ignore] // TODO: Once objects are printed in a simpler way this test can be simplified and used fn display_object() { let realm = Realm::create(); let mut engine = Interpreter::new(realm); From ae7fa2b9e9acd9d42361614f705d634cbac0c672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Mon, 27 Jul 2020 11:18:45 +0100 Subject: [PATCH 16/16] Refactor: Add documentation and docs as requested in #373 Docs: Add description of PropertyKey Refactor: Add #[inline] for short PropertyKey functions Refactor: Add #[inline] for short conversions --- boa/src/builtins/property/mod.rs | 16 ++++++++++++++++ boa/src/builtins/value/conversions.rs | 8 ++++++++ boa/src/builtins/value/mod.rs | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/boa/src/builtins/property/mod.rs b/boa/src/builtins/property/mod.rs index d215c58f135..0cfaa49b962 100644 --- a/boa/src/builtins/property/mod.rs +++ b/boa/src/builtins/property/mod.rs @@ -279,6 +279,13 @@ impl<'a> From<&'a Value> for Property { } } +/// This abstracts away the need for IsPropertyKey by transforming the PropertyKey +/// values into an enum with both valid types: String and Symbol +/// +/// More information: +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-ispropertykey #[derive(Trace, Finalize, Debug, Clone)] pub enum PropertyKey { String(RcString), @@ -286,36 +293,42 @@ pub enum PropertyKey { } impl From for PropertyKey { + #[inline] fn from(string: RcString) -> PropertyKey { PropertyKey::String(string) } } impl From<&str> for PropertyKey { + #[inline] fn from(string: &str) -> PropertyKey { PropertyKey::String(string.into()) } } impl From for PropertyKey { + #[inline] fn from(string: String) -> PropertyKey { PropertyKey::String(string.into()) } } impl From> for PropertyKey { + #[inline] fn from(string: Box) -> PropertyKey { PropertyKey::String(string.into()) } } impl From for PropertyKey { + #[inline] fn from(symbol: RcSymbol) -> PropertyKey { PropertyKey::Symbol(symbol) } } impl fmt::Display for PropertyKey { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PropertyKey::String(ref string) => string.fmt(f), @@ -325,6 +338,7 @@ impl fmt::Display for PropertyKey { } impl From<&PropertyKey> for RcString { + #[inline] fn from(property_key: &PropertyKey) -> RcString { match property_key { PropertyKey::String(ref string) => string.clone(), @@ -334,6 +348,7 @@ impl From<&PropertyKey> for RcString { } impl From<&PropertyKey> for Value { + #[inline] fn from(property_key: &PropertyKey) -> Value { match property_key { PropertyKey::String(ref string) => string.clone().into(), @@ -343,6 +358,7 @@ impl From<&PropertyKey> for Value { } impl From for Value { + #[inline] fn from(property_key: PropertyKey) -> Value { match property_key { PropertyKey::String(ref string) => string.clone().into(), diff --git a/boa/src/builtins/value/conversions.rs b/boa/src/builtins/value/conversions.rs index 9f982998c34..3a0a04872fa 100644 --- a/boa/src/builtins/value/conversions.rs +++ b/boa/src/builtins/value/conversions.rs @@ -2,12 +2,14 @@ use super::*; use std::convert::TryFrom; impl From<&Value> for Value { + #[inline] fn from(value: &Value) -> Self { value.clone() } } impl From for Value { + #[inline] fn from(value: String) -> Self { let _timer = BoaProfiler::global().start_event("From", "value"); Self::string(value) @@ -15,36 +17,42 @@ impl From for Value { } impl From> for Value { + #[inline] fn from(value: Box) -> Self { Self::string(String::from(value)) } } impl From<&str> for Value { + #[inline] fn from(value: &str) -> Value { Value::string(value) } } impl From<&Box> for Value { + #[inline] fn from(value: &Box) -> Self { Self::string(value.as_ref()) } } impl From for Value { + #[inline] fn from(value: char) -> Self { Value::string(value.to_string()) } } impl From for Value { + #[inline] fn from(value: RcString) -> Self { Value::String(value) } } impl From for Value { + #[inline] fn from(value: RcSymbol) -> Self { Value::Symbol(value) } diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 9db19eeab35..6f05364c22c 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -374,7 +374,7 @@ impl Value { matches!(self, Self::String(_)) } - /// Returns the a string if the values is a string, otherwise `None`. + /// Returns the string if the values is a string, otherwise `None`. #[inline] pub fn as_string(&self) -> Option<&RcString> { match self {