From b624be6927aad0c3129041de1f0fafd813072956 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Mon, 11 Oct 2021 21:06:16 +0200 Subject: [PATCH] Implement `delete` operator in the vm (#1649) --- boa/src/bytecompiler.rs | 30 ++++++++++++++++--- .../syntax/ast/node/operator/unary_op/mod.rs | 11 ++----- boa/src/vm/code_block.rs | 4 ++- boa/src/vm/mod.rs | 15 ++++++++++ boa/src/vm/opcode.rs | 20 +++++++++++++ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/boa/src/bytecompiler.rs b/boa/src/bytecompiler.rs index 7bc0007da8..c035a14e88 100644 --- a/boa/src/bytecompiler.rs +++ b/boa/src/bytecompiler.rs @@ -370,7 +370,29 @@ impl ByteCompiler { UnaryOp::DecrementPre => todo!(), UnaryOp::IncrementPost => todo!(), UnaryOp::DecrementPost => todo!(), - UnaryOp::Delete => todo!(), + UnaryOp::Delete => match unary.target() { + Node::GetConstField(ref get_const_field) => { + let index = self.get_or_insert_name(get_const_field.field()); + self.compile_expr(get_const_field.obj(), true); + self.emit(Opcode::DeletePropertyByName, &[index]); + None + } + Node::GetField(ref get_field) => { + self.compile_expr(get_field.field(), true); + self.compile_expr(get_field.obj(), true); + self.emit(Opcode::DeletePropertyByValue, &[]); + None + } + // TODO: implement delete on references. + Node::Identifier(_) => { + self.emit(Opcode::PushFalse, &[]); + None + } + _ => { + self.emit(Opcode::PushTrue, &[]); + None + } + }, UnaryOp::Minus => Some(Opcode::Neg), UnaryOp::Plus => Some(Opcode::Pos), UnaryOp::Not => Some(Opcode::LogicalNot), @@ -382,10 +404,10 @@ impl ByteCompiler { if let Some(opcode) = opcode { self.compile_expr(unary.target(), true); self.emit(opcode, &[]); + } - if !use_expr { - self.emit(Opcode::Pop, &[]); - } + if !use_expr { + self.emit(Opcode::Pop, &[]); } } Node::BinOp(binary) => { diff --git a/boa/src/syntax/ast/node/operator/unary_op/mod.rs b/boa/src/syntax/ast/node/operator/unary_op/mod.rs index 2ef824cf7b..24069c96a3 100644 --- a/boa/src/syntax/ast/node/operator/unary_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/unary_op/mod.rs @@ -114,16 +114,9 @@ impl Executable for UnaryOp { .__delete__(&field.to_property_key(context)?, context)?; return Ok(JsValue::new(res)); } + // TODO: implement delete on references. Node::Identifier(_) => JsValue::new(false), - Node::ArrayDecl(_) - | Node::Block(_) - | Node::Const(_) - | Node::FunctionDecl(_) - | Node::FunctionExpr(_) - | Node::New(_) - | Node::Object(_) - | Node::UnaryOp(_) => JsValue::new(true), - _ => return context.throw_syntax_error(format!("wrong delete argument {}", self)), + _ => JsValue::new(true), }, op::UnaryOp::TypeOf => JsValue::new(self.target().run(context)?.type_of()), }) diff --git a/boa/src/vm/code_block.rs b/boa/src/vm/code_block.rs index 4fa45f962c..e1ecc2dbbb 100644 --- a/boa/src/vm/code_block.rs +++ b/boa/src/vm/code_block.rs @@ -159,7 +159,8 @@ impl CodeBlock { | Opcode::GetName | Opcode::SetName | Opcode::GetPropertyByName - | Opcode::SetPropertyByName => { + | Opcode::SetPropertyByName + | Opcode::DeletePropertyByName => { let operand = self.read::(*pc); *pc += size_of::(); format!("{:04}: '{}'", operand, self.variables[operand as usize]) @@ -207,6 +208,7 @@ impl CodeBlock { | Opcode::Neg | Opcode::GetPropertyByValue | Opcode::SetPropertyByValue + | Opcode::DeletePropertyByValue | Opcode::ToBoolean | Opcode::Throw | Opcode::This diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs index 80d5694642..9b9008349a 100644 --- a/boa/src/vm/mod.rs +++ b/boa/src/vm/mod.rs @@ -397,6 +397,21 @@ impl Context { let key = key.to_property_key(self)?; object.set(key, value, true, self)?; } + Opcode::DeletePropertyByName => { + let index = self.vm.read::(); + let key = self.vm.frame().code.variables[index as usize].clone(); + let object = self.vm.pop(); + let result = object.to_object(self)?.__delete__(&key.into(), self)?; + self.vm.push(result); + } + Opcode::DeletePropertyByValue => { + let object = self.vm.pop(); + let key = self.vm.pop(); + let result = object + .to_object(self)? + .__delete__(&key.to_property_key(self)?, self)?; + self.vm.push(result); + } Opcode::Throw => { let value = self.vm.pop(); return Err(value); diff --git a/boa/src/vm/opcode.rs b/boa/src/vm/opcode.rs index 79bee2a75c..f7901b3594 100644 --- a/boa/src/vm/opcode.rs +++ b/boa/src/vm/opcode.rs @@ -442,6 +442,24 @@ pub enum Opcode { /// Stack: value, key, object **=>** SetPropertyByValue, + /// Deletes a property by name of an object. + /// + /// Like `delete object.key.` + /// + /// Operands: name_index: `u32` + /// + /// Stack: object **=>** + DeletePropertyByName, + + /// Deletes a property by value of an object. + /// + /// Like `delete object[key]` + /// + /// Operands: + /// + /// Stack: key, object **=>** + DeletePropertyByValue, + /// Unconditional jump to address. /// /// Operands: address: `u32` @@ -605,6 +623,8 @@ impl Opcode { Opcode::GetPropertyByValue => "GetPropertyByValue", Opcode::SetPropertyByName => "SetPropertyByName", Opcode::SetPropertyByValue => "SetPropertyByValue", + Opcode::DeletePropertyByName => "DeletePropertyByName", + Opcode::DeletePropertyByValue => "DeletePropertyByValue", Opcode::Jump => "Jump", Opcode::JumpIfFalse => "JumpIfFalse", Opcode::JumpIfTrue => "JumpIfTrue",