darkfi/zkas/
error.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::io::{self, Error, Write};
20
21pub(super) struct ErrorEmitter {
22    namespace: String,
23    file: String,
24    lines: Vec<String>,
25}
26
27impl ErrorEmitter {
28    pub fn new(namespace: &str, file: &str, lines: Vec<String>) -> Self {
29        Self { namespace: namespace.to_string(), file: file.to_string(), lines }
30    }
31
32    fn fmt(&self, msg: String, ln: usize, col: usize) -> String {
33        let (err_msg, dbg_msg, caret) = match ln {
34            0 => (msg, "".to_string(), "".to_string()),
35            _ => {
36                let err_msg = format!("{msg} (line {ln}, column {col})");
37                let dbg_msg = format!("{}:{ln}:{col}: {}", self.file, self.lines[ln - 1]);
38                let pad = dbg_msg.split(": ").next().unwrap().len() + col + 1;
39                let caret = format!("{:width$}^", "", width = pad);
40                (err_msg, dbg_msg, caret)
41            }
42        };
43        format!("{err_msg}\n{dbg_msg}\n{caret}\n")
44    }
45
46    pub fn abort(&self, msg: &str, ln: usize, col: usize) -> Error {
47        let m = self.fmt(msg.to_string(), ln, col);
48        self.emit("error", &m);
49        Error::other(m)
50    }
51
52    pub fn warn(&self, msg: &str, ln: usize, col: usize) {
53        let m = self.fmt(msg.to_string(), ln, col);
54        self.emit("warning", &m);
55    }
56
57    pub fn emit(&self, typ: &str, msg: &str) {
58        if std::env::var("ZKAS_SILENT").is_ok() {
59            return
60        }
61
62        let stderr = io::stderr();
63        let mut handle = stderr.lock();
64
65        match typ {
66            "error" => write!(handle, "\x1b[31;1m{} error:\x1b[0m {msg}", self.namespace).unwrap(),
67
68            "warning" => {
69                write!(handle, "\x1b[33;1m{} warning:\x1b[0m {msg}", self.namespace).unwrap()
70            }
71
72            _ => unreachable!(),
73        };
74
75        handle.flush().unwrap();
76    }
77}