From 886e0dc2301979ad0d83dd0ee7b04553b1dc61f8 Mon Sep 17 00:00:00 2001 From: taizu-jin Date: Fri, 22 Sep 2023 11:00:47 +0300 Subject: [PATCH 1/4] feat(vm): evaluate conditional statements --- src/vm.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vm.rs b/src/vm.rs index ceb9329..21455b3 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -136,6 +136,26 @@ impl VM { opcode if matches!(opcode, &OP_EQUAL | &OP_NOT_EQUAL | &OP_GREATER_THAN) => { self.execute_comparison(opcode)? } + &OP_JUMP => { + let slice: [u8; 2] = ins[ip + 1..=ip + 2].try_into().unwrap(); + let pos = u16::from_be_bytes(slice) as usize; + self.current_frame_mut().ip = pos - 1; + } + &OP_JUMP_NOT_TRUTH => { + let slice: [u8; 2] = ins[ip + 1..=ip + 2].try_into().unwrap(); + let pos = u16::from_be_bytes(slice) as usize; + self.current_frame_mut().ip += 2; + + let condition = if let Object::Bool(condition) = self.pop()? { + condition + } else { + unreachable!("there will always be a condition as last element") + }; + + if !condition { + self.current_frame_mut().ip = pos - 1; + } + } opcode => unimplemented!("handling for {} not implemented", opcode), } From af3ec82765a5dddfd80156b07275f5a7e652213a Mon Sep 17 00:00:00 2001 From: taizu-jin Date: Fri, 22 Sep 2023 11:00:58 +0300 Subject: [PATCH 2/4] test(vm): test conditional statements --- src/vm.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vm.rs b/src/vm.rs index 21455b3..1c4e0a9 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -585,4 +585,24 @@ mod tests { run_vm_tests(tests) } + + #[test] + fn test_conditionals() -> Result<()> { + let tests = def_case_int!( + "IF rbap_true. 10. ENDIF.", + 10, + "IF rbap_true. 10. ELSE. 20. ENDIF.", + 10, + "IF rbap_false. 10. ELSE. 20. ENDIF.", + 20, + "IF 1 < 2. 10. ENDIF.", + 10, + "IF 1 < 2. 10. ELSE. 20. ENDIF.", + 10, + "IF 1 > 2. 10. ELSE. 20. ENDIF.", + 20 + ); + + run_vm_tests(tests) + } } From fc5eb177818206d22fb64aad3de3a1a4b55ab1ff Mon Sep 17 00:00:00 2001 From: taizu-jin Date: Fri, 22 Sep 2023 11:17:16 +0300 Subject: [PATCH 3/4] ref(compiler): remove unnecessary OP_NULL from if statement compilation --- src/code.rs | 28 +++++++++++++--------------- src/compiler.rs | 41 +++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/code.rs b/src/code.rs index cb0fe0b..0002d83 100644 --- a/src/code.rs +++ b/src/code.rs @@ -38,20 +38,19 @@ define_constant!(OP_TRUE, 0x09); define_constant!(OP_FALSE, 0x0A); define_constant!(OP_JUMP_NOT_TRUTH, 0x0B, 2); define_constant!(OP_JUMP, 0x0C, 2); -define_constant!(OP_NULL, 0x0D); -define_constant!(OP_NOT, 0x0E); -define_constant!(OP_MINUS, 0x0F); -define_constant!(OP_GET_GLOBAL, 0x10, 2); -define_constant!(OP_SET_GLOBAL, 0x11, 2); -define_constant!(OP_GET_LOCAL, 0x12, 1); -define_constant!(OP_SET_LOCAL, 0x13, 1); -define_constant!(OP_CURRENT_CLOSURE, 0x14, 1); -define_constant!(OP_AND, 0x15); -define_constant!(OP_OR, 0x16); -define_constant!(OP_STRING_TEMPLATE, 0x17, 2); -define_constant!(OP_WRITE, 0x18, 2); -define_constant!(OP_FUNCTION, 0x19, 2); -define_constant!(OP_CALL, 0x1A, 1); +define_constant!(OP_NOT, 0x0D); +define_constant!(OP_MINUS, 0x0E); +define_constant!(OP_GET_GLOBAL, 0x0F, 2); +define_constant!(OP_SET_GLOBAL, 0x10, 2); +define_constant!(OP_GET_LOCAL, 0x11, 1); +define_constant!(OP_SET_LOCAL, 0x12, 1); +define_constant!(OP_CURRENT_CLOSURE, 0x13, 1); +define_constant!(OP_AND, 0x14); +define_constant!(OP_OR, 0x15); +define_constant!(OP_STRING_TEMPLATE, 0x16, 2); +define_constant!(OP_WRITE, 0x17, 2); +define_constant!(OP_FUNCTION, 0x18, 2); +define_constant!(OP_CALL, 0x19, 1); static DEFINITIONS: OnceLock> = OnceLock::new(); @@ -132,7 +131,6 @@ impl<'a> Opcode { map.insert(OP_FALSE.into(), &OP_FALSE); map.insert(OP_JUMP_NOT_TRUTH.into(), &OP_JUMP_NOT_TRUTH); map.insert(OP_JUMP.into(), &OP_JUMP); - map.insert(OP_NULL.into(), &OP_NULL); map.insert(OP_NOT.into(), &OP_NOT); map.insert(OP_MINUS.into(), &OP_MINUS); map.insert(OP_GET_GLOBAL.into(), &OP_GET_GLOBAL); diff --git a/src/compiler.rs b/src/compiler.rs index b8594c4..35ca733 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -126,27 +126,34 @@ impl Compiler { self.compile(is.consequence)?; - let jump_pos = self.emit(OP_JUMP, &[9999]); - - let after_pos: u16 = self - .current_instructions() - .len() - .try_into() - .expect("max jump index reached"); - self.change_operand(jump_not_truth_pos, after_pos as i32)?; + let after_not_truth_pos: u16; if let Some(alternative) = is.alternative { + let jump_pos = self.emit(OP_JUMP, &[9999]); + + after_not_truth_pos = self + .current_instructions() + .len() + .try_into() + .expect("max jump index reached"); + self.compile(alternative)?; + + let after_pos: u16 = self + .current_instructions() + .len() + .try_into() + .expect("max jump index reached"); + self.change_operand(jump_pos, after_pos as i32)?; } else { - self.emit(OP_NULL, &[]); + after_not_truth_pos = self + .current_instructions() + .len() + .try_into() + .expect("max jump index reached"); } - let after_pos: u16 = self - .current_instructions() - .len() - .try_into() - .expect("max jump index reached"); - self.change_operand(jump_pos, after_pos as i32)?; + self.change_operand(jump_not_truth_pos, after_not_truth_pos as i32)?; } Statement::Function(f) => { self.symbol_table.define( @@ -720,11 +727,9 @@ mod tests { define_case!("IF rbap_true. 10. ENDIF. 20."; Object::Int(10), Object::Int(20); [make(&OP_TRUE, &[]), - make(&OP_JUMP_NOT_TRUTH, &[11]), + make(&OP_JUMP_NOT_TRUTH, &[8]), make(&OP_CONSTANT, &[0]), make(&OP_POP, &[]), - make(&OP_JUMP, &[12]), - make(&OP_NULL, &[]), make(&OP_CONSTANT, &[1]), make(&OP_POP, &[])].concat().into()), define_case!("IF rbap_true. 10. ELSE. 15. ENDIF. 20."; From 750228f29e1ff91456a7e26ff74ce69fc724a207 Mon Sep 17 00:00:00 2001 From: taizu-jin Date: Fri, 22 Sep 2023 11:21:28 +0300 Subject: [PATCH 4/4] test(vm): test conditional without a block evaluation --- src/vm.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/vm.rs b/src/vm.rs index 1c4e0a9..2e95232 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -605,4 +605,18 @@ mod tests { run_vm_tests(tests) } + + #[test] + fn test_conditionals_without_bock() -> Result<()> { + let tests = def_case_bool!( + "IF rbap_false. 10. ENDIF.", + false, + "IF rbap_true. ELSE. 20. ENDIF.", + true, + "IF rbap_true. ELSE. ENDIF.", + true + ); + + run_vm_tests(tests) + } }