From 2c485cf046d68c232ca1f10180513bc6df6e03d4 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 23 Sep 2024 04:01:36 -0400 Subject: [PATCH] Implement logical and/or operators --- dust-lang/src/parser/mod.rs | 63 ++++++++++++++++++++++++++++++++++- dust-lang/src/parser/tests.rs | 10 +++--- dust-lang/src/vm.rs | 2 +- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index f5780a5..380efa9 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -547,7 +547,68 @@ impl<'src> Parser<'src> { } fn parse_logical_binary(&mut self) -> Result<(), ParseError> { - todo!() + let (left_instruction, left_position) = + self.chunk.pop_instruction(self.current_position)?; + let (push_back_left, left_is_constant, _) = + self.handle_binary_argument(&left_instruction)?; + + let operator = self.current_token; + let operator_position = self.current_position; + let rule = ParseRule::from(&operator.kind()); + + let mut instruction = match operator.kind() { + TokenKind::DoubleAmpersand => Instruction::test(self.current_register, true), + TokenKind::DoublePipe => Instruction::test(self.current_register, false), + _ => { + return Err(ParseError::ExpectedTokenMultiple { + expected: &[TokenKind::DoubleAmpersand, TokenKind::DoublePipe], + found: operator.to_owned(), + position: operator_position, + }) + } + }; + + if let Operation::LoadBoolean = left_instruction.operation() { + self.increment_register()?; + } + + self.advance()?; + self.parse(rule.precedence.increment())?; + + let (mut right_instruction, right_position) = + self.chunk.pop_instruction(self.current_position)?; + let (push_back_right, right_is_constant, _) = + self.handle_binary_argument(&right_instruction)?; + + if left_is_constant { + instruction.set_first_argument_to_constant(); + } + + if right_is_constant { + if let Operation::LoadBoolean = right_instruction.operation() { + right_instruction.set_second_argument_to_boolean(true); + } + + instruction.set_second_argument_to_constant(); + } + + if push_back_left { + self.emit_instruction(left_instruction, left_position); + } + + self.emit_instruction(instruction, operator_position); + self.emit_instruction(Instruction::jump(1, true), operator_position); + + if push_back_right { + self.emit_instruction(right_instruction, right_position); + } + + self.emit_instruction( + Instruction::r#move(self.current_register, self.current_register - 1), + operator_position, + ); + + Ok(()) } fn parse_variable( diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index 525e946..e8e13fe 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -457,6 +457,7 @@ fn or() { parse("true || false"), Ok(Chunk::with_data( vec![ + (Instruction::load_boolean(0, true, false), Span(0, 4)), ( *Instruction::test(0, false) .set_second_argument_to_constant() @@ -464,8 +465,8 @@ fn or() { Span(5, 7) ), (Instruction::jump(1, true), Span(5, 7)), - (Instruction::load_boolean(0, true, false), Span(0, 4)), - (Instruction::load_boolean(1, false, false), Span(8, 13)), + (Instruction::load_boolean(1, false, true), Span(8, 13)), + (Instruction::r#move(1, 0), Span(5, 7)), ], vec![], vec![] @@ -479,6 +480,7 @@ fn and() { parse("true && false"), Ok(Chunk::with_data( vec![ + (Instruction::load_boolean(0, true, false), Span(0, 4)), ( *Instruction::test(0, true) .set_second_argument_to_constant() @@ -486,8 +488,8 @@ fn and() { Span(5, 7) ), (Instruction::jump(1, true), Span(5, 7)), - (Instruction::load_boolean(0, true, false), Span(0, 4)), - (Instruction::load_boolean(1, false, false), Span(8, 13)), + (Instruction::load_boolean(1, false, true), Span(8, 13)), + (Instruction::r#move(1, 0), Span(5, 7)), ], vec![], vec![] diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b30301a..dbdef8a 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -86,7 +86,7 @@ impl Vm { self.insert(value, to_register, position)?; - if boolean && skip { + if skip { self.ip += 1; } }