Skip to main content

dinoco_compiler/
error.rs

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}