diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 583d314649..87249d29d0 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -334,11 +334,13 @@ impl ValueData { /// Removes a property from a Value object. /// /// It will return a boolean based on if the value was removed, if there was no value to remove false is returned - pub fn remove_property(&self, field: &str) { - match *self { + pub fn remove_property(&self, field: &str) -> bool { + let removed = match *self { Self::Object(ref obj) => obj.borrow_mut().deref_mut().properties.remove(field), _ => None, }; + + removed.is_some() } /// Resolve the property in the object. diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index dbea9f969e..f5e4deb83a 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -403,6 +403,27 @@ impl Executor for Interpreter { !(num_v_a as i32) }) } + UnaryOp::Void => Value::undefined(), + UnaryOp::Delete => match a.deref() { + Node::GetConstField(ref obj, ref field) => { + Value::boolean(self.run(obj)?.remove_property(field)) + } + Node::GetField(ref obj, ref field) => Value::boolean( + self.run(obj)? + .remove_property(&self.run(field)?.to_string()), + ), + Node::Local(_) => Value::boolean(false), + Node::ArrayDecl(_) + | Node::Block(_) + | Node::Const(_) + | Node::FunctionDecl(_, _, _) + | Node::FunctionExpr(_, _, _) + | Node::New(_) + | Node::Object(_) + | Node::TypeOf(_) + | Node::UnaryOp(_, _) => Value::boolean(true), + _ => panic!("SyntaxError: wrong delete argument {}", node), + }, _ => unimplemented!(), }) } diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 55dbbc006a..7f3b6f7812 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -428,6 +428,75 @@ fn unary_post() { assert_eq!(&exec(execs_after_dec), "true"); } +#[test] +fn unary_void() { + let void_should_return_undefined = r#" + const a = 0; + void a; + "#; + assert_eq!(&exec(void_should_return_undefined), "undefined"); + + let void_invocation = r#" + let a = 0; + const test = () => a = 42; + const b = void test() + ''; + a + b + "#; + assert_eq!(&exec(void_invocation), "42undefined"); +} + +#[test] +fn unary_delete() { + let delete_var = r#" + let a = 5; + const b = delete a + ''; + a + b + "#; + 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"); + + 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"); + + let delete_field = r#" + const a = { b: 5 }; + const c = delete a['b'] + ''; + a.b + c + "#; + assert_eq!(&exec(delete_field), "undefinedtrue"); + + let delete_object = r#" + const a = { b: 5 }; + delete a + "#; + assert_eq!(&exec(delete_object), "false"); + + let delete_array = r#" + delete []; + "#; + assert_eq!(&exec(delete_array), "true"); + + let delete_func = r#" + delete function() {}; + "#; + assert_eq!(&exec(delete_func), "true"); + + let delete_recursive = r#" + delete delete delete 1; + "#; + assert_eq!(&exec(delete_recursive), "true"); +} + #[cfg(test)] mod in_operator { use super::*;