Improved errors

This commit is contained in:
2026-06-24 14:33:11 +02:00
parent 1f2e989522
commit 9ce6d44eb4
2 changed files with 44 additions and 38 deletions
+33 -32
View File
@@ -7,7 +7,6 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use mist_parser::error::ParseError; use mist_parser::error::ParseError;
use mist_parser::parse;
use mist_parser::rev_mapper::{Mapping, MistMap, RustMap}; use mist_parser::rev_mapper::{Mapping, MistMap, RustMap};
use ropey::Rope; use ropey::Rope;
use serde::Deserialize; use serde::Deserialize;
@@ -17,7 +16,7 @@ use tower_lsp::lsp_types::{self, *};
use tower_lsp::{Client, LanguageServer, LspService, Server}; use tower_lsp::{Client, LanguageServer, LspService, Server};
use crate::rust_analyzer::RustAnalyzer; use crate::rust_analyzer::RustAnalyzer;
use crate::transpiler::{transpile_mist, transpile_mist_no_sem}; use crate::transpiler::{TranspileError, transpile_mist, transpile_mist_no_sem};
static MARKER_COUNTER: AtomicU64 = AtomicU64::new(0); static MARKER_COUNTER: AtomicU64 = AtomicU64::new(0);
@@ -240,9 +239,9 @@ struct MarkerRestore {
/// Re-parse the source to extract a proper LSP diagnostic from the error. /// Re-parse the source to extract a proper LSP diagnostic from the error.
/// Returns None when the error is a semantic check failure (can be multiple /// Returns None when the error is a semantic check failure (can be multiple
/// errors) or when re-parsing unexpectedly succeeds. /// errors) or when re-parsing unexpectedly succeeds.
fn transpile_error_to_diagnostic(source: &str) -> Option<Diagnostic> { fn transpile_error_to_diagnostic(source: &str, error: TranspileError<'_>) -> Vec<Diagnostic> {
match parse(source) { match error {
Err(ParseError::PreAst(pest_err)) => { TranspileError::Parse(ParseError::PreAst(pest_err)) => {
let (line, col) = match pest_err.line_col { let (line, col) = match pest_err.line_col {
pest::error::LineColLocation::Pos((l, c)) => (l, c), pest::error::LineColLocation::Pos((l, c)) => (l, c),
pest::error::LineColLocation::Span((l, c), _) => (l, c), pest::error::LineColLocation::Span((l, c), _) => (l, c),
@@ -281,7 +280,7 @@ fn transpile_error_to_diagnostic(source: &str) -> Option<Diagnostic> {
} }
pest::error::ErrorVariant::CustomError { message } => message.clone(), pest::error::ErrorVariant::CustomError { message } => message.clone(),
}; };
Some(Diagnostic { vec![Diagnostic {
range: Range { range: Range {
start: Position { start: Position {
line: line as u32 - 1, line: line as u32 - 1,
@@ -296,20 +295,38 @@ fn transpile_error_to_diagnostic(source: &str) -> Option<Diagnostic> {
source: Some("mist".to_string()), source: Some("mist".to_string()),
message, message,
..Default::default() ..Default::default()
}) }]
} }
Err(ParseError::Ast(ast_err)) => { TranspileError::Parse(ParseError::Ast(ast_err)) => {
let start = byte_offset_to_lsp_pos(source, ast_err.span.start()); let start = byte_offset_to_lsp_pos(source, ast_err.span.start());
let end = byte_offset_to_lsp_pos(source, ast_err.span.end()); let end = byte_offset_to_lsp_pos(source, ast_err.span.end());
Some(Diagnostic { vec![Diagnostic {
range: Range { start, end }, range: Range { start, end },
severity: Some(DiagnosticSeverity::ERROR), severity: Some(DiagnosticSeverity::ERROR),
source: Some("mist".to_string()), source: Some("mist".to_string()),
message: ast_err.error_message.clone(), message: ast_err.error_message.clone(),
..Default::default() ..Default::default()
}) }]
} }
Ok(_) => None, TranspileError::Semantic(e) => e
.into_iter()
.map(|e| Diagnostic {
range: Range {
start: Position {
line: e.line as u32 - 1,
character: e.column as u32 - 1,
},
end: Position {
line: e.line as u32 - 1,
character: e.column as u32,
},
},
severity: Some(DiagnosticSeverity::ERROR),
source: Some("mist".to_string()),
message: e.error_message,
..Default::default()
})
.collect(),
} }
} }
@@ -512,25 +529,10 @@ impl Backend {
let transpiled = match transpile_mist(mist_path, source, extra_mod_decl) { let transpiled = match transpile_mist(mist_path, source, extra_mod_decl) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
eprintln!("transpile error for {:?}: {e}", mist_path); eprintln!("transpile error for {:?}: {e:?}", mist_path);
let diag = transpile_error_to_diagnostic(source).unwrap_or_else(|| Diagnostic { let diag = transpile_error_to_diagnostic(source, e);
range: Range {
start: Position {
line: 0,
character: 0,
},
end: Position {
line: 0,
character: 1,
},
},
severity: Some(DiagnosticSeverity::ERROR),
source: Some("mist".to_string()),
message: format!("Transpile error: {e}"),
..Default::default()
});
if let Some(uri) = clean_lsp_url(mist_path) { if let Some(uri) = clean_lsp_url(mist_path) {
self.publish_diagnostics(uri, vec![diag]).await; self.publish_diagnostics(uri, diag).await;
} }
return; return;
} }
@@ -758,7 +760,7 @@ impl LanguageServer for Backend {
let transpiled = match transpile_mist(file, &source, decl) { let transpiled = match transpile_mist(file, &source, decl) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
eprintln!("transpile error for {:?}: {e}", file); eprintln!("transpile error for {:?}: {e:?}", file);
continue; continue;
} }
}; };
@@ -990,8 +992,7 @@ impl LanguageServer for Backend {
self.restore_after_marker(restore).await; self.restore_after_marker(restore).await;
} }
match completion_result match completion_result {
{
Ok(Some(CompletionResponse::Array(items))) => { Ok(Some(CompletionResponse::Array(items))) => {
let mut cleaned: Vec<CompletionItem> = let mut cleaned: Vec<CompletionItem> =
items.into_iter().map(clean_completion_item).collect(); items.into_iter().map(clean_completion_item).collect();
+11 -6
View File
@@ -11,11 +11,17 @@ pub struct TranspiledFile {
pub mapping: Mapping, pub mapping: Mapping,
} }
pub fn transpile_mist( #[derive(Debug)]
pub enum TranspileError<'a> {
Parse(mist_parser::error::ParseError<'a, Vec<mist_parser::ast::TopLevel>>),
Semantic(Vec<mist_parser::semantics::SemanticError>),
}
pub fn transpile_mist<'a>(
mist_path: &Path, mist_path: &Path,
source: &str, source: &'a str,
extra_mod_decl: &str, extra_mod_decl: &str,
) -> Result<TranspiledFile, String> { ) -> Result<TranspiledFile, TranspileError<'a>> {
let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf()); let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf());
// Package files (package.mist) must output as <dir>/mod.rs so the Rust module // Package files (package.mist) must output as <dir>/mod.rs so the Rust module
// hierarchy resolves correctly (pub mod <child>; declarations look for sibling // hierarchy resolves correctly (pub mod <child>; declarations look for sibling
@@ -24,11 +30,10 @@ pub fn transpile_mist(
rust_path.set_file_name("mod.rs"); rust_path.set_file_name("mod.rs");
} }
let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; let parsed = parse(source).map_err(TranspileError::Parse)?;
for item in &parsed.items { for item in &parsed.items {
mist_parser::semantics::check_class_semantics(item) mist_parser::semantics::check_class_semantics(item).map_err(TranspileError::Semantic)?;
.map_err(|e| format!("semantic error: {}", e[0].error_message))?;
} }
let mut codegen = RustCodegen::new(mist_path.to_path_buf()); let mut codegen = RustCodegen::new(mist_path.to_path_buf());