1
0

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"
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"

View File

@ -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<Value, ChunkError> {
pub fn remove_constant(&mut self, index: u8, position: Span) -> Result<Value, ChunkError> {
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<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> {
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<u8, ChunkError> {
pub fn get_identifier_index(
&self,
identifier: &Identifier,
position: Span,
) -> Result<u8, ChunkError> {
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<u8, ChunkError> {
@ -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<usize, ChunkError> {
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<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 {
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)
}
}

View File

@ -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<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> {
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(
|(
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<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> {
self.locals.iter()
}

View File

@ -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(),

View File

@ -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<Chunk, DustError> {
@ -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<u8, ParseError> {
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,35 +338,16 @@ 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 = if is_constant {
self.chunk.push_constant_identifier(identifier)
} else {
self.chunk.push_runtime_identifier(identifier)
}
let identifier_index = self
.chunk
.push_constant_identifier(identifier)
.map_err(|error| ParseError::Chunk { error, position })?;
if is_constant {
self.emit_byte(Instruction::DefineVariableConstant, position);
self.emit_byte(Instruction::DefineVariable, position);
self.emit_byte(identifier_index, position);
self.parse_expression()?;
} else {
self.parse_expression()?;
self.emit_byte(Instruction::DefineVariableRuntime, 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)),

View File

@ -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()),

View File

@ -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();
Instruction::DefineVariable => {
let (argument, _) = *self.read(position)?;
let identifier = self.chunk.get_identifier(argument)?.clone();
let stack_index_option = self.chunk.resolve_local(&identifier);
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::DefineVariableConstant => {
let (argument, _) = *self.read(position)?;
self.push_constant_value(argument, 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 })?;
match local.value_location {
ValueLocation::ConstantStack => {
let value = self
.chunk
.get_constant(argument)
.map_err(|error| VmError::Chunk { error, position })?
.clone();
log::trace!(
"Getting {} as value {value}",
self.chunk.get_identifier(argument)?,
);
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 => {
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<ChunkError> 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,
}
}

View File

@ -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"

View File

@ -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();