mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Implement void, add delete instruction
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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, _)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,9 @@ where
|
||||
JmpIf(arg, _) | JmpIfNot(arg, _) => {
|
||||
self.value(Some(owner), arg);
|
||||
}
|
||||
Delete(_obj, sub, _dst) => {
|
||||
self.value(Some(owner), sub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -603,6 +603,10 @@ impl StackFrameTrait for BytecodeStackFrame {
|
||||
|
||||
return Ok(FrameStepOk::YieldStar(val));
|
||||
}
|
||||
|
||||
Delete => {
|
||||
todo!()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(FrameStepOk::Continue)
|
||||
|
||||
Reference in New Issue
Block a user