neo_solidity/ir/expressions/
arrays.rs1fn lower_array_subscript_expression(
2 expr: &Expression,
3 array: &Expression,
4 index: &Expression,
5 ctx: &mut LoweringContext,
6 instructions: &mut Vec<Instruction>,
7) -> bool {
8 if let Some(mapping) = resolve_mapping_access(expr, ctx) {
9 let reference = mapping.to_storage_reference();
10 emit_storage_load(&reference, ctx, instructions)
11 } else if lower_expression(array, ctx, instructions) && lower_expression(index, ctx, instructions) {
12 instructions.push(Instruction::ArrayGet);
13 true
14 } else {
15 false
16 }
17}
18
19fn lower_array_slice_expression(
20 array: &Expression,
21 start: Option<&Expression>,
22 end: Option<&Expression>,
23 ctx: &mut LoweringContext,
24 instructions: &mut Vec<Instruction>,
25) -> bool {
26 let array_local = ctx.allocate_local("__slice_array".to_string(), None);
27 if !lower_expression(array, ctx, instructions) {
28 return false;
29 }
30 instructions.push(Instruction::StoreLocal(array_local));
31
32 let start_local = ctx.allocate_local("__slice_start".to_string(), None);
33 if let Some(start_expr) = start {
34 if !lower_expression(start_expr, ctx, instructions) {
35 return false;
36 }
37 } else {
38 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
39 }
40 instructions.push(Instruction::StoreLocal(start_local));
41
42 let end_local = ctx.allocate_local("__slice_end".to_string(), None);
43 if let Some(end_expr) = end {
44 if !lower_expression(end_expr, ctx, instructions) {
45 return false;
46 }
47 } else {
48 instructions.push(Instruction::LoadLocal(array_local));
49 instructions.push(Instruction::GetSize);
50 }
51 instructions.push(Instruction::StoreLocal(end_local));
52
53 let clamp_start_label = ctx.next_label();
55 let clamp_start_done = ctx.next_label();
56 instructions.push(Instruction::LoadLocal(start_local));
57 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
58 instructions.push(Instruction::BinaryOp(BinaryOperator::Ge));
59 instructions.push(Instruction::JumpIf {
60 target: clamp_start_label,
61 });
62 instructions.push(Instruction::Jump {
63 target: clamp_start_done,
64 });
65 instructions.push(Instruction::Label(clamp_start_label));
66 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
67 instructions.push(Instruction::StoreLocal(start_local));
68 instructions.push(Instruction::Label(clamp_start_done));
69
70 let size_local = ctx.allocate_local("__slice_size".to_string(), None);
72 instructions.push(Instruction::LoadLocal(array_local));
73 instructions.push(Instruction::GetSize);
74 instructions.push(Instruction::StoreLocal(size_local));
75
76 let clamp_end_label = ctx.next_label();
77 let clamp_end_done = ctx.next_label();
78 instructions.push(Instruction::LoadLocal(end_local));
79 instructions.push(Instruction::LoadLocal(size_local));
80 instructions.push(Instruction::BinaryOp(BinaryOperator::Le));
81 instructions.push(Instruction::JumpIf {
82 target: clamp_end_label,
83 });
84 instructions.push(Instruction::Jump {
85 target: clamp_end_done,
86 });
87 instructions.push(Instruction::Label(clamp_end_label));
88 instructions.push(Instruction::LoadLocal(size_local));
89 instructions.push(Instruction::StoreLocal(end_local));
90 instructions.push(Instruction::Label(clamp_end_done));
91
92 let len_local = ctx.allocate_local("__slice_len".to_string(), None);
93 instructions.push(Instruction::LoadLocal(end_local));
94 instructions.push(Instruction::LoadLocal(start_local));
95 instructions.push(Instruction::BinaryOp(BinaryOperator::Sub));
96 instructions.push(Instruction::StoreLocal(len_local));
97
98 let clamp_label = ctx.next_label();
99 let clamp_done = ctx.next_label();
100 instructions.push(Instruction::LoadLocal(len_local));
101 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
102 instructions.push(Instruction::BinaryOp(BinaryOperator::Ge));
103 instructions.push(Instruction::JumpIf { target: clamp_label });
104 instructions.push(Instruction::Jump { target: clamp_done });
105 instructions.push(Instruction::Label(clamp_label));
106 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
107 instructions.push(Instruction::StoreLocal(len_local));
108 instructions.push(Instruction::Label(clamp_done));
109
110 let element_type = infer_array_element_type(array, ctx).unwrap_or(ValueType::Any);
111 let slice_array_type = ValueType::Array(Box::new(element_type.clone()));
112 let out_local = ctx.allocate_local("__slice_out".to_string(), Some(slice_array_type));
113 instructions.push(Instruction::LoadLocal(len_local));
114 instructions.push(Instruction::NewArray { element_type });
115 instructions.push(Instruction::StoreLocal(out_local));
116
117 let idx_local = ctx.allocate_local("__slice_index".to_string(), None);
118 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
119 instructions.push(Instruction::StoreLocal(idx_local));
120
121 let loop_label = ctx.next_label();
122 let end_label = ctx.next_label();
123
124 instructions.push(Instruction::Label(loop_label));
125 instructions.push(Instruction::LoadLocal(idx_local));
126 instructions.push(Instruction::LoadLocal(len_local));
127 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
128 instructions.push(Instruction::JumpIf { target: end_label });
129
130 instructions.push(Instruction::LoadLocal(out_local));
131 instructions.push(Instruction::LoadLocal(idx_local));
132 instructions.push(Instruction::LoadLocal(array_local));
133 instructions.push(Instruction::LoadLocal(start_local));
134 instructions.push(Instruction::LoadLocal(idx_local));
135 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
136 instructions.push(Instruction::ArrayGet);
137 instructions.push(Instruction::ArraySet);
138
139 instructions.push(Instruction::LoadLocal(idx_local));
140 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(1u8))));
141 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
142 instructions.push(Instruction::StoreLocal(idx_local));
143
144 instructions.push(Instruction::Jump { target: loop_label });
145 instructions.push(Instruction::Label(end_label));
146 instructions.push(Instruction::LoadLocal(out_local));
147 true
148}
149
150fn lower_array_literal_expression(
151 elements: &[Expression],
152 ctx: &mut LoweringContext,
153 instructions: &mut Vec<Instruction>,
154) -> bool {
155 let element_type = infer_literal_array_element_type(elements);
156 let array_local = ctx.allocate_local(
157 "__array_literal".to_string(),
158 Some(ValueType::Array(Box::new(element_type.clone()))),
159 );
160 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(
161 elements.len(),
162 ))));
163 instructions.push(Instruction::NewArray { element_type });
164 instructions.push(Instruction::StoreLocal(array_local));
165
166 for (index, element) in elements.iter().enumerate() {
167 instructions.push(Instruction::LoadLocal(array_local));
168 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(
169 index as u64,
170 ))));
171 if !lower_expression(element, ctx, instructions) {
172 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
173 }
174 instructions.push(Instruction::ArraySet);
175 }
176
177 instructions.push(Instruction::LoadLocal(array_local));
178 true
179}