Pass all tests

This commit is contained in:
Jeff 2024-09-09 22:57:14 -04:00
parent 5b8ec74d05
commit 85f5f44946
4 changed files with 98 additions and 99 deletions

View File

@ -1,7 +1,4 @@
use std::{
fmt::{self, Debug, Display, Formatter},
rc::Weak,
};
use std::fmt::{self, Debug, Display, Formatter};
use serde::{Deserialize, Serialize};
@ -43,17 +40,13 @@ impl Chunk {
self.code.is_empty()
}
pub fn capacity(&self) -> usize {
self.code.capacity()
}
pub fn read(&self, offset: usize) -> Result<&(u8, Span), ChunkError> {
pub fn get_code(&self, offset: usize) -> Result<&(u8, Span), ChunkError> {
self.code
.get(offset)
.ok_or(ChunkError::CodeIndextOfBounds(offset))
}
pub fn write(&mut self, instruction: u8, position: Span) {
pub fn push_code(&mut self, instruction: u8, position: Span) {
self.code.push((instruction, position));
}
@ -123,7 +116,7 @@ impl Chunk {
for (offset, (byte, position)) in self.code.iter().enumerate() {
if let Some(Instruction::Constant) = previous {
let display = format!("{offset:04} CONSTANT_INDEX {byte}");
let display_with_postion = format!("{display:26} {position}\n");
let display_with_postion = format!("{display:27} {position}\n");
previous = None;
output.push_str(&display_with_postion);
@ -136,7 +129,7 @@ impl Chunk {
) = previous
{
let display = format!("{offset:04} IDENTIFIER_INDEX {byte}");
let display_with_postion = format!("{display:26} {position}\n");
let display_with_postion = format!("{display:27} {position}\n");
previous = None;
@ -147,7 +140,7 @@ impl Chunk {
let instruction = Instruction::from_byte(*byte).unwrap();
let display = format!("{offset:04} {}", instruction.disassemble(self, offset));
let display_with_postion = format!("{display:26} {position}\n");
let display_with_postion = format!("{display:27} {position}\n");
previous = Some(instruction);

View File

@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
use crate::Identifier;
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IdentifierStack {
locals: Vec<Local>,
scope_depth: usize,
@ -44,11 +44,20 @@ impl IdentifierStack {
}
pub fn get_index(&self, identifier: &Identifier) -> Option<u8> {
self.locals
.iter()
.rev()
.position(|local| &local.identifier == identifier)
.map(|index| index as u8)
self.locals.iter().enumerate().rev().find_map(
|(
index,
Local {
identifier: local, ..
},
)| {
if local == identifier {
Some(index as u8)
} else {
None
}
},
)
}
pub fn begin_scope(&mut self) {
@ -77,6 +86,14 @@ impl Default for IdentifierStack {
}
}
impl Eq for IdentifierStack {}
impl PartialEq for IdentifierStack {
fn eq(&self, other: &Self) -> bool {
self.locals == other.locals
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct Local {
pub identifier: Identifier,

View File

@ -54,6 +54,10 @@ impl<'src> Parser<'src> {
}
fn advance(&mut self) -> Result<(), ParseError> {
if self.is_eof() {
return Ok(());
}
let (new_token, position) = self.lexer.next_token()?;
log::trace!("Advancing to token {new_token} at {position}");
@ -87,7 +91,7 @@ impl<'src> Parser<'src> {
}
fn emit_byte(&mut self, byte: u8, position: Span) {
self.chunk.write(byte, position);
self.chunk.push_code(byte, position);
}
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
@ -168,6 +172,8 @@ impl<'src> Parser<'src> {
}
fn parse_binary(&mut self) -> Result<(), ParseError> {
log::trace!("Parsing binary expression");
let operator_position = self.previous_position;
let operator = self.previous_token.kind();
let rule = ParseRule::from(&operator);
@ -199,14 +205,11 @@ impl<'src> Parser<'src> {
}
fn parse_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
self.parse_named_variable_from(self.previous_token.to_owned(), allow_assignment)
self.parse_named_variable_from(allow_assignment)
}
fn parse_named_variable_from(
&mut self,
token: TokenOwned,
allow_assignment: bool,
) -> Result<(), ParseError> {
fn parse_named_variable_from(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
let token = self.previous_token.to_owned();
let identifier_index = self.parse_identifier_from(token)?;
if allow_assignment && self.allow(TokenKind::Equal)? {
@ -223,8 +226,6 @@ impl<'src> Parser<'src> {
fn parse_identifier_from(&mut self, token: TokenOwned) -> Result<u8, ParseError> {
if let TokenOwned::Identifier(text) = token {
self.advance()?;
let identifier = Identifier::new(text);
let identifier_index = self.chunk.get_identifier_index(&identifier)?;
@ -564,30 +565,26 @@ mod tests {
#[test]
fn add_variables() {
let source = "
let x = 42;
let y = 42;
x + y
";
let source = "let x = 42; let y = 42; x + y";
let test_chunk = parse(source);
assert_eq!(
test_chunk,
Ok(Chunk::with_data(
vec![
(Instruction::Constant as u8, Span(21, 23)),
(0, Span(21, 23)),
(Instruction::DefineVariable as u8, Span(17, 18)),
(0, Span(17, 18)),
(Instruction::Constant as u8, Span(44, 46)),
(1, Span(44, 46)),
(Instruction::DefineVariable as u8, Span(40, 41)),
(1, Span(40, 41)),
(Instruction::GetVariable as u8, Span(61, 62)),
(0, Span(61, 62)),
(Instruction::GetVariable as u8, Span(52, 53)),
(1, Span(52, 53)),
(Instruction::Add as u8, Span(48, 53))
(Instruction::DefineVariable as u8, Span(4, 5)),
(0, Span(4, 5)),
(Instruction::Constant as u8, Span(8, 10)),
(0, Span(8, 10)),
(Instruction::DefineVariable as u8, Span(16, 17)),
(1, Span(16, 17)),
(Instruction::Constant as u8, Span(20, 22)),
(1, Span(20, 22)),
(Instruction::GetVariable as u8, Span(24, 25)),
(0, Span(24, 25)),
(Instruction::GetVariable as u8, Span(28, 29)),
(1, Span(28, 29)),
(Instruction::Add as u8, Span(26, 27))
],
vec![Value::integer(42), Value::integer(42)],
vec![
@ -599,14 +596,6 @@ mod tests {
identifier: Identifier::new("y"),
depth: 0
},
Local {
identifier: Identifier::new("x"),
depth: 0
},
Local {
identifier: Identifier::new("y"),
depth: 0
},
],
))
);

View File

@ -193,7 +193,7 @@ impl Vm {
}
fn read(&mut self) -> Result<&(u8, Span), VmError> {
let current = self.chunk.read(self.ip)?;
let current = self.chunk.get_code(self.ip)?;
self.ip += 1;
@ -289,21 +289,21 @@ impl Instruction {
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
match self {
Instruction::Constant => {
let (index_display, value_display) = if let Ok((index, _)) = chunk.read(offset + 1)
{
let index_string = index.to_string();
let value_string = chunk
.get_constant(*index)
.map(|value| value.to_string())
.unwrap_or_else(|error| format!("{:?}", error));
let (index_display, value_display) =
if let Ok((index, _)) = chunk.get_code(offset + 1) {
let index_string = index.to_string();
let value_string = chunk
.get_constant(*index)
.map(|value| value.to_string())
.unwrap_or_else(|error| format!("{:?}", error));
(index_string, value_string)
} else {
let index = "ERROR".to_string();
let value = "ERROR".to_string();
(index_string, value_string)
} else {
let index = "ERROR".to_string();
let value = "ERROR".to_string();
(index, value)
};
(index, value)
};
format!("CONSTANT {index_display} {value_display}")
}
@ -312,7 +312,7 @@ impl Instruction {
// Variables
Instruction::DefineVariable => {
let (index, _) = chunk.read(offset + 1).unwrap();
let (index, _) = chunk.get_code(offset + 1).unwrap();
let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error),
@ -321,7 +321,7 @@ impl Instruction {
format!("DEFINE_VARIABLE {identifier_display} {index}")
}
Instruction::GetVariable => {
let (index, _) = chunk.read(offset + 1).unwrap();
let (index, _) = chunk.get_code(offset + 1).unwrap();
let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error),
@ -331,7 +331,7 @@ impl Instruction {
}
Instruction::SetVariable => {
let (index, _) = chunk.read(offset + 1).unwrap();
let (index, _) = chunk.get_code(offset + 1).unwrap();
let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error),
@ -376,10 +376,10 @@ pub mod tests {
let mut chunk = Chunk::new();
let constant = chunk.push_constant(Value::integer(42)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1));
chunk.write(constant, Span(2, 3));
chunk.write(Instruction::Negate as u8, Span(4, 5));
chunk.write(Instruction::Return as u8, Span(2, 3));
chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.push_code(constant, Span(2, 3));
chunk.push_code(Instruction::Negate as u8, Span(4, 5));
chunk.push_code(Instruction::Return as u8, Span(2, 3));
let mut vm = Vm::new(chunk);
let result = vm.run();
@ -393,12 +393,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7));
chunk.write(Instruction::Add as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11));
chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.push_code(left, Span(2, 3));
chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.push_code(right, Span(6, 7));
chunk.push_code(Instruction::Add as u8, Span(8, 9));
chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk);
let result = vm.run();
@ -412,12 +412,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7));
chunk.write(Instruction::Subtract as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11));
chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.push_code(left, Span(2, 3));
chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.push_code(right, Span(6, 7));
chunk.push_code(Instruction::Subtract as u8, Span(8, 9));
chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk);
let result = vm.run();
@ -431,12 +431,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7));
chunk.write(Instruction::Multiply as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11));
chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.push_code(left, Span(2, 3));
chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.push_code(right, Span(6, 7));
chunk.push_code(Instruction::Multiply as u8, Span(8, 9));
chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk);
let result = vm.run();
@ -451,12 +451,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7));
chunk.write(Instruction::Divide as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11));
chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.push_code(left, Span(2, 3));
chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.push_code(right, Span(6, 7));
chunk.push_code(Instruction::Divide as u8, Span(8, 9));
chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk);
let result = vm.run();