diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index f41e2d3..294d3f2 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -1,7 +1,4 @@ -use std::{ - fmt::{self, Debug, Display, Formatter}, - rc::Weak, -}; +use std::fmt::{self, Debug, Display, Formatter}; use colored::Colorize; use serde::{Deserialize, Serialize}; diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index 5ab30da..cf96451 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -139,7 +139,7 @@ impl Instruction { pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option { let info = match self.operation { Operation::Move => { - format!("R({}) R({})", self.destination, self.arguments[0]) + format!("R({}) = R({})", self.destination, self.arguments[0]) } Operation::Close => format!("R({})", self.destination), Operation::LoadConstant => { diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 67721b0..ba1f1c6 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -386,11 +386,47 @@ impl<'src> Lexer<'src> { fn lex_numeric(&mut self) -> Result<(Token<'src>, Span), LexError> { let start_pos = self.position; let mut is_float = false; + let peek_char = self.peek_char(); - if let Some('-') = self.peek_char() { + if let Some('-') = peek_char { self.next_char(); } + if let Some('0') = peek_char { + self.next_char(); + + if let Some('x') = self.peek_char() { + self.next_char(); + + let mut peek_chars = self.peek_chars(2).chars(); + + match (peek_chars.next(), peek_chars.next()) { + (Some('0'..='9' | 'A'..='f'), Some('0'..='9' | 'A'..='f')) => { + self.next_char(); + self.next_char(); + + let text = &self.source[start_pos..self.position]; + + return Ok((Token::Byte(text), Span(start_pos, self.position))); + } + (Some('0'..='9' | 'A'..='f'), erroneous) => { + self.next_char(); + + return Err(LexError::ExpectedAsciiHexDigit { + actual: erroneous, + position: self.position, + }); + } + (erroneous, _) => { + return Err(LexError::ExpectedAsciiHexDigit { + actual: erroneous, + position: self.position, + }); + } + } + } + } + while let Some(c) = self.peek_char() { if c == '.' { if let Some('0'..='9') = self.peek_second_char() { @@ -440,25 +476,6 @@ impl<'src> Lexer<'src> { } } - if c == 'x' { - self.next_char(); - - while let Some(c) = self.peek_char() { - if c.is_ascii_hexdigit() { - self.next_char(); - } else { - return Err(LexError::ExpectedAsciiHexDigit { - actual: c, - position: self.position, - }); - } - } - - let text = &self.source[start_pos..self.position]; - - return Ok((Token::Byte(text), Span(start_pos, self.position))); - } - if c.is_ascii_digit() { self.next_char(); } else { @@ -535,7 +552,7 @@ impl<'src> Lexer<'src> { #[derive(Debug, PartialEq, Clone)] pub enum LexError { ExpectedAsciiHexDigit { - actual: char, + actual: Option, position: usize, }, ExpectedCharacter { @@ -577,6 +594,8 @@ impl AnnotatedError for LexError { Self::ExpectedAsciiHexDigit { actual, .. } => Some(format!( "Expected ASCII hex digit (0-9 or A-F), found \"{}\"", actual + .map(|character| character.to_string()) + .unwrap_or("end of input".to_string()) )), Self::ExpectedCharacter { expected, actual, .. diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index ea76032..605143b 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -450,6 +450,33 @@ impl<'src> Parser<'src> { self.parse_expression()?; let local_index = self.chunk.declare_local(identifier, position)?; + let previous_instruction = self.chunk.pop_instruction(); + + if let Some(( + Instruction { + operation: Operation::GetLocal, + destination, + arguments, + }, + _, + )) = previous_instruction + { + self.emit_instruction( + Instruction { + operation: Operation::Move, + destination, + arguments, + }, + position, + ); + } else if let Some((instruction, position)) = previous_instruction { + self.chunk.push_instruction(instruction, position); + } else { + return Err(ParseError::ExpectedExpression { + found: self.previous_token.to_owned(), + position: self.previous_position, + }); + } self.emit_instruction( Instruction::declare_local(self.current_register - 1, local_index), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index f154ac4..811b356 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -39,20 +39,27 @@ impl Vm { log::trace!("Running instruction {instruction} at {position}"); match instruction.operation { - Operation::Move => todo!(), + Operation::Move => { + let from = instruction.arguments[0] as usize; + let to = instruction.destination as usize; + let value = self.clone(from, position)?; + + self.insert(value, to, position)?; + } Operation::Close => todo!(), Operation::LoadConstant => { - let constant_index = u16::from_le_bytes(instruction.arguments) as usize; - let value = self.chunk.use_constant(constant_index, position)?; + let to_register = instruction.destination as usize; + let from_constant = u16::from_le_bytes(instruction.arguments) as usize; + let value = self.chunk.use_constant(from_constant, position)?; - self.insert(value, instruction.destination as usize, position)?; + self.insert(value, to_register, position)?; } Operation::DeclareLocal => { - let register_index = instruction.destination as usize; - let local_index = u16::from_le_bytes(instruction.arguments) as usize; - let value = self.take(register_index, position)?; + let from_register = instruction.destination as usize; + let to_local = u16::from_le_bytes(instruction.arguments) as usize; + let value = self.clone(from_register, position)?; - self.chunk.define_local(local_index, value, position)?; + self.chunk.define_local(to_local, value, position)?; } Operation::GetLocal => { let register_index = instruction.destination as usize; @@ -148,6 +155,18 @@ impl Vm { } } + fn clone(&mut self, index: usize, position: Span) -> Result { + if let Some(register) = self.register_stack.get_mut(index) { + if let Some(value) = register.take() { + Ok(register.insert(value.into_reference()).clone()) + } else { + Err(VmError::EmptyRegister { index, position }) + } + } else { + Err(VmError::RegisterIndexOutOfBounds { position }) + } + } + fn take(&mut self, index: usize, position: Span) -> Result { if let Some(register) = self.register_stack.get_mut(index) { if let Some(value) = register.take() {