1use std::fmt::Display;
12
13use annotate_snippets::display_list::{DisplayList, FormatOptions};
14use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
15use core::fmt::Formatter;
16
17use crate::ir::DisciplineId;
18use crate::parser::error::{ Unsupported};
19use crate::symbol::Symbol;
20use crate::symbol_table::SymbolDeclaration;
21use crate::util::format_list;
22use crate::{parser, Ast, SourceMap, Span};
23use beef::lean::Cow;
24use core::fmt::Debug;
25
26pub type Error = crate::error::Error<Type>;
27pub type Result<T = ()> = std::result::Result<T, Error>;
29#[derive(Clone, Debug)]
30pub struct NetInfo {
31 pub discipline: DisciplineId,
32 pub name: Symbol,
33 pub declaration: Span,
34}
35#[derive(Clone, Debug)]
36pub enum Type {
37 TypeDeclarationMissing(Symbol),
38 NotFound(Symbol),
39 NotAScope {
40 declaration: Span,
41 name: Symbol,
42 },
43 DeclarationTypeMismatch {
44 expected: Vec<MockSymbolDeclaration>,
45 found: SymbolDeclaration,
46 },
47 UnexpectedTokenInBranchAccess,
48 EmptyBranchAccess,
49 NatureNotPotentialOrFlow(Symbol, DisciplineId),
50 DisciplineMismatch(NetInfo, NetInfo),
51 NotAllowedInConstantContext(NonConstantExpression),
52 NotAllowedInFunction(NotAllowedInFunction),
53 Unsupported(Unsupported),
54 DerivativeNotAllowed,
55}
56#[derive(Copy, Clone, Debug, Eq, PartialEq)]
57pub enum NonConstantExpression {
58 VariableReference,
59 BranchAccess,
60 FunctionCall,
61 AnalogFilter,
62}
63impl Display for NonConstantExpression {
64 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
65 match self {
66 Self::VariableReference => f.write_str("Variable references"),
67 Self::BranchAccess => f.write_str("Branch probe calls"),
68 Self::FunctionCall => f.write_str("Function calls"),
69 Self::AnalogFilter => f.write_str("Analog filters"),
70 }
71 }
72}
73
74#[derive(Copy, Clone, Debug, Eq, PartialEq)]
75pub enum NotAllowedInFunction {
76 BranchAccess,
77 AnalogFilters,
78 NamedBlocks,
79 Contribute,
80 NonLocalAccess,
81}
82impl Display for NotAllowedInFunction {
83 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
84 match self {
85 Self::BranchAccess => f.write_str("Accessing branches"),
86 Self::AnalogFilters => f.write_str("Analog filter functions"),
87 Self::NamedBlocks => f.write_str("Named blocks"),
88 Self::NonLocalAccess => f.write_str("Named blocks"),
89 Self::Contribute => f.write_str("contribute statements (<+)"),
90 }
91 }
92}
93
94impl Error {
95 pub fn print(self, source_map: &SourceMap, ast: &Ast, translate_lines: bool) {
96 let (line, line_number, substitution_name, range) =
97 source_map.resolve_span_within_line(self.source, translate_lines);
98 let (origin, mut footer) = if let Some(substitution_name) = substitution_name {
99 (Cow::owned(substitution_name), vec![Annotation {
100 id: None,
101 label: Some("If macros/files are included inside this macro/file the error output might be hard to understand/display incorrect line numbers (See fully expanded source)"),
102 annotation_type: AnnotationType::Note
103 }])
104 } else {
105 (Cow::const_str(source_map.main_file_name), Vec::new())
106 };
107 let opt = FormatOptions {
108 color: true,
109 anonymized_line_numbers: false,
110 };
111
112 match self.error_type {
113 Type::UnexpectedTokenInBranchAccess => {
114 let range = (range.start as usize,range.end as usize);
115 let snippet = Snippet {
116 title: Some(Annotation {
117 id: None,
118 label: Some("Unexpected Token"),
119 annotation_type: AnnotationType::Error,
120 }),
121 footer,
122 slices: vec![Slice {
123 source: line,
124 line_start: line_number as usize,
125 origin: Some(&*origin),
126 annotations: vec![SourceAnnotation {
127 range,
128 label: "Expected branch reference",
129 annotation_type: AnnotationType::Error,
130 }],
131 fold: false,
132 }],
133 opt,
134 };
135 let display_list = DisplayList::from(snippet);
136 eprintln!("{}", display_list);
137 }
138 Type::NotFound(sym) => {
139 let range = (range.start as usize,range.end as usize);
140 let label = format!("cannot find {} in this scope", sym.as_str());
141 let snippet = Snippet {
142 title: Some(Annotation {
143 id: None,
144 label: Some(label.as_str()),
145 annotation_type: AnnotationType::Error,
146 }),
147 footer,
148 slices: vec![Slice {
149 source: line,
150 line_start: line_number as usize,
151 origin: Some(&*origin),
152 annotations: vec![SourceAnnotation {
153 range,
154 label: "not found in this Scope",
155 annotation_type: AnnotationType::Error,
156 }],
157 fold: false,
158 }],
159 opt,
160 };
161 let display_list = DisplayList::from(snippet);
162 eprintln!("{}", display_list);
163 }
164 Type::DeclarationTypeMismatch {
165 ref expected,
166 found,
167 } => {
168 let range = (range.start as usize,range.end as usize);
169 let label = format!(
170 "Expected {} found {} {}",
171 format_list(expected, ""),
172 found.mock(),
173 found.name(&ast).as_str()
174 );
175 let inline_label = format!("Expected {:?}", expected);
176 let snippet = Snippet {
177 title: Some(Annotation {
178 id: None,
179 label: Some(&label),
180 annotation_type: AnnotationType::Error,
181 }),
182 footer,
183 slices: vec![Slice {
184 source: line,
185 line_start: line_number as usize,
186 origin: Some(&*origin),
187 annotations: vec![SourceAnnotation {
188 range,
189 label: &inline_label,
190 annotation_type: AnnotationType::Error,
191 }],
192 fold: false,
193 }],
194 opt,
195 };
196 let display_list = DisplayList::from(snippet);
197 eprintln!("{}", display_list);
198 }
199 Type::NatureNotPotentialOrFlow(name, discipline) => {
200 let (msg,expected) = match (ast[discipline].contents.potential_nature,ast[discipline].contents.flow_nature){
201 (None,None)=> (Cow::const_str("Discrete Disciplines can not be accessed using branch Probes"),Cow::const_str("Illegal branch access")),
202
203 (Some(nature),None) => (Cow::owned(format!(
204 "This branch can only be accessed using its Potential ({})",
205 nature.name,
206 )), Cow::owned(format!("Expected {}",nature.name))
207 ),
208 (None,Some(nature)) => (Cow::owned(format!(
209 "This branch can only be accessed using its Flow ({})",
210 nature.name,
211 )),Cow::owned(format!("Expected {}",nature.name))
212 ),
213 (Some(pot),Some(flow)) => (Cow::owned(format!(
214 "This branch can only be accessed using its Potential ({}) or its Flow ({})",
215 pot.name,
216 flow.name,
217 )),Cow::owned(format!("Expected {} or {}",pot.name,flow.name))
218 ),
219 };
220 footer.push(Annotation {
221 id: None,
222 label: Some(&*msg),
223 annotation_type: AnnotationType::Info,
224 });
225 let range = (range.start as usize,range.end as usize);
226 let label = format!(
227 "{} can not be accessed by {}",
228 ast[discipline].contents.name,
229 &name.as_str(),
230 );
231 let snippet = Snippet {
232 title: Some(Annotation {
233 id: None,
234 label: Some(&*label),
235 annotation_type: AnnotationType::Error,
236 }),
237 footer,
238 slices: vec![Slice {
239 source: line,
240 line_start: line_number as usize,
241 origin: Some(&*origin),
242 annotations: vec![SourceAnnotation {
243 range,
244 label: &*expected,
245 annotation_type: AnnotationType::Error,
246 }],
247 fold: false,
248 }],
249 opt,
250 };
251 let display_list = DisplayList::from(snippet);
252 eprintln!("{}", display_list);
253 }
254 Type::NotAScope { declaration, name } => {
255 let (
256 other_declaration_line,
257 other_declaration_line_number,
258 other_declaration_origin,
259 other_declaration_range,
260 ) = source_map.resolve_span_within_line(declaration, translate_lines);
261
262 let range = (range.start as usize,range.end as usize);
263 let other_declaration_range = (
264 other_declaration_range.start as usize,
265 other_declaration_range.end as usize,
266 );
267
268 let other_declaration_origin = if let Some(val) = other_declaration_origin {
269 Cow::owned(val)
270 } else {
271 Cow::borrowed(source_map.main_file_name)
272 };
273 let label = format!("Expected scope found reference to {}", name.as_str());
274 let inline_label = format!("{} is declared here", name);
275 let snippet = Snippet {
276 title: Some(Annotation {
277 id: None,
278 label: Some(&label),
279 annotation_type: AnnotationType::Error,
280 }),
281 footer,
282 slices: vec![
283 Slice {
284 source: line,
285 line_start: line_number as usize,
286 origin: Some(&*origin),
287 annotations: vec![SourceAnnotation {
288 range,
289 label: "Expected scope",
290 annotation_type: AnnotationType::Error,
291 }],
292 fold: false,
293 },
294 Slice {
295 source: other_declaration_line,
296 line_start: other_declaration_line_number as usize,
297 origin: Some(&*other_declaration_origin),
298 annotations: vec![SourceAnnotation {
299 range: other_declaration_range,
300 label: &inline_label,
301 annotation_type: AnnotationType::Info,
302 }],
303 fold: false,
304 },
305 ],
306 opt,
307 };
308 let display_list = DisplayList::from(snippet);
309 eprintln!("{}", display_list);
310 }
311 Type::DisciplineMismatch(net1, net2) => {
312 let (
313 declaration_line,
314 declaration_line_number,
315 declaration_origin,
316 declaration_range,
317 ) = source_map.resolve_span_within_line(net1.declaration, translate_lines);
318 let (
319 other_declaration_line,
320 other_declaration_line_number,
321 other_declaration_origin,
322 other_declaration_range,
323 ) = source_map.resolve_span_within_line(net2.declaration, translate_lines);
324
325 let range = (range.start as usize,range.end as usize);
326 let declaration_range = (
327 declaration_range.start as usize,
328 declaration_range.end as usize,
329 );
330 let other_declaration_range = (
331 other_declaration_range.start as usize,
332 other_declaration_range.end as usize,
333 );
334
335 let other_declaration_origin = if let Some(val) = other_declaration_origin {
336 Cow::owned(val)
337 } else {
338 Cow::borrowed(source_map.main_file_name)
339 };
340
341 let declaration_origin = if let Some(val) = declaration_origin {
342 Cow::owned(val)
343 } else {
344 Cow::borrowed(source_map.main_file_name)
345 };
346 let label = format!(
347 "Disciplines {} and {} of nets {} and {} are incompatible",
348 ast[net1.discipline].contents.name.name,
349 ast[net2.discipline].contents.name.name,
350 net1.name,
351 net2.name
352 );
353
354 let inline_label = format!("{} is declared here", net1.name);
355 let inline_label_2 = format!("{} is declared here", net2.name);
356
357 let snippet = Snippet {
358 title: Some(Annotation {
359 id: None,
360 label: Some(&label),
361 annotation_type: AnnotationType::Error,
362 }),
363 footer,
364 slices: vec![
365 Slice {
366 source: line,
367 line_start: line_number as usize,
368 origin: Some(&*origin),
369 annotations: vec![SourceAnnotation {
370 range,
371 label: "Incompatible disciplines",
372 annotation_type: AnnotationType::Error,
373 }],
374 fold: false,
375 },
376 Slice {
377 source: declaration_line,
378 line_start: declaration_line_number as usize,
379 origin: Some(&*declaration_origin),
380 annotations: vec![SourceAnnotation {
381 range: declaration_range,
382 label: &inline_label,
383 annotation_type: AnnotationType::Info,
384 }],
385 fold: false,
386 },
387 Slice {
388 source: other_declaration_line,
389 line_start: other_declaration_line_number as usize,
390 origin: Some(&*other_declaration_origin),
391 annotations: vec![SourceAnnotation {
392 range: other_declaration_range,
393 label: &inline_label_2,
394 annotation_type: AnnotationType::Info,
395 }],
396 fold: false,
397 },
398 ],
399 opt,
400 };
401 let display_list = DisplayList::from(snippet);
402 eprintln!("{}", display_list);
403 }
404 Type::NotAllowedInConstantContext(non_constant_expr) => {
405 let range = (range.start as usize,range.end as usize);
406 let label = format!(
407 "{} are not allowed in a constant context!",
408 non_constant_expr
409 );
410 let snippet = Snippet {
411 title: Some(Annotation {
412 id: None,
413 label: Some(label.as_str()),
414 annotation_type: AnnotationType::Error,
415 }),
416 footer,
417 slices: vec![Slice {
418 source: line,
419 line_start: line_number as usize,
420 origin: Some(&*origin),
421 annotations: vec![SourceAnnotation {
422 range,
423 label: "Not allowed in a constant expression!",
424 annotation_type: AnnotationType::Error,
425 }],
426 fold: false,
427 }],
428 opt,
429 };
430 let display_list = DisplayList::from(snippet);
431 eprintln!("{}", display_list);
432 }
433 Type::Unsupported(unsupported) => {
434 parser::error::Error {
435 error_type: parser::error::Type::Unsupported(unsupported),
436 source: self.source,
437 }
438 .print(source_map, translate_lines);
439 }
440 Type::EmptyBranchAccess => {
441 let range = (range.start as usize,range.end as usize);
442 let snippet = Snippet {
443 title: Some(Annotation {
444 id: None,
445 label: Some("This refers to a nature but the brackets afterwards are empty (expected branch probe)"),
446 annotation_type: AnnotationType::Error,
447 }),
448 footer,
449 slices: vec![Slice {
450 source: line,
451 line_start: line_number as usize,
452 origin:Some(&*origin),
453 annotations: vec![SourceAnnotation {
454 range,
455 label: "Expected a following branch probe",
456 annotation_type: AnnotationType::Error,
457 }],
458 fold: false,
459 }],
460 opt
461 };
462 let display_list = DisplayList::from(snippet);
463 eprintln!("{}", display_list);
464 }
465 Type::DerivativeNotAllowed => {
466 let range = (range.start as usize,range.end as usize);
467 let snippet = Snippet {
468 title: Some(Annotation {
469 id: None,
470 label: Some("Partial derivatives may only be calculated over node potentials (for example V(node))"),
471 annotation_type: AnnotationType::Error,
472 }),
473 footer,
474 slices: vec![Slice {
475 source: line,
476 line_start: line_number as usize,
477 origin:Some(&*origin),
478 annotations: vec![SourceAnnotation {
479 range,
480 label: "Illegal derivative",
481 annotation_type: AnnotationType::Error,
482 }],
483 fold: false,
484 }],
485 opt
486 };
487 let display_list = DisplayList::from(snippet);
488 eprintln!("{}", display_list);
489 }
490 Type::TypeDeclarationMissing(name) => {
491 let range = (range.start as usize,range.end as usize);
492 let label = format!(
493 "Function argument {} is missing separate type declaration",
494 name
495 );
496 let hint_label = format!(
497 "Add the following to the function declaration: real {}; (or integer {};)",
498 name, name
499 );
500 footer.push(Annotation {
501 id: None,
502 label: Some(&hint_label),
503 annotation_type: AnnotationType::Help,
504 });
505 let snippet = Snippet {
506 title: Some(Annotation {
507 id: None,
508 label: Some(&label),
509 annotation_type: AnnotationType::Error,
510 }),
511 footer,
512 slices: vec![Slice {
513 source: line,
514 line_start: line_number as usize,
515 origin: Some(&*origin),
516 annotations: vec![SourceAnnotation {
517 range,
518 label: "Type declaration missing",
519 annotation_type: AnnotationType::Error,
520 }],
521 fold: false,
522 }],
523 opt,
524 };
525 let display_list = DisplayList::from(snippet);
526 eprintln!("{}", display_list);
527 }
528 Type::NotAllowedInFunction(not_allowed) => {
529 let range = (range.start as usize,range.end as usize);
530 let label = format!("{} are not allowed inside functions!", not_allowed);
531 let snippet = Snippet {
532 title: Some(Annotation {
533 id: None,
534 label: Some(label.as_str()),
535 annotation_type: AnnotationType::Error,
536 }),
537 footer,
538 slices: vec![Slice {
539 source: line,
540 line_start: line_number as usize,
541 origin: Some(&*origin),
542 annotations: vec![SourceAnnotation {
543 range,
544 label: "Not allowed in a function",
545 annotation_type: AnnotationType::Error,
546 }],
547 fold: false,
548 }],
549 opt,
550 };
551 let display_list = DisplayList::from(snippet);
552 eprintln!("{}", display_list);
553 }
554 };
555 }
556}
557
558#[derive(Debug, Clone, Copy)]
559pub enum MockSymbolDeclaration {
560 Module,
561 Block,
562 Variable,
563 Branch,
564 Net,
565 Port,
566 Function,
567 Discipline,
568 Nature,
569 Parameter,
570}
571impl Display for MockSymbolDeclaration {
572 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
573 Debug::fmt(self, f)
574 }
575}