open_vaf/ast_lowering/
error.rs

1/*
2 * ******************************************************************************************
3 * Copyright (c) 2019 Pascal Kuthe. This file is part of the OpenVAF project.
4 * It is subject to the license terms in the LICENSE file found in the top-level directory
5 *  of this distribution and at  https://gitlab.com/DSPOM/OpenVAF/blob/master/LICENSE.
6 *  No part of OpenVAF, including this file, may be copied, modified, propagated, or
7 *  distributed except according to the terms contained in the LICENSE file.
8 * *****************************************************************************************
9 */
10
11use 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>;
27//pub(crate) type Warning = crate::error::Error<WarningType>;
28pub 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}