cairo_lang_lowering/lower/
generators.rs1use cairo_lang_semantic as semantic;
5use cairo_lang_semantic::ConcreteVariant;
6use cairo_lang_semantic::items::constant::ConstValueId;
7use cairo_lang_utils::{Intern, extract_matches};
8use itertools::chain;
9
10use super::VariableId;
11use super::context::VarRequest;
12use crate::ids::LocationId;
13use crate::lower::context::LoweringContext;
14use crate::objects::{
15 Statement, StatementCall, StatementConst, StatementStructConstruct, StatementStructDestructure,
16 VarUsage,
17};
18use crate::{StatementDesnap, StatementEnumConstruct, StatementSnapshot};
19
20#[derive(Clone, Default)]
21pub struct StatementsBuilder<'db> {
22 pub statements: Vec<Statement<'db>>,
23}
24impl<'db> StatementsBuilder<'db> {
25 pub fn push_statement(&mut self, statement: Statement<'db>) {
27 self.statements.push(statement);
28 }
29}
30
31pub struct Const<'db> {
33 pub value: ConstValueId<'db>,
34 pub location: LocationId<'db>,
35 pub ty: semantic::TypeId<'db>,
37}
38impl<'db> Const<'db> {
39 pub fn add(
40 self,
41 ctx: &mut LoweringContext<'db, '_>,
42 builder: &mut StatementsBuilder<'db>,
43 ) -> VarUsage<'db> {
44 let output = ctx.new_var(VarRequest { ty: self.ty, location: self.location });
45 builder.push_statement(Statement::Const(StatementConst::new_flat(self.value, output)));
46 VarUsage { var_id: output, location: self.location }
47 }
48}
49
50pub struct Call<'db> {
53 pub function: crate::ids::FunctionId<'db>,
55 pub inputs: Vec<VarUsage<'db>>,
57 pub coupon_input: Option<VarUsage<'db>>,
59 pub extra_ret_tys: Vec<semantic::TypeId<'db>>,
61 pub ret_tys: Vec<semantic::TypeId<'db>>,
63 pub location: LocationId<'db>,
65}
66impl<'db> Call<'db> {
67 pub fn add(
69 self,
70 ctx: &mut LoweringContext<'db, '_>,
71 builder: &mut StatementsBuilder<'db>,
72 ) -> CallResult<'db> {
73 let returns = self
74 .ret_tys
75 .into_iter()
76 .map(|ty| ctx.new_var_usage(VarRequest { ty, location: self.location }))
77 .collect();
78 let extra_outputs = self
79 .extra_ret_tys
80 .into_iter()
81 .map(|ty| ctx.new_var_usage(VarRequest { ty, location: self.location }))
82 .collect();
83 let outputs = chain!(&extra_outputs, &returns)
84 .map(|var_usage: &VarUsage<'_>| var_usage.var_id)
85 .collect();
86
87 let with_coupon = self.coupon_input.is_some();
88 let mut inputs = self.inputs;
89 inputs.extend(self.coupon_input);
90 builder.push_statement(Statement::Call(StatementCall {
91 function: self.function,
92 inputs,
93 with_coupon,
94 outputs,
95 location: self.location,
96 }));
97
98 CallResult { returns, extra_outputs }
99 }
100}
101pub struct CallResult<'db> {
103 pub returns: Vec<VarUsage<'db>>,
105 pub extra_outputs: Vec<VarUsage<'db>>,
107}
108
109pub struct EnumConstruct<'db> {
111 pub input: VarUsage<'db>,
112 pub variant: ConcreteVariant<'db>,
113 pub location: LocationId<'db>,
114}
115impl<'db> EnumConstruct<'db> {
116 pub fn add(
117 self,
118 ctx: &mut LoweringContext<'db, '_>,
119 builder: &mut StatementsBuilder<'db>,
120 ) -> VarUsage<'db> {
121 let ty = semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(
122 self.variant.concrete_enum_id,
123 ))
124 .intern(ctx.db);
125 let output = ctx.new_var(VarRequest { ty, location: self.location });
126 builder.push_statement(Statement::EnumConstruct(StatementEnumConstruct {
127 variant: self.variant,
128 input: self.input,
129 output,
130 }));
131 VarUsage { var_id: output, location: self.location }
132 }
133}
134
135pub struct Snapshot<'db> {
137 pub input: VarUsage<'db>,
138 pub location: LocationId<'db>,
139}
140impl<'db> Snapshot<'db> {
141 pub fn add(
142 self,
143 ctx: &mut LoweringContext<'db, '_>,
144 builder: &mut StatementsBuilder<'db>,
145 ) -> (VariableId, VariableId) {
146 let input_var = &ctx.variables[self.input.var_id];
147 let input_ty = input_var.ty;
148 let ty = semantic::TypeLongId::Snapshot(input_ty).intern(ctx.db);
149
150 let output_original =
152 ctx.new_var(VarRequest { ty: input_ty, location: input_var.location });
153 let output_snapshot = ctx.new_var(VarRequest { ty, location: self.location });
154 builder.push_statement(Statement::Snapshot(StatementSnapshot::new(
155 self.input,
156 output_original,
157 output_snapshot,
158 )));
159 (output_original, output_snapshot)
160 }
161}
162
163pub struct Desnap<'db> {
165 pub input: VarUsage<'db>,
166 pub location: LocationId<'db>,
167}
168impl<'db> Desnap<'db> {
169 pub fn add(
170 self,
171 ctx: &mut LoweringContext<'db, '_>,
172 builder: &mut StatementsBuilder<'db>,
173 ) -> VarUsage<'db> {
174 let ty = extract_matches!(
175 ctx.variables[self.input.var_id].ty.long(ctx.db),
176 semantic::TypeLongId::Snapshot
177 );
178 let output = ctx.new_var(VarRequest { ty: *ty, location: self.location });
179 builder.push_statement(Statement::Desnap(StatementDesnap { input: self.input, output }));
180 VarUsage { var_id: output, location: self.location }
181 }
182}
183
184pub struct StructDestructure<'db> {
189 pub input: VarUsage<'db>,
191 pub var_reqs: Vec<VarRequest<'db>>,
193}
194impl<'db> StructDestructure<'db> {
195 pub fn add(
196 self,
197 ctx: &mut LoweringContext<'db, '_>,
198 builder: &mut StatementsBuilder<'db>,
199 ) -> Vec<VariableId> {
200 let outputs: Vec<_> = self.var_reqs.into_iter().map(|req| ctx.new_var(req)).collect();
201 builder.push_statement(Statement::StructDestructure(StatementStructDestructure {
202 input: self.input,
203 outputs: outputs.clone(),
204 }));
205 outputs
206 }
207}
208
209pub struct StructMemberAccess<'db> {
211 pub input: VarUsage<'db>,
212 pub member_tys: Vec<semantic::TypeId<'db>>,
213 pub member_idx: usize,
214 pub location: LocationId<'db>,
215}
216impl<'db> StructMemberAccess<'db> {
217 pub fn add(
218 self,
219 ctx: &mut LoweringContext<'db, '_>,
220 builder: &mut StatementsBuilder<'db>,
221 ) -> VarUsage<'db> {
222 VarUsage {
223 var_id: StructDestructure {
224 input: self.input,
225 var_reqs: self
226 .member_tys
227 .into_iter()
228 .map(|ty| VarRequest { ty, location: self.location })
229 .collect(),
230 }
231 .add(ctx, builder)
232 .remove(self.member_idx),
233 location: self.location,
234 }
235 }
236}
237
238pub struct StructConstruct<'db> {
240 pub inputs: Vec<VarUsage<'db>>,
241 pub ty: semantic::TypeId<'db>,
242 pub location: LocationId<'db>,
243}
244impl<'db> StructConstruct<'db> {
245 pub fn add(
246 self,
247 ctx: &mut LoweringContext<'db, '_>,
248 builder: &mut StatementsBuilder<'db>,
249 ) -> VarUsage<'db> {
250 let output = ctx.new_var(VarRequest { ty: self.ty, location: self.location });
251 builder.push_statement(Statement::StructConstruct(StatementStructConstruct {
252 inputs: self.inputs,
253 output,
254 }));
255 VarUsage { var_id: output, location: self.location }
256 }
257}