Skip to main content

vm/compiler/
diagnostics.rs

1use 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}