1use std::fmt;
2
3use crate::SourceOrigin;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct RelatedDiagnostic {
7 pub message: String,
8 pub file: String,
9 pub line: usize,
10 pub column: usize,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct CompileError {
15 pub message: String,
16 pub file: Option<String>,
17 pub line: usize,
18 pub column: usize,
19 pub related: Vec<RelatedDiagnostic>,
20}
21
22impl CompileError {
23 pub(crate) fn new(message: impl Into<String>, line: usize, column: usize) -> Self {
24 Self { message: message.into(), file: None, line, column, related: Vec::new() }
25 }
26
27 pub(crate) fn at(message: impl Into<String>, origin: &SourceOrigin) -> Self {
28 Self {
29 message: message.into(),
30 file: Some(origin.file.clone()),
31 line: origin.line,
32 column: origin.column,
33 related: Vec::new(),
34 }
35 }
36
37 pub(crate) fn with_file(mut self, file: impl Into<String>) -> Self {
38 self.file = Some(file.into());
39 self
40 }
41
42 pub(crate) fn with_related(mut self, message: impl Into<String>, origin: &SourceOrigin) -> Self {
43 self.related.push(RelatedDiagnostic {
44 message: message.into(),
45 file: origin.file.clone(),
46 line: origin.line,
47 column: origin.column,
48 });
49 self
50 }
51}
52
53impl fmt::Display for CompileError {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{}", self.message)?;
56 if let Some(file) = &self.file {
57 write!(f, "\n --> {file}:{}:{}", self.line, self.column)?;
58 } else {
59 write!(f, " at {}:{}", self.line, self.column)?;
60 }
61 for related in &self.related {
62 write!(f, "\n = {}\n --> {}:{}:{}", related.message, related.file, related.line, related.column)?;
63 }
64 Ok(())
65 }
66}
67
68impl std::error::Error for CompileError {}
69
70impl<R: pest::RuleType> From<pest::error::Error<R>> for CompileError {
71 fn from(error: pest::error::Error<R>) -> Self {
72 let (line, column) = match error.line_col {
73 pest::error::LineColLocation::Pos((line, column)) => (line, column),
74 pest::error::LineColLocation::Span((line, column), _) => (line, column),
75 };
76
77 Self::new(error.to_string(), line, column)
78 }
79}