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