vm/compiler/
diagnostics.rs1use super::source_map::{SourceMap, Span};
2use super::{CompileError, ParseError};
3
4pub fn render_source_error(source_map: &SourceMap, err: &ParseError, _styled: bool) -> String {
5 let code_prefix = err
6 .code
7 .as_deref()
8 .map(|code| format!("error[{code}]"))
9 .unwrap_or_else(|| "error".to_string());
10
11 if let Some(span) = err.span
12 && let Some(rendered) = render_span_snippet(source_map, span, &err.message)
13 {
14 return format!("{code_prefix}: {}", rendered.trim_end());
15 }
16
17 format!("{code_prefix}: line {}: {}", err.line, err.message)
18}
19
20pub fn render_compile_error(source_map: &SourceMap, err: &CompileError, _styled: bool) -> String {
21 let message = err.diagnostic_message();
22 let source_id = err
23 .source_name()
24 .and_then(|name| source_map.source_id_by_name(name))
25 .unwrap_or(0);
26
27 if let Some(line) = err.line()
28 && let Some(span) = source_map.line_span(source_id, line)
29 && let Some(rendered) = render_span_snippet(source_map, span, &message)
30 {
31 return format!("compile error: {}", rendered.trim_end());
32 }
33
34 if let Some(line) = err.line() {
35 if let Some(source_name) = err.source_name() {
36 return format!("compile error: {source_name}:{line}: {message}");
37 }
38 return format!("compile error: line {line}: {message}");
39 }
40
41 format!("compile error: {message}")
42}
43
44fn render_span_snippet(source_map: &SourceMap, span: Span, message: &str) -> Option<String> {
45 let file = source_map.file(span.source_id)?;
46 let (line, col) = file.line_col_for_offset(span.lo)?;
47 let line_text = file.line_text(line)?;
48 let pointer_width = span.len().max(1);
49 let pointer = format!(
50 "{}{}",
51 " ".repeat(col.saturating_sub(1)),
52 "^".repeat(pointer_width)
53 );
54 Some(format!(
55 "{message}\n --> {}:{line}:{col}\n |\n{line:>3} | {line_text}\n | {pointer}",
56 file.name
57 ))
58}