Implement void, add delete instruction

This commit is contained in:
Andrew Morris
2023-12-18 13:47:10 +11:00
parent 339e65788c
commit 62108d1a49
12 changed files with 109 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
// //! test_output({})
export default function main() {
const x: Record<string, unknown> = { y: 3 };
let x: Record<string, unknown> = { y: 3 };
delete x.y;
return x;

View File

@@ -59,6 +59,7 @@ pub enum InstructionByte {
Cat = 0x38,
Yield = 0x39,
YieldStar = 0x3a,
Delete = 0x3b,
}
impl InstructionByte {
@@ -125,6 +126,7 @@ impl InstructionByte {
0x38 => Cat,
0x39 => Yield,
0x3a => YieldStar,
0x3b => Delete,
_ => panic!("Unrecognized instruction: {}", byte),
}

View File

@@ -326,6 +326,11 @@ impl Assembler {
self.value(value);
self.register(dst);
}
Delete(obj, sub, dst) => {
self.register(obj);
self.value(sub);
self.register(dst);
}
}
}

View File

@@ -260,6 +260,7 @@ impl<'a> AssemblyParser<'a> {
("cat", InstructionByte::Cat),
("yield", InstructionByte::Yield),
("yield*", InstructionByte::YieldStar),
("delete", InstructionByte::Delete),
]);
for (word, instruction) in instruction_word_map {
@@ -828,6 +829,11 @@ impl<'a> AssemblyParser<'a> {
Cat => Instruction::Cat(self.assemble_value(), self.assemble_register()),
Yield => Instruction::Yield(self.assemble_value(), self.assemble_register()),
YieldStar => Instruction::YieldStar(self.assemble_value(), self.assemble_register()),
Delete => Instruction::Delete(
self.assemble_register(),
self.assemble_value(),
self.assemble_register(),
),
};
self.parse_line();

View File

@@ -227,6 +227,29 @@ impl<'a, 'fnc> ExpressionCompiler<'a, 'fnc> {
&mut self,
un_exp: &swc_ecma_ast::UnaryExpr,
target_register: Option<Register>,
) -> CompiledExpression {
match UnaryOpType::from_unary_op(un_exp.op) {
UnaryOpType::Ordinary(ordinary_op) => {
self.ordinary_unary_expression(un_exp, ordinary_op, target_register)
}
UnaryOpType::Void => {
let arg = self.compile(&un_exp.arg, None);
self.fnc.release_ce(arg);
CompiledExpression::new(Value::Undefined, vec![])
}
UnaryOpType::Delete => {
self.todo(un_exp.span, &format!("Unary operator {:?}", un_exp.op));
CompiledExpression::default()
}
}
}
pub fn ordinary_unary_expression(
&mut self,
un_exp: &swc_ecma_ast::UnaryExpr,
op: OrdinaryUnaryOp,
target_register: Option<Register>,
) -> CompiledExpression {
let mut nested_registers = Vec::<Register>::new();
@@ -241,16 +264,9 @@ impl<'a, 'fnc> ExpressionCompiler<'a, 'fnc> {
Some(t) => t.clone(),
};
self.fnc.push(
match make_unary_op(un_exp.op, arg.value.clone(), target.clone()) {
Some(i) => i,
None => {
self.todo(un_exp.span, &format!("Unary operator {:?}", un_exp.op));
return CompiledExpression::empty();
}
},
);
self
.fnc
.push(op.make_instruction(arg.value.clone(), target.clone()));
self.fnc.release_ce(arg);
@@ -1546,17 +1562,43 @@ impl<'a, 'fnc> ExpressionCompiler<'a, 'fnc> {
}
}
pub fn make_unary_op(op: swc_ecma_ast::UnaryOp, arg: Value, dst: Register) -> Option<Instruction> {
use swc_ecma_ast::UnaryOp::*;
pub enum UnaryOpType {
Ordinary(OrdinaryUnaryOp),
Void,
Delete,
}
match op {
Minus => Some(Instruction::UnaryMinus(arg, dst)),
Plus => Some(Instruction::UnaryPlus(arg, dst)),
Bang => Some(Instruction::OpNot(arg, dst)),
Tilde => Some(Instruction::OpBitNot(arg, dst)),
TypeOf => Some(Instruction::TypeOf(arg, dst)),
Void => None, // TODO
Delete => None, // TODO
impl UnaryOpType {
fn from_unary_op(op: swc_ecma_ast::UnaryOp) -> Self {
match op {
swc_ecma_ast::UnaryOp::Minus => UnaryOpType::Ordinary(OrdinaryUnaryOp::Minus),
swc_ecma_ast::UnaryOp::Plus => UnaryOpType::Ordinary(OrdinaryUnaryOp::Plus),
swc_ecma_ast::UnaryOp::Bang => UnaryOpType::Ordinary(OrdinaryUnaryOp::Bang),
swc_ecma_ast::UnaryOp::Tilde => UnaryOpType::Ordinary(OrdinaryUnaryOp::Tilde),
swc_ecma_ast::UnaryOp::TypeOf => UnaryOpType::Ordinary(OrdinaryUnaryOp::TypeOf),
swc_ecma_ast::UnaryOp::Void => UnaryOpType::Void,
swc_ecma_ast::UnaryOp::Delete => UnaryOpType::Delete,
}
}
}
pub enum OrdinaryUnaryOp {
Minus,
Plus,
Bang,
Tilde,
TypeOf,
}
impl OrdinaryUnaryOp {
fn make_instruction(self, arg: Value, dst: Register) -> Instruction {
match self {
OrdinaryUnaryOp::Minus => Instruction::UnaryMinus(arg, dst),
OrdinaryUnaryOp::Plus => Instruction::UnaryPlus(arg, dst),
OrdinaryUnaryOp::Bang => Instruction::OpNot(arg, dst),
OrdinaryUnaryOp::Tilde => Instruction::OpBitNot(arg, dst),
OrdinaryUnaryOp::TypeOf => Instruction::TypeOf(arg, dst),
}
}
}

View File

@@ -63,6 +63,7 @@ pub enum Instruction {
Cat(Value, Register),
Yield(Value, Register),
YieldStar(Value, Register),
Delete(Register, Value, Register),
}
pub enum InstructionFieldMut<'a> {
@@ -218,6 +219,12 @@ impl Instruction {
}
UnsetCatch | RequireMutableThis => {}
Delete(obj, sub, dst) => {
visit(InstructionFieldMut::Register(obj));
visit(InstructionFieldMut::Value(sub));
visit(InstructionFieldMut::Register(dst));
}
}
}
@@ -351,6 +358,12 @@ impl Instruction {
}
UnsetCatch | RequireMutableThis => {}
Delete(obj, sub, dst) => {
visit(RegisterVisitMut::read_and_write(obj));
sub.visit_registers_mut_rev(visit);
visit(RegisterVisitMut::write(dst));
}
}
}
@@ -418,6 +431,7 @@ impl Instruction {
Cat(..) => InstructionByte::Cat,
Yield(..) => InstructionByte::Yield,
YieldStar(..) => InstructionByte::YieldStar,
Delete(..) => InstructionByte::Delete,
}
}
}
@@ -582,6 +596,7 @@ impl StructuredFormattable for Instruction {
Instruction::YieldStar(value, register) => {
sf.write_slice_joined(" ", &[&"yield*", value, register])
}
Instruction::Delete(obj, sub, dst) => sf.write_slice_joined(" ", &[&"delete", obj, sub, dst]),
}
}
}

View File

@@ -680,6 +680,11 @@ impl FnState {
self.set(value_reg.name.clone(), Kal::Unknown);
self.set(done.name.clone(), Kal::Unknown);
}
Delete(obj, sub, dst) => {
self.set(obj.name.clone(), Kal::Unknown);
self.eval_arg(sub);
self.set(dst.name.clone(), Kal::Bool(true));
}
}
match instr {
@@ -746,7 +751,8 @@ impl FnState {
| UnpackIterRes(_, _, _)
| Cat(_, _)
| Yield(_, _)
| YieldStar(_, _) => {}
| YieldStar(_, _)
| Delete(..) => {}
}
}

View File

@@ -27,7 +27,7 @@ fn reduce(instr: Instruction) -> Option<Instruction> {
match &instr {
End | OpInc(..) | OpDec(..) | Call(..) | Apply(..) | ConstApply(..) | SubCall(..) | Jmp(..)
| New(..) | Throw(..) | SetCatch(..) | UnsetCatch | ConstSubCall(..) | RequireMutableThis
| ThisSubCall(..) | Next(..) | Yield(..) | YieldStar(..) => Some(instr),
| ThisSubCall(..) | Next(..) | Yield(..) | YieldStar(..) | Delete(..) => Some(instr),
Mov(arg, dst) => 'b: {
if dst.is_ignore() {

View File

@@ -256,7 +256,7 @@ fn identify_primary_registers(fn_: &mut Function) -> HashSet<String> {
Instruction::Next(reg, _) => {
primary_registers.insert(reg.name.clone());
}
Instruction::Cat(value, _)
Instruction::Cat(value, _) // TODO: Why is the argument to cat a source of primary registers?
| Instruction::Yield(value, _)
| Instruction::YieldStar(value, _)
| Instruction::JmpIf(value, _)

View File

@@ -238,6 +238,7 @@ fn is_jmp_instr(instr: &Instruction) -> bool {
| Instruction::UnpackIterRes(..)
| Instruction::Cat(..)
| Instruction::Yield(..)
| Instruction::YieldStar(..) => false,
| Instruction::YieldStar(..)
| Instruction::Delete(..) => false,
}
}

View File

@@ -202,6 +202,9 @@ where
JmpIf(arg, _) | JmpIfNot(arg, _) => {
self.value(Some(owner), arg);
}
Delete(_obj, sub, _dst) => {
self.value(Some(owner), sub);
}
};
}

View File

@@ -603,6 +603,10 @@ impl StackFrameTrait for BytecodeStackFrame {
return Ok(FrameStepOk::YieldStar(val));
}
Delete => {
todo!()
}
};
Ok(FrameStepOk::Continue)