1use crate::{
18 Annotation,
19 CompositeType,
20 Function,
21 FutureType,
22 Identifier,
23 Input,
24 Location,
25 Mode,
26 Node,
27 NodeID,
28 Output,
29 Path,
30 ProgramId,
31 TupleType,
32 Type,
33 Variant,
34};
35use leo_span::{Span, Symbol, sym};
36
37use itertools::Itertools;
38use serde::{Deserialize, Serialize};
39use snarkvm::{
40 console::program::{
41 FinalizeType::{Future as FutureFinalizeType, Plaintext as PlaintextFinalizeType},
42 RegisterType::{ExternalRecord, Future, Plaintext, Record},
43 },
44 prelude::{Network, ValueType},
45 synthesizer::program::{ClosureCore, FunctionCore},
46};
47use std::fmt;
48
49#[derive(Clone, Serialize, Deserialize)]
51pub struct FunctionStub {
52 pub annotations: Vec<Annotation>,
54 pub variant: Variant,
56 pub identifier: Identifier,
58 pub input: Vec<Input>,
60 pub output: Vec<Output>,
62 pub output_type: Type,
64 pub span: Span,
66 pub id: NodeID,
68}
69
70impl PartialEq for FunctionStub {
71 fn eq(&self, other: &Self) -> bool {
72 self.identifier == other.identifier
73 }
74}
75
76impl Eq for FunctionStub {}
77
78impl FunctionStub {
79 #[allow(clippy::too_many_arguments)]
81 pub fn new(
82 annotations: Vec<Annotation>,
83 _is_async: bool,
84 variant: Variant,
85 identifier: Identifier,
86 input: Vec<Input>,
87 output: Vec<Output>,
88 span: Span,
89 id: NodeID,
90 ) -> Self {
91 let output_type = match output.len() {
92 0 => Type::Unit,
93 1 => output[0].type_.clone(),
94 _ => Type::Tuple(TupleType::new(output.iter().map(|o| o.type_.clone()).collect())),
95 };
96
97 FunctionStub { annotations, variant, identifier, input, output, output_type, span, id }
98 }
99
100 pub fn name(&self) -> Symbol {
102 self.identifier.name
103 }
104
105 pub fn is_main(&self) -> bool {
107 self.name() == sym::main
108 }
109
110 fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 match self.variant {
113 Variant::Inline => write!(f, "inline ")?,
114 Variant::Script => write!(f, "script ")?,
115 Variant::Function | Variant::AsyncFunction => write!(f, "function ")?,
116 Variant::Transition | Variant::AsyncTransition => write!(f, "transition ")?,
117 }
118 write!(f, "{}", self.identifier)?;
119
120 let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
121 let returns = match self.output.len() {
122 0 => "()".to_string(),
123 1 => self.output[0].to_string(),
124 _ => self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","),
125 };
126 write!(f, "({parameters}) -> {returns}")?;
127
128 Ok(())
129 }
130
131 pub fn from_function_core<N: Network>(function: &FunctionCore<N>, program: Symbol) -> Self {
133 let outputs = function
134 .outputs()
135 .iter()
136 .map(|output| match output.value_type() {
137 ValueType::Constant(val) => vec![Output {
138 mode: Mode::Constant,
139 type_: Type::from_snarkvm(val, None),
140 span: Default::default(),
141 id: Default::default(),
142 }],
143 ValueType::Public(val) => vec![Output {
144 mode: Mode::Public,
145 type_: Type::from_snarkvm(val, None),
146 span: Default::default(),
147 id: Default::default(),
148 }],
149 ValueType::Private(val) => vec![Output {
150 mode: Mode::Private,
151 type_: Type::from_snarkvm(val, None),
152 span: Default::default(),
153 id: Default::default(),
154 }],
155 ValueType::Record(id) => vec![Output {
156 mode: Mode::None,
157 type_: Type::Composite(CompositeType {
158 path: {
159 let ident = Identifier::from(id);
160 Path::from(ident).with_absolute_path(Some(vec![ident.name]))
161 },
162 const_arguments: Vec::new(),
163 program: Some(program),
164 }),
165 span: Default::default(),
166 id: Default::default(),
167 }],
168 ValueType::ExternalRecord(loc) => {
169 vec![Output {
170 mode: Mode::None,
171 span: Default::default(),
172 id: Default::default(),
173 type_: Type::Composite(CompositeType {
174 path: {
175 let ident = Identifier::from(loc.resource());
176 Path::from(ident).with_absolute_path(Some(vec![ident.name]))
177 },
178 const_arguments: Vec::new(),
179 program: Some(ProgramId::from(loc.program_id()).name.name),
180 }),
181 }]
182 }
183 ValueType::Future(_) => vec![Output {
184 mode: Mode::None,
185 span: Default::default(),
186 id: Default::default(),
187 type_: Type::Future(FutureType::new(
188 Vec::new(),
189 Some(Location::new(program, vec![Symbol::intern(&function.name().to_string())])),
190 false,
191 )),
192 }],
193 })
194 .collect_vec()
195 .concat();
196 let output_vec = outputs.iter().map(|output| output.type_.clone()).collect_vec();
197 let output_type = match output_vec.len() {
198 0 => Type::Unit,
199 1 => output_vec[0].clone(),
200 _ => Type::Tuple(TupleType::new(output_vec)),
201 };
202
203 Self {
204 annotations: Vec::new(),
205 variant: match function.finalize_logic().is_some() {
206 true => Variant::AsyncTransition,
207 false => Variant::Transition,
208 },
209 identifier: Identifier::from(function.name()),
210 input: function
211 .inputs()
212 .iter()
213 .enumerate()
214 .map(|(index, input)| {
215 let arg_name = Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default());
216 match input.value_type() {
217 ValueType::Constant(val) => Input {
218 identifier: arg_name,
219 mode: Mode::Constant,
220 type_: Type::from_snarkvm(val, None),
221 span: Default::default(),
222 id: Default::default(),
223 },
224 ValueType::Public(val) => Input {
225 identifier: arg_name,
226 mode: Mode::Public,
227 type_: Type::from_snarkvm(val, None),
228 span: Default::default(),
229 id: Default::default(),
230 },
231 ValueType::Private(val) => Input {
232 identifier: arg_name,
233 mode: Mode::Private,
234 type_: Type::from_snarkvm(val, None),
235 span: Default::default(),
236 id: Default::default(),
237 },
238 ValueType::Record(id) => Input {
239 identifier: arg_name,
240 mode: Mode::None,
241 type_: Type::Composite(CompositeType {
242 path: {
243 let ident = Identifier::from(id);
244 Path::from(ident).with_absolute_path(Some(vec![ident.name]))
245 },
246 const_arguments: Vec::new(),
247 program: Some(program),
248 }),
249 span: Default::default(),
250 id: Default::default(),
251 },
252 ValueType::ExternalRecord(loc) => Input {
253 identifier: arg_name,
254 mode: Mode::None,
255 span: Default::default(),
256 id: Default::default(),
257 type_: Type::Composite(CompositeType {
258 path: {
259 let ident = Identifier::from(loc.resource());
260 Path::from(ident).with_absolute_path(Some(vec![ident.name]))
261 },
262 const_arguments: Vec::new(),
263 program: Some(ProgramId::from(loc.program_id()).name.name),
264 }),
265 },
266 ValueType::Future(_) => panic!("Functions do not contain futures as inputs"),
267 }
268 })
269 .collect_vec(),
270 output: outputs,
271 output_type,
272 span: Default::default(),
273 id: Default::default(),
274 }
275 }
276
277 pub fn from_finalize<N: Network>(function: &FunctionCore<N>, key_name: Symbol, program: Symbol) -> Self {
278 Self {
279 annotations: Vec::new(),
280 variant: Variant::AsyncFunction,
281 identifier: Identifier::new(key_name, Default::default()),
282 input: function
283 .finalize_logic()
284 .unwrap()
285 .inputs()
286 .iter()
287 .enumerate()
288 .map(|(index, input)| Input {
289 identifier: Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default()),
290 mode: Mode::None,
291 type_: match input.finalize_type() {
292 PlaintextFinalizeType(val) => Type::from_snarkvm(val, Some(program)),
293 FutureFinalizeType(val) => Type::Future(FutureType::new(
294 Vec::new(),
295 Some(Location::new(Identifier::from(val.program_id().name()).name, vec![Symbol::intern(
296 &format!("finalize/{}", val.resource()),
297 )])),
298 false,
299 )),
300 },
301 span: Default::default(),
302 id: Default::default(),
303 })
304 .collect_vec(),
305 output: Vec::new(),
306 output_type: Type::Unit,
307 span: Default::default(),
308 id: 0,
309 }
310 }
311
312 pub fn from_closure<N: Network>(closure: &ClosureCore<N>, program: Symbol) -> Self {
313 let outputs = closure
314 .outputs()
315 .iter()
316 .map(|output| match output.register_type() {
317 Plaintext(val) => Output {
318 mode: Mode::None,
319 type_: Type::from_snarkvm(val, Some(program)),
320 span: Default::default(),
321 id: Default::default(),
322 },
323 Record(_) => panic!("Closures do not return records"),
324 ExternalRecord(_) => panic!("Closures do not return external records"),
325 Future(_) => panic!("Closures do not return futures"),
326 })
327 .collect_vec();
328 let output_vec = outputs.iter().map(|output| output.type_.clone()).collect_vec();
329 let output_type = match output_vec.len() {
330 0 => Type::Unit,
331 1 => output_vec[0].clone(),
332 _ => Type::Tuple(TupleType::new(output_vec)),
333 };
334 Self {
335 annotations: Vec::new(),
336 variant: Variant::Function,
337 identifier: Identifier::from(closure.name()),
338 input: closure
339 .inputs()
340 .iter()
341 .enumerate()
342 .map(|(index, input)| {
343 let arg_name = Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default());
344 match input.register_type() {
345 Plaintext(val) => Input {
346 identifier: arg_name,
347 mode: Mode::None,
348 type_: Type::from_snarkvm(val, None),
349 span: Default::default(),
350 id: Default::default(),
351 },
352 Record(_) => panic!("Closures do not contain records as inputs"),
353 ExternalRecord(_) => panic!("Closures do not contain external records as inputs"),
354 Future(_) => panic!("Closures do not contain futures as inputs"),
355 }
356 })
357 .collect_vec(),
358 output: outputs,
359 output_type,
360 span: Default::default(),
361 id: Default::default(),
362 }
363 }
364}
365
366impl From<Function> for FunctionStub {
367 fn from(function: Function) -> Self {
368 Self {
369 annotations: function.annotations,
370 variant: function.variant,
371 identifier: function.identifier,
372 input: function.input,
373 output: function.output,
374 output_type: function.output_type,
375 span: function.span,
376 id: function.id,
377 }
378 }
379}
380
381impl fmt::Debug for FunctionStub {
382 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383 self.format(f)
384 }
385}
386
387impl fmt::Display for FunctionStub {
388 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
389 self.format(f)
390 }
391}
392
393crate::simple_node_impl!(FunctionStub);