From f02c3d1fb5faf51defc0053848a4efba2ca55551 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 17 Sep 2024 19:35:33 -0400 Subject: [PATCH] Add lists --- dust-lang/src/instruction.rs | 52 +++++++++++++----- dust-lang/src/parser/mod.rs | 103 ++++++++++++++++++++++++++--------- dust-lang/src/vm.rs | 16 ++++++ 3 files changed, 131 insertions(+), 40 deletions(-) diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index f5924fe..4e5fde9 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -32,6 +32,15 @@ impl Instruction { instruction } + pub fn load_list(to_register: u8, list_length: u8) -> Instruction { + let mut instruction = Instruction(Operation::LoadList as u32); + + instruction.set_destination(to_register); + instruction.set_first_argument(list_length); + + instruction + } + pub fn declare_local(to_register: u8, variable_index: u8) -> Instruction { let mut instruction = Instruction(Operation::DeclareLocal as u32); @@ -244,6 +253,16 @@ impl Instruction { format!("R({}) = C({})", self.destination(), constant_index) } } + Operation::LoadList => { + let destination = self.destination(); + let first_index = destination - self.first_argument(); + let last_index = destination - 1; + + format!( + "R({}) = [R({})..R({})]", + destination, first_index, last_index + ) + } Operation::DeclareLocal => { let local_index = self.first_argument(); let identifier_display = if let Some(chunk) = chunk { @@ -430,19 +449,20 @@ impl Display for Instruction { const MOVE: u8 = 0b0000_0000; const CLOSE: u8 = 0b000_0001; const LOAD_CONSTANT: u8 = 0b0000_0010; -const DECLARE_LOCAL: u8 = 0b0000_0011; -const GET_LOCAL: u8 = 0b0000_0100; -const SET_LOCAL: u8 = 0b0000_0101; -const ADD: u8 = 0b0000_0110; -const SUBTRACT: u8 = 0b0000_0111; -const MULTIPLY: u8 = 0b0000_1000; -const MODULO: u8 = 0b0000_1001; -const AND: u8 = 0b0000_1010; -const OR: u8 = 0b0000_1011; -const DIVIDE: u8 = 0b0000_1100; -const NEGATE: u8 = 0b0000_1101; -const NOT: u8 = 0b0000_1110; -const RETURN: u8 = 0b0000_1111; +const LOAD_LIST: u8 = 0b0000_0011; +const DECLARE_LOCAL: u8 = 0b0000_0100; +const GET_LOCAL: u8 = 0b0000_0101; +const SET_LOCAL: u8 = 0b0000_0110; +const ADD: u8 = 0b0000_0111; +const SUBTRACT: u8 = 0b0000_1000; +const MULTIPLY: u8 = 0b0000_1001; +const MODULO: u8 = 0b0000_1010; +const AND: u8 = 0b0000_1011; +const OR: u8 = 0b0000_1100; +const DIVIDE: u8 = 0b0000_1101; +const NEGATE: u8 = 0b0000_1110; +const NOT: u8 = 0b0000_1111; +const RETURN: u8 = 0b0001_0000; #[derive(Clone, Copy, Debug, PartialEq)] pub enum Operation { @@ -450,8 +470,9 @@ pub enum Operation { Move = MOVE as isize, Close = CLOSE as isize, - // Constants + // Value loading LoadConstant = LOAD_CONSTANT as isize, + LoadList = LOAD_LIST as isize, // Variables DeclareLocal = DECLARE_LOCAL as isize, @@ -496,6 +517,7 @@ impl From for Operation { MOVE => Operation::Move, CLOSE => Operation::Close, LOAD_CONSTANT => Operation::LoadConstant, + LOAD_LIST => Operation::LoadList, DECLARE_LOCAL => Operation::DeclareLocal, GET_LOCAL => Operation::GetLocal, SET_LOCAL => Operation::SetLocal, @@ -520,6 +542,7 @@ impl From for u8 { Operation::Move => MOVE, Operation::Close => CLOSE, Operation::LoadConstant => LOAD_CONSTANT, + Operation::LoadList => LOAD_LIST, Operation::DeclareLocal => DECLARE_LOCAL, Operation::GetLocal => GET_LOCAL, Operation::SetLocal => SET_LOCAL, @@ -543,6 +566,7 @@ impl Display for Operation { Operation::Move => write!(f, "MOVE"), Operation::Close => write!(f, "CLOSE"), Operation::LoadConstant => write!(f, "LOAD_CONSTANT"), + Operation::LoadList => write!(f, "LOAD_LIST"), Operation::DeclareLocal => write!(f, "DECLARE_LOCAL"), Operation::GetLocal => write!(f, "GET_LOCAL"), Operation::SetLocal => write!(f, "SET_LOCAL"), diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index b6d0e81..b460729 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -240,35 +240,46 @@ impl<'src> Parser<'src> { } fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { - let operator_position = self.previous_position; - let mut instruction = match self.previous_token.kind() { - TokenKind::Minus => { - self.advance()?; - self.parse_expression()?; + let operator = self.current_token; + let operator_position = self.current_position; - Instruction::negate(self.current_register, self.current_register - 1) + self.advance()?; + self.parse_expression()?; + + let (previous_instruction, previous_position) = + self.chunk.pop_instruction(self.current_position)?; + + let (is_constant, destination, from_register) = match previous_instruction.operation() { + Operation::LoadConstant => { + self.decrement_register()?; + + ( + true, + previous_instruction.destination(), + previous_instruction.first_argument(), + ) } + _ => { + self.emit_instruction(previous_instruction, previous_position); + + (false, self.current_register, self.current_register - 1) + } + }; + + let mut instruction = match operator.kind() { + TokenKind::Bang => Instruction::not(destination, from_register), + TokenKind::Minus => Instruction::negate(destination, from_register), _ => { return Err(ParseError::ExpectedTokenMultiple { - expected: vec![TokenKind::Minus], - found: self.previous_token.to_owned(), + expected: &[TokenKind::Minus], + found: operator.to_owned(), position: operator_position, }) } }; - let (previous_instruction, previous_position) = - self.chunk.pop_instruction(self.current_position)?; - - match previous_instruction.operation() { - Operation::LoadConstant => { - self.decrement_register()?; - instruction.set_first_argument(previous_instruction.destination()); - instruction.set_first_argument_to_constant(); - } - _ => { - self.emit_instruction(previous_instruction, previous_position); - } + if is_constant { + instruction.set_first_argument_to_constant(); } self.increment_register()?; @@ -340,7 +351,7 @@ impl<'src> Parser<'src> { TokenKind::DoublePipe => Instruction::or(self.current_register, left, right), _ => { return Err(ParseError::ExpectedTokenMultiple { - expected: vec![ + expected: &[ TokenKind::Plus, TokenKind::Minus, TokenKind::Star, @@ -450,7 +461,7 @@ impl<'src> Parser<'src> { } } - pub fn parse_block(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { + fn parse_block(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { self.advance()?; self.chunk.begin_scope(); @@ -463,6 +474,34 @@ impl<'src> Parser<'src> { Ok(()) } + fn parse_list(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { + self.advance()?; + + let start = self.current_position.0; + let mut length = 0; + + while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() { + self.parse_expression()?; + + length += 1; + + if !self.allow(TokenKind::Comma)? { + self.expect(TokenKind::RightSquareBrace)?; + + break; + } + } + + let end = self.current_position.1; + + self.emit_instruction( + Instruction::load_list(self.current_register, length), + Span(start, end), + ); + + Ok(()) + } + fn parse_expression(&mut self) -> Result<(), ParseError> { self.parse(Precedence::None) } @@ -700,7 +739,11 @@ impl From<&TokenKind> for ParseRule<'_> { precedence: Precedence::Unary, }, TokenKind::Colon => todo!(), - TokenKind::Comma => todo!(), + TokenKind::Comma => ParseRule { + prefix: None, + infix: None, + precedence: Precedence::None, + }, TokenKind::Dot => todo!(), TokenKind::DoubleAmpersand => ParseRule { prefix: None, @@ -731,7 +774,11 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, - TokenKind::LeftSquareBrace => todo!(), + TokenKind::LeftSquareBrace => ParseRule { + prefix: Some(Parser::parse_list), + infix: None, + precedence: Precedence::None, + }, TokenKind::Less => todo!(), TokenKind::LessOrEqual => todo!(), TokenKind::Minus => ParseRule { @@ -758,7 +805,11 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, - TokenKind::RightSquareBrace => todo!(), + TokenKind::RightSquareBrace => ParseRule { + prefix: None, + infix: None, + precedence: Precedence::None, + }, TokenKind::Semicolon => ParseRule { prefix: None, infix: None, @@ -791,7 +842,7 @@ pub enum ParseError { position: Span, }, ExpectedTokenMultiple { - expected: Vec, + expected: &'static [TokenKind], found: TokenOwned, position: Span, }, diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 23d8db8..efe678f 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -54,6 +54,22 @@ impl Vm { self.insert(value, to_register, position)?; } + Operation::LoadList => { + let to_register = instruction.destination(); + let length = instruction.first_argument(); + let first_register = to_register - length; + let last_register = to_register - 1; + + let mut list = Vec::with_capacity(length as usize); + + for register_index in first_register..=last_register { + let value = self.clone(register_index, position)?; + + list.push(value); + } + + self.insert(Value::list(list), to_register, position)?; + } Operation::DeclareLocal => { let from_register = instruction.destination(); let to_local = instruction.first_argument();