Fix byte lexing bug; Implement Move operation

This commit is contained in:
Jeff 2024-09-12 21:14:15 -04:00
parent 5c54a5b9bd
commit 82a2b8f6b7
5 changed files with 96 additions and 34 deletions

View File

@ -1,7 +1,4 @@
use std::{ use std::fmt::{self, Debug, Display, Formatter};
fmt::{self, Debug, Display, Formatter},
rc::Weak,
};
use colored::Colorize; use colored::Colorize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -139,7 +139,7 @@ impl Instruction {
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> { pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> {
let info = match self.operation { let info = match self.operation {
Operation::Move => { 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::Close => format!("R({})", self.destination),
Operation::LoadConstant => { Operation::LoadConstant => {

View File

@ -386,11 +386,47 @@ impl<'src> Lexer<'src> {
fn lex_numeric(&mut self) -> Result<(Token<'src>, Span), LexError> { fn lex_numeric(&mut self) -> Result<(Token<'src>, Span), LexError> {
let start_pos = self.position; let start_pos = self.position;
let mut is_float = false; 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(); 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() { while let Some(c) = self.peek_char() {
if c == '.' { if c == '.' {
if let Some('0'..='9') = self.peek_second_char() { 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() { if c.is_ascii_digit() {
self.next_char(); self.next_char();
} else { } else {
@ -535,7 +552,7 @@ impl<'src> Lexer<'src> {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum LexError { pub enum LexError {
ExpectedAsciiHexDigit { ExpectedAsciiHexDigit {
actual: char, actual: Option<char>,
position: usize, position: usize,
}, },
ExpectedCharacter { ExpectedCharacter {
@ -577,6 +594,8 @@ impl AnnotatedError for LexError {
Self::ExpectedAsciiHexDigit { actual, .. } => Some(format!( Self::ExpectedAsciiHexDigit { actual, .. } => Some(format!(
"Expected ASCII hex digit (0-9 or A-F), found \"{}\"", "Expected ASCII hex digit (0-9 or A-F), found \"{}\"",
actual actual
.map(|character| character.to_string())
.unwrap_or("end of input".to_string())
)), )),
Self::ExpectedCharacter { Self::ExpectedCharacter {
expected, actual, .. expected, actual, ..

View File

@ -450,6 +450,33 @@ impl<'src> Parser<'src> {
self.parse_expression()?; self.parse_expression()?;
let local_index = self.chunk.declare_local(identifier, position)?; 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( self.emit_instruction(
Instruction::declare_local(self.current_register - 1, local_index), Instruction::declare_local(self.current_register - 1, local_index),

View File

@ -39,20 +39,27 @@ impl Vm {
log::trace!("Running instruction {instruction} at {position}"); log::trace!("Running instruction {instruction} at {position}");
match instruction.operation { 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::Close => todo!(),
Operation::LoadConstant => { Operation::LoadConstant => {
let constant_index = u16::from_le_bytes(instruction.arguments) as usize; let to_register = instruction.destination as usize;
let value = self.chunk.use_constant(constant_index, position)?; 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 => { Operation::DeclareLocal => {
let register_index = instruction.destination as usize; let from_register = instruction.destination as usize;
let local_index = u16::from_le_bytes(instruction.arguments) as usize; let to_local = u16::from_le_bytes(instruction.arguments) as usize;
let value = self.take(register_index, position)?; 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 => { Operation::GetLocal => {
let register_index = instruction.destination as usize; let register_index = instruction.destination as usize;
@ -148,6 +155,18 @@ impl Vm {
} }
} }
fn clone(&mut self, index: usize, position: Span) -> Result<Value, VmError> {
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<Value, VmError> { fn take(&mut self, index: usize, position: Span) -> Result<Value, VmError> {
if let Some(register) = self.register_stack.get_mut(index) { if let Some(register) = self.register_stack.get_mut(index) {
if let Some(value) = register.take() { if let Some(value) = register.take() {