diff --git a/valuescript_common/src/instruction_byte.rs b/valuescript_common/src/instruction_byte.rs index 7fad347..6b5c447 100644 --- a/valuescript_common/src/instruction_byte.rs +++ b/valuescript_common/src/instruction_byte.rs @@ -41,22 +41,23 @@ pub enum InstructionByte { SubCall = 0x26, Jmp = 0x27, JmpIf = 0x28, - UnaryPlus = 0x29, - UnaryMinus = 0x2a, - New = 0x2b, - Throw = 0x2c, - Import = 0x2d, - ImportStar = 0x2e, - SetCatch = 0x2f, - UnsetCatch = 0x30, - ConstSubCall = 0x31, - RequireMutableThis = 0x32, - ThisSubCall = 0x33, - Next = 0x34, - UnpackIterRes = 0x35, - Cat = 0x36, - Yield = 0x37, - YieldStar = 0x38, + JmpIfNot = 0x29, + UnaryPlus = 0x2a, + UnaryMinus = 0x2b, + New = 0x2c, + Throw = 0x2d, + Import = 0x2e, + ImportStar = 0x2f, + SetCatch = 0x30, + UnsetCatch = 0x31, + ConstSubCall = 0x32, + RequireMutableThis = 0x33, + ThisSubCall = 0x34, + Next = 0x35, + UnpackIterRes = 0x36, + Cat = 0x37, + Yield = 0x38, + YieldStar = 0x39, } impl InstructionByte { @@ -105,22 +106,23 @@ impl InstructionByte { 0x26 => SubCall, 0x27 => Jmp, 0x28 => JmpIf, - 0x29 => UnaryPlus, - 0x2a => UnaryMinus, - 0x2b => New, - 0x2c => Throw, - 0x2d => Import, - 0x2e => ImportStar, - 0x2f => SetCatch, - 0x30 => UnsetCatch, - 0x31 => ConstSubCall, - 0x32 => RequireMutableThis, - 0x33 => ThisSubCall, - 0x34 => Next, - 0x35 => UnpackIterRes, - 0x36 => Cat, - 0x37 => Yield, - 0x38 => YieldStar, + 0x29 => JmpIfNot, + 0x2a => UnaryPlus, + 0x2b => UnaryMinus, + 0x2c => New, + 0x2d => Throw, + 0x2e => Import, + 0x2f => ImportStar, + 0x30 => SetCatch, + 0x31 => UnsetCatch, + 0x32 => ConstSubCall, + 0x33 => RequireMutableThis, + 0x34 => ThisSubCall, + 0x35 => Next, + 0x36 => UnpackIterRes, + 0x37 => Cat, + 0x38 => Yield, + 0x39 => YieldStar, _ => panic!("Unrecognized instruction: {}", byte), }; diff --git a/valuescript_compiler/src/assembler.rs b/valuescript_compiler/src/assembler.rs index ffeb71b..8be5631 100644 --- a/valuescript_compiler/src/assembler.rs +++ b/valuescript_compiler/src/assembler.rs @@ -235,7 +235,7 @@ impl Assembler { Jmp(label_ref) => { self.label_ref(label_ref); } - JmpIf(value, label_ref) => { + JmpIf(value, label_ref) | JmpIfNot(value, label_ref) => { self.value(value); self.label_ref(label_ref); } diff --git a/valuescript_compiler/src/assembly_parser.rs b/valuescript_compiler/src/assembly_parser.rs index 543ea31..f89127f 100644 --- a/valuescript_compiler/src/assembly_parser.rs +++ b/valuescript_compiler/src/assembly_parser.rs @@ -238,6 +238,7 @@ impl<'a> AssemblyParser<'a> { ("subcall", InstructionByte::SubCall), ("jmp", InstructionByte::Jmp), ("jmpif", InstructionByte::JmpIf), + ("jmpif_not", InstructionByte::JmpIfNot), ("unary+", InstructionByte::UnaryPlus), ("unary-", InstructionByte::UnaryMinus), ("new", InstructionByte::New), @@ -731,6 +732,7 @@ impl<'a> AssemblyParser<'a> { ), Jmp => Instruction::Jmp(self.assemble_label_read()), JmpIf => Instruction::JmpIf(self.assemble_value(), self.assemble_label_read()), + JmpIfNot => Instruction::JmpIfNot(self.assemble_value(), self.assemble_label_read()), UnaryPlus => Instruction::UnaryPlus(self.assemble_value(), self.assemble_register()), UnaryMinus => Instruction::UnaryMinus(self.assemble_value(), self.assemble_register()), New => Instruction::New( diff --git a/valuescript_compiler/src/instruction.rs b/valuescript_compiler/src/instruction.rs index e716a94..30234e3 100644 --- a/valuescript_compiler/src/instruction.rs +++ b/valuescript_compiler/src/instruction.rs @@ -45,6 +45,7 @@ pub enum Instruction { SubCall(Register, Value, Value, Register), Jmp(LabelRef), JmpIf(Value, LabelRef), + JmpIfNot(Value, LabelRef), UnaryPlus(Value, Register), UnaryMinus(Value, Register), New(Value, Value, Register), @@ -190,7 +191,7 @@ impl Instruction { visit(InstructionFieldMut::LabelRef(label_ref)); } - JmpIf(cond, label_ref) => { + JmpIf(cond, label_ref) | JmpIfNot(cond, label_ref) => { visit(InstructionFieldMut::Value(cond)); visit(InstructionFieldMut::LabelRef(label_ref)); } @@ -313,7 +314,7 @@ impl Instruction { Jmp(_label_ref) => {} - JmpIf(cond, _label_ref) => { + JmpIf(cond, _label_ref) | JmpIfNot(cond, _label_ref) => { cond.visit_registers_mut_rev(visit); } @@ -393,6 +394,7 @@ impl Instruction { SubCall(..) => InstructionByte::SubCall, Jmp(..) => InstructionByte::Jmp, JmpIf(..) => InstructionByte::JmpIf, + JmpIfNot(..) => InstructionByte::JmpIfNot, UnaryPlus(..) => InstructionByte::UnaryPlus, UnaryMinus(..) => InstructionByte::UnaryMinus, New(..) => InstructionByte::New, @@ -531,6 +533,9 @@ impl std::fmt::Display for Instruction { Instruction::JmpIf(value, label_ref) => { write!(f, "jmpif {} {}", value, label_ref) } + Instruction::JmpIfNot(value, label_ref) => { + write!(f, "jmpif_not {} {}", value, label_ref) + } Instruction::UnaryPlus(value, register) => { write!(f, "unary+ {} {}", value, register) } diff --git a/valuescript_compiler/src/optimization/kal.rs b/valuescript_compiler/src/optimization/kal.rs index c867e7b..48d3742 100644 --- a/valuescript_compiler/src/optimization/kal.rs +++ b/valuescript_compiler/src/optimization/kal.rs @@ -442,7 +442,7 @@ impl FnState { self.set(dst.name.clone(), Kal::Unknown); } - JmpIf(a1, _) => { + JmpIf(a1, _) | JmpIfNot(a1, _) => { self.eval_arg(a1); } @@ -511,6 +511,7 @@ impl FnState { | SubCall(_, _, _, _) | Jmp(_) | JmpIf(_, _) + | JmpIfNot(_, _) | New(_, _, _) | Throw(_) | Import(_, _) diff --git a/valuescript_compiler/src/optimization/reduce_instructions.rs b/valuescript_compiler/src/optimization/reduce_instructions.rs index 9860b5e..d6a5f07 100644 --- a/valuescript_compiler/src/optimization/reduce_instructions.rs +++ b/valuescript_compiler/src/optimization/reduce_instructions.rs @@ -80,6 +80,12 @@ fn reduce(instr: Instruction) -> Option { Value::Bool(true) => Some(Instruction::Jmp(label_ref.clone())), _ => Some(instr), }, + JmpIfNot(cond, label_ref) => match cond { + // TODO: Kal::from_value(cond).is_truthy() + Value::Bool(false) => Some(Instruction::Jmp(label_ref.clone())), + Value::Bool(true) => None, + _ => Some(instr), + }, UnpackIterRes(_, value_dst, done_dst) => { if value_dst.is_ignore() && done_dst.is_ignore() { None diff --git a/valuescript_compiler/src/optimization/simplify.rs b/valuescript_compiler/src/optimization/simplify.rs index 285843f..307634d 100644 --- a/valuescript_compiler/src/optimization/simplify.rs +++ b/valuescript_compiler/src/optimization/simplify.rs @@ -150,7 +150,10 @@ fn is_jmp_or_label(line: &FnLine) -> bool { fn is_jmp_instr(instr: &Instruction) -> bool { match instr { - Instruction::End | Instruction::Jmp(..) | Instruction::JmpIf(..) => true, + Instruction::End + | Instruction::Jmp(..) + | Instruction::JmpIf(..) + | Instruction::JmpIfNot(..) => true, Instruction::Mov(..) | Instruction::OpInc(..) | Instruction::OpDec(..) diff --git a/valuescript_compiler/src/visit_pointers.rs b/valuescript_compiler/src/visit_pointers.rs index b3f8e33..0efe9c9 100644 --- a/valuescript_compiler/src/visit_pointers.rs +++ b/valuescript_compiler/src/visit_pointers.rs @@ -163,7 +163,7 @@ where self.value(Some(owner), key); self.value(Some(owner), args); } - JmpIf(arg, _) => { + JmpIf(arg, _) | JmpIfNot(arg, _) => { self.value(Some(owner), arg); } }; diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index c555444..4c7777d 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -412,6 +412,15 @@ impl StackFrameTrait for BytecodeStackFrame { } } + JmpIfNot => { + let cond = self.decoder.decode_val(&mut self.registers); + let dst = self.decoder.decode_pos(); + + if !cond.is_truthy() { + self.decoder.pos = dst; + } + } + UnaryPlus => self.apply_unary_op(operations::op_unary_plus), UnaryMinus => self.apply_unary_op(operations::op_unary_minus),