1use crate::diagnostics::{
2 byte_offset_for_line_column, DiagnosticSeverity, FileSourceDiagnostics, SourceDiagnostic,
3};
4use ariadne::{Color, Label, Report, ReportKind, Source};
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8pub enum CobbleError {
9 #[error("Parse error")]
10 ParseError(String),
11
12 #[error("IO error: {0}")]
13 IoError(#[from] std::io::Error),
14
15 #[error("Transpilation error: {0}")]
16 TranspileError(String),
17}
18
19pub fn report_error(filename: &str, src: &str, error: &CobbleError) {
20 match error {
21 CobbleError::ParseError(msg) => {
22 Report::build(ReportKind::Error, (filename, 0..1))
23 .with_message("Parse Error")
24 .with_label(
25 Label::new((filename, 0..1))
26 .with_message(msg.clone())
27 .with_color(Color::Red),
28 )
29 .finish()
30 .print((filename, Source::from(src)))
31 .unwrap();
32 }
33 CobbleError::TranspileError(msg) => {
34 Report::build(ReportKind::Error, (filename, 0..1))
35 .with_message("Transpilation Error")
36 .with_label(
37 Label::new((filename, 0..1))
38 .with_message(msg.clone())
39 .with_color(Color::Red),
40 )
41 .finish()
42 .print((filename, Source::from(src)))
43 .unwrap();
44 }
45 CobbleError::IoError(e) => {
46 eprintln!("IO Error: {}", e);
47 }
48 }
49}
50
51pub fn report_parse_errors(filename: &str, src: &str, errors: &[String]) {
53 for error in errors {
54 eprintln!("Parse error in {}: {}", filename, error);
55 }
56
57 if errors.len() == 1 {
59 Report::build(ReportKind::Error, (filename, 0..src.len().min(1)))
60 .with_message("Parse Error")
61 .with_note(&errors[0])
62 .finish()
63 .eprint((filename, Source::from(src)))
64 .ok();
65 }
66}
67
68pub fn report_source_diagnostics(filename: &str, src: &str, diagnostics: &[SourceDiagnostic]) {
69 for diagnostic in diagnostics {
70 let start = byte_offset_for_line_column(src, diagnostic.line, diagnostic.column);
71 let end = (start + 1).min(src.len());
72 let color = match diagnostic.severity {
73 DiagnosticSeverity::Error => Color::Red,
74 DiagnosticSeverity::Warning => Color::Yellow,
75 };
76 let report_kind = match diagnostic.severity {
77 DiagnosticSeverity::Error => ReportKind::Error,
78 DiagnosticSeverity::Warning => ReportKind::Warning,
79 };
80
81 let mut report = Report::build(report_kind, (filename, start..end))
82 .with_message(format!("{}: {}", diagnostic.kind, diagnostic.message))
83 .with_label(
84 Label::new((filename, start..end))
85 .with_message(diagnostic.message.clone())
86 .with_color(color),
87 );
88
89 if let Some(help) = &diagnostic.help {
90 report = report.with_note(help);
91 }
92
93 report.finish().eprint((filename, Source::from(src))).ok();
94 }
95}
96
97pub fn report_file_source_diagnostics(diagnostics: &[FileSourceDiagnostics]) {
98 for file_diagnostics in diagnostics {
99 let filename = file_diagnostics.path.to_string_lossy();
100 report_source_diagnostics(
101 &filename,
102 &file_diagnostics.source,
103 &file_diagnostics.diagnostics,
104 );
105 }
106}