dust/src/error.rs

186 lines
5.8 KiB
Rust
Raw Normal View History

2024-03-17 17:36:31 +00:00
use std::{ops::Range, sync::PoisonError};
2024-02-25 18:49:26 +00:00
2024-03-17 17:36:31 +00:00
use ariadne::{Label, ReportBuilder};
2024-03-16 19:01:45 +00:00
use chumsky::{prelude::Rich, span::Span};
2024-02-25 18:49:26 +00:00
2024-03-06 22:32:31 +00:00
use crate::{
2024-03-17 11:48:06 +00:00
abstract_tree::{Identifier, SourcePosition, Type},
2024-03-06 22:32:31 +00:00
lexer::Token,
};
2024-02-25 18:49:26 +00:00
#[derive(Debug, PartialEq)]
2024-03-06 20:36:58 +00:00
pub enum Error {
2024-03-06 22:32:31 +00:00
Parse {
expected: String,
2024-03-16 19:01:45 +00:00
span: (usize, usize),
2024-03-06 22:32:31 +00:00
},
Lex {
expected: String,
2024-03-16 19:01:45 +00:00
span: (usize, usize),
2024-03-06 22:32:31 +00:00
},
2024-03-17 17:36:31 +00:00
Runtime {
error: RuntimeError,
position: SourcePosition,
},
2024-03-17 11:31:45 +00:00
Validation {
error: ValidationError,
2024-03-17 11:48:06 +00:00
position: SourcePosition,
2024-03-17 11:31:45 +00:00
},
2024-02-25 18:49:26 +00:00
}
2024-03-07 03:15:35 +00:00
impl Error {
2024-03-17 17:36:31 +00:00
pub fn build_report(
self,
mut builder: ReportBuilder<'_, Range<usize>>,
) -> ReportBuilder<'_, Range<usize>> {
2024-03-07 03:15:35 +00:00
match self {
2024-03-16 19:01:45 +00:00
Error::Parse { expected, span } => {
let message = match expected.as_str() {
"" => "Invalid character.".to_string(),
expected => format!("Expected {expected}."),
};
2024-03-17 17:36:31 +00:00
builder.add_label(Label::new(span.0..span.1).with_message(message));
2024-03-16 19:01:45 +00:00
}
2024-03-07 03:15:35 +00:00
Error::Lex { expected, span } => {
2024-03-16 19:01:45 +00:00
let message = match expected.as_str() {
"" => "Invalid character.".to_string(),
expected => format!("Expected {expected}."),
2024-03-07 03:15:35 +00:00
};
2024-03-17 17:36:31 +00:00
builder.add_label(Label::new(span.0..span.1).with_message(message));
2024-03-07 03:15:35 +00:00
}
2024-03-17 17:36:31 +00:00
Error::Runtime { error, position } => match error {
RuntimeError::RwLockPoison(_) => todo!(),
RuntimeError::ValidationFailure(validation_error) => {
builder =
Error::Validation {
error: validation_error,
position,
}
.build_report(builder.with_note(
"The interpreter failed to catch this error during validation.",
));
2024-03-07 03:15:35 +00:00
}
2024-03-17 17:36:31 +00:00
},
Error::Validation { error, position } => match error {
ValidationError::ExpectedBoolean => {
builder.add_label(Label::new(0..0).with_message("Expected boolean."));
}
ValidationError::ExpectedIntegerOrFloat => {
builder.add_label(Label::new(0..0).with_message("Expected integer or float."));
}
ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck {
conflict,
actual_position,
expected_position: expected_postion,
} => {
let TypeConflict { actual, expected } = conflict;
builder.add_labels([
Label::new(expected_postion.0..expected_postion.1)
.with_message(format!("Type {expected} established here.")),
Label::new(actual_position.0..actual_position.1)
.with_message(format!("Got type {actual} here.")),
]);
}
ValidationError::VariableNotFound(identifier) => {
builder.add_label(
Label::new(position.0..position.1)
.with_message(format!("The variable {identifier} does not exist."))
.with_priority(1),
);
}
ValidationError::CannotIndex(_) => todo!(),
ValidationError::CannotIndexWith(_, _) => todo!(),
ValidationError::InterpreterExpectedReturn => todo!(),
ValidationError::ExpectedFunction => todo!(),
ValidationError::ExpectedValue => todo!(),
},
2024-03-07 03:15:35 +00:00
}
2024-03-17 17:36:31 +00:00
builder
2024-03-07 03:15:35 +00:00
}
}
2024-03-06 20:36:58 +00:00
impl From<Rich<'_, char>> for Error {
fn from(error: Rich<'_, char>) -> Self {
Error::Lex {
expected: error.expected().map(|error| error.to_string()).collect(),
2024-03-16 19:01:45 +00:00
span: (error.span().start(), error.span().end()),
2024-03-06 20:36:58 +00:00
}
2024-02-25 18:49:26 +00:00
}
}
2024-03-06 20:36:58 +00:00
impl<'src> From<Rich<'_, Token<'src>>> for Error {
fn from(error: Rich<'_, Token<'src>>) -> Self {
Error::Parse {
expected: error.expected().map(|error| error.to_string()).collect(),
2024-03-16 19:01:45 +00:00
span: (error.span().start(), error.span().end()),
2024-03-06 20:36:58 +00:00
}
}
}
2024-02-25 18:49:26 +00:00
#[derive(Debug, PartialEq)]
pub enum RuntimeError {
RwLockPoison(RwLockPoisonError),
ValidationFailure(ValidationError),
2024-02-25 18:49:26 +00:00
}
impl From<RwLockPoisonError> for RuntimeError {
fn from(error: RwLockPoisonError) -> Self {
RuntimeError::RwLockPoison(error)
}
}
impl From<ValidationError> for RuntimeError {
fn from(error: ValidationError) -> Self {
RuntimeError::ValidationFailure(error)
}
}
#[derive(Debug, PartialEq)]
pub enum ValidationError {
2024-03-07 17:29:07 +00:00
CannotIndex(Type),
CannotIndexWith(Type, Type),
ExpectedBoolean,
2024-03-09 13:10:54 +00:00
ExpectedFunction,
2024-03-07 11:33:54 +00:00
ExpectedIntegerOrFloat,
2024-03-09 13:10:54 +00:00
ExpectedValue,
2024-03-08 17:24:11 +00:00
InterpreterExpectedReturn,
2024-03-06 17:15:03 +00:00
RwLockPoison(RwLockPoisonError),
2024-03-17 04:49:01 +00:00
TypeCheck {
/// The mismatch that caused the error.
conflict: TypeConflict,
/// The position of the item that gave the "actual" type.
2024-03-17 11:48:06 +00:00
actual_position: SourcePosition,
2024-03-17 04:49:01 +00:00
/// The position of the item that gave the "expected" type.
2024-03-17 11:48:06 +00:00
expected_position: SourcePosition,
2024-03-17 04:49:01 +00:00
},
2024-03-06 22:32:31 +00:00
VariableNotFound(Identifier),
}
impl From<RwLockPoisonError> for ValidationError {
fn from(error: RwLockPoisonError) -> Self {
ValidationError::RwLockPoison(error)
}
}
2024-02-25 18:49:26 +00:00
#[derive(Debug, PartialEq)]
pub struct RwLockPoisonError;
impl<T> From<PoisonError<T>> for RwLockPoisonError {
fn from(_: PoisonError<T>) -> Self {
RwLockPoisonError
}
}
2024-03-06 17:15:03 +00:00
#[derive(Debug, PartialEq)]
2024-03-17 04:49:01 +00:00
pub struct TypeConflict {
2024-03-06 17:15:03 +00:00
pub actual: Type,
pub expected: Type,
}