Add error reports and byte operations
This commit is contained in:
parent
8f20e53880
commit
8798efc0af
@ -43,7 +43,7 @@ impl Chunk {
|
||||
pub fn get_code(&self, offset: usize) -> Result<&(u8, Span), ChunkError> {
|
||||
self.code
|
||||
.get(offset)
|
||||
.ok_or(ChunkError::CodeIndextOfBounds(offset))
|
||||
.ok_or(ChunkError::CodeIndexOfBounds(offset))
|
||||
}
|
||||
|
||||
pub fn push_code(&mut self, instruction: u8, position: Span) {
|
||||
@ -169,22 +169,47 @@ impl Default for Chunk {
|
||||
|
||||
impl Display for Chunk {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.disassemble("Chunk"))
|
||||
write!(f, "{}", self.disassemble("Chunk Disassembly"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Chunk {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.disassemble("Chunk"))
|
||||
write!(f, "{}", self.disassemble("Chunk Disassembly"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ChunkError {
|
||||
CodeIndextOfBounds(usize),
|
||||
CodeIndexOfBounds(usize),
|
||||
ConstantOverflow,
|
||||
ConstantIndexOutOfBounds(u8),
|
||||
IdentifierIndexOutOfBounds(u8),
|
||||
IdentifierOverflow,
|
||||
IdentifierNotFound(Identifier),
|
||||
}
|
||||
|
||||
impl ChunkError {
|
||||
pub fn title(&self) -> &'static str {
|
||||
"Chunk Error"
|
||||
}
|
||||
|
||||
pub fn description(&self) -> String {
|
||||
match self {
|
||||
Self::CodeIndexOfBounds(offset) => format!("{offset} is out of bounds",),
|
||||
Self::ConstantOverflow => "More than 256 constants declared in one chunk".to_string(),
|
||||
Self::ConstantIndexOutOfBounds(index) => {
|
||||
format!("{index} is out of bounds")
|
||||
}
|
||||
Self::IdentifierIndexOutOfBounds(index) => {
|
||||
format!("{index} is out of bounds")
|
||||
}
|
||||
Self::IdentifierOverflow => {
|
||||
"More than 256 identifiers declared in one chunk".to_string()
|
||||
}
|
||||
Self::IdentifierNotFound(identifier) => {
|
||||
format!("{} does not exist in this scope", identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use annotate_snippets::{Level, Renderer, Snippet};
|
||||
|
||||
use crate::{vm::VmError, LexError, ParseError};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@ -15,3 +17,30 @@ pub enum DustError<'src> {
|
||||
source: &'src str,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'src> DustError<'src> {
|
||||
pub fn report(&self) -> String {
|
||||
let mut report = String::new();
|
||||
let renderer = Renderer::styled();
|
||||
|
||||
match self {
|
||||
DustError::Runtime { error, source } => {
|
||||
let position = error.position();
|
||||
let label = format!("Runtime {}", error.title());
|
||||
let description = error.description();
|
||||
let message = Level::Error.title(&label).snippet(
|
||||
Snippet::source(source).fold(true).annotation(
|
||||
Level::Error
|
||||
.span(position.0..position.1)
|
||||
.label(&description),
|
||||
),
|
||||
);
|
||||
|
||||
report.push_str(&renderer.render(message).to_string());
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
||||
report
|
||||
}
|
||||
}
|
||||
|
@ -206,6 +206,7 @@ impl<'src> Parser<'src> {
|
||||
TokenKind::Minus => Instruction::Subtract as u8,
|
||||
TokenKind::Star => Instruction::Multiply as u8,
|
||||
TokenKind::Slash => Instruction::Divide as u8,
|
||||
TokenKind::DoubleAmpersand => Instruction::And as u8,
|
||||
_ => {
|
||||
return Err(ParseError::ExpectedTokenMultiple {
|
||||
expected: vec![
|
||||
@ -319,8 +320,8 @@ impl<'src> Parser<'src> {
|
||||
fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> {
|
||||
self.advance()?;
|
||||
|
||||
let prefix_rule = if let Some(prefix) = ParseRule::from(&self.previous_token.kind()).prefix
|
||||
{
|
||||
let prefix_parser =
|
||||
if let Some(prefix) = ParseRule::from(&self.previous_token.kind()).prefix {
|
||||
log::trace!(
|
||||
"Parsing {} as prefix with precedence {precedence}",
|
||||
self.previous_token,
|
||||
@ -333,17 +334,14 @@ impl<'src> Parser<'src> {
|
||||
position: self.previous_position,
|
||||
});
|
||||
};
|
||||
|
||||
let allow_assignment = precedence <= Precedence::Assignment;
|
||||
|
||||
prefix_rule(self, allow_assignment)?;
|
||||
prefix_parser(self, allow_assignment)?;
|
||||
|
||||
while precedence < ParseRule::from(&self.current_token.kind()).precedence {
|
||||
self.advance()?;
|
||||
|
||||
let infix_rule = ParseRule::from(&self.previous_token.kind()).infix;
|
||||
|
||||
if let Some(infix) = infix_rule {
|
||||
if let Some(infix_parser) = ParseRule::from(&self.previous_token.kind()).infix {
|
||||
log::trace!(
|
||||
"Parsing {} as infix with precedence {precedence}",
|
||||
self.previous_token,
|
||||
@ -356,7 +354,7 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
infix(self)?;
|
||||
infix_parser(self)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -485,7 +483,11 @@ impl From<&TokenKind> for ParseRule<'_> {
|
||||
TokenKind::Colon => todo!(),
|
||||
TokenKind::Comma => todo!(),
|
||||
TokenKind::Dot => todo!(),
|
||||
TokenKind::DoubleAmpersand => todo!(),
|
||||
TokenKind::DoubleAmpersand => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_binary),
|
||||
precedence: Precedence::LogicalAnd,
|
||||
},
|
||||
TokenKind::DoubleDot => todo!(),
|
||||
TokenKind::DoubleEqual => todo!(),
|
||||
TokenKind::DoublePipe => todo!(),
|
||||
|
@ -2,7 +2,6 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
error::Error,
|
||||
fmt::{self, Display, Formatter},
|
||||
ops::{Range, RangeInclusive},
|
||||
sync::{Arc, RwLock},
|
||||
@ -1006,6 +1005,9 @@ impl ValueData {
|
||||
|
||||
pub fn add(&self, other: &ValueData) -> Option<ValueData> {
|
||||
match (self, other) {
|
||||
(ValueData::Byte(left), ValueData::Byte(right)) => {
|
||||
Some(ValueData::Byte(left.saturating_add(*right)))
|
||||
}
|
||||
(ValueData::Float(left), ValueData::Float(right)) => {
|
||||
Some(ValueData::Float(left + right))
|
||||
}
|
||||
@ -1021,6 +1023,9 @@ impl ValueData {
|
||||
|
||||
pub fn subtract(&self, other: &ValueData) -> Option<ValueData> {
|
||||
match (self, other) {
|
||||
(ValueData::Byte(left), ValueData::Byte(right)) => {
|
||||
Some(ValueData::Byte(left.saturating_sub(*right)))
|
||||
}
|
||||
(ValueData::Float(left), ValueData::Float(right)) => {
|
||||
Some(ValueData::Float(left - right))
|
||||
}
|
||||
@ -1033,6 +1038,9 @@ impl ValueData {
|
||||
|
||||
pub fn multiply(&self, other: &ValueData) -> Option<ValueData> {
|
||||
match (self, other) {
|
||||
(ValueData::Byte(left), ValueData::Byte(right)) => {
|
||||
Some(ValueData::Byte(left.saturating_mul(*right)))
|
||||
}
|
||||
(ValueData::Float(left), ValueData::Float(right)) => {
|
||||
Some(ValueData::Float(left * right))
|
||||
}
|
||||
@ -1045,6 +1053,9 @@ impl ValueData {
|
||||
|
||||
pub fn divide(&self, other: &ValueData) -> Option<ValueData> {
|
||||
match (self, other) {
|
||||
(ValueData::Byte(left), ValueData::Byte(right)) => {
|
||||
Some(ValueData::Byte(left.saturating_div(*right)))
|
||||
}
|
||||
(ValueData::Float(left), ValueData::Float(right)) => {
|
||||
Some(ValueData::Float(left / right))
|
||||
}
|
||||
@ -1170,7 +1181,7 @@ impl Display for ValueData {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ValueData::Boolean(boolean) => write!(f, "{boolean}"),
|
||||
ValueData::Byte(byte) => write!(f, "{byte}"),
|
||||
ValueData::Byte(byte) => write!(f, "0x{byte:02x}"),
|
||||
ValueData::Character(character) => write!(f, "{character}"),
|
||||
ValueData::Enum(r#enum) => write!(f, "{enum}"),
|
||||
ValueData::Float(float) => {
|
||||
@ -1757,12 +1768,68 @@ pub enum ValueError {
|
||||
CannotNot(Value),
|
||||
CannotSubtract(Value, Value),
|
||||
CannotOr(Value, Value),
|
||||
DivisionByZero,
|
||||
ExpectedList(Value),
|
||||
IndexOutOfBounds { value: Value, index: i64 },
|
||||
}
|
||||
|
||||
impl Error for ValueError {}
|
||||
impl ValueError {
|
||||
pub fn title(&self) -> &'static str {
|
||||
"Value Error"
|
||||
}
|
||||
|
||||
pub fn description(&self) -> String {
|
||||
match self {
|
||||
ValueError::CannotAdd(left, right) => format!("Cannot add {} and {}", left, right),
|
||||
ValueError::CannotAnd(left, right) => {
|
||||
format!(
|
||||
"Cannot use logical \"and\" operation on {} and {}",
|
||||
left, right
|
||||
)
|
||||
}
|
||||
ValueError::CannotDivide(left, right) => {
|
||||
format!("Cannot divide {} by {}", left, right)
|
||||
}
|
||||
ValueError::CannotGreaterThan(left, right) => {
|
||||
format!("Cannot compare {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotGreaterThanOrEqual(left, right) => {
|
||||
format!("Cannot compare {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotIndex { value, index } => {
|
||||
format!("Cannot index {} with {}", value, index)
|
||||
}
|
||||
ValueError::CannotLessThan(left, right) => {
|
||||
format!("Cannot compare {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotLessThanOrEqual(left, right) => {
|
||||
format!("Cannot compare {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotMakeMutable => "Cannot make this value mutable".to_string(),
|
||||
ValueError::CannotModulo(left, right) => {
|
||||
format!("Cannot modulo {} by {}", left, right)
|
||||
}
|
||||
ValueError::CannotMultiply(left, right) => {
|
||||
format!("Cannot multiply {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotMutate(value) => format!("Cannot mutate {}", value),
|
||||
ValueError::CannotNegate(value) => format!("Cannot negate {}", value),
|
||||
ValueError::CannotNot(value) => {
|
||||
format!("Cannot use logical not operation on {}", value)
|
||||
}
|
||||
ValueError::CannotSubtract(left, right) => {
|
||||
format!("Cannot subtract {} and {}", left, right)
|
||||
}
|
||||
ValueError::CannotOr(left, right) => {
|
||||
format!(
|
||||
"Cannot use logical \"or\" operation on {} and {}",
|
||||
left, right
|
||||
)
|
||||
}
|
||||
ValueError::IndexOutOfBounds { value, index } => {
|
||||
format!("Index out of bounds: {} with index {}", value, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ValueError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
@ -1810,11 +1877,9 @@ impl Display for ValueError {
|
||||
left, right
|
||||
)
|
||||
}
|
||||
ValueError::DivisionByZero => write!(f, "Division by zero"),
|
||||
ValueError::IndexOutOfBounds { value, index } => {
|
||||
write!(f, "{} does not have an index of {}", value, index)
|
||||
}
|
||||
ValueError::ExpectedList(value) => write!(f, "{} is not a list", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,11 @@ impl Vm {
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
|
||||
while let Ok((byte, position)) = self.read().copied() {
|
||||
let mut current_postion = Span(0, 0);
|
||||
|
||||
while let Ok((byte, position)) = self.read(current_postion).copied() {
|
||||
current_postion = position;
|
||||
|
||||
let instruction = Instruction::from_byte(byte)
|
||||
.ok_or_else(|| VmError::InvalidInstruction(byte, position))?;
|
||||
|
||||
@ -38,142 +42,179 @@ impl Vm {
|
||||
|
||||
match instruction {
|
||||
Instruction::Constant => {
|
||||
let (index, _) = self.read().copied()?;
|
||||
let value = self.read_constant(index)?;
|
||||
let (index, _) = self.read(position).copied()?;
|
||||
let value = self.read_constant(index, position)?.clone();
|
||||
|
||||
self.push(value)?;
|
||||
self.push(value, position)?;
|
||||
}
|
||||
Instruction::Return => {
|
||||
let value = self.pop()?;
|
||||
let value = self.pop(position)?;
|
||||
|
||||
return Ok(Some(value));
|
||||
}
|
||||
Instruction::Pop => {
|
||||
self.pop()?;
|
||||
self.pop(position)?;
|
||||
}
|
||||
|
||||
// Variables
|
||||
Instruction::DefineVariable => {
|
||||
let (index, _) = *self.read()?;
|
||||
let value = self.read_constant(index)?;
|
||||
let (index, _) = *self.read(position)?;
|
||||
let value = self
|
||||
.read_constant(index, position)?
|
||||
.clone()
|
||||
.into_reference();
|
||||
|
||||
self.stack.insert(index as usize, value);
|
||||
}
|
||||
Instruction::GetVariable => {
|
||||
let (index, _) = *self.read()?;
|
||||
let (index, _) = *self.read(position)?;
|
||||
let value = self.stack[index as usize].clone();
|
||||
|
||||
self.push(value)?;
|
||||
self.push(value, position)?;
|
||||
}
|
||||
Instruction::SetVariable => {
|
||||
let (index, _) = *self.read()?;
|
||||
let identifier = self.chunk.get_identifier(index)?.clone();
|
||||
let (index, _) = *self.read(position)?;
|
||||
let identifier = self
|
||||
.chunk
|
||||
.get_identifier(index)
|
||||
.map_err(|error| VmError::Chunk { error, position })?
|
||||
.clone();
|
||||
|
||||
if !self.chunk.contains_identifier(&identifier) {
|
||||
return Err(VmError::UndefinedVariable(identifier, position));
|
||||
}
|
||||
|
||||
let value = self.pop()?;
|
||||
let value = self.pop(position)?;
|
||||
|
||||
self.stack[index as usize] = value;
|
||||
}
|
||||
|
||||
// Unary
|
||||
Instruction::Negate => {
|
||||
let negated = self.pop()?.negate()?;
|
||||
let negated = self
|
||||
.pop(position)?
|
||||
.negate()
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(negated)?;
|
||||
self.push(negated, position)?;
|
||||
}
|
||||
Instruction::Not => {
|
||||
let not = self.pop()?.not()?;
|
||||
let not = self
|
||||
.pop(position)?
|
||||
.not()
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(not)?;
|
||||
self.push(not, position)?;
|
||||
}
|
||||
|
||||
// Binary
|
||||
Instruction::Add => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let sum = left.add(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let sum = left
|
||||
.add(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(sum)?;
|
||||
self.push(sum, position)?;
|
||||
}
|
||||
Instruction::Subtract => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let difference = left.subtract(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let difference = left
|
||||
.subtract(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(difference)?;
|
||||
self.push(difference, position)?;
|
||||
}
|
||||
Instruction::Multiply => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let product = left.multiply(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let product = left
|
||||
.multiply(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(product)?;
|
||||
self.push(product, position)?;
|
||||
}
|
||||
Instruction::Divide => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let quotient = left.divide(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let quotient = left
|
||||
.divide(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(quotient)?;
|
||||
self.push(quotient, position)?;
|
||||
}
|
||||
Instruction::Greater => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let greater = left.greater_than(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let greater = left
|
||||
.greater_than(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(greater)?;
|
||||
self.push(greater, position)?;
|
||||
}
|
||||
Instruction::Less => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let less = left.less_than(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let less = left
|
||||
.less_than(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(less)?;
|
||||
self.push(less, position)?;
|
||||
}
|
||||
Instruction::GreaterEqual => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let greater_equal = left.greater_than_or_equal(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let greater_equal = left
|
||||
.greater_than_or_equal(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(greater_equal)?;
|
||||
self.push(greater_equal, position)?;
|
||||
}
|
||||
Instruction::LessEqual => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let less_equal = left.less_than_or_equal(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let less_equal = left
|
||||
.less_than_or_equal(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(less_equal)?;
|
||||
self.push(less_equal, position)?;
|
||||
}
|
||||
Instruction::Equal => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let equal = left.equal(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let equal = left
|
||||
.equal(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(equal)?;
|
||||
self.push(equal, position)?;
|
||||
}
|
||||
Instruction::NotEqual => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let not_equal = left.not_equal(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let not_equal = left
|
||||
.not_equal(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(not_equal)?;
|
||||
self.push(not_equal, position)?;
|
||||
}
|
||||
Instruction::And => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let and = left.and(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let and = left
|
||||
.and(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(and)?;
|
||||
self.push(and, position)?;
|
||||
}
|
||||
Instruction::Or => {
|
||||
let right = self.pop()?;
|
||||
let left = self.pop()?;
|
||||
let or = left.or(&right)?;
|
||||
let right = self.pop(position)?;
|
||||
let left = self.pop(position)?;
|
||||
let or = left
|
||||
.or(&right)
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
|
||||
self.push(or)?;
|
||||
self.push(or, position)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,9 +222,9 @@ impl Vm {
|
||||
Ok(self.stack.pop())
|
||||
}
|
||||
|
||||
fn push(&mut self, value: Value) -> Result<(), VmError> {
|
||||
fn push(&mut self, value: Value, position: Span) -> Result<(), VmError> {
|
||||
if self.stack.len() == Self::STACK_SIZE {
|
||||
Err(VmError::StackOverflow)
|
||||
Err(VmError::StackOverflow(position))
|
||||
} else {
|
||||
self.stack.push(value);
|
||||
|
||||
@ -191,48 +232,85 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Result<Value, VmError> {
|
||||
fn pop(&mut self, position: Span) -> Result<Value, VmError> {
|
||||
if let Some(value) = self.stack.pop() {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(VmError::StackUnderflow)
|
||||
Err(VmError::StackUnderflow(position))
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Result<&(u8, Span), VmError> {
|
||||
let current = self.chunk.get_code(self.ip)?;
|
||||
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 })?;
|
||||
|
||||
self.ip += 1;
|
||||
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
fn read_constant(&self, index: u8) -> Result<Value, VmError> {
|
||||
Ok(self.chunk.get_constant(index)?.clone())
|
||||
fn read_constant(&self, index: u8, position: Span) -> Result<&Value, VmError> {
|
||||
let value = self
|
||||
.chunk
|
||||
.get_constant(index)
|
||||
.map_err(|error| VmError::Chunk { error, position })?;
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum VmError {
|
||||
InvalidInstruction(u8, Span),
|
||||
StackUnderflow,
|
||||
StackOverflow,
|
||||
StackOverflow(Span),
|
||||
StackUnderflow(Span),
|
||||
UndefinedVariable(Identifier, Span),
|
||||
|
||||
// Wrappers for foreign errors
|
||||
Chunk(ChunkError),
|
||||
Value(ValueError),
|
||||
Chunk { error: ChunkError, position: Span },
|
||||
Value { error: ValueError, position: Span },
|
||||
}
|
||||
|
||||
impl From<ChunkError> for VmError {
|
||||
fn from(error: ChunkError) -> Self {
|
||||
Self::Chunk(error)
|
||||
impl VmError {
|
||||
pub fn chunk(error: ChunkError, position: Span) -> Self {
|
||||
Self::Chunk { error, position }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ValueError> for VmError {
|
||||
fn from(error: ValueError) -> Self {
|
||||
Self::Value(error)
|
||||
pub fn value(error: ValueError, position: Span) -> Self {
|
||||
Self::Value { error, position }
|
||||
}
|
||||
|
||||
pub fn title(&self) -> &'static str {
|
||||
"VM Error"
|
||||
}
|
||||
|
||||
pub fn description(&self) -> String {
|
||||
match self {
|
||||
Self::InvalidInstruction(byte, _) => {
|
||||
format!("The byte {byte} does not correspond to a valid instruction")
|
||||
}
|
||||
Self::StackOverflow(position) => format!("Stack overflow at {position}"),
|
||||
Self::StackUnderflow(position) => format!("Stack underflow at {position}"),
|
||||
Self::UndefinedVariable(identifier, position) => {
|
||||
format!("{identifier} is not in scope at {position}")
|
||||
}
|
||||
|
||||
Self::Chunk { error, .. } => error.description(),
|
||||
Self::Value { error, .. } => error.description(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
Self::InvalidInstruction(_, position) => *position,
|
||||
Self::StackUnderflow(position) => *position,
|
||||
Self::StackOverflow(position) => *position,
|
||||
Self::UndefinedVariable(_, position) => *position,
|
||||
Self::Chunk { position, .. } => *position,
|
||||
Self::Value { position, .. } => *position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ fn run_and_display_errors(source: &str) {
|
||||
Ok(Some(value)) => println!("{}", value),
|
||||
Ok(_) => {}
|
||||
Err(error) => {
|
||||
eprintln!("{:?}", error);
|
||||
eprintln!("{}", error.report());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user