Make everything messy

This commit is contained in:
Jeff 2024-09-10 18:19:59 -04:00
parent c3790e90bf
commit 8f58bf30a4
9 changed files with 422 additions and 210 deletions

104
Cargo.lock generated
View File

@ -56,7 +56,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -121,6 +121,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 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]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.5" version = "0.8.5"
@ -164,8 +174,10 @@ name = "dust-shell"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"colored",
"dust-lang", "dust-lang",
"env_logger", "env_logger",
"log",
] ]
[[package]] [[package]]
@ -226,6 +238,12 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ 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]] [[package]]
@ -440,51 +482,93 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.52.4",
"windows_i686_gnu", "windows_i686_gnu 0.52.4",
"windows_i686_msvc", "windows_i686_msvc 0.52.4",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc", "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]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 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]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 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]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 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]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.4" version = "0.52.4"

View File

@ -3,7 +3,8 @@ use std::fmt::{self, Debug, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ 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)] #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
@ -42,27 +43,34 @@ impl Chunk {
self.code.is_empty() 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 self.code
.get(offset) .get(offset)
.ok_or(ChunkError::CodeIndexOfBounds(offset)) .ok_or(ChunkError::CodeIndexOfBounds { offset, position })
} }
pub fn push_code(&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));
} }
pub fn get_constant(&self, index: u8) -> Result<&Value, ChunkError> { pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> {
self.constants self.constants
.get(index as usize) .get(index as usize)
.ok_or(ChunkError::ConstantIndexOutOfBounds(index)) .ok_or(ChunkError::ConstantIndexOutOfBounds { index, position })
} }
pub fn remove_constant(&mut self, index: u8) -> Result<Value, ChunkError> { pub fn remove_constant(&mut self, index: u8, position: Span) -> Result<Value, ChunkError> {
let index = index as usize; let index = index as usize;
if index >= self.constants.len() { if index >= self.constants.len() {
Err(ChunkError::ConstantIndexOutOfBounds(index as u8)) Err(ChunkError::ConstantIndexOutOfBounds {
index: index as u8,
position,
})
} else { } else {
Ok(self.constants.remove(index)) Ok(self.constants.remove(index))
} }
@ -90,6 +98,14 @@ impl Chunk {
.ok_or(ChunkError::IdentifierIndexOutOfBounds(index)) .ok_or(ChunkError::IdentifierIndexOutOfBounds(index))
} }
pub fn resolve_local(&self, identifier: &Identifier) -> Option<u8> {
self.identifiers.resolve(self, identifier)
}
pub fn resolve_local_index(&self, identifier: &Identifier) -> Option<u8> {
self.identifiers.resolve_index(identifier)
}
pub fn get_identifier(&self, index: u8) -> Result<&Identifier, ChunkError> { pub fn get_identifier(&self, index: u8) -> Result<&Identifier, ChunkError> {
self.identifiers self.identifiers
.get(index as usize) .get(index as usize)
@ -97,10 +113,18 @@ impl Chunk {
.ok_or(ChunkError::IdentifierIndexOutOfBounds(index)) .ok_or(ChunkError::IdentifierIndexOutOfBounds(index))
} }
pub fn get_identifier_index(&self, identifier: &Identifier) -> Result<u8, ChunkError> { pub fn get_identifier_index(
&self,
identifier: &Identifier,
position: Span,
) -> Result<u8, ChunkError> {
self.identifiers self.identifiers
.get_index(identifier) .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<u8, ChunkError> { pub fn push_constant_identifier(&mut self, identifier: Identifier) -> Result<u8, ChunkError> {
@ -110,7 +134,7 @@ impl Chunk {
Err(ChunkError::IdentifierOverflow) Err(ChunkError::IdentifierOverflow)
} else { } else {
self.identifiers self.identifiers
.declare(identifier, ValueLocation::ConstantStack); .define(identifier, ValueLocation::ConstantStack);
Ok(starting_length as u8) Ok(starting_length as u8)
} }
@ -123,12 +147,25 @@ impl Chunk {
Err(ChunkError::IdentifierOverflow) Err(ChunkError::IdentifierOverflow)
} else { } else {
self.identifiers self.identifiers
.declare(identifier, ValueLocation::RuntimeStack); .define(identifier, ValueLocation::RuntimeStack);
Ok(starting_length as u8) Ok(starting_length as u8)
} }
} }
pub fn redefine_as_runtime_identifier(
&mut self,
identifier: &Identifier,
position: Span,
) -> Result<usize, ChunkError> {
self.identifiers
.redefine(identifier, ValueLocation::RuntimeStack)
.ok_or_else(|| ChunkError::IdentifierNotFound {
identifier: identifier.clone(),
position,
})
}
pub fn begin_scope(&mut self) { pub fn begin_scope(&mut self) {
self.identifiers.begin_scope(); self.identifiers.begin_scope();
} }
@ -162,7 +199,7 @@ impl Chunk {
for (offset, (byte, position)) in self.code.iter().enumerate() { for (offset, (byte, position)) in self.code.iter().enumerate() {
if let Some( if let Some(
Instruction::Constant Instruction::Constant
| Instruction::DefineVariableConstant | Instruction::DefineVariable
| Instruction::GetVariable | Instruction::GetVariable
| Instruction::SetVariable, | Instruction::SetVariable,
) = previous ) = previous
@ -179,9 +216,9 @@ impl Chunk {
instruction.disassemble(self, offset) instruction.disassemble(self, offset)
); );
previous = Some(instruction);
output.push_str(&display); output.push_str(&display);
previous = Some(instruction);
} }
output.push_str("\n Constants \n"); output.push_str("\n Constants \n");
@ -245,29 +282,80 @@ impl Debug for Chunk {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ChunkError { pub enum ChunkError {
CodeIndexOfBounds(usize), CodeIndexOfBounds {
offset: usize,
position: Span,
},
ConstantOverflow, ConstantOverflow,
ConstantIndexOutOfBounds(u8), ConstantIndexOutOfBounds {
index: u8,
position: Span,
},
IdentifierIndexOutOfBounds(u8), IdentifierIndexOutOfBounds(u8),
IdentifierOverflow, 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<String> {
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 { impl Display for ChunkError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
ChunkError::CodeIndexOfBounds(offset) => { ChunkError::CodeIndexOfBounds { offset, .. } => {
write!(f, "Code index out of bounds: {}", offset) write!(f, "Code index out of bounds: {}", offset)
} }
ChunkError::ConstantOverflow => write!(f, "Constant overflow"), ChunkError::ConstantOverflow => write!(f, "Constant overflow"),
ChunkError::ConstantIndexOutOfBounds(index) => { ChunkError::ConstantIndexOutOfBounds { index, .. } => {
write!(f, "Constant index out of bounds: {}", index) write!(f, "Constant index out of bounds: {}", index)
} }
ChunkError::IdentifierIndexOutOfBounds(index) => { ChunkError::IdentifierIndexOutOfBounds(index) => {
write!(f, "Identifier index out of bounds: {}", index) write!(f, "Identifier index out of bounds: {}", index)
} }
ChunkError::IdentifierOverflow => write!(f, "Identifier overflow"), ChunkError::IdentifierOverflow => write!(f, "Identifier overflow"),
ChunkError::IdentifierNotFound(identifier) => { ChunkError::IdentifierNotFound { identifier, .. } => {
write!(f, "Identifier not found: {}", identifier) write!(f, "Identifier not found: {}", identifier)
} }
} }

View File

@ -2,7 +2,7 @@ use std::fmt::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Identifier; use crate::{Chunk, Identifier};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IdentifierStack { pub struct IdentifierStack {
@ -41,11 +41,33 @@ impl IdentifierStack {
.any(|local| &local.identifier == identifier) .any(|local| &local.identifier == identifier)
} }
pub fn resolve(&self, chunk: &Chunk, identifier: &Identifier) -> Option<u8> {
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<u8> {
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> { pub fn get(&self, index: usize) -> Option<&Local> {
self.locals.get(index) self.locals.get(index)
} }
pub fn get_index(&self, identifier: &Identifier) -> Option<u8> { pub fn get_index(&self, identifier: &Identifier) -> Option<usize> {
self.locals.iter().enumerate().rev().find_map( self.locals.iter().enumerate().rev().find_map(
|( |(
index, index,
@ -54,7 +76,7 @@ impl IdentifierStack {
}, },
)| { )| {
if local == identifier { if local == identifier {
Some(index as u8) Some(index)
} else { } else {
None None
} }
@ -62,6 +84,10 @@ impl IdentifierStack {
) )
} }
pub fn scope_depth(&self) -> usize {
self.scope_depth
}
pub fn begin_scope(&mut self) { pub fn begin_scope(&mut self) {
self.scope_depth += 1; self.scope_depth += 1;
} }
@ -70,7 +96,7 @@ impl IdentifierStack {
self.scope_depth -= 1; 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 { self.locals.push(Local {
identifier, identifier,
depth: self.scope_depth, depth: self.scope_depth,
@ -78,6 +104,20 @@ impl IdentifierStack {
}); });
} }
pub fn redefine(
&mut self,
identifier: &Identifier,
value_location: ValueLocation,
) -> Option<usize> {
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<Item = &Local> { pub fn iter(&self) -> impl Iterator<Item = &Local> {
self.locals.iter() self.locals.iter()
} }

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Chunk; use crate::{Chunk, Span};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum Instruction { pub enum Instruction {
@ -11,28 +11,27 @@ pub enum Instruction {
Pop = 2, Pop = 2,
// Variables // Variables
DefineVariableRuntime = 3, DefineVariable = 3,
DefineVariableConstant = 4, GetVariable = 4,
GetVariable = 5, SetVariable = 5,
SetVariable = 6,
// Unary // Unary
Negate = 7, Negate = 6,
Not = 8, Not = 7,
// Binary // Binary
Add = 9, Add = 8,
Subtract = 10, Subtract = 9,
Multiply = 11, Multiply = 10,
Divide = 12, Divide = 11,
Greater = 13, Greater = 12,
Less = 14, Less = 13,
GreaterEqual = 15, GreaterEqual = 14,
LessEqual = 16, LessEqual = 15,
Equal = 17, Equal = 16,
NotEqual = 18, NotEqual = 17,
And = 19, And = 18,
Or = 20, Or = 19,
} }
impl Instruction { impl Instruction {
@ -41,65 +40,65 @@ impl Instruction {
0 => Some(Instruction::Constant), 0 => Some(Instruction::Constant),
1 => Some(Instruction::Return), 1 => Some(Instruction::Return),
2 => Some(Instruction::Pop), 2 => Some(Instruction::Pop),
3 => Some(Instruction::DefineVariableRuntime), 3 => Some(Instruction::DefineVariable),
4 => Some(Instruction::DefineVariableConstant), 4 => Some(Instruction::GetVariable),
5 => Some(Instruction::GetVariable), 5 => Some(Instruction::SetVariable),
6 => Some(Instruction::SetVariable), 6 => Some(Instruction::Negate),
7 => Some(Instruction::Negate), 7 => Some(Instruction::Not),
8 => Some(Instruction::Not), 8 => Some(Instruction::Add),
9 => Some(Instruction::Add), 9 => Some(Instruction::Subtract),
10 => Some(Instruction::Subtract), 10 => Some(Instruction::Multiply),
11 => Some(Instruction::Multiply), 11 => Some(Instruction::Divide),
12 => Some(Instruction::Divide), 12 => Some(Instruction::Greater),
13 => Some(Instruction::Greater), 13 => Some(Instruction::Less),
14 => Some(Instruction::Less), 14 => Some(Instruction::GreaterEqual),
15 => Some(Instruction::GreaterEqual), 15 => Some(Instruction::LessEqual),
16 => Some(Instruction::LessEqual), 16 => Some(Instruction::Equal),
17 => Some(Instruction::Equal), 17 => Some(Instruction::NotEqual),
18 => Some(Instruction::NotEqual), 18 => Some(Instruction::And),
19 => Some(Instruction::And), 19 => Some(Instruction::Or),
20 => Some(Instruction::Or),
_ => None, _ => None,
} }
} }
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String { pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
let dummy_position = Span(0, 0);
match self { match self {
Instruction::Constant => { 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 let value_display = chunk
.get_constant(*argument) .get_constant(argument, position)
.map(|value| value.to_string()) .map(|value| value.to_string())
.unwrap_or_else(|error| error.to_string()); .unwrap_or_else(|error| error.to_string());
format!("CONSTANT {argument} {value_display}") format!("CONSTANT {value_display}")
} }
Instruction::Return => "RETURN".to_string(), Instruction::Return => "RETURN".to_string(),
Instruction::Pop => "POP".to_string(), Instruction::Pop => "POP".to_string(),
// Variables // Variables
Instruction::DefineVariableRuntime => "DEFINE_VARIABLE_RUNTIME".to_string(), Instruction::DefineVariable => {
Instruction::DefineVariableConstant => { let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
let (argument, _) = chunk.get_code(offset + 1).unwrap();
let identifier_display = match chunk.get_identifier(*argument) { let identifier_display = match chunk.get_identifier(*argument) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => error.to_string(), Err(error) => error.to_string(),
}; };
format!("DEFINE_VARIABLE_CONSTANT {argument} {identifier_display}") format!("DEFINE_VARIABLE {identifier_display}")
} }
Instruction::GetVariable => { 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) { let identifier_display = match chunk.get_identifier(*argument) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => error.to_string(), Err(error) => error.to_string(),
}; };
format!("GET_VARIABLE {argument} {identifier_display}") format!("GET_VARIABLE {identifier_display}")
} }
Instruction::SetVariable => { 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) { let identifier_display = match chunk.get_identifier(*argument) {
Ok(identifier) => identifier.to_string(), Ok(identifier) => identifier.to_string(),
Err(error) => error.to_string(), Err(error) => error.to_string(),

View File

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, 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<Chunk, DustError> { pub fn parse(source: &str) -> Result<Chunk, DustError> {
@ -234,10 +234,10 @@ 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(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 token = self.previous_token.to_owned();
let identifier_index = self.parse_identifier_from(token)?; 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<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 {
let identifier = Identifier::new(text); let identifier = Identifier::new(text);
let identifier_index = let identifier_index =
self.chunk self.chunk
.get_identifier_index(&identifier) .push_constant_identifier(identifier)
.map_err(|error| ParseError::Chunk { .map_err(|error| ParseError::Chunk {
error, error,
position: self.previous_position, position: self.previous_position,
@ -337,34 +338,15 @@ impl<'src> Parser<'src> {
}; };
self.expect(TokenKind::Equal)?; self.expect(TokenKind::Equal)?;
self.parse_expression()?;
let is_constant = matches!( let identifier_index = self
self.current_token, .chunk
Token::Boolean(_) .push_constant_identifier(identifier)
| Token::Byte(_) .map_err(|error| ParseError::Chunk { error, position })?;
| Token::Character(_)
| Token::Float(_)
| Token::Integer(_)
| Token::String(_)
);
let identifier_index = if is_constant { self.emit_byte(Instruction::DefineVariable, position);
self.chunk.push_constant_identifier(identifier) self.emit_byte(identifier_index, position);
} 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);
}
Ok(()) Ok(())
} }
@ -729,11 +711,11 @@ mod tests {
test_chunk, test_chunk,
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![
(Instruction::DefineVariableConstant as u8, Span(4, 5)), (Instruction::DefineVariable as u8, Span(4, 5)),
(0, Span(4, 5)), (0, Span(4, 5)),
(Instruction::Constant as u8, Span(8, 10)), (Instruction::Constant as u8, Span(8, 10)),
(0, 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)), (1, Span(16, 17)),
(Instruction::Constant as u8, Span(20, 22)), (Instruction::Constant as u8, Span(20, 22)),
(1, Span(20, 22)), (1, Span(20, 22)),
@ -770,7 +752,7 @@ mod tests {
test_chunk, test_chunk,
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![
(Instruction::DefineVariableConstant as u8, Span(4, 5)), (Instruction::DefineVariable as u8, Span(4, 5)),
(0, Span(4, 5)), (0, Span(4, 5)),
(Instruction::Constant as u8, Span(8, 10)), (Instruction::Constant as u8, Span(8, 10)),
(0, Span(8, 10)), (0, Span(8, 10)),

View File

@ -796,7 +796,7 @@ impl From<&str> for Value {
impl Clone for Value { impl Clone for Value {
fn clone(&self) -> Self { fn clone(&self) -> Self {
log::trace!("Cloning value: {:?}", self); log::trace!("Cloning value {:?}", self);
match self { match self {
Value::Raw(data) => Value::Raw(data.clone()), Value::Raw(data) => Value::Raw(data.clone()),

View File

@ -45,9 +45,12 @@ impl Vm {
match instruction { match instruction {
Instruction::Constant => { 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 => { Instruction::Return => {
let stacked = self.pop(position)?; let stacked = self.pop(position)?;
@ -55,73 +58,76 @@ impl Vm {
StackedValue::Runtime(value) => value, StackedValue::Runtime(value) => value,
StackedValue::Constant(index) => Rc::get_mut(&mut self.chunk) StackedValue::Constant(index) => Rc::get_mut(&mut self.chunk)
.unwrap() .unwrap()
.remove_constant(index) .remove_constant(index, position)?,
.map_err(|error| VmError::Chunk { error, position })?,
}; };
log::trace!("Returning {value}");
return Ok(Some(value)); return Ok(Some(value));
} }
Instruction::Pop => { Instruction::Pop => {
self.pop(position)?; let value = self.pop(position)?;
log::trace!("Popping {value:?}");
} }
// Variables // Variables
Instruction::DefineVariableRuntime => { Instruction::DefineVariable => {
let value = self.pop(position)?.resolve(&self.chunk, position)?.clone();
self.push_runtime_value(value, position)?;
}
Instruction::DefineVariableConstant => {
let (argument, _) = *self.read(position)?; 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 => { Instruction::GetVariable => {
let (argument, _) = *self.read(position)?; let (argument, _) = *self.read(position)?;
let value = self.pop(position)?.to_value(&self.chunk, position)?.clone();
let local = self log::trace!(
.chunk "Getting {} as value {value}",
.get_local(argument) self.chunk.get_identifier(argument)?,
.map_err(|error| VmError::Chunk { error, position })?; );
match local.value_location { self.push_runtime_value(value, position)?;
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)?;
}
}
} }
Instruction::SetVariable => { Instruction::SetVariable => {
let (argument, _) = *self.read(position)?; let (argument, _) = *self.read(position)?;
let identifier = self let identifier = self.chunk.get_identifier(argument)?.clone();
.chunk
.get_identifier(argument)
.map_err(|error| VmError::Chunk { error, position })?;
if !self.chunk.contains_identifier(identifier) { if !self.chunk.contains_identifier(&identifier) {
return Err(VmError::UndefinedVariable(identifier.clone(), position)); 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 // Unary
Instruction::Negate => { Instruction::Negate => {
let negated = self let negated = self
.pop(position)? .pop(position)?
.resolve(&self.chunk, position)? .to_value(&self.chunk, position)?
.negate() .negate()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -130,7 +136,7 @@ impl Vm {
Instruction::Not => { Instruction::Not => {
let not = self let not = self
.pop(position)? .pop(position)?
.resolve(&self.chunk, position)? .to_value(&self.chunk, position)?
.not() .not()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -141,9 +147,9 @@ impl Vm {
Instruction::Add => { Instruction::Add => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let sum = left let sum = left
.add(right) .add(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -153,9 +159,9 @@ impl Vm {
Instruction::Subtract => { Instruction::Subtract => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let difference = left let difference = left
.subtract(right) .subtract(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -165,9 +171,9 @@ impl Vm {
Instruction::Multiply => { Instruction::Multiply => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let product = left let product = left
.multiply(right) .multiply(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -177,9 +183,9 @@ impl Vm {
Instruction::Divide => { Instruction::Divide => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let quotient = left let quotient = left
.divide(right) .divide(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -189,9 +195,9 @@ impl Vm {
Instruction::Greater => { Instruction::Greater => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let greater = left let greater = left
.greater_than(right) .greater_than(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -201,9 +207,9 @@ impl Vm {
Instruction::Less => { Instruction::Less => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let less = left let less = left
.less_than(right) .less_than(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -213,9 +219,9 @@ impl Vm {
Instruction::GreaterEqual => { Instruction::GreaterEqual => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_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 let greater_equal = left
.greater_than_or_equal(right) .greater_than_or_equal(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -225,9 +231,9 @@ impl Vm {
Instruction::LessEqual => { Instruction::LessEqual => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_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 let less_equal = left
.less_than_or_equal(right) .less_than_or_equal(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -237,9 +243,9 @@ impl Vm {
Instruction::Equal => { Instruction::Equal => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let equal = left let equal = left
.equal(right) .equal(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -249,9 +255,9 @@ impl Vm {
Instruction::NotEqual => { Instruction::NotEqual => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_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 let not_equal = left
.not_equal(right) .not_equal(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -261,9 +267,9 @@ impl Vm {
Instruction::And => { Instruction::And => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let and = left let and = left
.and(right) .and(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -273,9 +279,9 @@ impl Vm {
Instruction::Or => { Instruction::Or => {
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
let right_stacked = self.pop(position)?; 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_stacked = self.pop(position)?;
let left = left_stacked.resolve(&self.chunk, position)?; let left = left_stacked.to_value(&self.chunk, position)?;
let or = left let or = left
.or(right) .or(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -323,10 +329,7 @@ impl Vm {
} }
fn read(&mut self, position: Span) -> Result<&(u8, Span), VmError> { fn read(&mut self, position: Span) -> Result<&(u8, Span), VmError> {
let current = self let current = self.chunk.get_code(self.ip, position)?;
.chunk
.get_code(self.ip)
.map_err(|error| VmError::Chunk { error, position })?;
self.ip += 1; self.ip += 1;
@ -341,12 +344,10 @@ pub enum StackedValue {
} }
impl 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 { match self {
Self::Runtime(value) => Ok(value), Self::Runtime(value) => Ok(value),
Self::Constant(index) => chunk Self::Constant(index) => Ok(chunk.get_constant(*index, position)?),
.get_constant(*index)
.map_err(|error| VmError::Chunk { error, position }),
} }
} }
} }
@ -356,20 +357,22 @@ pub enum VmError {
InvalidInstruction(u8, Span), InvalidInstruction(u8, Span),
StackOverflow(Span), StackOverflow(Span),
StackUnderflow(Span), StackUnderflow(Span),
UndefinedVariable(Identifier, Span), UndefinedVariable {
identifier: Identifier,
position: Span,
},
// Wrappers for foreign errors // Wrappers for foreign errors
Chunk { error: ChunkError, position: Span }, Chunk(ChunkError),
Value { error: ValueError, position: Span }, Value {
error: ValueError,
position: Span,
},
} }
impl VmError { impl From<ChunkError> for VmError {
pub fn chunk(error: ChunkError, position: Span) -> Self { fn from(v: ChunkError) -> Self {
Self::Chunk { error, position } Self::Chunk(v)
}
pub fn value(error: ValueError, position: Span) -> Self {
Self::Value { error, position }
} }
} }
@ -383,8 +386,8 @@ impl AnnotatedError for VmError {
Self::InvalidInstruction(_, _) => "Invalid instruction", Self::InvalidInstruction(_, _) => "Invalid instruction",
Self::StackOverflow(_) => "Stack overflow", Self::StackOverflow(_) => "Stack overflow",
Self::StackUnderflow(_) => "Stack underflow", Self::StackUnderflow(_) => "Stack underflow",
Self::UndefinedVariable(_, _) => "Undefined variable", Self::UndefinedVariable { .. } => "Undefined variable",
Self::Chunk { .. } => "Chunk error", Self::Chunk(_) => "Chunk error",
Self::Value { .. } => "Value error", Self::Value { .. } => "Value error",
} }
} }
@ -396,11 +399,11 @@ impl AnnotatedError for VmError {
)), )),
Self::StackOverflow(position) => Some(format!("Stack overflow at {position}")), Self::StackOverflow(position) => Some(format!("Stack overflow at {position}")),
Self::StackUnderflow(position) => Some(format!("Stack underflow at {position}")), Self::StackUnderflow(position) => Some(format!("Stack underflow at {position}")),
Self::UndefinedVariable(identifier, position) => { Self::UndefinedVariable { identifier, .. } => {
Some(format!("{identifier} is not in scope at {position}")) 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()), Self::Value { error, .. } => Some(error.to_string()),
} }
} }
@ -410,8 +413,8 @@ impl AnnotatedError for VmError {
Self::InvalidInstruction(_, position) => *position, Self::InvalidInstruction(_, position) => *position,
Self::StackUnderflow(position) => *position, Self::StackUnderflow(position) => *position,
Self::StackOverflow(position) => *position, Self::StackOverflow(position) => *position,
Self::UndefinedVariable(_, position) => *position, Self::UndefinedVariable { position, .. } => *position,
Self::Chunk { position, .. } => *position, Self::Chunk(error) => error.position(),
Self::Value { position, .. } => *position, Self::Value { position, .. } => *position,
} }
} }

View File

@ -9,5 +9,7 @@ repository.workspace = true
[dependencies] [dependencies]
clap = { version = "4.5.14", features = ["derive"] } clap = { version = "4.5.14", features = ["derive"] }
colored = "2.1.0"
dust-lang = { path = "../dust-lang" } dust-lang = { path = "../dust-lang" }
env_logger = "0.11.5" env_logger = "0.11.5"
log = "0.4.22"

View File

@ -1,8 +1,9 @@
use std::fs::read_to_string; use std::{fs::read_to_string, io::Write};
use clap::Parser; use clap::Parser;
use colored::Colorize;
use dust_lang::{parse, run}; use dust_lang::{parse, run};
use env_logger::WriteStyle; use log::Level;
#[derive(Parser)] #[derive(Parser)]
struct Cli { struct Cli {
@ -18,8 +19,21 @@ struct Cli {
fn main() { fn main() {
env_logger::builder() env_logger::builder()
.parse_env("DUST_LOG") .parse_env("DUST_LOG")
.format_timestamp_secs() .format(|buf, record| {
.write_style(WriteStyle::Always) 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(); .init();
let args = Cli::parse(); let args = Cli::parse();