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