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

View File

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

View File

@ -54,6 +54,10 @@ impl<'src> Parser<'src> {
} }
fn advance(&mut self) -> Result<(), ParseError> { fn advance(&mut self) -> Result<(), ParseError> {
if self.is_eof() {
return Ok(());
}
let (new_token, position) = self.lexer.next_token()?; let (new_token, position) = self.lexer.next_token()?;
log::trace!("Advancing to token {new_token} at {position}"); 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) { 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> { fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
@ -168,6 +172,8 @@ impl<'src> Parser<'src> {
} }
fn parse_binary(&mut self) -> Result<(), ParseError> { fn parse_binary(&mut self) -> Result<(), ParseError> {
log::trace!("Parsing binary expression");
let operator_position = self.previous_position; let operator_position = self.previous_position;
let operator = self.previous_token.kind(); let operator = self.previous_token.kind();
let rule = ParseRule::from(&operator); let rule = ParseRule::from(&operator);
@ -199,14 +205,11 @@ impl<'src> Parser<'src> {
} }
fn parse_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> { 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( fn parse_named_variable_from(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
&mut self, let token = self.previous_token.to_owned();
token: TokenOwned,
allow_assignment: bool,
) -> Result<(), ParseError> {
let identifier_index = self.parse_identifier_from(token)?; let identifier_index = self.parse_identifier_from(token)?;
if allow_assignment && self.allow(TokenKind::Equal)? { 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> { fn parse_identifier_from(&mut self, token: TokenOwned) -> Result<u8, ParseError> {
if let TokenOwned::Identifier(text) = token { if let TokenOwned::Identifier(text) = token {
self.advance()?;
let identifier = Identifier::new(text); let identifier = Identifier::new(text);
let identifier_index = self.chunk.get_identifier_index(&identifier)?; let identifier_index = self.chunk.get_identifier_index(&identifier)?;
@ -564,30 +565,26 @@ mod tests {
#[test] #[test]
fn add_variables() { fn add_variables() {
let source = " let source = "let x = 42; let y = 42; x + y";
let x = 42;
let y = 42;
x + y
";
let test_chunk = parse(source); let test_chunk = parse(source);
assert_eq!( assert_eq!(
test_chunk, test_chunk,
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![
(Instruction::Constant as u8, Span(21, 23)), (Instruction::DefineVariable as u8, Span(4, 5)),
(0, Span(21, 23)), (0, Span(4, 5)),
(Instruction::DefineVariable as u8, Span(17, 18)), (Instruction::Constant as u8, Span(8, 10)),
(0, Span(17, 18)), (0, Span(8, 10)),
(Instruction::Constant as u8, Span(44, 46)), (Instruction::DefineVariable as u8, Span(16, 17)),
(1, Span(44, 46)), (1, Span(16, 17)),
(Instruction::DefineVariable as u8, Span(40, 41)), (Instruction::Constant as u8, Span(20, 22)),
(1, Span(40, 41)), (1, Span(20, 22)),
(Instruction::GetVariable as u8, Span(61, 62)), (Instruction::GetVariable as u8, Span(24, 25)),
(0, Span(61, 62)), (0, Span(24, 25)),
(Instruction::GetVariable as u8, Span(52, 53)), (Instruction::GetVariable as u8, Span(28, 29)),
(1, Span(52, 53)), (1, Span(28, 29)),
(Instruction::Add as u8, Span(48, 53)) (Instruction::Add as u8, Span(26, 27))
], ],
vec![Value::integer(42), Value::integer(42)], vec![Value::integer(42), Value::integer(42)],
vec![ vec![
@ -599,14 +596,6 @@ mod tests {
identifier: Identifier::new("y"), identifier: Identifier::new("y"),
depth: 0 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> { 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; self.ip += 1;
@ -289,8 +289,8 @@ impl Instruction {
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String { pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
match self { match self {
Instruction::Constant => { Instruction::Constant => {
let (index_display, value_display) = if let Ok((index, _)) = chunk.read(offset + 1) let (index_display, value_display) =
{ if let Ok((index, _)) = chunk.get_code(offset + 1) {
let index_string = index.to_string(); let index_string = index.to_string();
let value_string = chunk let value_string = chunk
.get_constant(*index) .get_constant(*index)
@ -312,7 +312,7 @@ impl Instruction {
// Variables // Variables
Instruction::DefineVariable => { 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) { let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error), Err(error) => format!("{:?}", error),
@ -321,7 +321,7 @@ impl Instruction {
format!("DEFINE_VARIABLE {identifier_display} {index}") format!("DEFINE_VARIABLE {identifier_display} {index}")
} }
Instruction::GetVariable => { 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) { let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error), Err(error) => format!("{:?}", error),
@ -331,7 +331,7 @@ impl Instruction {
} }
Instruction::SetVariable => { 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) { let identifier_display = match chunk.get_identifier(*index) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => format!("{:?}", error), Err(error) => format!("{:?}", error),
@ -376,10 +376,10 @@ pub mod tests {
let mut chunk = Chunk::new(); let mut chunk = Chunk::new();
let constant = chunk.push_constant(Value::integer(42)).unwrap(); let constant = chunk.push_constant(Value::integer(42)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1)); chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.write(constant, Span(2, 3)); chunk.push_code(constant, Span(2, 3));
chunk.write(Instruction::Negate as u8, Span(4, 5)); chunk.push_code(Instruction::Negate as u8, Span(4, 5));
chunk.write(Instruction::Return as u8, Span(2, 3)); chunk.push_code(Instruction::Return as u8, Span(2, 3));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.run(); let result = vm.run();
@ -393,12 +393,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap(); let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap(); let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1)); chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3)); chunk.push_code(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5)); chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7)); chunk.push_code(right, Span(6, 7));
chunk.write(Instruction::Add as u8, Span(8, 9)); chunk.push_code(Instruction::Add as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.run(); let result = vm.run();
@ -412,12 +412,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap(); let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap(); let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1)); chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3)); chunk.push_code(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5)); chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7)); chunk.push_code(right, Span(6, 7));
chunk.write(Instruction::Subtract as u8, Span(8, 9)); chunk.push_code(Instruction::Subtract as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.run(); let result = vm.run();
@ -431,12 +431,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap(); let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap(); let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1)); chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3)); chunk.push_code(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5)); chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7)); chunk.push_code(right, Span(6, 7));
chunk.write(Instruction::Multiply as u8, Span(8, 9)); chunk.push_code(Instruction::Multiply as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.run(); let result = vm.run();
@ -451,12 +451,12 @@ pub mod tests {
let left = chunk.push_constant(Value::integer(42)).unwrap(); let left = chunk.push_constant(Value::integer(42)).unwrap();
let right = chunk.push_constant(Value::integer(23)).unwrap(); let right = chunk.push_constant(Value::integer(23)).unwrap();
chunk.write(Instruction::Constant as u8, Span(0, 1)); chunk.push_code(Instruction::Constant as u8, Span(0, 1));
chunk.write(left, Span(2, 3)); chunk.push_code(left, Span(2, 3));
chunk.write(Instruction::Constant as u8, Span(4, 5)); chunk.push_code(Instruction::Constant as u8, Span(4, 5));
chunk.write(right, Span(6, 7)); chunk.push_code(right, Span(6, 7));
chunk.write(Instruction::Divide as u8, Span(8, 9)); chunk.push_code(Instruction::Divide as u8, Span(8, 9));
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.push_code(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.run(); let result = vm.run();