1use santiago::lexer::Lexeme;
6use std::collections::BTreeMap;
7use std::sync::{Arc, Mutex};
8use std::{error, fmt, iter};
9
10use crate::types;
11
12use super::Position;
13
14#[derive(Clone, Debug, Default)]
16pub struct ErrorSet {
17 context: Option<Arc<str>>,
18 line_map: Arc<Mutex<Vec<usize>>>,
19 errors: BTreeMap<Option<Position>, Vec<Error>>,
20}
21
22impl<T> From<santiago::parser::ParseError<T>> for ErrorSet {
23 fn from(e: santiago::parser::ParseError<T>) -> Self {
24 let lex = e.at.map(|rc| (*rc).clone());
25 match lex.as_ref().map(|lex| &lex.position).map(Position::from) {
26 Some(pos) => ErrorSet::single(pos, Error::ParseFailed(lex)),
27 None => ErrorSet::single_no_position(Error::ParseFailed(lex)),
28 }
29 }
30}
31
32impl From<santiago::lexer::LexerError> for ErrorSet {
33 fn from(e: santiago::lexer::LexerError) -> Self {
34 ErrorSet::single(e.position, Error::LexFailed(e.message))
35 }
36}
37
38impl ErrorSet {
39 pub fn new() -> Self {
41 ErrorSet::default()
42 }
43
44 pub fn first_error(&self) -> Option<(Option<Position>, &Error)> {
47 self.errors.iter().next().map(|(a, b)| (*a, &b[0]))
48 }
49
50 pub fn iter(&self) -> impl Iterator<Item = &Error> {
52 self.errors.values().flatten()
53 }
54
55 pub fn single<P: Into<Position>, E: Into<Error>>(position: P, err: E) -> Self {
57 let mut errors = BTreeMap::default();
58 errors.insert(Some(position.into()), vec![err.into()]);
59 ErrorSet {
60 context: None,
61 line_map: Arc::new(Mutex::new(vec![])),
62 errors,
63 }
64 }
65
66 pub fn single_no_position<E: Into<Error>>(err: E) -> Self {
68 let mut errors = BTreeMap::default();
69 errors.insert(None, vec![err.into()]);
70 ErrorSet {
71 context: None,
72 line_map: Arc::new(Mutex::new(vec![])),
73 errors,
74 }
75 }
76
77 pub fn add<P: Into<Position>, E: Into<Error>>(&mut self, position: P, err: E) {
79 self.errors
80 .entry(Some(position.into()))
81 .or_default()
82 .push(err.into());
83 }
84
85 pub fn add_no_position<E: Into<Error>>(&mut self, err: E) {
87 self.errors.entry(None).or_default().push(err.into());
88 }
89
90 pub fn merge(&mut self, other: &Self) {
96 match (self.context.as_ref(), other.context.as_ref()) {
97 (None, None) => {}
98 (Some(_), None) => {}
99 (None, Some(b)) => self.context = Some(Arc::clone(b)),
100 (Some(a), Some(b)) => {
101 assert_eq!(a, b, "cannot merge error sets for different source input");
102 }
103 };
104
105 for (pos, errs) in &other.errors {
106 self.errors
107 .entry(*pos)
108 .or_default()
109 .extend(errs.iter().cloned());
110 }
111 }
112
113 pub fn add_context(&mut self, s: Arc<str>) {
121 if self.context.is_some() {
122 panic!("tried to add context to the same error context twice");
123 }
124 self.context = Some(s);
125 }
126
127 pub fn is_empty(&self) -> bool {
129 self.errors.is_empty()
130 }
131
132 pub fn len(&self) -> usize {
134 self.errors.len()
135 }
136
137 pub fn into_result<T>(self, ok: T) -> Result<T, Self> {
142 if self.is_empty() {
143 Ok(ok)
144 } else {
145 Err(self)
146 }
147 }
148
149 pub fn into_result_with<T, F: FnOnce() -> T>(self, okfn: F) -> Result<T, Self> {
154 if self.is_empty() {
155 Ok(okfn())
156 } else {
157 Err(self)
158 }
159 }
160}
161
162impl error::Error for ErrorSet {
163 fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
164 match self.first_error()?.1 {
165 Error::Bad2ExpNumber(..) => None,
166 Error::BadWordLength { .. } => None,
167 Error::EntropyInsufficient { .. } => None,
168 Error::EntropyTooMuch { .. } => None,
169 Error::HoleAtCommitTime { .. } => None,
170 Error::HoleFilledAtCommitTime => None,
171 Error::NameIllegal(_) => None,
172 Error::NameIncomplete(_) => None,
173 Error::NameMissing(_) => None,
174 Error::NameRepeated(_) => None,
175 Error::NoMain => None,
176 Error::ParseFailed(_) => None,
177 Error::LexFailed(_) => None,
178 Error::NumberOutOfRange(_) => None,
179 Error::TypeCheck(ref e) => Some(e),
180 Error::Undefined(_) => None,
181 Error::UnknownJet(_) => None,
182 Error::WitnessDisconnectRepeated { .. } => None,
183 }
184 }
185}
186
187impl fmt::Display for ErrorSet {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 let mut line_map = self.line_map.lock().unwrap();
190 if line_map.is_empty() {
191 if let Some(ref s) = self.context {
192 *line_map = iter::repeat(0)
193 .take(2)
194 .chain(
195 s.char_indices()
196 .filter_map(|(n, ch)| if ch == '\n' { Some(n) } else { None }),
197 )
198 .collect();
199 }
200 }
201
202 for (pos, errs) in &self.errors {
203 if let Some(pos) = pos {
204 for err in errs {
205 if let Some(ref s) = self.context {
206 let end = line_map.get(pos.line + 1).copied().unwrap_or(s.len());
207 let line = &s[line_map[pos.line] + 1..end];
208 writeln!(f, "{:5} | {}", pos.line, line)?;
209 writeln!(f, " | {:>width$}", "^", width = pos.column)?;
210 writeln!(f, " \\-- {}", err)?;
211 writeln!(f)?;
212 } else {
213 writeln!(f, "{:4}:{:2}: {}", pos.line, pos.column, err,)?;
214 writeln!(f)?;
215 }
216 }
217 } else {
218 for err in errs {
219 writeln!(f, "Error: {}", err)?;
220 }
221 }
222 }
223 Ok(())
224 }
225}
226
227#[derive(Clone, Debug)]
234pub enum Error {
235 Bad2ExpNumber(u32),
237 BadWordLength { bit_length: usize },
239 EntropyInsufficient { bit_length: usize },
241 EntropyTooMuch { bit_length: usize },
243 HoleAtCommitTime {
246 name: Arc<str>,
247 arrow_source: Arc<types::Incomplete>,
248 arrow_target: Arc<types::Incomplete>,
249 },
250 HoleFilledAtCommitTime,
253 NameIllegal(Arc<str>),
255 NameIncomplete(Arc<str>),
257 NameMissing(Arc<str>),
259 NameRepeated(Arc<str>),
261 NoMain,
263 ParseFailed(Option<Lexeme>),
266 LexFailed(String),
268 NumberOutOfRange(String),
270 TypeCheck(types::Error),
272 Undefined(String),
274 UnknownJet(String),
276 WitnessDisconnectRepeated { name: Arc<str>, count: usize },
278}
279
280impl From<types::Error> for Error {
281 fn from(e: types::Error) -> Self {
282 Error::TypeCheck(e)
283 }
284}
285
286impl fmt::Display for Error {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 match *self {
289 Error::BadWordLength { bit_length } => {
290 write!(f, "word length {} is not a valid power of 2", bit_length)
291 }
292 Error::Bad2ExpNumber(exp) => {
293 write!(f, "types may be 2^n for n a power of 2, but not 2^{}", exp)
294 }
295 Error::EntropyInsufficient { bit_length } => write!(
296 f,
297 "fail node has insufficient entropy ({} bits, need 128)",
298 bit_length
299 ),
300 Error::EntropyTooMuch { bit_length } => write!(
301 f,
302 "fail node has too much entropy ({} bits, max 512)",
303 bit_length
304 ),
305 Error::HoleAtCommitTime {
306 ref name,
307 ref arrow_source,
308 ref arrow_target,
309 } => write!(
310 f,
311 "unfilled hole ?{} at commitment time; type arrow {} -> {}",
312 name, arrow_source, arrow_target,
313 ),
314 Error::HoleFilledAtCommitTime => {
315 f.write_str("disconnect node has a non-hole child at commit time")
316 }
317 Error::NameIllegal(ref s) => {
318 write!(f, "name `{}` is not allowed in this context", s)
319 }
320 Error::NameIncomplete(ref s) => write!(f, "name `{}` has no expression", s),
321 Error::NameMissing(ref s) => {
322 write!(f, "name `{}` is referred to but does not exist", s)
323 }
324 Error::NameRepeated(ref s) => write!(f, "name `{}` occured mulitple times", s),
325 Error::NoMain => f.write_str("program does not define `main`"),
326 Error::NumberOutOfRange(ref n) => {
327 write!(f, "number {} was out of allowable range", n)
328 }
329 Error::ParseFailed(None) => f.write_str("could not parse"),
330 Error::ParseFailed(Some(ref lex)) => write!(f, "could not parse `{}`", lex.raw),
331 Error::LexFailed(ref msg) => write!(f, "could not parse: {}", msg),
332 Error::TypeCheck(ref e) => fmt::Display::fmt(e, f),
333 Error::Undefined(ref s) => write!(f, "reference to undefined symbol `{}`", s),
334 Error::UnknownJet(ref s) => write!(f, "unknown jet `{}`", s),
335 Error::WitnessDisconnectRepeated { ref name, count } => write!(
336 f,
337 "witness/disconnect node {} was accessible by {} distinct paths from the same root",
338 name, count,
339 ),
340 }
341 }
342}