Browse Source

Implement `delete` operator in the vm (#1649)

pull/1661/head
raskad 3 years ago committed by GitHub
parent
commit
b624be6927
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      boa/src/bytecompiler.rs
  2. 11
      boa/src/syntax/ast/node/operator/unary_op/mod.rs
  3. 4
      boa/src/vm/code_block.rs
  4. 15
      boa/src/vm/mod.rs
  5. 20
      boa/src/vm/opcode.rs

26
boa/src/bytecompiler.rs

@ -370,7 +370,29 @@ impl ByteCompiler {
UnaryOp::DecrementPre => todo!(), UnaryOp::DecrementPre => todo!(),
UnaryOp::IncrementPost => todo!(), UnaryOp::IncrementPost => todo!(),
UnaryOp::DecrementPost => 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::Minus => Some(Opcode::Neg),
UnaryOp::Plus => Some(Opcode::Pos), UnaryOp::Plus => Some(Opcode::Pos),
UnaryOp::Not => Some(Opcode::LogicalNot), UnaryOp::Not => Some(Opcode::LogicalNot),
@ -382,12 +404,12 @@ impl ByteCompiler {
if let Some(opcode) = opcode { if let Some(opcode) = opcode {
self.compile_expr(unary.target(), true); self.compile_expr(unary.target(), true);
self.emit(opcode, &[]); self.emit(opcode, &[]);
}
if !use_expr { if !use_expr {
self.emit(Opcode::Pop, &[]); self.emit(Opcode::Pop, &[]);
} }
} }
}
Node::BinOp(binary) => { Node::BinOp(binary) => {
self.compile_expr(binary.lhs(), true); self.compile_expr(binary.lhs(), true);
match binary.op() { match binary.op() {

11
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)?; .__delete__(&field.to_property_key(context)?, context)?;
return Ok(JsValue::new(res)); return Ok(JsValue::new(res));
} }
// TODO: implement delete on references.
Node::Identifier(_) => JsValue::new(false), Node::Identifier(_) => JsValue::new(false),
Node::ArrayDecl(_) _ => JsValue::new(true),
| 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)),
}, },
op::UnaryOp::TypeOf => JsValue::new(self.target().run(context)?.type_of()), op::UnaryOp::TypeOf => JsValue::new(self.target().run(context)?.type_of()),
}) })

4
boa/src/vm/code_block.rs

@ -159,7 +159,8 @@ impl CodeBlock {
| Opcode::GetName | Opcode::GetName
| Opcode::SetName | Opcode::SetName
| Opcode::GetPropertyByName | Opcode::GetPropertyByName
| Opcode::SetPropertyByName => { | Opcode::SetPropertyByName
| Opcode::DeletePropertyByName => {
let operand = self.read::<u32>(*pc); let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>(); *pc += size_of::<u32>();
format!("{:04}: '{}'", operand, self.variables[operand as usize]) format!("{:04}: '{}'", operand, self.variables[operand as usize])
@ -207,6 +208,7 @@ impl CodeBlock {
| Opcode::Neg | Opcode::Neg
| Opcode::GetPropertyByValue | Opcode::GetPropertyByValue
| Opcode::SetPropertyByValue | Opcode::SetPropertyByValue
| Opcode::DeletePropertyByValue
| Opcode::ToBoolean | Opcode::ToBoolean
| Opcode::Throw | Opcode::Throw
| Opcode::This | Opcode::This

15
boa/src/vm/mod.rs

@ -397,6 +397,21 @@ impl Context {
let key = key.to_property_key(self)?; let key = key.to_property_key(self)?;
object.set(key, value, true, self)?; object.set(key, value, true, self)?;
} }
Opcode::DeletePropertyByName => {
let index = self.vm.read::<u32>();
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 => { Opcode::Throw => {
let value = self.vm.pop(); let value = self.vm.pop();
return Err(value); return Err(value);

20
boa/src/vm/opcode.rs

@ -442,6 +442,24 @@ pub enum Opcode {
/// Stack: value, key, object **=>** /// Stack: value, key, object **=>**
SetPropertyByValue, 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. /// Unconditional jump to address.
/// ///
/// Operands: address: `u32` /// Operands: address: `u32`
@ -605,6 +623,8 @@ impl Opcode {
Opcode::GetPropertyByValue => "GetPropertyByValue", Opcode::GetPropertyByValue => "GetPropertyByValue",
Opcode::SetPropertyByName => "SetPropertyByName", Opcode::SetPropertyByName => "SetPropertyByName",
Opcode::SetPropertyByValue => "SetPropertyByValue", Opcode::SetPropertyByValue => "SetPropertyByValue",
Opcode::DeletePropertyByName => "DeletePropertyByName",
Opcode::DeletePropertyByValue => "DeletePropertyByValue",
Opcode::Jump => "Jump", Opcode::Jump => "Jump",
Opcode::JumpIfFalse => "JumpIfFalse", Opcode::JumpIfFalse => "JumpIfFalse",
Opcode::JumpIfTrue => "JumpIfTrue", Opcode::JumpIfTrue => "JumpIfTrue",

Loading…
Cancel
Save