Add Elm-style error diagnostics
Implement beautiful, informative error messages inspired by Elm: - Rich diagnostic rendering with source code snippets - Colored output with proper underlines showing error locations - Categorized error titles (Type Mismatch, Unknown Name, etc.) - Contextual hints and suggestions for common errors - Support for type errors, runtime errors, and parse errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::diagnostics::{Diagnostic, Severity};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
@@ -327,6 +328,74 @@ impl fmt::Display for RuntimeError {
|
||||
|
||||
impl std::error::Error for RuntimeError {}
|
||||
|
||||
impl RuntimeError {
|
||||
/// Convert to a rich diagnostic for Elm-style error display
|
||||
pub fn to_diagnostic(&self) -> Diagnostic {
|
||||
let (title, hints) = categorize_runtime_error(&self.message);
|
||||
|
||||
Diagnostic {
|
||||
severity: Severity::Error,
|
||||
title,
|
||||
message: self.message.clone(),
|
||||
span: self.span.unwrap_or_default(),
|
||||
hints,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Categorize runtime errors to provide better titles and hints
|
||||
fn categorize_runtime_error(message: &str) -> (String, Vec<String>) {
|
||||
let message_lower = message.to_lowercase();
|
||||
|
||||
if message_lower.contains("undefined") || message_lower.contains("not found") {
|
||||
(
|
||||
"Undefined Reference".to_string(),
|
||||
vec!["Make sure the name is defined and in scope.".to_string()],
|
||||
)
|
||||
} else if message_lower.contains("division by zero") || message_lower.contains("divide by zero") {
|
||||
(
|
||||
"Division by Zero".to_string(),
|
||||
vec![
|
||||
"Check that the divisor is not zero before dividing.".to_string(),
|
||||
"Consider using a guard or match to handle this case.".to_string(),
|
||||
],
|
||||
)
|
||||
} else if message_lower.contains("type") && message_lower.contains("mismatch") {
|
||||
(
|
||||
"Type Mismatch".to_string(),
|
||||
vec!["The value has a different type than expected.".to_string()],
|
||||
)
|
||||
} else if message_lower.contains("effect") && message_lower.contains("unhandled") {
|
||||
(
|
||||
"Unhandled Effect".to_string(),
|
||||
vec![
|
||||
"This effect must be handled before the program can continue.".to_string(),
|
||||
"Wrap this code in a 'handle' expression.".to_string(),
|
||||
],
|
||||
)
|
||||
} else if message_lower.contains("pattern") && message_lower.contains("match") {
|
||||
(
|
||||
"Non-exhaustive Pattern".to_string(),
|
||||
vec!["Add more patterns to cover all possible cases.".to_string()],
|
||||
)
|
||||
} else if message_lower.contains("argument") {
|
||||
(
|
||||
"Wrong Arguments".to_string(),
|
||||
vec!["Check the number and types of arguments provided.".to_string()],
|
||||
)
|
||||
} else if message_lower.contains("index") || message_lower.contains("bounds") {
|
||||
(
|
||||
"Index Out of Bounds".to_string(),
|
||||
vec![
|
||||
"The index is outside the valid range.".to_string(),
|
||||
"Check the length of the collection before accessing.".to_string(),
|
||||
],
|
||||
)
|
||||
} else {
|
||||
("Runtime Error".to_string(), vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// Effect operation request
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EffectRequest {
|
||||
|
||||
Reference in New Issue
Block a user