Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
419 changes: 328 additions & 91 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ selen = "0.15.5"
sha2 = "0.10.9"
serde = { version = "1.0.228", features = ["derive"] }
hex = "0.4.3"
boolmesh = { version = "0.1.7", features = ["rayon"] }
# boolmesh = { version = "0.1.7", features = ["rayon"] }
boolmesh = { git = "https://github.com/IamTheCarl/boolmesh.git", branch = "serde", features = ["rayon", "serde"] }
stl_io = "0.10.0"
itertools = "0.14.0"
thiserror = "2.0.18"

[build-dependencies]
type-sitter-gen = "0.8"
Expand Down
55 changes: 46 additions & 9 deletions interpreter/src/execution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ use std::{any::Any, borrow::Cow, fmt::Display};

use ariadne::{Label, Report, ReportKind};

use crate::compile::SourceReference;
use crate::{compile::SourceReference, StackTrace};

pub type ExpressionResult<R> = std::result::Result<R, Error>;
pub type ExecutionResult<R> = std::result::Result<R, Error>;

#[derive(Debug)]
pub struct Error {
pub ty: Box<dyn ErrorType>,
pub trace: Vec<SourceReference>,
pub failure_chain: Vec<Cow<'static, str>>,
}

impl Error {
Expand All @@ -38,6 +39,8 @@ impl Error {
builder.set_message("Failed to evaluate");
builder.add_label(Label::new(bottom).with_message(format!("{}", self.ty)));

builder.with_helps(self.failure_chain.iter());

builder.finish()
}
}
Expand All @@ -58,27 +61,61 @@ impl std::error::Error for Error {}

/// A generic error that will just display a static message.
#[derive(Debug, Eq, PartialEq)]
pub struct GenericFailure(pub Cow<'static, str>);
pub struct StrError(pub &'static str);

impl ErrorType for GenericFailure {}
impl std::error::Error for StrError {}

impl Display for GenericFailure {
impl Display for StrError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

pub trait ErrorType: std::fmt::Debug + std::fmt::Display + Any + Send + Sync {}
/// A generic error that will just display a formatted message.
#[derive(Debug, Eq, PartialEq)]
pub struct StringError(pub String);

impl std::error::Error for StringError {}

impl Display for StringError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

pub trait ErrorType: std::error::Error + Send + Sync + Any {
fn as_any(&self) -> &dyn Any;
}

impl<E> ErrorType for E
where
E: std::error::Error + Send + Sync + Any,
{
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
}

pub trait Raise {
fn to_error<'s>(self, stack_trace: impl IntoIterator<Item = &'s SourceReference>) -> Error;
fn to_error<'s>(self, stack_trace: impl IntoIterator<Item = &'s StackTrace<'s>>) -> Error;
}

impl<E: ErrorType> Raise for E {
fn to_error<'s>(self, stack_trace: impl IntoIterator<Item = &'s SourceReference>) -> Error {
fn to_error<'s>(self, stack_trace: impl IntoIterator<Item = &'s StackTrace<'s>>) -> Error {
let mut trace = Vec::new();
let mut failure_chain = Vec::new();

for layer in stack_trace {
trace.push(layer.reference.clone());
if let Some(message) = layer.failure_message.clone() {
failure_chain.push(message);
}
}

Error {
ty: Box::new(self),
trace: stack_trace.into_iter().cloned().collect(),
trace,
failure_chain,
}
}
}
41 changes: 29 additions & 12 deletions interpreter/src/execution/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ impl RuntimeLog for Mutex<Vec<LogMessage>> {

#[derive(Debug, Clone)]
pub struct StackTrace<'p> {
parent: Option<&'p StackTrace<'p>>,
reference: SourceReference,
pub parent: Option<&'p StackTrace<'p>>,
pub reference: SourceReference,
pub failure_message: Option<Cow<'static, str>>,
}

impl<'p> Display for StackTrace<'p> {
Expand All @@ -76,6 +77,7 @@ impl StackTrace<'static> {
Self {
parent: None,
reference,
failure_message: None,
}
}

Expand All @@ -92,6 +94,7 @@ impl StackTrace<'static> {
end_point: Point { row: 0, column: 0 },
},
},
failure_message: Some("Bootstrap failed".into()),
}
}

Expand All @@ -108,21 +111,35 @@ impl StackTrace<'static> {
end_point: Point { row: 0, column: 0 },
},
},
failure_message: Some("Test failed".into()),
}
}
}

impl<'p> StackTrace<'p> {
pub fn trace_scope<F, R>(&'p self, reference: impl Into<SourceReference>, code: F) -> R
pub fn trace_scope<F, R>(
&'p self,
failure_message: Option<Cow<'static, str>>,
reference: impl Into<SourceReference>,
code: F,
) -> R
where
F: FnOnce(StackTrace<'p>) -> R,
F: FnOnce(&StackTrace<'p>) -> R,
{
let scope = Self {
parent: Some(self),
reference: reference.into(),
};
let reference = reference.into();

code(scope)
if self.reference != reference || self.failure_message != failure_message {
let scope = Self {
parent: Some(self),
reference,
failure_message,
};

code(&scope)
} else {
// This is not actually a new scope
code(self)
}
}

pub fn bottom(&self) -> &SourceReference {
Expand All @@ -137,7 +154,7 @@ impl<'p> StackTrace<'p> {
}

impl<'p> IntoIterator for &'p StackTrace<'p> {
type Item = &'p SourceReference;
type Item = &'p StackTrace<'p>;
type IntoIter = StackTraceIter<'p>;

fn into_iter(self) -> Self::IntoIter {
Expand All @@ -150,14 +167,14 @@ pub struct StackTraceIter<'p> {
}

impl<'p> Iterator for StackTraceIter<'p> {
type Item = &'p SourceReference;
type Item = &'p StackTrace<'p>;

fn next(&mut self) -> Option<Self::Item> {
let next = self.current.take();
if let Some(next) = next {
self.current = next.parent;
}
next.map(|next| &next.reference)
next
}
}

Expand Down
Loading