Improved errors
This commit is contained in:
+33
-32
@@ -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,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());
|
||||||
|
|||||||
Reference in New Issue
Block a user