Fix byte lexing bug; Implement Move operation
This commit is contained in:
parent
5c54a5b9bd
commit
82a2b8f6b7
@ -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};
|
||||||
|
@ -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 => {
|
||||||
|
@ -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, ..
|
||||||
|
@ -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),
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user