1use crate::ast::{self, LogArgument};
2use crate::report::ReportCollection;
3
4use crate::ir;
5use crate::ir::declarations::{Declaration, Declarations};
6use crate::ir::errors::{IRError, IRResult};
7use crate::nonempty_vec::NonEmptyVec;
8
9pub(crate) trait TryLift<Context> {
13 type IR;
14 type Error;
15
16 fn try_lift(
18 &self,
19 context: Context,
20 reports: &mut ReportCollection,
21 ) -> Result<Self::IR, Self::Error>;
22}
23
24#[derive(Default)]
25pub(crate) struct LiftingEnvironment {
26 declarations: Declarations,
28}
29
30impl LiftingEnvironment {
31 #[must_use]
32 pub fn new() -> LiftingEnvironment {
33 LiftingEnvironment::default()
34 }
35
36 pub fn add_declaration(&mut self, declaration: &Declaration) {
37 self.declarations.add_declaration(declaration);
38 }
39}
40
41impl From<LiftingEnvironment> for Declarations {
42 fn from(env: LiftingEnvironment) -> Declarations {
43 env.declarations
44 }
45}
46
47impl TryLift<()> for ast::Statement {
52 type IR = ir::Statement;
53 type Error = IRError;
54
55 fn try_lift(&self, _: (), reports: &mut ReportCollection) -> IRResult<Self::IR> {
56 match self {
57 ast::Statement::Return { meta, value } => Ok(ir::Statement::Return {
58 meta: meta.try_lift((), reports)?,
59 value: value.try_lift((), reports)?,
60 }),
61 ast::Statement::Substitution { meta, var, op, rhe, access } => {
62 let rhe = if access.is_empty() {
65 rhe.try_lift((), reports)?
66 } else {
67 ir::Expression::Update {
68 meta: meta.try_lift((), reports)?,
69 var: var.try_lift(meta, reports)?,
70 access: access
71 .iter()
72 .map(|access| access.try_lift((), reports))
73 .collect::<IRResult<Vec<ir::AccessType>>>()?,
74 rhe: Box::new(rhe.try_lift((), reports)?),
75 }
76 };
77 Ok(ir::Statement::Substitution {
78 meta: meta.try_lift((), reports)?,
79 var: var.try_lift(meta, reports)?,
80 op: op.try_lift((), reports)?,
81 rhe,
82 })
83 }
84 ast::Statement::ConstraintEquality { meta, lhe, rhe } => {
85 Ok(ir::Statement::ConstraintEquality {
86 meta: meta.try_lift((), reports)?,
87 lhe: lhe.try_lift((), reports)?,
88 rhe: rhe.try_lift((), reports)?,
89 })
90 }
91 ast::Statement::LogCall { meta, args } => Ok(ir::Statement::LogCall {
92 meta: meta.try_lift((), reports)?,
93 args: args
94 .iter()
95 .map(|arg| arg.try_lift((), reports))
96 .collect::<IRResult<Vec<_>>>()?,
97 }),
98 ast::Statement::Assert { meta, arg } => Ok(ir::Statement::Assert {
99 meta: meta.try_lift((), reports)?,
100 arg: arg.try_lift((), reports)?,
101 }),
102 ast::Statement::Declaration { meta, xtype, name, dimensions, .. } => {
103 Ok(ir::Statement::Declaration {
104 meta: meta.try_lift((), reports)?,
105 names: NonEmptyVec::new(name.try_lift(meta, reports)?),
106 var_type: xtype.try_lift((), reports)?,
107 dimensions: dimensions
108 .iter()
109 .map(|size| size.try_lift((), reports))
110 .collect::<IRResult<Vec<_>>>()?,
111 })
112 }
113 ast::Statement::Block { .. }
114 | ast::Statement::While { .. }
115 | ast::Statement::IfThenElse { .. }
116 | ast::Statement::MultiSubstitution { .. }
117 | ast::Statement::InitializationBlock { .. } => {
118 panic!("failed to convert AST statement to IR")
120 }
121 }
122 }
123}
124
125impl TryLift<()> for ast::Expression {
129 type IR = ir::Expression;
130 type Error = IRError;
131
132 fn try_lift(&self, _: (), reports: &mut ReportCollection) -> IRResult<Self::IR> {
133 match self {
134 ast::Expression::InfixOp { meta, lhe, infix_op, rhe } => Ok(ir::Expression::InfixOp {
135 meta: meta.try_lift((), reports)?,
136 lhe: Box::new(lhe.try_lift((), reports)?),
137 infix_op: infix_op.try_lift((), reports)?,
138 rhe: Box::new(rhe.try_lift((), reports)?),
139 }),
140 ast::Expression::PrefixOp { meta, prefix_op, rhe } => Ok(ir::Expression::PrefixOp {
141 meta: meta.try_lift((), reports)?,
142 prefix_op: prefix_op.try_lift((), reports)?,
143 rhe: Box::new(rhe.try_lift((), reports)?),
144 }),
145 ast::Expression::InlineSwitchOp { meta, cond, if_true, if_false } => {
146 Ok(ir::Expression::SwitchOp {
147 meta: meta.try_lift((), reports)?,
148 cond: Box::new(cond.try_lift((), reports)?),
149 if_true: Box::new(if_true.try_lift((), reports)?),
150 if_false: Box::new(if_false.try_lift((), reports)?),
151 })
152 }
153 ast::Expression::Variable { meta, name, access } => {
154 if access.is_empty() {
155 Ok(ir::Expression::Variable {
156 meta: meta.try_lift((), reports)?,
157 name: name.try_lift(meta, reports)?,
158 })
159 } else {
160 Ok(ir::Expression::Access {
161 meta: meta.try_lift((), reports)?,
162 var: name.try_lift(meta, reports)?,
163 access: access
164 .iter()
165 .map(|access| access.try_lift((), reports))
166 .collect::<IRResult<Vec<ir::AccessType>>>()?,
167 })
168 }
169 }
170 ast::Expression::Number(meta, value) => {
171 Ok(ir::Expression::Number(meta.try_lift((), reports)?, value.clone()))
172 }
173 ast::Expression::Call { meta, id, args } => Ok(ir::Expression::Call {
174 meta: meta.try_lift((), reports)?,
175 name: id.clone(),
176 args: args
177 .iter()
178 .map(|arg| arg.try_lift((), reports))
179 .collect::<IRResult<Vec<ir::Expression>>>()?,
180 }),
181 ast::Expression::ArrayInLine { meta, values } => Ok(ir::Expression::InlineArray {
182 meta: meta.try_lift((), reports)?,
183 values: values
184 .iter()
185 .map(|value| value.try_lift((), reports))
186 .collect::<IRResult<Vec<ir::Expression>>>()?,
187 }),
188 ast::Expression::ParallelOp { rhe, .. } => rhe.try_lift((), reports),
191 ast::Expression::Tuple { .. } | ast::Expression::AnonymousComponent { .. } => {
192 panic!("failed to convert AST expression to IR")
194 }
195 }
196 }
197}
198
199impl TryLift<()> for ast::Meta {
201 type IR = ir::Meta;
202 type Error = IRError;
203
204 fn try_lift(&self, _: (), _: &mut ReportCollection) -> IRResult<Self::IR> {
205 Ok(ir::Meta::new(&self.location, &self.file_id))
206 }
207}
208
209impl TryLift<()> for ast::VariableType {
211 type IR = ir::VariableType;
212 type Error = IRError;
213
214 fn try_lift(&self, _: (), reports: &mut ReportCollection) -> IRResult<Self::IR> {
215 match self {
216 ast::VariableType::Var => Ok(ir::VariableType::Local),
217 ast::VariableType::Component => Ok(ir::VariableType::Component),
218 ast::VariableType::AnonymousComponent => Ok(ir::VariableType::AnonymousComponent),
219 ast::VariableType::Signal(signal_type, tag_list) => {
220 Ok(ir::VariableType::Signal(signal_type.try_lift((), reports)?, tag_list.clone()))
221 }
222 }
223 }
224}
225
226impl TryLift<()> for ast::SignalType {
228 type IR = ir::SignalType;
229 type Error = IRError;
230
231 fn try_lift(&self, _: (), _: &mut ReportCollection) -> IRResult<Self::IR> {
232 match self {
233 ast::SignalType::Input => Ok(ir::SignalType::Input),
234 ast::SignalType::Output => Ok(ir::SignalType::Output),
235 ast::SignalType::Intermediate => Ok(ir::SignalType::Intermediate),
236 }
237 }
238}
239
240impl TryLift<&ast::Meta> for String {
242 type IR = ir::VariableName;
243 type Error = IRError;
244
245 fn try_lift(&self, meta: &ast::Meta, _: &mut ReportCollection) -> IRResult<Self::IR> {
246 let tokens: Vec<_> = self.split('.').collect();
248 match tokens.len() {
249 1 => Ok(ir::VariableName::from_string(tokens[0])),
250 2 => Ok(ir::VariableName::from_string(tokens[0]).with_suffix(tokens[1])),
251 _ => Err(IRError::InvalidVariableNameError {
255 name: self.clone(),
256 file_id: meta.file_id,
257 file_location: meta.location.clone(),
258 }),
259 }
260 }
261}
262
263impl TryLift<()> for ast::Access {
265 type IR = ir::AccessType;
266 type Error = IRError;
267
268 fn try_lift(&self, _: (), reports: &mut ReportCollection) -> IRResult<Self::IR> {
269 match self {
270 ast::Access::ArrayAccess(expr) => {
271 Ok(ir::AccessType::ArrayAccess(Box::new(expr.try_lift((), reports)?)))
272 }
273 ast::Access::ComponentAccess(s) => Ok(ir::AccessType::ComponentAccess(s.clone())),
274 }
275 }
276}
277
278impl TryLift<()> for ast::AssignOp {
280 type IR = ir::AssignOp;
281 type Error = IRError;
282
283 fn try_lift(&self, _: (), _: &mut ReportCollection) -> IRResult<Self::IR> {
284 match self {
285 ast::AssignOp::AssignSignal => Ok(ir::AssignOp::AssignSignal),
286 ast::AssignOp::AssignVar => Ok(ir::AssignOp::AssignLocalOrComponent),
287 ast::AssignOp::AssignConstraintSignal => Ok(ir::AssignOp::AssignConstraintSignal),
288 }
289 }
290}
291
292impl TryLift<()> for ast::ExpressionPrefixOpcode {
294 type IR = ir::ExpressionPrefixOpcode;
295 type Error = IRError;
296
297 fn try_lift(&self, _: (), _: &mut ReportCollection) -> IRResult<Self::IR> {
298 match self {
299 ast::ExpressionPrefixOpcode::Sub => Ok(ir::ExpressionPrefixOpcode::Sub),
300 ast::ExpressionPrefixOpcode::BoolNot => Ok(ir::ExpressionPrefixOpcode::BoolNot),
301 ast::ExpressionPrefixOpcode::Complement => Ok(ir::ExpressionPrefixOpcode::Complement),
302 }
303 }
304}
305
306impl TryLift<()> for ast::ExpressionInfixOpcode {
308 type IR = ir::ExpressionInfixOpcode;
309 type Error = IRError;
310
311 fn try_lift(&self, _: (), _: &mut ReportCollection) -> IRResult<Self::IR> {
312 match self {
313 ast::ExpressionInfixOpcode::Mul => Ok(ir::ExpressionInfixOpcode::Mul),
314 ast::ExpressionInfixOpcode::Div => Ok(ir::ExpressionInfixOpcode::Div),
315 ast::ExpressionInfixOpcode::Add => Ok(ir::ExpressionInfixOpcode::Add),
316 ast::ExpressionInfixOpcode::Sub => Ok(ir::ExpressionInfixOpcode::Sub),
317 ast::ExpressionInfixOpcode::Pow => Ok(ir::ExpressionInfixOpcode::Pow),
318 ast::ExpressionInfixOpcode::IntDiv => Ok(ir::ExpressionInfixOpcode::IntDiv),
319 ast::ExpressionInfixOpcode::Mod => Ok(ir::ExpressionInfixOpcode::Mod),
320 ast::ExpressionInfixOpcode::ShiftL => Ok(ir::ExpressionInfixOpcode::ShiftL),
321 ast::ExpressionInfixOpcode::ShiftR => Ok(ir::ExpressionInfixOpcode::ShiftR),
322 ast::ExpressionInfixOpcode::LesserEq => Ok(ir::ExpressionInfixOpcode::LesserEq),
323 ast::ExpressionInfixOpcode::GreaterEq => Ok(ir::ExpressionInfixOpcode::GreaterEq),
324 ast::ExpressionInfixOpcode::Lesser => Ok(ir::ExpressionInfixOpcode::Lesser),
325 ast::ExpressionInfixOpcode::Greater => Ok(ir::ExpressionInfixOpcode::Greater),
326 ast::ExpressionInfixOpcode::Eq => Ok(ir::ExpressionInfixOpcode::Eq),
327 ast::ExpressionInfixOpcode::NotEq => Ok(ir::ExpressionInfixOpcode::NotEq),
328 ast::ExpressionInfixOpcode::BoolOr => Ok(ir::ExpressionInfixOpcode::BoolOr),
329 ast::ExpressionInfixOpcode::BoolAnd => Ok(ir::ExpressionInfixOpcode::BoolAnd),
330 ast::ExpressionInfixOpcode::BitOr => Ok(ir::ExpressionInfixOpcode::BitOr),
331 ast::ExpressionInfixOpcode::BitAnd => Ok(ir::ExpressionInfixOpcode::BitAnd),
332 ast::ExpressionInfixOpcode::BitXor => Ok(ir::ExpressionInfixOpcode::BitXor),
333 }
334 }
335}
336
337impl TryLift<()> for LogArgument {
338 type IR = ir::LogArgument;
339 type Error = IRError;
340
341 fn try_lift(&self, _: (), reports: &mut ReportCollection) -> IRResult<Self::IR> {
342 match self {
343 ast::LogArgument::LogStr(message) => Ok(ir::LogArgument::String(message.clone())),
344 ast::LogArgument::LogExp(value) => {
345 Ok(ir::LogArgument::Expr(Box::new(value.try_lift((), reports)?)))
346 }
347 }
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use proptest::prelude::*;
354
355 use crate::report::ReportCollection;
356
357 use super::*;
358
359 proptest! {
360 #[test]
361 fn variable_name_from_string(name in "[$_]*[a-zA-Z][a-zA-Z$_0-9]*") {
362 let meta = ast::Meta::new(0, 1);
363 let mut reports = ReportCollection::new();
364
365 let var = name.try_lift(&meta, &mut reports).unwrap();
366 assert!(var.suffix().is_none());
367 assert!(var.version().is_none());
368 assert!(reports.is_empty());
369 }
370
371 #[test]
372 fn variable_name_with_suffix_from_string(name in "[$_]*[a-zA-Z][a-zA-Z$_0-9]*\\.[a-zA-Z$_0-9]*") {
373 let meta = ast::Meta::new(0, 1);
374 let mut reports = ReportCollection::new();
375
376 let var = name.try_lift(&meta, &mut reports).unwrap();
377 assert!(var.suffix().is_some());
378 assert!(var.version().is_none());
379 assert!(reports.is_empty());
380 }
381
382 #[test]
383 fn variable_name_from_invalid_string(name in "[$_]*[a-zA-Z][a-zA-Z$_0-9]*\\.[a-zA-Z$_0-9]*\\.[a-zA-Z$_0-9]*") {
384 let meta = ast::Meta::new(0, 1);
385 let mut reports = ReportCollection::new();
386
387 let result = name.try_lift(&meta, &mut reports);
388 assert!(result.is_err());
389 assert!(reports.is_empty());
390 }
391 }
392}