From 57edf48e36aafb7dd6ccf7478d4176f6baacd5a7 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 22 Sep 2024 18:17:21 -0400 Subject: [PATCH] Extend parsing --- dust-lang/src/chunk.rs | 31 +++- dust-lang/src/instruction.rs | 20 +++ dust-lang/src/lexer.rs | 23 ++- dust-lang/src/parser/mod.rs | 330 ++++++++++++++++++++++------------ dust-lang/src/parser/tests.rs | 215 +++++++++++++++++++++- dust-lang/src/token.rs | 12 +- dust-lang/src/vm.rs | 2 +- 7 files changed, 494 insertions(+), 139 deletions(-) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 470b6df..9c9e41f 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -58,6 +58,10 @@ impl Chunk { .ok_or(ChunkError::CodeIndexOfBounds { offset, position }) } + pub fn remove_instruction(&mut self, index: usize) -> (Instruction, Span) { + self.instructions.remove(index) + } + pub fn push_instruction(&mut self, instruction: Instruction, position: Span) { self.instructions.push((instruction, position)); } @@ -72,17 +76,32 @@ impl Chunk { .ok_or(ChunkError::InstructionUnderflow { position }) } - pub fn get_previous(&self, position: Span) -> Result<&(Instruction, Span), ChunkError> { - self.instructions - .last() - .ok_or(ChunkError::InstructionUnderflow { position }) + pub fn get_previous(&self) -> Option<&(Instruction, Span)> { + self.instructions.last() } - pub fn get_last_operation(&self, position: Span) -> Result { - self.get_previous(position) + pub fn get_last_operation(&self) -> Option { + self.get_previous() .map(|(instruction, _)| instruction.operation()) } + pub fn get_last_n_operations(&self) -> [Option; N] { + let mut operations = [None; N]; + + for i in 0..N { + let index = self.instructions.len().saturating_sub(i + 1); + + let operation = self + .instructions + .get(index) + .map(|(instruction, _)| instruction.operation()); + + operations[i] = operation; + } + + operations + } + pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> { let index = index as usize; diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index 6178f54..745e31e 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -160,6 +160,26 @@ impl Instruction { instruction } + pub fn less(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction { + let mut instruction = Instruction(Operation::Less as u32); + + instruction.set_destination(if comparison_boolean { 1 } else { 0 }); + instruction.set_first_argument(left_index); + instruction.set_second_argument(right_index); + + instruction + } + + pub fn less_equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction { + let mut instruction = Instruction(Operation::LessEqual as u32); + + instruction.set_destination(if comparison_boolean { 1 } else { 0 }); + instruction.set_first_argument(left_index); + instruction.set_second_argument(right_index); + + instruction + } + pub fn negate(to_register: u8, from_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Negate as u32); diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index ba1f1c6..ea0cbe0 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -309,7 +309,13 @@ impl<'src> Lexer<'src> { '!' => { self.position += 1; - (Token::Bang, Span(self.position - 1, self.position)) + if let Some('=') = self.peek_char() { + self.position += 1; + + (Token::BangEqual, Span(self.position - 2, self.position)) + } else { + (Token::Bang, Span(self.position - 1, self.position)) + } } ':' => { self.position += 1; @@ -969,6 +975,21 @@ mod tests { ) } + #[test] + fn not_equal() { + let input = "42 != 42"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Integer("42"), Span(0, 2)), + (Token::BangEqual, Span(3, 5)), + (Token::Integer("42"), Span(6, 8)), + (Token::Eof, Span(8, 8)), + ]) + ) + } + #[test] fn equal() { let input = "42 == 42"; diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index ed0735a..1613d96 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -8,8 +8,8 @@ use std::{ }; use crate::{ - dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, - Lexer, Operation, Span, Token, TokenKind, TokenOwned, Value, + AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer, + Operation, Span, Token, TokenKind, TokenOwned, Value, }; pub fn parse(source: &str) -> Result { @@ -150,26 +150,52 @@ impl<'src> Parser<'src> { ) -> Result<(), ParseError> { if let Token::Boolean(text) = self.current_token { let position = self.current_position; + let boolean = text.parse::().unwrap(); self.advance()?; - let boolean = text.parse::().unwrap(); + let previous_operations = self.chunk.get_last_n_operations::<2>(); - if let Ok((last_instruction, _)) = - self.chunk.get_previous(self.current_position).copied() + if let [Some(Operation::LoadBoolean), Some(Operation::LoadBoolean)] = + previous_operations { - let skip = last_instruction.operation() == Operation::Jump; + let (second_boolean, second_position) = + self.chunk.pop_instruction(self.current_position)?; + let (first_boolean, first_position) = + self.chunk.pop_instruction(self.current_position)?; - self.emit_instruction( - Instruction::load_boolean(self.current_register, boolean, skip), - position, - ); - } else { - self.emit_instruction( - Instruction::load_boolean(self.current_register, boolean, false), - position, - ); + if first_boolean.first_argument_as_boolean() == boolean { + let skip = first_boolean.second_argument_as_boolean(); + + self.emit_instruction( + Instruction::load_boolean(self.current_register, boolean, skip), + position, + ); + + return Ok(()); + } + + if second_boolean.first_argument_as_boolean() == boolean { + let skip = second_boolean.second_argument_as_boolean(); + + self.emit_instruction( + Instruction::load_boolean(self.current_register, boolean, skip), + position, + ); + + return Ok(()); + } + + self.emit_instruction(first_boolean, first_position); + self.emit_instruction(second_boolean, second_position); } + + let skip = previous_operations[0] == Some(Operation::Jump); + + self.emit_instruction( + Instruction::load_boolean(self.current_register, boolean, skip), + position, + ); } Ok(()) @@ -390,11 +416,21 @@ impl<'src> Parser<'src> { 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::BangEqual => (Instruction::equal(false, left, 0), true), + TokenKind::Less => (Instruction::less(true, left, 0), true), + TokenKind::LessEqual => (Instruction::less_equal(true, left, 0), true), + TokenKind::Greater => (Instruction::less_equal(false, left, 0), true), + TokenKind::GreaterEqual => (Instruction::less(false, left, 0), true), TokenKind::DoubleAmpersand => { let and_test = Instruction::test(self.current_register, false); (and_test, true) } + TokenKind::DoublePipe => { + let or_test = Instruction::test(self.current_register, true); + + (or_test, true) + } _ => { return Err(ParseError::ExpectedTokenMultiple { expected: &[ @@ -403,9 +439,14 @@ impl<'src> Parser<'src> { TokenKind::Star, TokenKind::Slash, TokenKind::Percent, + TokenKind::DoubleEqual, + TokenKind::BangEqual, + TokenKind::Less, + TokenKind::LessEqual, + TokenKind::Greater, + TokenKind::GreaterEqual, TokenKind::DoubleAmpersand, TokenKind::DoublePipe, - TokenKind::DoubleEqual, ], found: operator.to_owned(), position: operator_position, @@ -466,6 +507,21 @@ impl<'src> Parser<'src> { if push_back_right { self.emit_instruction(right_instruction, right_position); } + + if !push_back_left && !push_back_right { + if self.current_register > 0 { + self.decrement_register()?; + } + + self.emit_instruction( + Instruction::load_boolean(self.current_register, true, true), + operator_position, + ); + self.emit_instruction( + Instruction::load_boolean(self.current_register, false, false), + operator_position, + ); + } } Ok(()) @@ -482,16 +538,17 @@ impl<'src> Parser<'src> { self.advance()?; let local_index = self.parse_identifier_from(token, start_position)?; - let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable; - - 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)? { + let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable; + + if !is_mutable { + return Err(ParseError::CannotMutateImmutableVariable { + identifier: self.chunk.get_identifier(local_index).cloned().unwrap(), + position: start_position, + }); + } + self.parse_expression()?; let (mut previous_instruction, previous_position) = @@ -614,6 +671,13 @@ impl<'src> Parser<'src> { fn parse_if(&mut self, allow_assignment: bool, allow_return: bool) -> Result<(), ParseError> { self.advance()?; self.parse_expression()?; + + let (second_load_boolean, second_position) = + self.chunk.pop_instruction(self.current_position)?; + let (first_load_boolean, first_position) = + self.chunk.pop_instruction(self.current_position)?; + let length_after_expression = self.chunk.len(); + self.parse_block(allow_assignment, allow_return)?; let jump_start = self.current_register; @@ -627,12 +691,22 @@ impl<'src> Parser<'src> { } } - let jump_end = self.current_register; - let jump_distance = (jump_end - jump_start).max(1); - let jump = Instruction::jump(jump_distance, true); + if self.chunk.len() == length_after_expression { + self.emit_instruction(first_load_boolean, first_position); + self.emit_instruction(second_load_boolean, second_position); + } - self.chunk - .insert_instruction(jump_index, jump, self.current_position); + if let Some(Operation::LoadBoolean) = self.chunk.get_last_operation() { + // Skip the jump if the last instruction was a LoadBoolean operation. A LoadBoolean can + // skip the following instruction, so a jump is unnecessary. + } else { + 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(()) } @@ -702,35 +776,37 @@ impl<'src> Parser<'src> { self.expect(TokenKind::Equal)?; self.parse_expression()?; - let (previous_instruction, previous_position) = *self.chunk.get_previous(position)?; + let (previous_instruction, previous_position) = + *self + .chunk + .get_previous() + .ok_or_else(|| ParseError::ExpectedExpression { + found: self.current_token.to_owned(), + position, + })?; let register = previous_instruction.destination(); let local_index = self.chunk .declare_local(identifier, is_mutable, register, previous_position)?; // Optimize for assignment to a comparison - if let Operation::Jump = previous_instruction.operation() { - let (jump, jump_position) = self.chunk.pop_instruction(self.current_position)?; + // if let Operation::Jump = previous_instruction.operation() { + // let (jump, jump_position) = self.chunk.pop_instruction(self.current_position)?; - if let Operation::Equal = self - .chunk - .get_previous(self.current_position)? - .0 - .operation() - { - self.emit_instruction(jump, jump_position); - self.emit_instruction( - Instruction::load_boolean(self.current_register, true, true), - self.current_position, - ); - self.emit_instruction( - Instruction::load_boolean(self.current_register, false, false), - self.current_position, - ); - } else { - self.emit_instruction(jump, jump_position); - } - } + // if let Some(Operation::Equal) = self.chunk.get_last_operation() { + // self.emit_instruction(jump, jump_position); + // self.emit_instruction( + // Instruction::load_boolean(self.current_register, true, true), + // self.current_position, + // ); + // self.emit_instruction( + // Instruction::load_boolean(self.current_register, false, false), + // self.current_position, + // ); + // } else { + // self.emit_instruction(jump, jump_position); + // } + // } self.emit_instruction( Instruction::define_local(register, local_index, is_mutable), @@ -836,21 +912,24 @@ pub struct ParseRule<'a> { impl From<&TokenKind> for ParseRule<'_> { fn from(token_kind: &TokenKind) -> Self { match token_kind { - TokenKind::Eof => ParseRule { + TokenKind::Async => todo!(), + TokenKind::Bang => ParseRule { + prefix: Some(Parser::parse_unary), + infix: None, + precedence: Precedence::Unary, + }, + TokenKind::BangEqual => ParseRule { prefix: None, - infix: None, - precedence: Precedence::None, - }, - TokenKind::Identifier => ParseRule { - prefix: Some(Parser::parse_variable), - infix: None, - precedence: Precedence::None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Equality, }, + TokenKind::Bool => todo!(), TokenKind::Boolean => ParseRule { prefix: Some(Parser::parse_boolean), infix: None, precedence: Precedence::None, }, + TokenKind::Break => todo!(), TokenKind::Byte => ParseRule { prefix: Some(Parser::parse_byte), infix: None, @@ -861,55 +940,6 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, - TokenKind::Float => ParseRule { - prefix: Some(Parser::parse_float), - infix: None, - precedence: Precedence::None, - }, - TokenKind::Integer => ParseRule { - prefix: Some(Parser::parse_integer), - infix: None, - precedence: Precedence::None, - }, - TokenKind::String => ParseRule { - prefix: Some(Parser::parse_string), - infix: None, - precedence: Precedence::None, - }, - TokenKind::Async => todo!(), - TokenKind::Bool => todo!(), - TokenKind::Break => todo!(), - TokenKind::Else => ParseRule { - prefix: None, - infix: None, - precedence: Precedence::None, - }, - TokenKind::FloatKeyword => todo!(), - TokenKind::If => ParseRule { - prefix: Some(Parser::parse_if), - infix: None, - precedence: Precedence::None, - }, - TokenKind::Int => todo!(), - TokenKind::Let => ParseRule { - prefix: Some(Parser::parse_let_statement), - infix: None, - precedence: Precedence::None, - }, - TokenKind::Loop => todo!(), - TokenKind::Map => todo!(), - TokenKind::Str => todo!(), - TokenKind::While => ParseRule { - prefix: Some(Parser::parse_while), - infix: None, - precedence: Precedence::None, - }, - TokenKind::BangEqual => todo!(), - TokenKind::Bang => ParseRule { - prefix: Some(Parser::parse_unary), - infix: None, - precedence: Precedence::Unary, - }, TokenKind::Colon => todo!(), TokenKind::Comma => ParseRule { prefix: None, @@ -922,7 +952,6 @@ impl From<&TokenKind> for ParseRule<'_> { infix: Some(Parser::parse_binary), precedence: Precedence::LogicalAnd, }, - TokenKind::DoubleDot => todo!(), TokenKind::DoubleEqual => ParseRule { prefix: None, infix: Some(Parser::parse_binary), @@ -933,13 +962,54 @@ impl From<&TokenKind> for ParseRule<'_> { infix: Some(Parser::parse_binary), precedence: Precedence::LogicalOr, }, + TokenKind::DoubleDot => todo!(), + TokenKind::Eof => ParseRule { + prefix: None, + infix: None, + precedence: Precedence::None, + }, TokenKind::Equal => ParseRule { prefix: None, infix: None, precedence: Precedence::Assignment, }, - TokenKind::Greater => todo!(), - TokenKind::GreaterOrEqual => todo!(), + TokenKind::Else => ParseRule { + prefix: None, + infix: None, + precedence: Precedence::None, + }, + TokenKind::Float => ParseRule { + prefix: Some(Parser::parse_float), + infix: None, + precedence: Precedence::None, + }, + TokenKind::FloatKeyword => todo!(), + TokenKind::Greater => ParseRule { + prefix: None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Comparison, + }, + TokenKind::GreaterEqual => ParseRule { + prefix: None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Comparison, + }, + TokenKind::Identifier => ParseRule { + prefix: Some(Parser::parse_variable), + infix: None, + precedence: Precedence::None, + }, + TokenKind::If => ParseRule { + prefix: Some(Parser::parse_if), + infix: None, + precedence: Precedence::None, + }, + TokenKind::Int => todo!(), + TokenKind::Integer => ParseRule { + prefix: Some(Parser::parse_integer), + infix: None, + precedence: Precedence::None, + }, TokenKind::LeftCurlyBrace => ParseRule { prefix: Some(Parser::parse_block), infix: None, @@ -955,8 +1025,23 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, - TokenKind::Less => todo!(), - TokenKind::LessOrEqual => todo!(), + TokenKind::Less => ParseRule { + prefix: None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Comparison, + }, + TokenKind::LessEqual => ParseRule { + prefix: None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Comparison, + }, + TokenKind::Let => ParseRule { + prefix: Some(Parser::parse_let_statement), + infix: None, + precedence: Precedence::None, + }, + TokenKind::Loop => todo!(), + TokenKind::Map => todo!(), TokenKind::Minus => ParseRule { prefix: Some(Parser::parse_unary), infix: Some(Parser::parse_binary), @@ -999,16 +1084,27 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, + TokenKind::Slash => ParseRule { + prefix: None, + infix: Some(Parser::parse_binary), + precedence: Precedence::Factor, + }, TokenKind::Star => ParseRule { prefix: None, infix: Some(Parser::parse_binary), precedence: Precedence::Factor, }, + TokenKind::Str => todo!(), + TokenKind::String => ParseRule { + prefix: Some(Parser::parse_string), + infix: None, + precedence: Precedence::None, + }, TokenKind::Struct => todo!(), - TokenKind::Slash => ParseRule { - prefix: None, - infix: Some(Parser::parse_binary), - precedence: Precedence::Factor, + TokenKind::While => ParseRule { + prefix: Some(Parser::parse_while), + infix: None, + precedence: Precedence::None, }, } } diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index f604e4d..3d31a25 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -2,6 +2,184 @@ use crate::Local; use super::*; +#[test] +fn not() { + let source = "!true"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + (Instruction::load_boolean(0, true, true), Span(1, 5)), + (Instruction::not(0, 0), Span(1, 5)), + ], + vec![], + vec![] + )), + ); +} + +#[test] +fn negate() { + let source = "-(42)"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + (Instruction::load_constant(0, 0), Span(2, 4)), + (Instruction::negate(0, 0), Span(1, 5)), + ], + vec![Value::integer(42),], + vec![] + )), + ); +} + +#[test] +fn greater_than_or_equal() { + let source = "1 >= 2;"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::less(false, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 4) + ), + (Instruction::jump(1, true), Span(2, 4)), + (Instruction::load_boolean(0, true, true), Span(2, 4)), + (Instruction::load_boolean(0, false, false), Span(2, 4)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + +#[test] +fn greater() { + let source = "1 > 2;"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::less_equal(false, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ), + (Instruction::jump(1, true), Span(2, 3)), + (Instruction::load_boolean(0, true, true), Span(2, 3)), + (Instruction::load_boolean(0, false, false), Span(2, 3)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + +#[test] +fn less_than_or_equal() { + let source = "1 <= 2;"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::less_equal(true, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 4) + ), + (Instruction::jump(1, true), Span(2, 4)), + (Instruction::load_boolean(0, true, true), Span(2, 4)), + (Instruction::load_boolean(0, false, false), Span(2, 4)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + +#[test] +fn less_than() { + let source = "1 < 2;"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::less(true, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 3) + ), + (Instruction::jump(1, true), Span(2, 3)), + (Instruction::load_boolean(0, true, true), Span(2, 3)), + (Instruction::load_boolean(0, false, false), Span(2, 3)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + +#[test] +fn not_equal() { + let source = "1 != 2;"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::equal(false, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 4) + ), + (Instruction::jump(1, true), Span(2, 4)), + (Instruction::load_boolean(0, true, true), Span(2, 4)), + (Instruction::load_boolean(0, false, false), Span(2, 4)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + +#[test] +fn equal() { + let source = "1 == 2"; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::equal(true, 0, 1) + .set_first_argument_to_constant() + .set_second_argument_to_constant(), + Span(2, 4) + ), + (Instruction::jump(1, true), Span(2, 4)), + (Instruction::load_boolean(0, true, true), Span(2, 4)), + (Instruction::load_boolean(0, false, false), Span(2, 4)), + ], + vec![Value::integer(1), Value::integer(2)], + vec![] + )), + ); +} + #[test] fn equality_assignment_long() { let source = "let a = if 4 == 4 { true } else { false };"; @@ -18,12 +196,11 @@ 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)), ], - vec![Value::integer(4), Value::integer(4),], - vec![Local::new(Identifier::new("a"), false, 0, Some(0)),] + vec![Value::integer(4), Value::integer(4)], + vec![Local::new(Identifier::new("a"), false, 0, Some(0))] )), ); } @@ -43,12 +220,12 @@ fn equality_assignment_short() { Span(10, 12) ), (Instruction::jump(1, true), Span(10, 12)), - (Instruction::load_boolean(0, true, true), Span(14, 15)), - (Instruction::load_boolean(0, false, false), Span(14, 15)), + (Instruction::load_boolean(0, true, true), Span(10, 12)), + (Instruction::load_boolean(0, false, false), Span(10, 12)), (Instruction::define_local(0, 0, false), Span(4, 5)), ], - vec![Value::integer(4), Value::integer(4),], - vec![Local::new(Identifier::new("a"), false, 0, Some(0)),] + vec![Value::integer(4), Value::integer(4)], + vec![Local::new(Identifier::new("a"), false, 0, Some(0))] )), ); } @@ -274,13 +451,34 @@ fn declare_local() { ); } +#[test] +fn or() { + assert_eq!( + parse("true || false"), + Ok(Chunk::with_data( + vec![ + ( + *Instruction::test(0, false) + .set_second_argument_to_constant() + .set_first_argument_to_constant(), + 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)), + ], + vec![], + vec![] + )) + ); +} + #[test] fn and() { assert_eq!( 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() @@ -288,6 +486,7 @@ 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)), ], vec![], diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index abff7fb..6b2d7e3 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -198,7 +198,7 @@ impl<'src> Token<'src> { Token::Float(_) => TokenKind::Float, Token::FloatKeyword => TokenKind::FloatKeyword, Token::Greater => TokenKind::Greater, - Token::GreaterEqual => TokenKind::GreaterOrEqual, + Token::GreaterEqual => TokenKind::GreaterEqual, Token::Identifier(_) => TokenKind::Identifier, Token::If => TokenKind::If, Token::Int => TokenKind::Int, @@ -208,7 +208,7 @@ impl<'src> Token<'src> { Token::LeftSquareBrace => TokenKind::LeftSquareBrace, Token::Let => TokenKind::Let, Token::Less => TokenKind::Less, - Token::LessEqual => TokenKind::LessOrEqual, + Token::LessEqual => TokenKind::LessEqual, Token::Loop => TokenKind::Loop, Token::Map => TokenKind::Map, Token::Minus => TokenKind::Minus, @@ -450,12 +450,12 @@ pub enum TokenKind { DoublePipe, Equal, Greater, - GreaterOrEqual, + GreaterEqual, LeftCurlyBrace, LeftParenthesis, LeftSquareBrace, Less, - LessOrEqual, + LessEqual, Minus, MinusEqual, Mut, @@ -495,7 +495,7 @@ impl Display for TokenKind { TokenKind::Float => write!(f, "float value"), TokenKind::FloatKeyword => Token::FloatKeyword.fmt(f), TokenKind::Greater => Token::Greater.fmt(f), - TokenKind::GreaterOrEqual => Token::GreaterEqual.fmt(f), + TokenKind::GreaterEqual => Token::GreaterEqual.fmt(f), TokenKind::Identifier => write!(f, "identifier"), TokenKind::If => Token::If.fmt(f), TokenKind::Int => Token::Int.fmt(f), @@ -505,7 +505,7 @@ impl Display for TokenKind { TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f), TokenKind::Let => Token::Let.fmt(f), TokenKind::Less => Token::Less.fmt(f), - TokenKind::LessOrEqual => Token::LessEqual.fmt(f), + TokenKind::LessEqual => Token::LessEqual.fmt(f), TokenKind::Loop => Token::Loop.fmt(f), TokenKind::Map => Token::Map.fmt(f), TokenKind::Minus => Token::Minus.fmt(f), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 3f96787..bf3fa98 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -60,7 +60,7 @@ impl Vm { } while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() { - log::trace!("Running instruction {instruction} at {position}"); + log::trace!("Running IP {} {instruction} at {position}", self.ip); match instruction.operation() { Operation::Move => {