Pass all tests
This commit is contained in:
parent
5b8ec74d05
commit
85f5f44946
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
},
|
||||
],
|
||||
))
|
||||
);
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user