neo_solidity/ir/
ir_deploy.rs1#[allow(clippy::too_many_arguments)]
2fn build_deploy_function(
3 metadata: &FunctionMetadata,
4 constructors: &[&Function],
5 state_variables: &[StateVariableMetadata],
6 state_index_map: &HashMap<String, usize>,
7 state_types: &[ValueType],
8 defined_struct_types: &[ValueType],
9 event_index_map: &HashMap<String, usize>,
10 event_signature_map: &HashMap<String, Vec<ManifestType>>,
11 enum_variant_map: &HashMap<String, HashMap<String, u64>>,
12 contract_types: &HashSet<String>,
13 selector_registry: &SelectorRegistry,
14 function_names: &HashSet<String>,
15 function_overloads: &HashMap<(String, usize), String>,
16 function_param_names: &HashMap<(String, usize), Vec<String>>,
17 void_functions: &HashSet<String>,
18 super_method_map: &HashMap<String, String>,
19) -> Result<Function, Vec<IrDiagnostic>> {
20 let parameters: Vec<ValueType> = metadata
21 .parameters
22 .iter()
23 .map(ValueType::from_parameter)
24 .collect();
25 let returns: Vec<ValueType> = metadata
26 .return_parameters
27 .iter()
28 .map(ValueType::from_parameter)
29 .collect();
30
31 let param_index_map = build_parameter_index_map(metadata);
32 let mut ctx = LoweringContext::new(
33 &metadata.name,
34 false,
35 param_index_map,
36 ¶meters,
37 state_variables,
38 state_index_map,
39 state_types,
40 defined_struct_types,
41 event_index_map,
42 event_signature_map,
43 enum_variant_map,
44 contract_types,
45 selector_registry,
46 function_names,
47 function_overloads,
48 function_param_names,
49 void_functions,
50 super_method_map,
51 );
52
53 let mut init_instructions = Vec::new();
55 for (index, state) in state_variables.iter().enumerate() {
56 if state.is_constant {
57 continue;
58 }
59 if let Some(initializer) = state.initializer.as_ref() {
60 if lower_expression(initializer, &mut ctx, &mut init_instructions) {
61 init_instructions.push(Instruction::StoreState(index));
62 }
63 }
64 }
65
66 if !ctx.errors.is_empty() {
67 return Err(ctx.errors);
68 }
69
70 let mut instructions = Vec::new();
71 let mut local_count = ctx.local_count as usize;
72
73 let has_init = !init_instructions.is_empty();
74 if constructors.is_empty() && !has_init {
75 instructions.push(Instruction::ReturnVoid);
76 } else {
77 let run_label = ctx.next_label();
78 let end_label = ctx.next_label();
79
80 instructions.push(Instruction::LoadParameter(1));
87 instructions.push(Instruction::JumpIf { target: run_label });
88 instructions.push(Instruction::Jump { target: end_label });
89 instructions.push(Instruction::Label(run_label));
90
91 if has_init {
92 instructions.extend(init_instructions);
93 }
94
95 let needs_data_local = constructors.iter().any(|c| !c.parameters.is_empty());
96 let data_local = local_count;
97 if needs_data_local {
98 instructions.push(Instruction::LoadParameter(0));
99 instructions.push(Instruction::StoreLocal(data_local));
100
101 let json_catch_label = ctx.next_label();
116 let deserialize_label = ctx.next_label();
117 let deserialize_catch_label = ctx.next_label();
118 let decode_done_label = ctx.next_label();
119 instructions.push(Instruction::Try {
120 catch_target: json_catch_label,
121 });
122 instructions.push(Instruction::LoadLocal(data_local));
123 instructions.push(Instruction::CallBuiltin {
124 builtin: BuiltinCall::NativeCall {
125 contract: NativeContract::StdLib,
126 method: "jsonDeserialize".to_string(),
127 },
128 arg_count: 1,
129 });
130 instructions.push(Instruction::StoreLocal(data_local));
131 instructions.push(Instruction::EndTry {
132 target: decode_done_label,
133 });
134
135 instructions.push(Instruction::Label(json_catch_label));
136 instructions.push(Instruction::Drop(ValueType::Any));
139 instructions.push(Instruction::EndTry {
140 target: deserialize_label,
141 });
142
143 instructions.push(Instruction::Label(deserialize_label));
144 instructions.push(Instruction::Try {
145 catch_target: deserialize_catch_label,
146 });
147 instructions.push(Instruction::LoadLocal(data_local));
148 instructions.push(Instruction::CallBuiltin {
149 builtin: BuiltinCall::NativeCall {
150 contract: NativeContract::StdLib,
151 method: "deserialize".to_string(),
152 },
153 arg_count: 1,
154 });
155 instructions.push(Instruction::StoreLocal(data_local));
156 instructions.push(Instruction::EndTry {
157 target: decode_done_label,
158 });
159 instructions.push(Instruction::Label(deserialize_catch_label));
160 instructions.push(Instruction::Drop(ValueType::Any));
162 instructions.push(Instruction::EndTry {
163 target: decode_done_label,
164 });
165
166 instructions.push(Instruction::Label(decode_done_label));
167 local_count += 1;
168 }
169
170 for constructor in constructors {
171 let param_count = constructor.parameters.len();
172 if param_count > 0 {
173 for index in 0..param_count {
174 instructions.push(Instruction::LoadLocal(data_local));
175 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
176 BigInt::from(index as u64),
177 )));
178 instructions.push(Instruction::ArrayGet);
179 }
180 }
181
182 instructions.push(Instruction::CallFunction {
183 name: constructor.name.clone(),
184 arg_count: param_count,
185 });
186 }
187
188 instructions.push(Instruction::Label(end_label));
189 instructions.push(Instruction::ReturnVoid);
190 }
191
192 Ok(Function {
193 name: metadata.neo_name.clone(),
194 kind: FunctionKind::Regular,
195 parameters,
196 returns,
197 basic_blocks: vec![BasicBlock { instructions }],
198 local_count: local_count as u16,
199 })
200}