1
0

Bring back chunk errors

This commit is contained in:
Jeff 2024-11-06 13:50:49 -05:00
parent c0b998c0d8
commit 78840cf3e7
4 changed files with 114 additions and 126 deletions

View File

@ -37,7 +37,7 @@
use std::{
cmp::Ordering,
env::current_exe,
fmt::{self, Debug, Display},
fmt::{self, Debug, Display, Formatter},
};
use colored::Colorize;
@ -127,6 +127,12 @@ impl Chunk {
&mut self.instructions
}
pub fn get_instruction(&self, index: usize) -> Result<&(Instruction, Span), ChunkError> {
self.instructions
.get(index)
.ok_or(ChunkError::InstructionIndexOutOfBounds { index })
}
pub fn locals(&self) -> &Vec<Local> {
&self.locals
}
@ -135,12 +141,32 @@ impl Chunk {
&mut self.locals
}
pub fn get_local(&self, index: u8) -> Result<&Local, ChunkError> {
self.locals
.get(index as usize)
.ok_or(ChunkError::LocalIndexOutOfBounds {
index: index as usize,
})
}
pub fn get_local_mut(&mut self, index: u8) -> Result<&mut Local, ChunkError> {
self.locals
.get_mut(index as usize)
.ok_or(ChunkError::LocalIndexOutOfBounds {
index: index as usize,
})
}
pub fn current_scope(&self) -> Scope {
self.current_scope
}
pub fn get_constant(&self, index: u8) -> Option<&Value> {
self.constants.get(index as usize)
pub fn get_constant(&self, index: u8) -> Result<&Value, ChunkError> {
self.constants
.get(index as usize)
.ok_or(ChunkError::ConstantIndexOutOfBounds {
index: index as usize,
})
}
pub fn push_or_get_constant(&mut self, value: Value) -> u8 {
@ -181,6 +207,14 @@ impl Chunk {
}
}
pub fn expect_not_poisoned(&self) -> Result<(), ChunkError> {
if self.is_poisoned {
Err(ChunkError::PoisonedChunk)
} else {
Ok(())
}
}
pub fn get_constant_type(&self, constant_index: u8) -> Option<Type> {
self.constants
.get(constant_index as usize)
@ -652,3 +686,28 @@ impl<'a> ChunkDisassembler<'a> {
self.output
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ChunkError {
ConstantIndexOutOfBounds { index: usize },
InstructionIndexOutOfBounds { index: usize },
LocalIndexOutOfBounds { index: usize },
PoisonedChunk,
}
impl Display for ChunkError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
ChunkError::ConstantIndexOutOfBounds { index } => {
write!(f, "Constant index {} out of bounds", index)
}
ChunkError::InstructionIndexOutOfBounds { index } => {
write!(f, "Instruction index {} out of bounds", index)
}
ChunkError::LocalIndexOutOfBounds { index } => {
write!(f, "Local index {} out of bounds", index)
}
ChunkError::PoisonedChunk => write!(f, "Chunk is poisoned"),
}
}
}

View File

@ -14,7 +14,7 @@ pub mod r#type;
pub mod value;
pub mod vm;
pub use crate::chunk::{Chunk, ChunkDisassembler, Local, Scope};
pub use crate::chunk::{Chunk, ChunkDisassembler, ChunkError, Local, Scope};
pub use crate::dust_error::{AnnotatedError, DustError};
pub use crate::formatter::{format, Formatter};
pub use crate::instruction::Instruction;

View File

@ -13,8 +13,9 @@ use std::{
use colored::Colorize;
use crate::{
optimize, AnnotatedError, Chunk, DustError, FunctionType, Instruction, LexError, Lexer, Local,
NativeFunction, Operation, Scope, Span, Token, TokenKind, TokenOwned, Type, Value,
optimize, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Instruction, LexError,
Lexer, Local, NativeFunction, Operation, Scope, Span, Token, TokenKind, TokenOwned, Type,
Value,
};
/// Parses the input and returns a chunk.
@ -127,13 +128,10 @@ impl<'src> Parser<'src> {
}
fn get_local(&self, index: u8) -> Result<&Local, ParseError> {
let index = index as usize;
self.chunk
.locals()
.get(index)
.ok_or(ParseError::LocalIndexOutOfBounds {
index,
.get_local(index)
.map_err(|error| ParseError::Chunk {
error,
position: self.current_position,
})
}
@ -1882,7 +1880,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
}
}
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum ParseError {
// Token errors
ExpectedToken {
@ -1934,19 +1932,11 @@ pub enum ParseError {
position: Span,
},
// Chunk errors
LocalIndexOutOfBounds {
index: usize,
position: Span,
},
RegisterOverflow {
position: Span,
},
RegisterUnderflow {
position: Span,
},
// Wrappers around foreign errors
Chunk {
error: ChunkError,
position: Span,
},
Lex(LexError),
ParseFloatError {
error: ParseFloatError,
@ -1967,17 +1957,15 @@ impl AnnotatedError for ParseError {
match self {
Self::CannotChainComparison { .. } => "Cannot chain comparison",
Self::CannotMutateImmutableVariable { .. } => "Cannot mutate immutable variable",
Self::Chunk { .. } => "Chunk error",
Self::ExpectedExpression { .. } => "Expected an expression",
Self::ExpectedMutableVariable { .. } => "Expected a mutable variable",
Self::ExpectedToken { .. } => "Expected a specific token",
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
Self::Lex(error) => error.description(),
Self::LocalIndexOutOfBounds { .. } => "Local index out of bounds",
Self::ParseFloatError { .. } => "Failed to parse float",
Self::ParseIntError { .. } => "Failed to parse integer",
Self::RegisterOverflow { .. } => "Register overflow",
Self::RegisterUnderflow { .. } => "Register underflow",
Self::UndeclaredVariable { .. } => "Undeclared variable",
Self::UnexpectedReturn { .. } => "Unexpected return",
Self::VariableOutOfScope { .. } => "Variable out of scope",
@ -1992,6 +1980,7 @@ impl AnnotatedError for ParseError {
Self::CannotMutateImmutableVariable { identifier, .. } => {
Some(format!("Cannot mutate immutable variable {identifier}"))
}
Self::Chunk { error, .. } => Some(error.to_string()),
Self::ExpectedExpression { found, .. } => Some(format!("Found {found}")),
Self::ExpectedToken {
expected, found, ..
@ -2024,13 +2013,9 @@ impl AnnotatedError for ParseError {
Some(format!("Invalid assignment target, found {found}"))
}
Self::Lex(error) => error.details(),
Self::LocalIndexOutOfBounds { index, .. } => {
Some(format!("Local index {index} out of bounds"))
}
Self::ParseFloatError { error, .. } => Some(error.to_string()),
Self::ParseIntError { error, .. } => Some(error.to_string()),
Self::RegisterOverflow { .. } => None,
Self::RegisterUnderflow { .. } => None,
Self::UndeclaredVariable { identifier, .. } => {
Some(format!("Undeclared variable {identifier}"))
}
@ -2045,17 +2030,15 @@ impl AnnotatedError for ParseError {
match self {
Self::CannotChainComparison { position } => *position,
Self::CannotMutateImmutableVariable { position, .. } => *position,
Self::Chunk { position, .. } => *position,
Self::ExpectedExpression { position, .. } => *position,
Self::ExpectedMutableVariable { position, .. } => *position,
Self::ExpectedToken { position, .. } => *position,
Self::ExpectedTokenMultiple { position, .. } => *position,
Self::InvalidAssignmentTarget { position, .. } => *position,
Self::Lex(error) => error.position(),
Self::LocalIndexOutOfBounds { position, .. } => *position,
Self::ParseFloatError { position, .. } => *position,
Self::ParseIntError { position, .. } => *position,
Self::RegisterOverflow { position } => *position,
Self::RegisterUnderflow { position } => *position,
Self::UndeclaredVariable { position, .. } => *position,
Self::UnexpectedReturn { position } => *position,
Self::VariableOutOfScope { position, .. } => *position,

View File

@ -2,8 +2,9 @@
use std::{cmp::Ordering, mem::replace};
use crate::{
parse, value::ConcreteValue, AnnotatedError, Chunk, DustError, FunctionType, Instruction,
Local, NativeFunction, NativeFunctionError, Operation, Span, Type, Value, ValueError,
parse, value::ConcreteValue, AnnotatedError, Chunk, ChunkError, DustError, FunctionType,
Instruction, Local, NativeFunction, NativeFunctionError, Operation, Span, Type, Value,
ValueError,
};
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
@ -45,22 +46,12 @@ impl Vm {
position: Span,
) -> Result<(&Value, &Value), VmError> {
let left = if instruction.b_is_constant() {
vm.chunk.get_constant(instruction.b()).ok_or_else(|| {
VmError::ConstantIndexOutOfBounds {
index: instruction.b() as usize,
position,
}
})?
vm.get_constant(instruction.b(), position)?
} else {
vm.get_register(instruction.b(), position)?
};
let right = if instruction.c_is_constant() {
vm.chunk.get_constant(instruction.c()).ok_or_else(|| {
VmError::ConstantIndexOutOfBounds {
index: instruction.c() as usize,
position,
}
})?
vm.get_constant(instruction.c(), position)?
} else {
vm.get_register(instruction.c(), position)?
};
@ -336,12 +327,7 @@ impl Vm {
}
Operation::Negate => {
let value = if instruction.b_is_constant() {
self.chunk.get_constant(instruction.b()).ok_or_else(|| {
VmError::ConstantIndexOutOfBounds {
index: instruction.b() as usize,
position,
}
})?
self.get_constant(instruction.b(), position)?
} else {
self.get_register(instruction.b(), position)?
};
@ -353,12 +339,7 @@ impl Vm {
}
Operation::Not => {
let value = if instruction.b_is_constant() {
self.chunk.get_constant(instruction.b()).ok_or_else(|| {
VmError::ConstantIndexOutOfBounds {
index: instruction.b() as usize,
position,
}
})?
self.get_constant(instruction.b(), position)?
} else {
self.get_register(instruction.b(), position)?
};
@ -588,6 +569,12 @@ impl Vm {
}
}
fn get_constant(&self, index: u8, position: Span) -> Result<&Value, VmError> {
self.chunk
.get_constant(index)
.map_err(|error| VmError::Chunk { error, position })
}
pub fn get_register(&self, index: u8, position: Span) -> Result<&Value, VmError> {
let index = index as usize;
let register = self
@ -598,13 +585,7 @@ impl Vm {
match register {
Register::Value(value) => Ok(value),
Register::Pointer(register_index) => self.get_register(*register_index, position),
Register::Constant(constant_index) => self
.chunk
.get_constant(*constant_index)
.ok_or_else(|| VmError::ConstantIndexOutOfBounds {
index: *constant_index as usize,
position,
}),
Register::Constant(constant_index) => self.get_constant(*constant_index, position),
Register::Empty => Err(VmError::EmptyRegister { index, position }),
}
}
@ -640,24 +621,19 @@ impl Vm {
}
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
if self.chunk.is_poisoned {
return Err(VmError::PoisonedChunk { position });
self.chunk
.expect_not_poisoned()
.map_err(|error| VmError::Chunk { error, position })?;
let max_ip = self.chunk.len() - 1;
if self.ip > max_ip {
return self.get_instruction(max_ip, position);
} else {
self.ip += 1;
}
if self.ip >= self.chunk.len() {
self.ip = self.chunk.len() - 1;
}
let current = self.chunk.instructions().get(self.ip).ok_or_else(|| {
VmError::InstructionIndexOutOfBounds {
index: self.ip,
position,
}
})?;
self.ip += 1;
Ok(current)
self.get_instruction(self.ip - 1, position)
}
fn define_local(
@ -668,12 +644,8 @@ impl Vm {
) -> Result<(), VmError> {
let local = self
.chunk
.locals_mut()
.get_mut(local_index as usize)
.ok_or_else(|| VmError::LocalIndexOutOfBounds {
index: local_index as usize,
position,
})?;
.get_local_mut(local_index)
.map_err(|error| VmError::Chunk { error, position })?;
log::debug!("Define local L{}", local_index);
@ -683,15 +655,9 @@ impl Vm {
}
fn get_local(&self, local_index: u8, position: Span) -> Result<&Local, VmError> {
let local_index = local_index as usize;
self.chunk
.locals()
.get(local_index)
.ok_or_else(|| VmError::LocalIndexOutOfBounds {
index: local_index,
position,
})
.get_local(local_index)
.map_err(|error| VmError::Chunk { error, position })
}
fn get_instruction(
@ -700,9 +666,8 @@ impl Vm {
position: Span,
) -> Result<&(Instruction, Span), VmError> {
self.chunk
.instructions()
.get(index)
.ok_or_else(|| VmError::InstructionIndexOutOfBounds { index, position })
.get_instruction(index)
.map_err(|error| VmError::Chunk { error, position })
}
}
@ -714,7 +679,7 @@ enum Register {
Constant(u8),
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum VmError {
// Stack errors
StackOverflow { position: Span },
@ -724,17 +689,12 @@ pub enum VmError {
EmptyRegister { index: usize, position: Span },
RegisterIndexOutOfBounds { index: usize, position: Span },
// Chunk errors
ConstantIndexOutOfBounds { index: usize, position: Span },
InstructionIndexOutOfBounds { index: usize, position: Span },
LocalIndexOutOfBounds { index: usize, position: Span },
PoisonedChunk { position: Span },
// Execution errors
ExpectedBoolean { found: Value, position: Span },
ExpectedFunction { found: Value, position: Span },
// Wrappers for foreign errors
Chunk { error: ChunkError, position: Span },
NativeFunction(NativeFunctionError),
Value { error: ValueError, position: Span },
}
@ -746,14 +706,11 @@ impl AnnotatedError for VmError {
fn description(&self) -> &'static str {
match self {
Self::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
Self::Chunk { .. } => "Chunk error",
Self::EmptyRegister { .. } => "Empty register",
Self::ExpectedBoolean { .. } => "Expected boolean",
Self::ExpectedFunction { .. } => "Expected function",
Self::InstructionIndexOutOfBounds { .. } => "Instruction index out of bounds",
Self::LocalIndexOutOfBounds { .. } => "Local index out of bounds",
Self::NativeFunction(error) => error.description(),
Self::PoisonedChunk { .. } => "Poisoned chunk",
Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds",
Self::StackOverflow { .. } => "Stack overflow",
Self::StackUnderflow { .. } => "Stack underflow",
@ -763,20 +720,12 @@ impl AnnotatedError for VmError {
fn details(&self) -> Option<String> {
match self {
Self::ConstantIndexOutOfBounds { index, .. } => {
Some(format!("Constant C{index} does not exist"))
}
Self::Chunk { error, .. } => Some(error.to_string()),
Self::EmptyRegister { index, .. } => Some(format!("Register R{index} is empty")),
Self::ExpectedFunction { found, .. } => Some(format!("{found} is not a function")),
Self::RegisterIndexOutOfBounds { index, .. } => {
Some(format!("Register {index} does not exist"))
}
Self::InstructionIndexOutOfBounds { index, .. } => {
Some(format!("Instruction {index} does not exist"))
}
Self::LocalIndexOutOfBounds { index, .. } => {
Some(format!("Local L{index} does not exist"))
}
Self::NativeFunction(error) => error.details(),
Self::Value { error, .. } => Some(error.to_string()),
_ => None,
@ -785,14 +734,11 @@ impl AnnotatedError for VmError {
fn position(&self) -> Span {
match self {
Self::ConstantIndexOutOfBounds { position, .. } => *position,
Self::Chunk { position, .. } => *position,
Self::EmptyRegister { position, .. } => *position,
Self::ExpectedBoolean { position, .. } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::InstructionIndexOutOfBounds { position, .. } => *position,
Self::LocalIndexOutOfBounds { position, .. } => *position,
Self::NativeFunction(error) => error.position(),
Self::PoisonedChunk { position } => *position,
Self::RegisterIndexOutOfBounds { position, .. } => *position,
Self::StackOverflow { position } => *position,
Self::StackUnderflow { position } => *position,