Skip to main content

veryl_simulator/
simulator_error.rs

1use miette::{Diagnostic, SourceSpan};
2use thiserror::Error;
3use veryl_analyzer::multi_sources::{MultiSources, Source};
4use veryl_parser::token_range::TokenRange;
5use veryl_parser::veryl_token::TokenSource;
6
7#[derive(Error, Diagnostic, Debug)]
8pub enum SimulatorError {
9    #[diagnostic(severity(Error), code(top_module_not_found))]
10    #[error("top module \"{module_name}\" not found")]
11    TopModuleNotFound { module_name: String },
12
13    #[diagnostic(severity(Error), code(no_initial_block))]
14    #[error("no initial block found in module \"{module_name}\"")]
15    NoInitialBlock {
16        module_name: String,
17        #[source_code]
18        input: MultiSources,
19        #[label("this module has no initial block")]
20        error_location: SourceSpan,
21        token_source: TokenSource,
22    },
23
24    #[diagnostic(severity(Error), code(test_failed))]
25    #[error("{message}")]
26    TestFailed { message: String },
27
28    #[diagnostic(severity(Error), code(io_error))]
29    #[error("{message}")]
30    IoError { message: String },
31
32    #[diagnostic(severity(Error), code(unresolved_expression))]
33    #[error("unresolved expression")]
34    UnresolvedExpression {
35        #[source_code]
36        input: MultiSources,
37        #[label("could not resolve this expression")]
38        error_location: SourceSpan,
39        token_source: TokenSource,
40    },
41
42    #[diagnostic(severity(Error), code(recursive_function))]
43    #[error("recursive function \"{function_name}\" cannot be inlined")]
44    RecursiveFunction {
45        function_name: String,
46        #[source_code]
47        input: MultiSources,
48        #[label("recursive call here")]
49        error_location: SourceSpan,
50        token_source: TokenSource,
51    },
52
53    #[diagnostic(severity(Error), code(unsupported_description))]
54    #[error("unsupported description")]
55    UnsupportedDescription {
56        #[source_code]
57        input: MultiSources,
58        #[label("this description is not supported by the simulator")]
59        error_location: SourceSpan,
60        token_source: TokenSource,
61    },
62
63    #[diagnostic(severity(Error), code(combinational_loop))]
64    #[error("combinational loop detected")]
65    CombinationalLoop {
66        #[source_code]
67        input: MultiSources,
68        #[label("Error location")]
69        error_location: SourceSpan,
70        #[label(collection, "involved in loop")]
71        loop_participants: Vec<SourceSpan>,
72        token_source: TokenSource,
73    },
74}
75
76fn source_with_context(
77    token: &TokenRange,
78    context: &[TokenRange],
79) -> (MultiSources, Vec<SourceSpan>) {
80    let path = token.beg.source.to_string();
81    let text = token.beg.source.get_text();
82
83    let mut base = text.len();
84    let mut ranges = Vec::new();
85    let mut sources = Vec::new();
86
87    sources.push(Source { path, text });
88
89    for x in context.iter().rev() {
90        let path = x.beg.source.to_string();
91        let text = x.beg.source.get_text();
92
93        let mut range = *x;
94        range.offset(base as u32);
95        ranges.push(range.into());
96
97        base += text.len();
98
99        sources.push(Source { path, text });
100    }
101
102    let sources = MultiSources { sources };
103    (sources, ranges)
104}
105
106impl SimulatorError {
107    pub fn no_initial_block(module_name: &str, token: &TokenRange) -> Self {
108        let path = token.beg.source.to_string();
109        let text = token.beg.source.get_text();
110        let input = MultiSources {
111            sources: vec![Source { path, text }],
112        };
113        SimulatorError::NoInitialBlock {
114            module_name: module_name.to_string(),
115            input,
116            error_location: (*token).into(),
117            token_source: token.beg.source,
118        }
119    }
120
121    pub fn unresolved_expression(token: &TokenRange) -> Self {
122        let path = token.beg.source.to_string();
123        let text = token.beg.source.get_text();
124        let input = MultiSources {
125            sources: vec![Source { path, text }],
126        };
127        SimulatorError::UnresolvedExpression {
128            input,
129            error_location: (*token).into(),
130            token_source: token.beg.source,
131        }
132    }
133
134    pub fn unsupported_description(token: &TokenRange) -> Self {
135        let path = token.beg.source.to_string();
136        let text = token.beg.source.get_text();
137        let input = MultiSources {
138            sources: vec![Source { path, text }],
139        };
140        SimulatorError::UnsupportedDescription {
141            input,
142            error_location: (*token).into(),
143            token_source: token.beg.source,
144        }
145    }
146
147    pub fn recursive_function(function_name: &str, token: &TokenRange) -> Self {
148        let path = token.beg.source.to_string();
149        let text = token.beg.source.get_text();
150        let input = MultiSources {
151            sources: vec![Source { path, text }],
152        };
153        SimulatorError::RecursiveFunction {
154            function_name: function_name.to_string(),
155            input,
156            error_location: (*token).into(),
157            token_source: token.beg.source,
158        }
159    }
160
161    pub fn combinational_loop(token: &TokenRange, participants: &[TokenRange]) -> Self {
162        let (input, loop_participants) = source_with_context(token, participants);
163        SimulatorError::CombinationalLoop {
164            input,
165            error_location: (*token).into(),
166            loop_participants,
167            token_source: token.beg.source,
168        }
169    }
170}