leo_passes/destructuring/
visitor.rs1use crate::CompilerState;
18
19use leo_ast::{
20 AstReconstructor,
21 BinaryExpression,
22 BinaryOperation,
23 DefinitionPlace,
24 DefinitionStatement,
25 Expression,
26 Identifier,
27 Node as _,
28 Path,
29 Statement,
30 TupleExpression,
31 Type,
32};
33use leo_span::Symbol;
34
35use indexmap::IndexMap;
36
37pub struct DestructuringVisitor<'a> {
38 pub state: &'a mut CompilerState,
39 pub tuples: IndexMap<Symbol, Vec<Identifier>>,
41 pub is_async: bool,
43}
44
45impl DestructuringVisitor<'_> {
46 pub fn reconstruct_expression_tuple(&mut self, expression: Expression) -> (Expression, Vec<Statement>) {
49 let Type::Tuple(tuple_type) =
50 self.state.type_table.get(&expression.id()).expect("Expressions should have types.")
51 else {
52 return self.reconstruct_expression(expression, &());
54 };
55
56 let (new_expression, mut statements) = self.reconstruct_expression(expression, &());
57
58 match new_expression {
59 Expression::Path(path) => {
60 let identifiers = self.tuples.get(&path.identifier().name).expect("Tuples should have been found");
62 let elements: Vec<Expression> =
63 identifiers.iter().map(|identifier| Path::from(*identifier).into_absolute().into()).collect();
64
65 let tuple: Expression =
66 TupleExpression { elements, span: Default::default(), id: self.state.node_builder.next_id() }
67 .into();
68
69 self.state.type_table.insert(tuple.id(), Type::Tuple(tuple_type.clone()));
70
71 (tuple, statements)
72 }
73
74 tuple @ Expression::Tuple(..) => {
75 (tuple, statements)
77 }
78
79 expr @ Expression::Call(..) => {
80 let definition_stmt = self.assign_tuple(expr, Symbol::intern("destructure"));
82 let Statement::Definition(DefinitionStatement {
83 place: DefinitionPlace::Multiple(identifiers), ..
84 }) = &definition_stmt
85 else {
86 panic!("`assign_tuple` always creates a definition with `Multiple`");
87 };
88
89 let elements =
90 identifiers.iter().map(|identifier| Path::from(*identifier).into_absolute().into()).collect();
91
92 let expr = Expression::Tuple(TupleExpression {
93 elements,
94 span: Default::default(),
95 id: self.state.node_builder.next_id(),
96 });
97
98 self.state.type_table.insert(expr.id(), Type::Tuple(tuple_type.clone()));
99
100 statements.push(definition_stmt);
101
102 (expr, statements)
103 }
104
105 _ => panic!("Tuples may only be identifiers, tuple literals, or calls."),
106 }
107 }
108
109 pub fn fold_with_op<I>(&mut self, op: BinaryOperation, pieces: I) -> Expression
117 where
118 I: Iterator<Item = Expression>,
119 {
120 pieces
121 .reduce(|left, right| {
122 let expr: Expression = BinaryExpression {
123 op,
124 left,
125 right,
126 span: Default::default(),
127 id: self.state.node_builder.next_id(),
128 }
129 .into();
130
131 self.state.type_table.insert(expr.id(), Type::Boolean);
132 expr
133 })
134 .expect("fold_with_op called with empty iterator")
135 }
136
137 pub fn assign_tuple(&mut self, expression: Expression, name: Symbol) -> Statement {
141 let Type::Tuple(tuple_type) =
142 self.state.type_table.get(&expression.id()).expect("Expressions should have types.")
143 else {
144 panic!("assign_tuple should only be called for tuple types.");
145 };
146
147 let new_identifiers: Vec<Identifier> = (0..tuple_type.length())
148 .map(|i| {
149 let new_symbol = self.state.assigner.unique_symbol(name, format_args!("#{i}#"));
150 Identifier::new(new_symbol, self.state.node_builder.next_id())
151 })
152 .collect();
153
154 Statement::Definition(DefinitionStatement {
155 place: DefinitionPlace::Multiple(new_identifiers),
156 type_: Some(Type::Tuple(tuple_type.clone())),
157 value: expression,
158 span: Default::default(),
159 id: self.state.node_builder.next_id(),
160 })
161 }
162}