circom_lsp_program_structure/program_library/
error_definition.rs

1use super::error_code::ReportCode;
2use super::file_definition::{FileID, FileLibrary, FileLocation};
3use codespan_reporting::diagnostic::{Diagnostic, Label};
4use codespan_reporting::term;
5
6pub type ReportCollection = Vec<Report>;
7pub type DiagnosticCode = String;
8type ReportLabel = Label<FileID>;
9type ReportNote = String;
10
11#[derive(Copy, Clone)]
12pub enum MessageCategory {
13    Error,
14    Warning,
15}
16impl MessageCategory {
17    fn is_error(&self) -> bool {
18        use MessageCategory::*;
19        match self {
20            Error => true,
21            _ => false,
22        }
23    }
24    fn is_warning(&self) -> bool {
25        use MessageCategory::*;
26        match self {
27            Warning => true,
28            _ => false,
29        }
30    }
31}
32
33#[derive(Clone)]
34pub struct Report {
35    category: MessageCategory,
36    error_message: String,
37    error_code: ReportCode,
38    primary: Vec<ReportLabel>,
39    secondary: Vec<ReportLabel>,
40    notes: Vec<ReportNote>,
41}
42impl Report {
43    fn new(category: MessageCategory, error_message: String, error_code: ReportCode) -> Report {
44        Report {
45            category,
46            error_message,
47            error_code,
48            primary: Vec::new(),
49            secondary: Vec::new(),
50            notes: Vec::new(),
51        }
52    }
53    pub fn print_reports(reports: &[Report], file_library: &FileLibrary) {
54        use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
55        let writer = StandardStream::stderr(ColorChoice::Always);
56        let config = term::Config::default();
57        let mut diagnostics = Vec::new();
58        let files = file_library.to_storage();
59        for report in reports.iter() {
60            diagnostics.push(report.to_diagnostic());
61        }
62        for diagnostic in diagnostics.iter() {
63            let print_result = term::emit(&mut writer.lock(), &config, files, &diagnostic);
64            if print_result.is_err() {
65                panic!("Error printing reports")
66            }
67        }
68    }
69    pub fn error_code_to_diagnostic_code(error_code: &ReportCode) -> DiagnosticCode {
70        error_code.to_string()
71    }
72    pub fn error(error_message: String, code: ReportCode) -> Report {
73        Report::new(MessageCategory::Error, error_message, code)
74    }
75    pub fn warning(error_message: String, code: ReportCode) -> Report {
76        Report::new(MessageCategory::Warning, error_message, code)
77    }
78    pub fn add_primary(
79        &mut self,
80        location: FileLocation,
81        file_id: FileID,
82        message: String,
83    ) -> &mut Self {
84        let label = ReportLabel::primary(file_id, location).with_message(message);
85        self.get_mut_primary().push(label);
86        self
87    }
88    pub fn add_secondary(
89        &mut self,
90        location: FileLocation,
91        file_id: FileID,
92        possible_message: Option<String>,
93    ) -> &mut Self {
94        let mut label = ReportLabel::secondary(file_id, location);
95        if let Option::Some(message) = possible_message {
96            label = label.with_message(message);
97        }
98        self.get_mut_secondary().push(label);
99        self
100    }
101    pub fn add_note(&mut self, note: String) -> &mut Self {
102        self.get_mut_notes().push(note);
103        self
104    }
105
106    pub fn to_diagnostic(&self) -> Diagnostic<FileID> {
107        let mut labels = self.get_primary().clone();
108        let mut secondary = self.get_secondary().clone();
109        labels.append(&mut secondary);
110
111        if self.is_warning() { Diagnostic::warning() } else { Diagnostic::error() }
112            .with_message(self.get_message())
113            .with_code(Report::error_code_to_diagnostic_code(self.get_code()))
114            .with_labels(labels)
115            .with_notes(self.get_notes().clone())
116    }
117
118    pub fn is_error(&self) -> bool {
119        self.get_category().is_error()
120    }
121    pub fn is_warning(&self) -> bool {
122        self.get_category().is_warning()
123    }
124    pub fn get_category(&self) -> &MessageCategory {
125        &self.category
126    }
127    pub fn get_message(&self) -> &String {
128        &self.error_message
129    }
130    pub fn get_code(&self) -> &ReportCode {
131        &self.error_code
132    }
133    pub fn get_primary(&self) -> &Vec<ReportLabel> {
134        &self.primary
135    }
136    fn get_mut_primary(&mut self) -> &mut Vec<ReportLabel> {
137        &mut self.primary
138    }
139    pub fn get_secondary(&self) -> &Vec<ReportLabel> {
140        &self.secondary
141    }
142    fn get_mut_secondary(&mut self) -> &mut Vec<ReportLabel> {
143        &mut self.secondary
144    }
145    pub fn get_notes(&self) -> &Vec<ReportNote> {
146        &self.notes
147    }
148    fn get_mut_notes(&mut self) -> &mut Vec<ReportNote> {
149        &mut self.notes
150    }
151}