1use crate::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18 network::prelude::*,
19 program::{Identifier, Locator, Register, RegisterType},
20};
21
22#[derive(Clone, PartialEq, Eq, Hash)]
24pub enum CallOperator<N: Network> {
25 Locator(Locator<N>),
27 Resource(Identifier<N>),
29}
30
31impl<N: Network> Parser for CallOperator<N> {
32 #[inline]
34 fn parse(string: &str) -> ParserResult<Self> {
35 alt((map(Locator::parse, CallOperator::Locator), map(Identifier::parse, CallOperator::Resource)))(string)
36 }
37}
38
39impl<N: Network> FromStr for CallOperator<N> {
40 type Err = Error;
41
42 #[inline]
44 fn from_str(string: &str) -> Result<Self> {
45 match Self::parse(string) {
46 Ok((remainder, object)) => {
47 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
49 Ok(object)
51 }
52 Err(error) => bail!("Failed to parse string. {error}"),
53 }
54 }
55}
56
57impl<N: Network> Debug for CallOperator<N> {
58 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
60 Display::fmt(self, f)
61 }
62}
63
64impl<N: Network> Display for CallOperator<N> {
65 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
67 match self {
68 CallOperator::Locator(locator) => Display::fmt(locator, f),
69 CallOperator::Resource(resource) => Display::fmt(resource, f),
70 }
71 }
72}
73
74impl<N: Network> FromBytes for CallOperator<N> {
75 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
77 let variant = u8::read_le(&mut reader)?;
79 match variant {
81 0 => Ok(CallOperator::Locator(Locator::read_le(&mut reader)?)),
82 1 => Ok(CallOperator::Resource(Identifier::read_le(&mut reader)?)),
83 _ => Err(error("Failed to read CallOperator. Invalid variant.")),
84 }
85 }
86}
87
88impl<N: Network> ToBytes for CallOperator<N> {
89 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
91 match self {
92 CallOperator::Locator(locator) => {
93 0u8.write_le(&mut writer)?;
95 locator.write_le(&mut writer)
97 }
98 CallOperator::Resource(resource) => {
99 1u8.write_le(&mut writer)?;
101 resource.write_le(&mut writer)
103 }
104 }
105 }
106}
107
108#[derive(Clone, PartialEq, Eq, Hash)]
111pub struct Call<N: Network> {
112 operator: CallOperator<N>,
114 operands: Vec<Operand<N>>,
116 destinations: Vec<Register<N>>,
118}
119
120impl<N: Network> Call<N> {
121 #[inline]
123 pub const fn opcode() -> Opcode {
124 Opcode::Call
125 }
126
127 #[inline]
129 pub const fn operator(&self) -> &CallOperator<N> {
130 &self.operator
131 }
132
133 #[inline]
135 pub fn operands(&self) -> &[Operand<N>] {
136 &self.operands
137 }
138
139 #[inline]
141 pub fn destinations(&self) -> Vec<Register<N>> {
142 self.destinations.clone()
143 }
144
145 #[inline]
147 pub fn contains_external_struct(&self) -> bool {
148 false
149 }
150
151 #[inline]
153 pub fn is_function_call(&self, stack: &impl StackTrait<N>) -> Result<bool> {
154 match self.operator() {
155 CallOperator::Locator(locator) => {
157 let external_stack = stack.get_external_stack(locator.program_id())?;
159 let program = external_stack.program();
161 Ok(program.contains_function(locator.resource()))
163 }
164 CallOperator::Resource(resource) => Ok(stack.program().contains_function(resource)),
166 }
167 }
168
169 pub fn evaluate(&self, _stack: &impl StackTrait<N>, _registers: &mut impl RegistersTrait<N>) -> Result<()> {
171 bail!("Forbidden operation: Evaluate cannot invoke a 'call' directly. Use 'call' in 'Stack' instead.")
172 }
173
174 pub fn execute<A: circuit::Aleo<Network = N>>(
176 &self,
177 _stack: &impl StackTrait<N>,
178 _registers: &mut impl RegistersCircuit<N, A>,
179 ) -> Result<()> {
180 bail!("Forbidden operation: Execute cannot invoke a 'call' directly. Use 'call' in 'Stack' instead.")
181 }
182
183 #[inline]
185 pub fn finalize(&self, _stack: &impl StackTrait<N>, _registers: &mut impl RegistersTrait<N>) -> Result<()> {
186 bail!("Forbidden operation: Finalize cannot invoke a 'call' directly. Use 'call' in 'Stack' instead.")
187 }
188
189 pub fn output_types(
191 &self,
192 stack: &impl StackTrait<N>,
193 input_types: &[RegisterType<N>],
194 ) -> Result<Vec<RegisterType<N>>> {
195 let stack_value;
197 let (is_external, program, name) = match &self.operator {
198 CallOperator::Locator(locator) => {
199 let program_name = locator.program_id();
200 stack_value = Some(stack.get_external_stack(program_name)?);
201 (true, stack_value.as_ref().unwrap().program(), locator.resource())
202 }
203 CallOperator::Resource(resource) => {
204 if stack.program().contains_function(resource) {
208 bail!("Cannot call '{resource}'. Use a closure ('closure {resource}:') instead.")
209 }
210 (false, stack.program(), resource)
211 }
212 };
213
214 if let Ok(closure) = program.get_closure(name) {
216 if closure.inputs().len() != self.operands.len() {
218 bail!("Expected {} inputs, found {}", closure.inputs().len(), self.operands.len())
219 }
220 if closure.inputs().len() != input_types.len() {
222 bail!("Expected {} input types, found {}", closure.inputs().len(), input_types.len())
223 }
224 if closure.outputs().len() != self.destinations.len() {
226 bail!("Expected {} outputs, found {}", closure.outputs().len(), self.destinations.len())
227 }
228 Ok(closure
230 .output_types()
231 .into_iter()
232 .map(|output_type| if is_external { output_type.qualify(*program.id()) } else { output_type })
235 .collect::<Vec<_>>())
236 }
237 else if let Ok(function) = program.get_function(name) {
239 if function.inputs().len() != self.operands.len() {
241 bail!("Expected {} inputs, found {}", function.inputs().len(), self.operands.len())
242 }
243 if function.inputs().len() != input_types.len() {
245 bail!("Expected {} input types, found {}", function.inputs().len(), input_types.len())
246 }
247 if function.outputs().len() != self.destinations.len() {
249 bail!("Expected {} outputs, found {}", function.outputs().len(), self.destinations.len())
250 }
251 Ok(function
253 .output_types()
254 .into_iter()
255 .map(RegisterType::from)
256 .map(|register_type| if is_external { register_type.qualify(*program.id()) } else { register_type })
259 .collect::<Vec<_>>())
260 }
261 else {
263 bail!("Call operator '{}' is invalid or unsupported.", self.operator)
264 }
265 }
266}
267
268impl<N: Network> Parser for Call<N> {
269 #[inline]
271 fn parse(string: &str) -> ParserResult<Self> {
272 fn parse_operand<N: Network>(string: &str) -> ParserResult<Operand<N>> {
274 let (string, _) = Sanitizer::parse_whitespaces(string)?;
276 Operand::parse(string)
278 }
279
280 fn parse_destination<N: Network>(string: &str) -> ParserResult<Register<N>> {
282 let (string, _) = Sanitizer::parse_whitespaces(string)?;
284 Register::parse(string)
286 }
287
288 let (string, _) = tag(*Self::opcode())(string)?;
290 let (string, _) = Sanitizer::parse_whitespaces(string)?;
292 let (string, operator) = CallOperator::parse(string)?;
294 let (string, _) = Sanitizer::parse_whitespaces(string)?;
296 let (string, operands) = map_res(many0(complete(parse_operand)), |operands: Vec<Operand<N>>| {
298 match operands.len() <= N::MAX_OPERANDS {
300 true => Ok(operands),
301 false => Err(error("Failed to parse 'call' opcode: too many operands")),
302 }
303 })(string)?;
304 let (string, _) = Sanitizer::parse_whitespaces(string)?;
306
307 let (string, destinations) = match opt(tag("into"))(string)? {
309 (string, None) => (string, vec![]),
311 (string, Some(_)) => {
313 let (string, _) = Sanitizer::parse_whitespaces(string)?;
315 let (string, destinations) =
317 map_res(many1(complete(parse_destination)), |destinations: Vec<Register<N>>| {
318 match destinations.len() <= N::MAX_OPERANDS {
320 true => Ok(destinations),
321 false => Err(error("Failed to parse 'call' opcode: too many destinations")),
322 }
323 })(string)?;
324 (string, destinations)
326 }
327 };
328
329 Ok((string, Self { operator, operands, destinations }))
330 }
331}
332
333impl<N: Network> FromStr for Call<N> {
334 type Err = Error;
335
336 #[inline]
338 fn from_str(string: &str) -> Result<Self> {
339 match Self::parse(string) {
340 Ok((remainder, object)) => {
341 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
343 Ok(object)
345 }
346 Err(error) => bail!("Failed to parse string. {error}"),
347 }
348 }
349}
350
351impl<N: Network> Debug for Call<N> {
352 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
354 Display::fmt(self, f)
355 }
356}
357
358impl<N: Network> Display for Call<N> {
359 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
361 if self.operands.len() > N::MAX_OPERANDS {
363 return Err(fmt::Error);
364 }
365 if self.destinations.len() > N::MAX_OPERANDS {
367 return Err(fmt::Error);
368 }
369 write!(f, "{} {}", Self::opcode(), self.operator)?;
371 self.operands.iter().try_for_each(|operand| write!(f, " {operand}"))?;
372 if !self.destinations.is_empty() {
373 write!(f, " into")?;
374 self.destinations.iter().try_for_each(|destination| write!(f, " {destination}"))?;
375 }
376 Ok(())
377 }
378}
379
380impl<N: Network> FromBytes for Call<N> {
381 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
383 let operator = CallOperator::read_le(&mut reader)?;
385
386 let num_operands = u8::read_le(&mut reader)? as usize;
388 if num_operands > N::MAX_OPERANDS {
390 return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
391 }
392
393 let mut operands = Vec::with_capacity(num_operands);
395 for _ in 0..num_operands {
397 operands.push(Operand::read_le(&mut reader)?);
398 }
399
400 let num_destinations = u8::read_le(&mut reader)? as usize;
402 if num_destinations > N::MAX_OPERANDS {
404 return Err(error(format!("The number of destinations must be <= {}", N::MAX_OPERANDS)));
405 }
406
407 let mut destinations = Vec::with_capacity(num_destinations);
409 for _ in 0..num_destinations {
411 destinations.push(Register::read_le(&mut reader)?);
412 }
413
414 Ok(Self { operator, operands, destinations })
416 }
417}
418
419impl<N: Network> ToBytes for Call<N> {
420 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
422 if self.operands.len() > N::MAX_OPERANDS {
424 return Err(error(format!("The number of operands must be <= {}", N::MAX_OPERANDS)));
425 }
426 if self.destinations.len() > N::MAX_OPERANDS {
428 return Err(error(format!("The number of destinations must be <= {}", N::MAX_OPERANDS)));
429 }
430
431 self.operator.write_le(&mut writer)?;
433 u8::try_from(self.operands.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?;
435 self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
437 u8::try_from(self.destinations.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?;
439 self.destinations.iter().try_for_each(|destination| destination.write_le(&mut writer))
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447 use console::{
448 network::MainnetV0,
449 program::{Access, Address, Identifier, Literal, U64},
450 };
451
452 type CurrentNetwork = MainnetV0;
453
454 const TEST_CASES: &[&str] = &[
455 "call foo",
456 "call foo r0",
457 "call foo r0.owner",
458 "call foo r0 r1",
459 "call foo into r0",
460 "call foo into r0 r1",
461 "call foo into r0 r1 r2",
462 "call foo r0 into r1",
463 "call foo r0 r1 into r2",
464 "call foo r0 r1 into r2 r3",
465 "call foo r0 r1 r2 into r3 r4",
466 "call foo r0 r1 r2 into r3 r4 r5",
467 ];
468
469 fn check_parser(
470 string: &str,
471 expected_operator: CallOperator<CurrentNetwork>,
472 expected_operands: Vec<Operand<CurrentNetwork>>,
473 expected_destinations: Vec<Register<CurrentNetwork>>,
474 ) {
475 let (string, call) = Call::<CurrentNetwork>::parse(string).unwrap();
477
478 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
480
481 assert_eq!(call.operator, expected_operator, "The call operator is incorrect");
483
484 assert_eq!(call.operands.len(), expected_operands.len(), "The number of operands is incorrect");
486 for (i, (given, expected)) in call.operands.iter().zip(expected_operands.iter()).enumerate() {
487 assert_eq!(given, expected, "The {i}-th operand is incorrect");
488 }
489
490 assert_eq!(call.destinations.len(), expected_destinations.len(), "The number of destinations is incorrect");
492 for (i, (given, expected)) in call.destinations.iter().zip(expected_destinations.iter()).enumerate() {
493 assert_eq!(given, expected, "The {i}-th destination is incorrect");
494 }
495 }
496
497 #[test]
498 fn test_parse() {
499 check_parser(
500 "call transfer r0.owner r0.token_amount into r1 r2 r3",
501 CallOperator::from_str("transfer").unwrap(),
502 vec![
503 Operand::Register(Register::Access(0, vec![Access::from(Identifier::from_str("owner").unwrap())])),
504 Operand::Register(Register::Access(0, vec![Access::from(
505 Identifier::from_str("token_amount").unwrap(),
506 )])),
507 ],
508 vec![Register::Locator(1), Register::Locator(2), Register::Locator(3)],
509 );
510
511 check_parser(
512 "call mint_public aleo1wfyyj2uvwuqw0c0dqa5x70wrawnlkkvuepn4y08xyaqfqqwweqys39jayw 100u64",
513 CallOperator::from_str("mint_public").unwrap(),
514 vec![
515 Operand::Literal(Literal::Address(
516 Address::from_str("aleo1wfyyj2uvwuqw0c0dqa5x70wrawnlkkvuepn4y08xyaqfqqwweqys39jayw").unwrap(),
517 )),
518 Operand::Literal(Literal::U64(U64::from_str("100u64").unwrap())),
519 ],
520 vec![],
521 );
522
523 check_parser(
524 "call get_magic_number into r0",
525 CallOperator::from_str("get_magic_number").unwrap(),
526 vec![],
527 vec![Register::Locator(0)],
528 );
529
530 check_parser("call noop", CallOperator::from_str("noop").unwrap(), vec![], vec![])
531 }
532
533 #[test]
534 fn test_display() {
535 for expected in TEST_CASES {
536 assert_eq!(Call::<CurrentNetwork>::from_str(expected).unwrap().to_string(), *expected);
537 }
538 }
539
540 #[test]
541 fn test_bytes() {
542 for case in TEST_CASES {
543 let expected = Call::<CurrentNetwork>::from_str(case).unwrap();
544
545 let expected_bytes = expected.to_bytes_le().unwrap();
547 assert_eq!(expected, Call::read_le(&expected_bytes[..]).unwrap());
548 }
549 }
550}