1use num_bigint::BigInt;
2use std::fmt;
3
4use crate::file_definition::{FileID, FileLocation};
5use crate::nonempty_vec::NonEmptyVec;
6
7use super::degree_meta::DegreeKnowledge;
8use super::type_meta::TypeKnowledge;
9use super::value_meta::ValueKnowledge;
10use super::variable_meta::VariableKnowledge;
11
12type Index = usize;
13type Version = usize;
14
15#[derive(Clone, Default)]
16pub struct Meta {
17 pub location: FileLocation,
18 pub file_id: Option<FileID>,
19 degree_knowledge: DegreeKnowledge,
20 type_knowledge: TypeKnowledge,
21 value_knowledge: ValueKnowledge,
22 variable_knowledge: VariableKnowledge,
23}
24
25impl Meta {
26 #[must_use]
27 pub fn new(location: &FileLocation, file_id: &Option<FileID>) -> Meta {
28 Meta {
29 location: location.clone(),
30 file_id: *file_id,
31 degree_knowledge: DegreeKnowledge::default(),
32 type_knowledge: TypeKnowledge::default(),
33 value_knowledge: ValueKnowledge::default(),
34 variable_knowledge: VariableKnowledge::default(),
35 }
36 }
37
38 #[must_use]
39 pub fn start(&self) -> usize {
40 self.location.start
41 }
42
43 #[must_use]
44 pub fn end(&self) -> usize {
45 self.location.end
46 }
47
48 #[must_use]
49 pub fn file_id(&self) -> Option<FileID> {
50 self.file_id
51 }
52
53 #[must_use]
54 pub fn file_location(&self) -> FileLocation {
55 self.location.clone()
56 }
57
58 #[must_use]
59 pub fn degree_knowledge(&self) -> &DegreeKnowledge {
60 &self.degree_knowledge
61 }
62
63 #[must_use]
64 pub fn type_knowledge(&self) -> &TypeKnowledge {
65 &self.type_knowledge
66 }
67
68 #[must_use]
69 pub fn value_knowledge(&self) -> &ValueKnowledge {
70 &self.value_knowledge
71 }
72
73 #[must_use]
74 pub fn variable_knowledge(&self) -> &VariableKnowledge {
75 &self.variable_knowledge
76 }
77
78 #[must_use]
79 pub fn degree_knowledge_mut(&mut self) -> &mut DegreeKnowledge {
80 &mut self.degree_knowledge
81 }
82
83 #[must_use]
84 pub fn type_knowledge_mut(&mut self) -> &mut TypeKnowledge {
85 &mut self.type_knowledge
86 }
87
88 #[must_use]
89 pub fn value_knowledge_mut(&mut self) -> &mut ValueKnowledge {
90 &mut self.value_knowledge
91 }
92
93 #[must_use]
94 pub fn variable_knowledge_mut(&mut self) -> &mut VariableKnowledge {
95 &mut self.variable_knowledge
96 }
97}
98
99impl std::hash::Hash for Meta {
100 fn hash<H>(&self, state: &mut H)
101 where
102 H: std::hash::Hasher,
103 {
104 self.location.hash(state);
105 self.file_id.hash(state);
106 state.finish();
107 }
108}
109
110impl PartialEq for Meta {
111 fn eq(&self, other: &Meta) -> bool {
112 self.location == other.location && self.file_id == other.file_id
113 }
114}
115
116impl Eq for Meta {}
117
118#[derive(Clone)]
120#[allow(clippy::large_enum_variant)]
121pub enum Statement {
122 Declaration {
125 meta: Meta,
126 names: NonEmptyVec<VariableName>,
127 var_type: VariableType,
128 dimensions: Vec<Expression>,
129 },
130 IfThenElse {
131 meta: Meta,
132 cond: Expression,
133 true_index: Index,
134 false_index: Option<Index>,
135 },
136 Return {
137 meta: Meta,
138 value: Expression,
139 },
140 Substitution {
146 meta: Meta,
147 var: VariableName,
148 op: AssignOp,
149 rhe: Expression,
150 },
151 ConstraintEquality {
152 meta: Meta,
153 lhe: Expression,
154 rhe: Expression,
155 },
156 LogCall {
157 meta: Meta,
158 args: Vec<LogArgument>,
159 },
160 Assert {
161 meta: Meta,
162 arg: Expression,
163 },
164}
165
166#[derive(Clone)]
167pub enum Expression {
168 InfixOp {
170 meta: Meta,
171 lhe: Box<Expression>,
172 infix_op: ExpressionInfixOpcode,
173 rhe: Box<Expression>,
174 },
175 PrefixOp { meta: Meta, prefix_op: ExpressionPrefixOpcode, rhe: Box<Expression> },
177 SwitchOp {
180 meta: Meta,
181 cond: Box<Expression>,
182 if_true: Box<Expression>,
183 if_false: Box<Expression>,
184 },
185 Variable { meta: Meta, name: VariableName },
187 Number(Meta, BigInt),
189 Call { meta: Meta, name: String, args: Vec<Expression> },
191 InlineArray { meta: Meta, values: Vec<Expression> },
193 Access { meta: Meta, var: VariableName, access: Vec<AccessType> },
195 Update { meta: Meta, var: VariableName, access: Vec<AccessType>, rhe: Box<Expression> },
204 Phi { meta: Meta, args: Vec<VariableName> },
206}
207
208pub type TagList = Vec<String>;
209
210#[derive(Clone, PartialEq, Eq, Hash)]
211pub enum VariableType {
212 Local,
213 Component,
214 AnonymousComponent,
215 Signal(SignalType, TagList),
216}
217
218impl fmt::Display for VariableType {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
220 use SignalType::*;
221 use VariableType::*;
222 match self {
223 Local => write!(f, "var"),
224 AnonymousComponent | Component => write!(f, "component"),
225 Signal(signal_type, tag_list) => {
226 if matches!(signal_type, Intermediate) {
227 write!(f, "signal")?;
228 } else {
229 write!(f, "signal {signal_type}")?;
230 }
231 if !tag_list.is_empty() {
232 write!(f, " {{{}}}", tag_list.join(", "))
233 } else {
234 Ok(())
235 }
236 }
237 }
238 }
239}
240
241#[derive(Copy, Clone, PartialEq, Eq, Hash)]
242pub enum SignalType {
243 Input,
244 Output,
245 Intermediate,
246}
247
248impl fmt::Display for SignalType {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
250 use SignalType::*;
251 match self {
252 Input => write!(f, "input"),
253 Output => write!(f, "output"),
254 Intermediate => Ok(()), }
256 }
257}
258
259#[derive(Clone, Hash, PartialEq, Eq)]
265pub struct VariableName {
266 name: String,
269 suffix: Option<String>,
273 version: Option<Version>,
276}
277
278impl VariableName {
279 #[must_use]
281 pub fn from_string<N: ToString>(name: N) -> VariableName {
282 VariableName { name: name.to_string(), suffix: None, version: None }
283 }
284
285 #[must_use]
286 pub fn name(&self) -> &String {
287 &self.name
288 }
289
290 #[must_use]
291 pub fn suffix(&self) -> &Option<String> {
292 &self.suffix
293 }
294
295 #[must_use]
296 pub fn version(&self) -> &Option<Version> {
297 &self.version
298 }
299
300 #[must_use]
302 pub fn with_suffix<S: ToString>(&self, suffix: S) -> VariableName {
303 let mut result = self.clone();
304 result.suffix = Some(suffix.to_string());
305 result
306 }
307
308 #[must_use]
310 pub fn with_version(&self, version: Version) -> VariableName {
311 let mut result = self.clone();
312 result.version = Some(version);
313 result
314 }
315
316 #[must_use]
318 pub fn without_suffix(&self) -> VariableName {
319 let mut result = self.clone();
320 result.suffix = None;
321 result
322 }
323
324 #[must_use]
326 pub fn without_version(&self) -> VariableName {
327 let mut result = self.clone();
328 result.version = None;
329 result
330 }
331}
332
333impl fmt::Display for VariableName {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
336 write!(f, "{}", self.name)
337 }
338}
339
340impl fmt::Debug for VariableName {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
343 write!(f, "{}", self.name)?;
344 if let Some(suffix) = self.suffix() {
345 write!(f, "_{suffix}")?;
346 }
347 if let Some(version) = self.version() {
348 write!(f, ".{version}")?;
349 }
350 Ok(())
351 }
352}
353
354#[derive(Clone, Hash, Eq, PartialEq)]
355pub enum AccessType {
356 ArrayAccess(Box<Expression>),
357 ComponentAccess(String),
358}
359
360#[derive(Copy, Clone, Hash, Eq, PartialEq)]
361pub enum AssignOp {
362 AssignSignal,
364 AssignConstraintSignal,
366 AssignLocalOrComponent,
368}
369
370#[derive(Copy, Clone, Hash, Eq, PartialEq)]
371pub enum ExpressionInfixOpcode {
372 Mul,
373 Div,
374 Add,
375 Sub,
376 Pow,
377 IntDiv,
378 Mod,
379 ShiftL,
380 ShiftR,
381 LesserEq,
382 GreaterEq,
383 Lesser,
384 Greater,
385 Eq,
386 NotEq,
387 BoolOr,
388 BoolAnd,
389 BitOr,
390 BitAnd,
391 BitXor,
392}
393
394#[derive(Copy, Clone, Hash, Eq, PartialEq)]
395pub enum ExpressionPrefixOpcode {
396 Sub,
397 BoolNot,
398 Complement,
399}
400
401#[derive(Clone)]
402pub enum LogArgument {
403 String(String),
404 Expr(Box<Expression>),
405}