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::RegisterType,
41 prelude::{FinalizeType, Network, ValueType},
42 synthesizer::program::{ClosureCore, FunctionCore, ViewCore},
43};
44use std::fmt;
45
46#[derive(Clone, Serialize, Deserialize)]
48pub struct FunctionStub {
49 pub annotations: Vec<Annotation>,
51 pub variant: Variant,
53 pub identifier: Identifier,
55 pub input: Vec<Input>,
57 pub output: Vec<Output>,
59 pub output_type: Type,
61 pub span: Span,
63 pub id: NodeID,
65}
66
67impl PartialEq for FunctionStub {
68 fn eq(&self, other: &Self) -> bool {
69 self.identifier == other.identifier
70 }
71}
72
73impl Eq for FunctionStub {}
74
75impl FunctionStub {
76 #[allow(clippy::too_many_arguments)]
78 pub fn new(
79 annotations: Vec<Annotation>,
80 _is_async: bool,
81 variant: Variant,
82 identifier: Identifier,
83 input: Vec<Input>,
84 output: Vec<Output>,
85 span: Span,
86 id: NodeID,
87 ) -> Self {
88 let output_type = match output.len() {
89 0 => Type::Unit,
90 1 => output[0].type_.clone(),
91 _ => Type::Tuple(TupleType::new(output.iter().map(|o| o.type_.clone()).collect())),
92 };
93
94 FunctionStub { annotations, variant, identifier, input, output, output_type, span, id }
95 }
96
97 pub fn name(&self) -> Symbol {
99 self.identifier.name
100 }
101
102 pub fn is_main(&self) -> bool {
104 self.name() == sym::main
105 }
106
107 pub fn has_final_output(&self) -> bool {
109 self.output.iter().any(|o| matches!(o.type_, Type::Future(_)))
110 }
111
112 fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match self.variant {
115 Variant::FinalFn => write!(f, "final fn ")?,
116 Variant::Finalize => write!(f, "finalize ")?,
117 Variant::Fn => write!(f, "fn ")?,
118 Variant::EntryPoint => write!(f, "entry ")?,
119 Variant::View => write!(f, "view fn ")?,
120 }
121 write!(f, "{}", self.identifier)?;
122
123 let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
124 let returns = match self.output.len() {
125 0 => "()".to_string(),
126 1 => self.output[0].to_string(),
127 _ => self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","),
128 };
129 write!(f, "({parameters}) -> {returns}")?;
130
131 Ok(())
132 }
133
134 pub fn from_function_core<N: Network>(function: &FunctionCore<N>, program_id: ProgramId) -> Self {
136 let outputs = function
137 .outputs()
138 .iter()
139 .map(|output| match output.value_type() {
140 ValueType::Constant(val) => vec![Output {
141 mode: Mode::Constant,
142 type_: Type::from_snarkvm(val, program_id),
143 span: Default::default(),
144 id: Default::default(),
145 }],
146 ValueType::Public(val) => vec![Output {
147 mode: Mode::Public,
148 type_: Type::from_snarkvm(val, program_id),
149 span: Default::default(),
150 id: Default::default(),
151 }],
152 ValueType::Private(val) => vec![Output {
153 mode: Mode::Private,
154 type_: Type::from_snarkvm(val, program_id),
155 span: Default::default(),
156 id: Default::default(),
157 }],
158 ValueType::Record(id) => vec![Output {
159 mode: Mode::None,
160 type_: Type::Composite(CompositeType {
161 path: {
162 let ident = Identifier::from(id);
163 Path::from(ident)
164 .to_global(Location::new(program_id.as_symbol(), vec![ident.name]))
165 .with_user_program(program_id)
166 },
167 const_arguments: Vec::new(),
168 }),
169 span: Default::default(),
170 id: Default::default(),
171 }],
172 ValueType::ExternalRecord(loc) => {
173 let external_program_id = ProgramId::from(loc.program_id());
174 vec![Output {
175 mode: Mode::None,
176 span: Default::default(),
177 id: Default::default(),
178 type_: Type::Composite(CompositeType {
179 path: {
180 let ident = Identifier::from(loc.resource());
181 Path::from(ident)
182 .to_global(Location::new(external_program_id.as_symbol(), vec![ident.name]))
183 .with_user_program(external_program_id)
184 },
185 const_arguments: Vec::new(),
186 }),
187 }]
188 }
189 ValueType::Future(_) => vec![Output {
190 mode: Mode::None,
191 span: Default::default(),
192 id: Default::default(),
193 type_: Type::Future(FutureType::new(
194 Vec::new(),
195 Some(Location::new(program_id.as_symbol(), vec![Symbol::intern(&function.name().to_string())])),
196 false,
197 )),
198 }],
199 ValueType::DynamicRecord => vec![Output {
200 mode: Mode::None,
201 span: Default::default(),
202 id: Default::default(),
203 type_: Type::DynRecord,
204 }],
205 ValueType::DynamicFuture => vec![Output {
206 mode: Mode::None,
207 span: Default::default(),
208 id: Default::default(),
209 type_: Type::Future(FutureType::new(
210 Vec::new(),
211 Some(Location::new(program_id.as_symbol(), vec![Symbol::intern(&function.name().to_string())])),
212 false,
213 )),
214 }],
215 })
216 .collect_vec()
217 .concat();
218 let output_vec = outputs.iter().map(|output| output.type_.clone()).collect_vec();
219 let output_type = match output_vec.len() {
220 0 => Type::Unit,
221 1 => output_vec[0].clone(),
222 _ => Type::Tuple(TupleType::new(output_vec)),
223 };
224
225 Self {
226 annotations: Vec::new(),
227 variant: Variant::EntryPoint,
228 identifier: Identifier::from(function.name()),
229 input: function
230 .inputs()
231 .iter()
232 .enumerate()
233 .map(|(index, input)| {
234 let arg_name = Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default());
235 match input.value_type() {
236 ValueType::Constant(val) => Input {
237 identifier: arg_name,
238 mode: Mode::Constant,
239 type_: Type::from_snarkvm(val, program_id),
240 span: Default::default(),
241 id: Default::default(),
242 },
243 ValueType::Public(val) => Input {
244 identifier: arg_name,
245 mode: Mode::Public,
246 type_: Type::from_snarkvm(val, program_id),
247 span: Default::default(),
248 id: Default::default(),
249 },
250 ValueType::Private(val) => Input {
251 identifier: arg_name,
252 mode: Mode::Private,
253 type_: Type::from_snarkvm(val, program_id),
254 span: Default::default(),
255 id: Default::default(),
256 },
257 ValueType::Record(id) => Input {
258 identifier: arg_name,
259 mode: Mode::None,
260 type_: Type::Composite(CompositeType {
261 path: {
262 let ident = Identifier::from(id);
263 Path::from(ident)
264 .to_global(Location::new(program_id.as_symbol(), vec![ident.name]))
265 .with_user_program(program_id)
266 },
267 const_arguments: Vec::new(),
268 }),
269 span: Default::default(),
270 id: Default::default(),
271 },
272 ValueType::ExternalRecord(loc) => {
273 let external_program = ProgramId::from(loc.program_id());
274 Input {
275 identifier: arg_name,
276 mode: Mode::None,
277 span: Default::default(),
278 id: Default::default(),
279 type_: Type::Composite(CompositeType {
280 path: {
281 let ident = Identifier::from(loc.resource());
282 Path::from(ident)
283 .to_global(Location::new(external_program.as_symbol(), vec![ident.name]))
284 .with_user_program(external_program)
285 },
286 const_arguments: Vec::new(),
287 }),
288 }
289 }
290 ValueType::Future(_) | ValueType::DynamicFuture => {
291 panic!("Functions do not contain futures as inputs")
292 }
293
294 ValueType::DynamicRecord => Input {
295 identifier: arg_name,
296 mode: Mode::None,
297 span: Default::default(),
298 id: Default::default(),
299 type_: Type::DynRecord,
300 },
301 }
302 })
303 .collect_vec(),
304 output: outputs,
305 output_type,
306 span: Default::default(),
307 id: Default::default(),
308 }
309 }
310
311 pub fn from_finalize<N: Network>(function: &FunctionCore<N>, key_name: Symbol, program_id: ProgramId) -> Self {
312 Self {
313 annotations: Vec::new(),
314 variant: Variant::Finalize,
315 identifier: Identifier::new(key_name, Default::default()),
316 input: function
317 .finalize_logic()
318 .unwrap()
319 .inputs()
320 .iter()
321 .enumerate()
322 .map(|(index, input)| Input {
323 identifier: Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default()),
324 mode: Mode::None,
325 type_: match input.finalize_type() {
326 FinalizeType::Plaintext(val) => Type::from_snarkvm(val, program_id),
327 FinalizeType::Future(val) => Type::Future(FutureType::new(
328 Vec::new(),
329 Some(Location::new(ProgramId::from(val.program_id()).as_symbol(), vec![Symbol::intern(
330 &format!("finalize/{}", val.resource()),
331 )])),
332 false,
333 )),
334 FinalizeType::DynamicFuture => Type::Future(FutureType::new(Vec::new(), None, false)),
335 },
336 span: Default::default(),
337 id: Default::default(),
338 })
339 .collect_vec(),
340 output: Vec::new(),
341 output_type: Type::Unit,
342 span: Default::default(),
343 id: 0,
344 }
345 }
346
347 pub fn from_view<N: Network>(view: &ViewCore<N>, program_id: ProgramId) -> Self {
357 let plaintext_or_panic = |finalize_type: &FinalizeType<N>| match finalize_type {
358 FinalizeType::Plaintext(val) => Type::from_snarkvm(val, program_id),
359 FinalizeType::Future(_) | FinalizeType::DynamicFuture => {
360 panic!("Views do not contain futures as inputs or outputs")
361 }
362 };
363
364 let outputs = view
365 .outputs()
366 .iter()
367 .map(|output| Output {
368 mode: Mode::None,
369 type_: plaintext_or_panic(output.finalize_type()),
370 span: Default::default(),
371 id: Default::default(),
372 })
373 .collect_vec();
374 let output_vec = outputs.iter().map(|o| o.type_.clone()).collect_vec();
375 let output_type = match output_vec.len() {
376 0 => Type::Unit,
377 1 => output_vec[0].clone(),
378 _ => Type::Tuple(TupleType::new(output_vec)),
379 };
380
381 Self {
382 annotations: Vec::new(),
383 variant: Variant::View,
384 identifier: Identifier::from(view.name()),
385 input: view
386 .inputs()
387 .iter()
388 .enumerate()
389 .map(|(index, input)| Input {
390 identifier: Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default()),
391 mode: Mode::None,
392 type_: plaintext_or_panic(input.finalize_type()),
393 span: Default::default(),
394 id: Default::default(),
395 })
396 .collect_vec(),
397 output: outputs,
398 output_type,
399 span: Default::default(),
400 id: 0,
401 }
402 }
403
404 pub fn from_closure<N: Network>(closure: &ClosureCore<N>, program_id: ProgramId) -> Self {
405 let outputs = closure
406 .outputs()
407 .iter()
408 .map(|output| match output.register_type() {
409 RegisterType::Plaintext(val) => Output {
410 mode: Mode::None,
411 type_: Type::from_snarkvm(val, program_id),
412 span: Default::default(),
413 id: Default::default(),
414 },
415 RegisterType::Record(_) | RegisterType::DynamicRecord => panic!("Closures do not return records"),
416 RegisterType::ExternalRecord(_) => panic!("Closures do not return external records"),
417 RegisterType::Future(_) | RegisterType::DynamicFuture => panic!("Closures do not return futures"),
418 })
419 .collect_vec();
420 let output_vec = outputs.iter().map(|output| output.type_.clone()).collect_vec();
421 let output_type = match output_vec.len() {
422 0 => Type::Unit,
423 1 => output_vec[0].clone(),
424 _ => Type::Tuple(TupleType::new(output_vec)),
425 };
426 Self {
427 annotations: Vec::new(),
428 variant: Variant::Fn,
429 identifier: Identifier::from(closure.name()),
430 input: closure
431 .inputs()
432 .iter()
433 .enumerate()
434 .map(|(index, input)| {
435 let arg_name = Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default());
436 match input.register_type() {
437 RegisterType::Plaintext(val) => Input {
438 identifier: arg_name,
439 mode: Mode::None,
440 type_: Type::from_snarkvm(val, program_id),
441 span: Default::default(),
442 id: Default::default(),
443 },
444 RegisterType::Record(_) | RegisterType::DynamicRecord => {
445 panic!("Closures do not contain records as inputs")
446 }
447 RegisterType::ExternalRecord(_) => panic!("Closures do not contain external records as inputs"),
448 RegisterType::Future(_) | RegisterType::DynamicFuture => {
449 panic!("Closures do not contain futures as inputs")
450 }
451 }
452 })
453 .collect_vec(),
454 output: outputs,
455 output_type,
456 span: Default::default(),
457 id: Default::default(),
458 }
459 }
460}
461
462impl From<Function> for FunctionStub {
463 fn from(function: Function) -> Self {
464 Self {
465 annotations: function.annotations,
466 variant: function.variant,
467 identifier: function.identifier,
468 input: function.input,
469 output: function.output,
470 output_type: function.output_type,
471 span: function.span,
472 id: function.id,
473 }
474 }
475}
476
477impl fmt::Debug for FunctionStub {
478 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
479 self.format(f)
480 }
481}
482
483impl fmt::Display for FunctionStub {
484 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
485 self.format(f)
486 }
487}
488
489crate::simple_node_impl!(FunctionStub);