neo_solidity/ir/expressions/calls/storage_array/
state_var.rs1fn try_lower_state_array_helpers(
2 func: &Expression,
3 args: &[Expression],
4 ctx: &mut LoweringContext,
5 instructions: &mut Vec<Instruction>,
6) -> Option<bool> {
7 let Expression::MemberAccess(_, inner, member) = func else {
8 return None;
9 };
10
11 if !matches!(member.name.as_str(), "push" | "pop") {
12 return None;
13 }
14
15 let Expression::Variable(base) = inner.as_ref() else {
16 return None;
17 };
18
19 let state_index = ctx.state_index_map.get(&base.name).copied()?;
20
21 let Some(ValueType::Array(element_type)) = ctx.state_type(state_index).cloned() else {
22 return None;
23 };
24
25 match member.name.as_str() {
26 "push" => Some(lower_state_array_push(state_index, args, ctx, instructions)),
27 "pop" => Some(lower_state_array_pop(
28 state_index,
29 element_type.as_ref(),
30 args,
31 ctx,
32 instructions,
33 )),
34 _ => None,
35 }
36}
37
38fn lower_state_array_push(
39 state_index: usize,
40 args: &[Expression],
41 ctx: &mut LoweringContext,
42 instructions: &mut Vec<Instruction>,
43) -> bool {
44 if args.len() != 1 {
45 ctx.record_error("array push expects exactly one argument");
46 return false;
47 }
48
49 if !lower_expression(&args[0], ctx, instructions) {
50 return false;
51 }
52 let value_local = ctx.allocate_local("__array_push_value".to_string(), None);
53 instructions.push(Instruction::StoreLocal(value_local));
54
55 let len_local = ctx.allocate_local("__array_len".to_string(), None);
56 instructions.push(Instruction::LoadState(state_index));
57 instructions.push(Instruction::StoreLocal(len_local));
58
59 instructions.push(Instruction::LoadLocal(value_local));
61 instructions.push(Instruction::LoadLocal(len_local));
62 instructions.push(Instruction::StoreMappingElement {
63 state_index,
64 key_types: vec![ValueType::Integer {
65 signed: false,
66 bits: 256,
67 }],
68 });
69
70 instructions.push(Instruction::LoadLocal(len_local));
72 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::one())));
73 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
74 instructions.push(Instruction::StoreState(state_index));
75
76 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
77 true
78}
79
80fn lower_state_array_pop(
81 state_index: usize,
82 element_type: &ValueType,
83 args: &[Expression],
84 ctx: &mut LoweringContext,
85 instructions: &mut Vec<Instruction>,
86) -> bool {
87 if !args.is_empty() {
88 ctx.record_error("array pop expects no arguments");
89 return false;
90 }
91
92 let len_local = ctx.allocate_local("__array_len".to_string(), None);
93 instructions.push(Instruction::LoadState(state_index));
94 instructions.push(Instruction::StoreLocal(len_local));
95
96 let empty_label = ctx.next_label();
97 let end_label = ctx.next_label();
98
99 instructions.push(Instruction::LoadLocal(len_local));
101 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
102 instructions.push(Instruction::BinaryOp(BinaryOperator::Ne));
103 instructions.push(Instruction::JumpIf { target: empty_label });
104
105 let new_len_local = ctx.allocate_local("__array_new_len".to_string(), None);
106 instructions.push(Instruction::LoadLocal(len_local));
107 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::one())));
108 instructions.push(Instruction::BinaryOp(BinaryOperator::Sub));
109 instructions.push(Instruction::StoreLocal(new_len_local));
110
111 instructions.push(Instruction::LoadLocal(new_len_local));
113 instructions.push(Instruction::StoreState(state_index));
114
115 instructions.push(Instruction::LoadLocal(new_len_local));
117 instructions.push(Instruction::LoadMappingElement {
118 state_index,
119 key_types: vec![ValueType::Integer {
120 signed: false,
121 bits: 256,
122 }],
123 });
124
125 let popped_local = ctx.allocate_local("__array_popped".to_string(), Some(element_type.clone()));
126 instructions.push(Instruction::StoreLocal(popped_local));
127
128 push_default_for_value_type(element_type, ctx, instructions);
130 instructions.push(Instruction::LoadLocal(new_len_local));
131 instructions.push(Instruction::StoreMappingElement {
132 state_index,
133 key_types: vec![ValueType::Integer {
134 signed: false,
135 bits: 256,
136 }],
137 });
138
139 instructions.push(Instruction::LoadLocal(popped_local));
140 instructions.push(Instruction::Jump { target: end_label });
141
142 instructions.push(Instruction::Label(empty_label));
143 instructions.push(Instruction::PushLiteral(LiteralValue::Null));
144 instructions.push(Instruction::Throw);
145
146 instructions.push(Instruction::Label(end_label));
147 true
148}