diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index 3deafc1..e956826 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -383,17 +383,17 @@ impl<'src> Parser<'src> { let operator_position = self.current_position; let rule = ParseRule::from(&operator.kind()); - let (mut instruction, push_args_first) = match operator.kind() { - TokenKind::Plus => (Instruction::add(self.current_register, left, 0), true), - TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), true), - TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), true), - TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), true), - TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), true), - TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), false), + let (mut instruction, is_comparison) = match operator.kind() { + TokenKind::Plus => (Instruction::add(self.current_register, left, 0), false), + TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), false), + TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), false), + TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), false), + TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), false), + TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), true), TokenKind::DoubleAmpersand => { let and_test = Instruction::test(self.current_register, false); - (and_test, false) + (and_test, true) } _ => { return Err(ParseError::ExpectedTokenMultiple { @@ -435,7 +435,7 @@ impl<'src> Parser<'src> { instruction.set_second_argument_to_constant(); } - if push_args_first { + if !is_comparison { if push_back_left { self.emit_instruction(left_instruction, left_position); } @@ -447,7 +447,7 @@ impl<'src> Parser<'src> { self.emit_instruction(instruction, operator_position); } - if !push_args_first { + if is_comparison { let push_left_first = self.current_register.saturating_sub(1) == left; if push_back_left && push_left_first { @@ -476,23 +476,19 @@ impl<'src> Parser<'src> { allow_assignment: bool, _allow_return: bool, ) -> Result<(), ParseError> { - let token = self.current_token.to_owned(); + let token = self.current_token; let start_position = self.current_position; let local_index = self.parse_identifier_from(token, start_position)?; let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable; - self.advance()?; + if !is_mutable { + return Err(ParseError::CannotMutateImmutableVariable { + identifier: self.chunk.get_identifier(local_index).cloned().unwrap(), + position: start_position, + }); + } if allow_assignment && self.allow(TokenKind::Equal)? { - if !is_mutable { - let identifier = self.chunk.get_identifier(local_index).cloned().unwrap(); - - return Err(ParseError::CannotMutateImmutableVariable { - identifier, - position: start_position, - }); - } - self.parse_expression()?; let (mut previous_instruction, previous_position) = @@ -530,12 +526,8 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_identifier_from( - &mut self, - token: TokenOwned, - position: Span, - ) -> Result { - if let TokenOwned::Identifier(text) = token { + fn parse_identifier_from(&mut self, token: Token, position: Span) -> Result { + if let Token::Identifier(text) = token { let identifier = Identifier::new(text); if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) { @@ -616,20 +608,29 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_if(&mut self, allow_assignment: bool, _allow_return: bool) -> Result<(), ParseError> { + fn parse_if(&mut self, allow_assignment: bool, allow_return: bool) -> Result<(), ParseError> { self.advance()?; self.parse_expression()?; + self.parse_block(allow_assignment, allow_return)?; - self.parse_block(allow_assignment, false)?; + let jump_start = self.current_register; + let jump_index = self.chunk.len(); if self.allow(TokenKind::Else)? { if self.allow(TokenKind::If)? { - self.parse_if(allow_assignment, false)?; + self.parse_if(allow_assignment, allow_return)?; } else { - self.parse_block(allow_assignment, false)?; + self.parse_block(allow_assignment, allow_return)?; } } + let jump_end = self.current_register; + let jump_distance = (jump_end - jump_start).max(1); + let jump = Instruction::jump(jump_distance, true); + + self.chunk + .insert_instruction(jump_index, jump, self.current_position); + Ok(()) } @@ -650,53 +651,18 @@ impl<'src> Parser<'src> { } fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> { - let start = self.current_position.0; - let is_expression = match self.current_token { + match self.current_token { Token::Let => { self.parse_let_statement(true, allow_return)?; - - false } Token::LeftCurlyBrace => { self.parse_block(true, true)?; - - let last_operation = self.chunk.get_last_operation(self.current_position)?; - let ends_in_return = last_operation == Operation::Return; - - if ends_in_return { - self.chunk.pop_instruction(self.current_position)?; - } - - ends_in_return } _ => { self.parse_expression()?; - - true } }; - if !allow_return || !is_expression { - return Ok(()); - } - - let (last_instruction, _) = *self.chunk.get_previous(self.current_position)?; - let ends_in_assignment = matches!( - last_instruction.operation(), - Operation::DefineLocal | Operation::SetLocal - ); - let has_semicolon = self.allow(TokenKind::Semicolon)?; - - if !ends_in_assignment && !has_semicolon { - let end = self.previous_position.1; - let return_register = last_instruction.destination(); - - self.emit_instruction( - Instruction::r#return(return_register, return_register), - Span(start, end), - ); - } - Ok(()) } @@ -712,7 +678,7 @@ impl<'src> Parser<'src> { }); } - self.advance()?; + self.allow(TokenKind::Let)?; let is_mutable = self.allow(TokenKind::Mut)?; let position = self.current_position; diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index 7dd4a2b..f604e4d 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -18,6 +18,7 @@ fn equality_assignment_long() { ), (Instruction::jump(1, true), Span(13, 15)), (Instruction::load_boolean(0, true, true), Span(20, 24)), + (Instruction::jump(1, true), Span(41, 42)), (Instruction::load_boolean(0, false, false), Span(34, 39)), (Instruction::define_local(0, 0, false), Span(4, 5)), ], @@ -68,8 +69,8 @@ fn if_else_expression() { ), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_constant(0, 2), Span(12, 13)), + (Instruction::jump(1, true), Span(26, 26)), (Instruction::load_constant(1, 3), Span(23, 24)), - (Instruction::r#return(1, 1), Span(0, 26)), ], vec![ Value::integer(1), @@ -99,7 +100,6 @@ fn list_with_expression() { ), (Instruction::load_constant(2, 3), Span(11, 12)), (Instruction::load_list(3, 0, 3), Span(0, 13)), - (Instruction::r#return(3, 3), Span(0, 13)), ], vec![ Value::integer(1), @@ -124,7 +124,6 @@ fn list() { (Instruction::load_constant(1, 1), Span(4, 5)), (Instruction::load_constant(2, 2), Span(7, 8)), (Instruction::load_list(3, 0, 3), Span(0, 9)), - (Instruction::r#return(3, 3), Span(0, 9)), ], vec![Value::integer(1), Value::integer(2), Value::integer(3),], vec![] @@ -217,7 +216,6 @@ fn parentheses_precedence() { *Instruction::multiply(1, 0, 2).set_second_argument_to_constant(), Span(8, 9) ), - (Instruction::r#return(1, 1), Span(0, 11)), ], vec![Value::integer(1), Value::integer(2), Value::integer(3)], vec![] @@ -248,7 +246,6 @@ fn math_operator_precedence() { Span(14, 15) ), (Instruction::subtract(1, 0, 3), Span(6, 7)), - (Instruction::r#return(1, 1), Span(0, 17)), ], vec![ Value::integer(1), @@ -284,10 +281,14 @@ fn and() { Ok(Chunk::with_data( vec![ (Instruction::load_boolean(0, true, false), Span(0, 4)), - (Instruction::test(0, true), Span(5, 7)), + ( + *Instruction::test(0, true) + .set_second_argument_to_constant() + .set_first_argument_to_constant(), + Span(5, 7) + ), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_boolean(1, false, false), Span(8, 13)), - (Instruction::r#return(1, 1), Span(0, 13)), ], vec![], vec![] @@ -300,15 +301,12 @@ fn divide() { assert_eq!( parse("1 / 2"), Ok(Chunk::with_data( - vec![ - ( - *Instruction::divide(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), - Span(2, 3) - ), - (Instruction::r#return(0, 0), Span(0, 5)), - ], + vec![( + *Instruction::divide(0, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ),], vec![Value::integer(1), Value::integer(2)], vec![] )) @@ -320,15 +318,12 @@ fn multiply() { assert_eq!( parse("1 * 2"), Ok(Chunk::with_data( - vec![ - ( - *Instruction::multiply(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), - Span(2, 3) - ), - (Instruction::r#return(0, 0), Span(0, 5)), - ], + vec![( + *Instruction::multiply(0, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ),], vec![Value::integer(1), Value::integer(2)], vec![] )) @@ -340,15 +335,12 @@ fn add() { assert_eq!( parse("1 + 2"), Ok(Chunk::with_data( - vec![ - ( - *Instruction::add(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), - Span(2, 3) - ), - (Instruction::r#return(0, 0), Span(0, 5)), - ], + vec![( + *Instruction::add(0, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ),], vec![Value::integer(1), Value::integer(2)], vec![] )) @@ -360,15 +352,12 @@ fn subtract() { assert_eq!( parse("1 - 2"), Ok(Chunk::with_data( - vec![ - ( - *Instruction::subtract(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), - Span(2, 3) - ), - (Instruction::r#return(0, 0), Span(0, 5)), - ], + vec![( + *Instruction::subtract(0, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ),], vec![Value::integer(1), Value::integer(2)], vec![] )) @@ -380,10 +369,7 @@ fn constant() { assert_eq!( parse("42"), Ok(Chunk::with_data( - vec![ - (Instruction::load_constant(0, 0), Span(0, 2)), - (Instruction::r#return(0, 0), Span(0, 2)), - ], + vec![(Instruction::load_constant(0, 0), Span(0, 2)),], vec![Value::integer(42)], vec![] )) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index ac9726e..22975ba 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -292,9 +292,13 @@ impl Vm { self.ip = new_ip; } Operation::Return => { - let return_value = self.pop(position)?; + let start_register = instruction.destination(); + let end_register = instruction.first_argument(); + let return_value_count = end_register - start_register; - return Ok(Some(return_value)); + if return_value_count == 1 { + return Ok(Some(self.take(start_register, position)?)); + } } } }