From 8f58bf30a4215b14440acc59bace66e4e548469c Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 10 Sep 2024 18:19:59 -0400 Subject: [PATCH] Make everything messy --- Cargo.lock | 104 +++++++++++++++-- dust-lang/src/chunk.rs | 128 +++++++++++++++++---- dust-lang/src/identifier_stack.rs | 48 +++++++- dust-lang/src/instruction.rs | 93 ++++++++------- dust-lang/src/parser.rs | 48 +++----- dust-lang/src/value.rs | 2 +- dust-lang/src/vm.rs | 185 +++++++++++++++--------------- dust-shell/Cargo.toml | 2 + dust-shell/src/main.rs | 22 +++- 9 files changed, 422 insertions(+), 210 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b46f0b..e9ffb36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,7 +56,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -121,6 +121,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -164,8 +174,10 @@ name = "dust-shell" version = "0.1.0" dependencies = [ "clap", + "colored", "dust-lang", "env_logger", + "log", ] [[package]] @@ -226,6 +238,12 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.153" @@ -425,13 +443,37 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -440,51 +482,93 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.4" diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 610785b..5b9287e 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -3,7 +3,8 @@ use std::fmt::{self, Debug, Display, Formatter}; use serde::{Deserialize, Serialize}; use crate::{ - identifier_stack::Local, Identifier, IdentifierStack, Instruction, Span, Value, ValueLocation, + identifier_stack::Local, AnnotatedError, Identifier, IdentifierStack, Instruction, Span, Value, + ValueLocation, }; #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] @@ -42,27 +43,34 @@ impl Chunk { self.code.is_empty() } - pub fn get_code(&self, offset: usize) -> Result<&(u8, Span), ChunkError> { + pub fn scope_depth(&self) -> usize { + self.identifiers.scope_depth() + } + + pub fn get_code(&self, offset: usize, position: Span) -> Result<&(u8, Span), ChunkError> { self.code .get(offset) - .ok_or(ChunkError::CodeIndexOfBounds(offset)) + .ok_or(ChunkError::CodeIndexOfBounds { offset, position }) } pub fn push_code(&mut self, instruction: u8, position: Span) { self.code.push((instruction, position)); } - pub fn get_constant(&self, index: u8) -> Result<&Value, ChunkError> { + pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> { self.constants .get(index as usize) - .ok_or(ChunkError::ConstantIndexOutOfBounds(index)) + .ok_or(ChunkError::ConstantIndexOutOfBounds { index, position }) } - pub fn remove_constant(&mut self, index: u8) -> Result { + pub fn remove_constant(&mut self, index: u8, position: Span) -> Result { let index = index as usize; if index >= self.constants.len() { - Err(ChunkError::ConstantIndexOutOfBounds(index as u8)) + Err(ChunkError::ConstantIndexOutOfBounds { + index: index as u8, + position, + }) } else { Ok(self.constants.remove(index)) } @@ -90,6 +98,14 @@ impl Chunk { .ok_or(ChunkError::IdentifierIndexOutOfBounds(index)) } + pub fn resolve_local(&self, identifier: &Identifier) -> Option { + self.identifiers.resolve(self, identifier) + } + + pub fn resolve_local_index(&self, identifier: &Identifier) -> Option { + self.identifiers.resolve_index(identifier) + } + pub fn get_identifier(&self, index: u8) -> Result<&Identifier, ChunkError> { self.identifiers .get(index as usize) @@ -97,10 +113,18 @@ impl Chunk { .ok_or(ChunkError::IdentifierIndexOutOfBounds(index)) } - pub fn get_identifier_index(&self, identifier: &Identifier) -> Result { + pub fn get_identifier_index( + &self, + identifier: &Identifier, + position: Span, + ) -> Result { self.identifiers .get_index(identifier) - .ok_or(ChunkError::IdentifierNotFound(identifier.clone())) + .map(|index| index as u8) + .ok_or(ChunkError::IdentifierNotFound { + identifier: identifier.clone(), + position, + }) } pub fn push_constant_identifier(&mut self, identifier: Identifier) -> Result { @@ -110,7 +134,7 @@ impl Chunk { Err(ChunkError::IdentifierOverflow) } else { self.identifiers - .declare(identifier, ValueLocation::ConstantStack); + .define(identifier, ValueLocation::ConstantStack); Ok(starting_length as u8) } @@ -123,12 +147,25 @@ impl Chunk { Err(ChunkError::IdentifierOverflow) } else { self.identifiers - .declare(identifier, ValueLocation::RuntimeStack); + .define(identifier, ValueLocation::RuntimeStack); Ok(starting_length as u8) } } + pub fn redefine_as_runtime_identifier( + &mut self, + identifier: &Identifier, + position: Span, + ) -> Result { + self.identifiers + .redefine(identifier, ValueLocation::RuntimeStack) + .ok_or_else(|| ChunkError::IdentifierNotFound { + identifier: identifier.clone(), + position, + }) + } + pub fn begin_scope(&mut self) { self.identifiers.begin_scope(); } @@ -162,7 +199,7 @@ impl Chunk { for (offset, (byte, position)) in self.code.iter().enumerate() { if let Some( Instruction::Constant - | Instruction::DefineVariableConstant + | Instruction::DefineVariable | Instruction::GetVariable | Instruction::SetVariable, ) = previous @@ -179,9 +216,9 @@ impl Chunk { instruction.disassemble(self, offset) ); - previous = Some(instruction); - output.push_str(&display); + + previous = Some(instruction); } output.push_str("\n Constants \n"); @@ -245,29 +282,80 @@ impl Debug for Chunk { #[derive(Debug, Clone, PartialEq)] pub enum ChunkError { - CodeIndexOfBounds(usize), + CodeIndexOfBounds { + offset: usize, + position: Span, + }, ConstantOverflow, - ConstantIndexOutOfBounds(u8), + ConstantIndexOutOfBounds { + index: u8, + position: Span, + }, IdentifierIndexOutOfBounds(u8), IdentifierOverflow, - IdentifierNotFound(Identifier), + IdentifierNotFound { + identifier: Identifier, + position: Span, + }, +} + +impl AnnotatedError for ChunkError { + fn title() -> &'static str { + "Chunk Error" + } + + fn description(&self) -> &'static str { + match self { + ChunkError::CodeIndexOfBounds { .. } => "Code index out of bounds", + ChunkError::ConstantOverflow => "Constant overflow", + ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds", + ChunkError::IdentifierIndexOutOfBounds(_) => "Identifier index out of bounds", + ChunkError::IdentifierOverflow => "Identifier overflow", + ChunkError::IdentifierNotFound { .. } => "Identifier not found", + } + } + + fn details(&self) -> Option { + match self { + ChunkError::CodeIndexOfBounds { offset, .. } => Some(format!("Code index: {}", offset)), + ChunkError::ConstantIndexOutOfBounds { index, .. } => { + Some(format!("Constant index: {}", index)) + } + ChunkError::IdentifierIndexOutOfBounds(index) => { + Some(format!("Identifier index: {}", index)) + } + ChunkError::IdentifierNotFound { identifier, .. } => { + Some(format!("Identifier: {}", identifier)) + } + _ => None, + } + } + + fn position(&self) -> Span { + match self { + ChunkError::CodeIndexOfBounds { position, .. } => *position, + ChunkError::ConstantIndexOutOfBounds { position, .. } => *position, + ChunkError::IdentifierNotFound { position, .. } => *position, + _ => todo!(), + } + } } impl Display for ChunkError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - ChunkError::CodeIndexOfBounds(offset) => { + ChunkError::CodeIndexOfBounds { offset, .. } => { write!(f, "Code index out of bounds: {}", offset) } ChunkError::ConstantOverflow => write!(f, "Constant overflow"), - ChunkError::ConstantIndexOutOfBounds(index) => { + ChunkError::ConstantIndexOutOfBounds { index, .. } => { write!(f, "Constant index out of bounds: {}", index) } ChunkError::IdentifierIndexOutOfBounds(index) => { write!(f, "Identifier index out of bounds: {}", index) } ChunkError::IdentifierOverflow => write!(f, "Identifier overflow"), - ChunkError::IdentifierNotFound(identifier) => { + ChunkError::IdentifierNotFound { identifier, .. } => { write!(f, "Identifier not found: {}", identifier) } } diff --git a/dust-lang/src/identifier_stack.rs b/dust-lang/src/identifier_stack.rs index 4dc3d39..ab4ba12 100644 --- a/dust-lang/src/identifier_stack.rs +++ b/dust-lang/src/identifier_stack.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use serde::{Deserialize, Serialize}; -use crate::Identifier; +use crate::{Chunk, Identifier}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct IdentifierStack { @@ -41,11 +41,33 @@ impl IdentifierStack { .any(|local| &local.identifier == identifier) } + pub fn resolve(&self, chunk: &Chunk, identifier: &Identifier) -> Option { + for (index, local) in self.locals.iter().rev().enumerate() { + if &local.identifier == identifier { + let offset = index; + + return Some(offset as u8); + } + } + + None + } + + pub fn resolve_index(&self, identifier: &Identifier) -> Option { + self.locals.iter().enumerate().find_map(|(index, local)| { + if &local.identifier == identifier && local.depth <= self.scope_depth { + Some(index as u8) + } else { + None + } + }) + } + pub fn get(&self, index: usize) -> Option<&Local> { self.locals.get(index) } - pub fn get_index(&self, identifier: &Identifier) -> Option { + pub fn get_index(&self, identifier: &Identifier) -> Option { self.locals.iter().enumerate().rev().find_map( |( index, @@ -54,7 +76,7 @@ impl IdentifierStack { }, )| { if local == identifier { - Some(index as u8) + Some(index) } else { None } @@ -62,6 +84,10 @@ impl IdentifierStack { ) } + pub fn scope_depth(&self) -> usize { + self.scope_depth + } + pub fn begin_scope(&mut self) { self.scope_depth += 1; } @@ -70,7 +96,7 @@ impl IdentifierStack { self.scope_depth -= 1; } - pub fn declare(&mut self, identifier: Identifier, value_location: ValueLocation) { + pub fn define(&mut self, identifier: Identifier, value_location: ValueLocation) { self.locals.push(Local { identifier, depth: self.scope_depth, @@ -78,6 +104,20 @@ impl IdentifierStack { }); } + pub fn redefine( + &mut self, + identifier: &Identifier, + value_location: ValueLocation, + ) -> Option { + if let Some(index) = self.get_index(identifier) { + self.locals[index].value_location = value_location; + + Some(index) + } else { + None + } + } + pub fn iter(&self) -> impl Iterator { self.locals.iter() } diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index e2c63c5..6f1293a 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::Chunk; +use crate::{Chunk, Span}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] pub enum Instruction { @@ -11,28 +11,27 @@ pub enum Instruction { Pop = 2, // Variables - DefineVariableRuntime = 3, - DefineVariableConstant = 4, - GetVariable = 5, - SetVariable = 6, + DefineVariable = 3, + GetVariable = 4, + SetVariable = 5, // Unary - Negate = 7, - Not = 8, + Negate = 6, + Not = 7, // Binary - Add = 9, - Subtract = 10, - Multiply = 11, - Divide = 12, - Greater = 13, - Less = 14, - GreaterEqual = 15, - LessEqual = 16, - Equal = 17, - NotEqual = 18, - And = 19, - Or = 20, + Add = 8, + Subtract = 9, + Multiply = 10, + Divide = 11, + Greater = 12, + Less = 13, + GreaterEqual = 14, + LessEqual = 15, + Equal = 16, + NotEqual = 17, + And = 18, + Or = 19, } impl Instruction { @@ -41,65 +40,65 @@ impl Instruction { 0 => Some(Instruction::Constant), 1 => Some(Instruction::Return), 2 => Some(Instruction::Pop), - 3 => Some(Instruction::DefineVariableRuntime), - 4 => Some(Instruction::DefineVariableConstant), - 5 => Some(Instruction::GetVariable), - 6 => Some(Instruction::SetVariable), - 7 => Some(Instruction::Negate), - 8 => Some(Instruction::Not), - 9 => Some(Instruction::Add), - 10 => Some(Instruction::Subtract), - 11 => Some(Instruction::Multiply), - 12 => Some(Instruction::Divide), - 13 => Some(Instruction::Greater), - 14 => Some(Instruction::Less), - 15 => Some(Instruction::GreaterEqual), - 16 => Some(Instruction::LessEqual), - 17 => Some(Instruction::Equal), - 18 => Some(Instruction::NotEqual), - 19 => Some(Instruction::And), - 20 => Some(Instruction::Or), + 3 => Some(Instruction::DefineVariable), + 4 => Some(Instruction::GetVariable), + 5 => Some(Instruction::SetVariable), + 6 => Some(Instruction::Negate), + 7 => Some(Instruction::Not), + 8 => Some(Instruction::Add), + 9 => Some(Instruction::Subtract), + 10 => Some(Instruction::Multiply), + 11 => Some(Instruction::Divide), + 12 => Some(Instruction::Greater), + 13 => Some(Instruction::Less), + 14 => Some(Instruction::GreaterEqual), + 15 => Some(Instruction::LessEqual), + 16 => Some(Instruction::Equal), + 17 => Some(Instruction::NotEqual), + 18 => Some(Instruction::And), + 19 => Some(Instruction::Or), _ => None, } } pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String { + let dummy_position = Span(0, 0); + match self { Instruction::Constant => { - let (argument, _) = chunk.get_code(offset + 1).unwrap(); + let (argument, position) = *chunk.get_code(offset + 1, dummy_position).unwrap(); let value_display = chunk - .get_constant(*argument) + .get_constant(argument, position) .map(|value| value.to_string()) .unwrap_or_else(|error| error.to_string()); - format!("CONSTANT {argument} {value_display}") + format!("CONSTANT {value_display}") } Instruction::Return => "RETURN".to_string(), Instruction::Pop => "POP".to_string(), // Variables - Instruction::DefineVariableRuntime => "DEFINE_VARIABLE_RUNTIME".to_string(), - Instruction::DefineVariableConstant => { - let (argument, _) = chunk.get_code(offset + 1).unwrap(); + Instruction::DefineVariable => { + let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); let identifier_display = match chunk.get_identifier(*argument) { Ok(identifier) => identifier.to_string(), Err(error) => error.to_string(), }; - format!("DEFINE_VARIABLE_CONSTANT {argument} {identifier_display}") + format!("DEFINE_VARIABLE {identifier_display}") } Instruction::GetVariable => { - let (argument, _) = chunk.get_code(offset + 1).unwrap(); + let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); let identifier_display = match chunk.get_identifier(*argument) { Ok(identifier) => identifier.to_string(), Err(error) => error.to_string(), }; - format!("GET_VARIABLE {argument} {identifier_display}") + format!("GET_VARIABLE {identifier_display}") } Instruction::SetVariable => { - let (argument, _) = chunk.get_code(offset + 1).unwrap(); + let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); let identifier_display = match chunk.get_identifier(*argument) { Ok(identifier) => identifier.to_string(), Err(error) => error.to_string(), diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 33fd825..e302eb2 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, - Lexer, Span, Token, TokenKind, TokenOwned, Value, + Lexer, Local, Span, Token, TokenKind, TokenOwned, Value, ValueLocation, }; pub fn parse(source: &str) -> Result { @@ -234,10 +234,10 @@ impl<'src> Parser<'src> { } fn parse_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> { - self.parse_named_variable_from(allow_assignment) + self.parse_named_variable(allow_assignment) } - fn parse_named_variable_from(&mut self, allow_assignment: bool) -> Result<(), ParseError> { + fn parse_named_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> { let token = self.previous_token.to_owned(); let identifier_index = self.parse_identifier_from(token)?; @@ -256,9 +256,10 @@ impl<'src> Parser<'src> { fn parse_identifier_from(&mut self, token: TokenOwned) -> Result { if let TokenOwned::Identifier(text) = token { let identifier = Identifier::new(text); + let identifier_index = self.chunk - .get_identifier_index(&identifier) + .push_constant_identifier(identifier) .map_err(|error| ParseError::Chunk { error, position: self.previous_position, @@ -337,34 +338,15 @@ impl<'src> Parser<'src> { }; self.expect(TokenKind::Equal)?; + self.parse_expression()?; - let is_constant = matches!( - self.current_token, - Token::Boolean(_) - | Token::Byte(_) - | Token::Character(_) - | Token::Float(_) - | Token::Integer(_) - | Token::String(_) - ); + let identifier_index = self + .chunk + .push_constant_identifier(identifier) + .map_err(|error| ParseError::Chunk { error, position })?; - let identifier_index = if is_constant { - self.chunk.push_constant_identifier(identifier) - } else { - self.chunk.push_runtime_identifier(identifier) - } - .map_err(|error| ParseError::Chunk { error, position })?; - - if is_constant { - self.emit_byte(Instruction::DefineVariableConstant, position); - self.emit_byte(identifier_index, position); - - self.parse_expression()?; - } else { - self.parse_expression()?; - - self.emit_byte(Instruction::DefineVariableRuntime, position); - } + self.emit_byte(Instruction::DefineVariable, position); + self.emit_byte(identifier_index, position); Ok(()) } @@ -729,11 +711,11 @@ mod tests { test_chunk, Ok(Chunk::with_data( vec![ - (Instruction::DefineVariableConstant as u8, Span(4, 5)), + (Instruction::DefineVariable as u8, Span(4, 5)), (0, Span(4, 5)), (Instruction::Constant as u8, Span(8, 10)), (0, Span(8, 10)), - (Instruction::DefineVariableConstant as u8, Span(16, 17)), + (Instruction::DefineVariable as u8, Span(16, 17)), (1, Span(16, 17)), (Instruction::Constant as u8, Span(20, 22)), (1, Span(20, 22)), @@ -770,7 +752,7 @@ mod tests { test_chunk, Ok(Chunk::with_data( vec![ - (Instruction::DefineVariableConstant as u8, Span(4, 5)), + (Instruction::DefineVariable as u8, Span(4, 5)), (0, Span(4, 5)), (Instruction::Constant as u8, Span(8, 10)), (0, Span(8, 10)), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index a5b88a6..3817c48 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -796,7 +796,7 @@ impl From<&str> for Value { impl Clone for Value { fn clone(&self) -> Self { - log::trace!("Cloning value: {:?}", self); + log::trace!("Cloning value {:?}", self); match self { Value::Raw(data) => Value::Raw(data.clone()), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b5e9702..28f3c88 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -45,9 +45,12 @@ impl Vm { match instruction { Instruction::Constant => { - let (argument, _) = self.read(position).copied()?; + let (argument, _) = *self.read(position)?; + let value = self.chunk.get_constant(argument, position)?.clone(); - self.push_constant_value(argument, position)?; + log::trace!("Pushing constant {value}"); + + self.push_runtime_value(value, position)?; } Instruction::Return => { let stacked = self.pop(position)?; @@ -55,73 +58,76 @@ impl Vm { StackedValue::Runtime(value) => value, StackedValue::Constant(index) => Rc::get_mut(&mut self.chunk) .unwrap() - .remove_constant(index) - .map_err(|error| VmError::Chunk { error, position })?, + .remove_constant(index, position)?, }; + log::trace!("Returning {value}"); + return Ok(Some(value)); } Instruction::Pop => { - self.pop(position)?; + let value = self.pop(position)?; + + log::trace!("Popping {value:?}"); } // Variables - Instruction::DefineVariableRuntime => { - let value = self.pop(position)?.resolve(&self.chunk, position)?.clone(); - - self.push_runtime_value(value, position)?; - } - Instruction::DefineVariableConstant => { + Instruction::DefineVariable => { let (argument, _) = *self.read(position)?; + let identifier = self.chunk.get_identifier(argument)?.clone(); + let stack_index_option = self.chunk.resolve_local(&identifier); - self.push_constant_value(argument, position)?; + if let Some(index) = stack_index_option { + let value = self.stack[index as usize] + .to_value(&self.chunk, position)? + .clone(); + + log::trace!("Defining {identifier} as value {value}"); + + self.push_runtime_value(value, position)?; + } else { + return Err(VmError::UndefinedVariable { + identifier, + position, + }); + } } Instruction::GetVariable => { let (argument, _) = *self.read(position)?; + let value = self.pop(position)?.to_value(&self.chunk, position)?.clone(); - let local = self - .chunk - .get_local(argument) - .map_err(|error| VmError::Chunk { error, position })?; + log::trace!( + "Getting {} as value {value}", + self.chunk.get_identifier(argument)?, + ); - match local.value_location { - ValueLocation::ConstantStack => { - let value = self - .chunk - .get_constant(argument) - .map_err(|error| VmError::Chunk { error, position })? - .clone(); - - self.push_runtime_value(value, position)?; - } - ValueLocation::RuntimeStack => { - let value = self.pop(position)?.resolve(&self.chunk, position)?.clone(); - - self.push_runtime_value(value, position)?; - } - } + self.push_runtime_value(value, position)?; } Instruction::SetVariable => { let (argument, _) = *self.read(position)?; - let identifier = self - .chunk - .get_identifier(argument) - .map_err(|error| VmError::Chunk { error, position })?; + let identifier = self.chunk.get_identifier(argument)?.clone(); - if !self.chunk.contains_identifier(identifier) { - return Err(VmError::UndefinedVariable(identifier.clone(), position)); + if !self.chunk.contains_identifier(&identifier) { + return Err(VmError::UndefinedVariable { + identifier, + position, + }); } - let stacked = self.pop(position)?; + let value = self.stack[argument as usize] + .to_value(&self.chunk, position)? + .clone(); - self.stack[argument as usize] = stacked; + log::trace!("Setting {identifier} to {value}"); + + self.push_runtime_value(value, position)?; } // Unary Instruction::Negate => { let negated = self .pop(position)? - .resolve(&self.chunk, position)? + .to_value(&self.chunk, position)? .negate() .map_err(|error| VmError::Value { error, position })?; @@ -130,7 +136,7 @@ impl Vm { Instruction::Not => { let not = self .pop(position)? - .resolve(&self.chunk, position)? + .to_value(&self.chunk, position)? .not() .map_err(|error| VmError::Value { error, position })?; @@ -141,9 +147,9 @@ impl Vm { Instruction::Add => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let sum = left .add(right) .map_err(|error| VmError::Value { error, position })?; @@ -153,9 +159,9 @@ impl Vm { Instruction::Subtract => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let difference = left .subtract(right) .map_err(|error| VmError::Value { error, position })?; @@ -165,9 +171,9 @@ impl Vm { Instruction::Multiply => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let product = left .multiply(right) .map_err(|error| VmError::Value { error, position })?; @@ -177,9 +183,9 @@ impl Vm { Instruction::Divide => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let quotient = left .divide(right) .map_err(|error| VmError::Value { error, position })?; @@ -189,9 +195,9 @@ impl Vm { Instruction::Greater => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let greater = left .greater_than(right) .map_err(|error| VmError::Value { error, position })?; @@ -201,9 +207,9 @@ impl Vm { Instruction::Less => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let less = left .less_than(right) .map_err(|error| VmError::Value { error, position })?; @@ -213,9 +219,9 @@ impl Vm { Instruction::GreaterEqual => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let greater_equal = left .greater_than_or_equal(right) .map_err(|error| VmError::Value { error, position })?; @@ -225,9 +231,9 @@ impl Vm { Instruction::LessEqual => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let less_equal = left .less_than_or_equal(right) .map_err(|error| VmError::Value { error, position })?; @@ -237,9 +243,9 @@ impl Vm { Instruction::Equal => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let equal = left .equal(right) .map_err(|error| VmError::Value { error, position })?; @@ -249,9 +255,9 @@ impl Vm { Instruction::NotEqual => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let not_equal = left .not_equal(right) .map_err(|error| VmError::Value { error, position })?; @@ -261,9 +267,9 @@ impl Vm { Instruction::And => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let and = left .and(right) .map_err(|error| VmError::Value { error, position })?; @@ -273,9 +279,9 @@ impl Vm { Instruction::Or => { let chunk = self.chunk.clone(); let right_stacked = self.pop(position)?; - let right = right_stacked.resolve(chunk.as_ref(), position)?; + let right = right_stacked.to_value(chunk.as_ref(), position)?; let left_stacked = self.pop(position)?; - let left = left_stacked.resolve(&self.chunk, position)?; + let left = left_stacked.to_value(&self.chunk, position)?; let or = left .or(right) .map_err(|error| VmError::Value { error, position })?; @@ -323,10 +329,7 @@ impl Vm { } fn read(&mut self, position: Span) -> Result<&(u8, Span), VmError> { - let current = self - .chunk - .get_code(self.ip) - .map_err(|error| VmError::Chunk { error, position })?; + let current = self.chunk.get_code(self.ip, position)?; self.ip += 1; @@ -341,12 +344,10 @@ pub enum StackedValue { } impl StackedValue { - fn resolve<'a>(&'a self, chunk: &'a Chunk, position: Span) -> Result<&'a Value, VmError> { + fn to_value<'a>(&'a self, chunk: &'a Chunk, position: Span) -> Result<&'a Value, VmError> { match self { Self::Runtime(value) => Ok(value), - Self::Constant(index) => chunk - .get_constant(*index) - .map_err(|error| VmError::Chunk { error, position }), + Self::Constant(index) => Ok(chunk.get_constant(*index, position)?), } } } @@ -356,20 +357,22 @@ pub enum VmError { InvalidInstruction(u8, Span), StackOverflow(Span), StackUnderflow(Span), - UndefinedVariable(Identifier, Span), + UndefinedVariable { + identifier: Identifier, + position: Span, + }, // Wrappers for foreign errors - Chunk { error: ChunkError, position: Span }, - Value { error: ValueError, position: Span }, + Chunk(ChunkError), + Value { + error: ValueError, + position: Span, + }, } -impl VmError { - pub fn chunk(error: ChunkError, position: Span) -> Self { - Self::Chunk { error, position } - } - - pub fn value(error: ValueError, position: Span) -> Self { - Self::Value { error, position } +impl From for VmError { + fn from(v: ChunkError) -> Self { + Self::Chunk(v) } } @@ -383,8 +386,8 @@ impl AnnotatedError for VmError { Self::InvalidInstruction(_, _) => "Invalid instruction", Self::StackOverflow(_) => "Stack overflow", Self::StackUnderflow(_) => "Stack underflow", - Self::UndefinedVariable(_, _) => "Undefined variable", - Self::Chunk { .. } => "Chunk error", + Self::UndefinedVariable { .. } => "Undefined variable", + Self::Chunk(_) => "Chunk error", Self::Value { .. } => "Value error", } } @@ -396,11 +399,11 @@ impl AnnotatedError for VmError { )), Self::StackOverflow(position) => Some(format!("Stack overflow at {position}")), Self::StackUnderflow(position) => Some(format!("Stack underflow at {position}")), - Self::UndefinedVariable(identifier, position) => { - Some(format!("{identifier} is not in scope at {position}")) + Self::UndefinedVariable { identifier, .. } => { + Some(format!("{identifier} is not in scope")) } - Self::Chunk { error, .. } => Some(error.to_string()), + Self::Chunk(error) => Some(error.to_string()), Self::Value { error, .. } => Some(error.to_string()), } } @@ -410,8 +413,8 @@ impl AnnotatedError for VmError { Self::InvalidInstruction(_, position) => *position, Self::StackUnderflow(position) => *position, Self::StackOverflow(position) => *position, - Self::UndefinedVariable(_, position) => *position, - Self::Chunk { position, .. } => *position, + Self::UndefinedVariable { position, .. } => *position, + Self::Chunk(error) => error.position(), Self::Value { position, .. } => *position, } } diff --git a/dust-shell/Cargo.toml b/dust-shell/Cargo.toml index cbf4d8d..f1b5cd0 100644 --- a/dust-shell/Cargo.toml +++ b/dust-shell/Cargo.toml @@ -9,5 +9,7 @@ repository.workspace = true [dependencies] clap = { version = "4.5.14", features = ["derive"] } +colored = "2.1.0" dust-lang = { path = "../dust-lang" } env_logger = "0.11.5" +log = "0.4.22" diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 889c2f5..3cbf3cd 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -1,8 +1,9 @@ -use std::fs::read_to_string; +use std::{fs::read_to_string, io::Write}; use clap::Parser; +use colored::Colorize; use dust_lang::{parse, run}; -use env_logger::WriteStyle; +use log::Level; #[derive(Parser)] struct Cli { @@ -18,8 +19,21 @@ struct Cli { fn main() { env_logger::builder() .parse_env("DUST_LOG") - .format_timestamp_secs() - .write_style(WriteStyle::Always) + .format(|buf, record| { + let level = match record.level() { + Level::Error => "ERROR".red(), + Level::Warn => "WARN".yellow(), + Level::Info => "INFO".white(), + Level::Debug => "DEBUG".blue(), + Level::Trace => "TRACE".purple(), + }; + let module = record + .module_path() + .map(|path| path.split("::").last().unwrap_or("UNKNOWN").to_uppercase()) + .unwrap_or("UNKNOWN".to_string()); + + writeln!(buf, "[{level:^5}] {module:^6} {}", record.args()) + }) .init(); let args = Cli::parse();