conjure_cp_essence_parser/
errors.rs1pub use conjure_cp_core::error::Error as ConjureParseError;
2use conjure_cp_core::error::Error;
3use serde_json::Error as JsonError;
4use thiserror::Error as ThisError;
5
6#[derive(Debug, ThisError)]
7pub enum FatalParseError {
8 #[error("Could not parse Essence AST: {0}")]
9 TreeSitterError(String),
10 #[error("Error running `conjure pretty`: {0}")]
11 ConjurePrettyError(String),
12 #[error("Essence syntax error: {msg}{}",
13 match range {
14 Some(range) => format!(" at {}-{}", range.start_point, range.end_point),
15 None => "".to_string(),
16 }
17 )]
18 ParseError {
19 msg: String,
20 range: Option<tree_sitter::Range>,
21 },
22 #[error("JSON Error: {0}")]
23 JsonError(#[from] JsonError),
24 #[error("Error: {0} is not yet implemented.")]
25 NotImplemented(String),
26 #[error("Error: {0}")]
27 Other(Error),
28}
29
30impl FatalParseError {
31 pub fn syntax_error(msg: String, range: Option<tree_sitter::Range>) -> Self {
32 FatalParseError::ParseError { msg, range }
33 }
34}
35
36impl From<ConjureParseError> for FatalParseError {
37 fn from(value: ConjureParseError) -> Self {
38 match value {
39 Error::Parse(msg) => FatalParseError::syntax_error(msg, None),
40 Error::NotImplemented(msg) => FatalParseError::NotImplemented(msg),
41 Error::Json(err) => FatalParseError::JsonError(err),
42 Error::Other(err) => FatalParseError::Other(err.into()),
43 }
44 }
45}
46
47#[derive(Debug)]
48pub struct RecoverableParseError {
49 pub msg: String,
50 pub range: Option<tree_sitter::Range>,
51 pub file_name: Option<String>,
52 pub source_code: Option<String>,
53}
54
55impl RecoverableParseError {
56 pub fn new(msg: String, range: Option<tree_sitter::Range>) -> Self {
57 Self {
58 msg,
59 range,
60 file_name: None,
61 source_code: None,
62 }
63 }
64
65 pub fn enrich(mut self, file_name: Option<String>, source_code: Option<String>) -> Self {
66 self.file_name = file_name;
67 self.source_code = source_code;
68 self
69 }
70}
71
72impl std::fmt::Display for RecoverableParseError {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 if let (Some(range), Some(file_name), Some(source_code)) =
76 (&self.range, &self.file_name, &self.source_code)
77 {
78 let line_num = range.start_point.row + 1; let col_num = range.start_point.column + 1; let lines: Vec<&str> = source_code.lines().collect();
83 let line_content = lines.get(range.start_point.row).unwrap_or(&"");
84
85 let pointer = " ".repeat(range.start_point.column) + "^";
87
88 write!(
89 f,
90 "{}:{}:{}:\n |\n{} | {}\n | {}\n{}",
91 file_name, line_num, col_num, line_num, line_content, pointer, self.msg
92 )
93 } else {
94 write!(f, "Essence syntax error: {}", self.msg)?;
96 if let Some(range) = &self.range {
97 write!(f, " at {}-{}", range.start_point, range.end_point)?;
98 }
99 Ok(())
100 }
101 }
102}
103
104#[derive(Debug)]
106pub enum ParseErrorCollection {
107 Fatal(FatalParseError),
109 Multiple { errors: Vec<RecoverableParseError> },
111}
112
113impl ParseErrorCollection {
114 pub fn fatal(error: FatalParseError) -> Self {
116 ParseErrorCollection::Fatal(error)
117 }
118
119 pub fn multiple(
122 errors: Vec<RecoverableParseError>,
123 source_code: Option<String>,
124 file_name: Option<String>,
125 ) -> Self {
126 let enriched_errors = errors
127 .into_iter()
128 .map(|err| err.enrich(file_name.clone(), source_code.clone()))
129 .collect();
130 ParseErrorCollection::Multiple {
131 errors: enriched_errors,
132 }
133 }
134}
135
136impl std::fmt::Display for ParseErrorCollection {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 ParseErrorCollection::Fatal(error) => write!(f, "{}", error),
140 ParseErrorCollection::Multiple { errors } => {
141 let mut indices: Vec<usize> = (0..errors.len()).collect();
143 indices.sort_by(|&a, &b| {
144 match (&errors[a], &errors[b]) {
145 (
146 RecoverableParseError {
147 range: Some(r1), ..
148 },
149 RecoverableParseError {
150 range: Some(r2), ..
151 },
152 ) => {
153 match r1.start_point.row.cmp(&r2.start_point.row) {
155 std::cmp::Ordering::Equal => {
156 r1.start_point.column.cmp(&r2.start_point.column)
157 }
158 other => other,
159 }
160 }
161 (RecoverableParseError { range: Some(_), .. }, _) => {
163 std::cmp::Ordering::Less
164 }
165 (_, RecoverableParseError { range: Some(_), .. }) => {
166 std::cmp::Ordering::Greater
167 }
168 _ => std::cmp::Ordering::Equal,
169 }
170 });
171
172 for (i, &idx) in indices.iter().enumerate() {
174 if i > 0 {
175 write!(f, "\n\n")?;
176 }
177 write!(f, "{}", errors[idx])?;
178 }
179 Ok(())
180 }
181 }
182 }
183}
184
185impl std::error::Error for ParseErrorCollection {}