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 is_specialization_base_call: false,
97 }));
98
99 CallResult { returns, extra_outputs }
100 }
101}
102pub struct CallResult<'db> {
104 pub returns: Vec<VarUsage<'db>>,
106 pub extra_outputs: Vec<VarUsage<'db>>,
108}
109
110pub struct EnumConstruct<'db> {
112 pub input: VarUsage<'db>,
113 pub variant: ConcreteVariant<'db>,
114 pub location: LocationId<'db>,
115}
116impl<'db> EnumConstruct<'db> {
117 pub fn add(
118 self,
119 ctx: &mut LoweringContext<'db, '_>,
120 builder: &mut StatementsBuilder<'db>,
121 ) -> VarUsage<'db> {
122 let ty = semantic::TypeLongId::Concrete(semantic::ConcreteTypeId::Enum(
123 self.variant.concrete_enum_id,
124 ))
125 .intern(ctx.db);
126 let output = ctx.new_var(VarRequest { ty, location: self.location });
127 builder.push_statement(Statement::EnumConstruct(StatementEnumConstruct {
128 variant: self.variant,
129 input: self.input,
130 output,
131 }));
132 VarUsage { var_id: output, location: self.location }
133 }
134}
135
136pub struct Snapshot<'db> {
138 pub input: VarUsage<'db>,
139 pub location: LocationId<'db>,
140}
141impl<'db> Snapshot<'db> {
142 pub fn add(
143 self,
144 ctx: &mut LoweringContext<'db, '_>,
145 builder: &mut StatementsBuilder<'db>,
146 ) -> (VariableId, VariableId) {
147 let input_var = &ctx.variables[self.input.var_id];
148 let input_ty = input_var.ty;
149 let ty = semantic::TypeLongId::Snapshot(input_ty).intern(ctx.db);
150
151 let output_original =
153 ctx.new_var(VarRequest { ty: input_ty, location: input_var.location });
154 let output_snapshot = ctx.new_var(VarRequest { ty, location: self.location });
155 builder.push_statement(Statement::Snapshot(StatementSnapshot::new(
156 self.input,
157 output_original,
158 output_snapshot,
159 )));
160 (output_original, output_snapshot)
161 }
162}
163
164pub struct Desnap<'db> {
166 pub input: VarUsage<'db>,
167 pub location: LocationId<'db>,
168}
169impl<'db> Desnap<'db> {
170 pub fn add(
171 self,
172 ctx: &mut LoweringContext<'db, '_>,
173 builder: &mut StatementsBuilder<'db>,
174 ) -> VarUsage<'db> {
175 let ty = extract_matches!(
176 ctx.variables[self.input.var_id].ty.long(ctx.db),
177 semantic::TypeLongId::Snapshot
178 );
179 let output = ctx.new_var(VarRequest { ty: *ty, location: self.location });
180 builder.push_statement(Statement::Desnap(StatementDesnap { input: self.input, output }));
181 VarUsage { var_id: output, location: self.location }
182 }
183}
184
185pub struct StructDestructure<'db> {
190 pub input: VarUsage<'db>,
192 pub var_reqs: Vec<VarRequest<'db>>,
194}
195impl<'db> StructDestructure<'db> {
196 pub fn add(
197 self,
198 ctx: &mut LoweringContext<'db, '_>,
199 builder: &mut StatementsBuilder<'db>,
200 ) -> Vec<VariableId> {
201 let outputs: Vec<_> = self.var_reqs.into_iter().map(|req| ctx.new_var(req)).collect();
202 builder.push_statement(Statement::StructDestructure(StatementStructDestructure {
203 input: self.input,
204 outputs: outputs.clone(),
205 }));
206 outputs
207 }
208}
209
210pub struct StructMemberAccess<'db> {
212 pub input: VarUsage<'db>,
213 pub member_tys: Vec<semantic::TypeId<'db>>,
214 pub member_idx: usize,
215 pub location: LocationId<'db>,
216}
217impl<'db> StructMemberAccess<'db> {
218 pub fn add(
219 self,
220 ctx: &mut LoweringContext<'db, '_>,
221 builder: &mut StatementsBuilder<'db>,
222 ) -> VarUsage<'db> {
223 VarUsage {
224 var_id: StructDestructure {
225 input: self.input,
226 var_reqs: self
227 .member_tys
228 .into_iter()
229 .map(|ty| VarRequest { ty, location: self.location })
230 .collect(),
231 }
232 .add(ctx, builder)
233 .remove(self.member_idx),
234 location: self.location,
235 }
236 }
237}
238
239pub struct StructConstruct<'db> {
241 pub inputs: Vec<VarUsage<'db>>,
242 pub ty: semantic::TypeId<'db>,
243 pub location: LocationId<'db>,
244}
245impl<'db> StructConstruct<'db> {
246 pub fn add(
247 self,
248 ctx: &mut LoweringContext<'db, '_>,
249 builder: &mut StatementsBuilder<'db>,
250 ) -> VarUsage<'db> {
251 let output = ctx.new_var(VarRequest { ty: self.ty, location: self.location });
252 builder.push_statement(Statement::StructConstruct(StatementStructConstruct {
253 inputs: self.inputs,
254 output,
255 }));
256 VarUsage { var_id: output, location: self.location }
257 }
258}