cursor.rs
1 // Copyright (C) 2019-2025 ADnet Contributors 2 // This file is part of the ADL library. 3 4 // The ADL library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 9 // The ADL library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with the ADL library. If not, see <https://www.gnu.org/licenses/>. 16 17 use super::*; 18 19 use adl_ast::{ 20 ArrayType, 21 AssertVariant, 22 AsyncExpression, 23 BinaryOperation, 24 Block, 25 CompositeFieldInitializer, 26 DefinitionPlace, 27 Expression, 28 Function, 29 Intrinsic, 30 Location, 31 NodeID, 32 Statement, 33 Type, 34 UnaryOperation, 35 Variant, 36 interpreter_value::{ 37 AsyncExecution, 38 IntrinsicHelper, 39 Value, 40 evaluate_binary, 41 evaluate_intrinsic, 42 evaluate_unary, 43 literal_to_value, 44 }, 45 }; 46 use adl_errors::{InterpreterHalt, Result}; 47 use adl_span::{Span, Symbol}; 48 49 use snarkvm::prelude::{ 50 Address, 51 CanaryV0, 52 Closure as SvmClosure, 53 Finalize as SvmFinalize, 54 Function as SvmFunctionParam, 55 MainnetV0, 56 Network, 57 PrivateKey, 58 ProgramID, 59 TestnetV0, 60 }; 61 62 use indexmap::IndexMap; 63 use itertools::Itertools; 64 use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng}; 65 use std::{cmp::Ordering, collections::HashMap, mem, str::FromStr as _}; 66 67 pub type Closure = SvmClosure<TestnetV0>; 68 pub type Finalize = SvmFinalize<TestnetV0>; 69 pub type SvmFunction = SvmFunctionParam<TestnetV0>; 70 71 /// Names associated to values in a function being executed. 72 #[derive(Clone, Debug)] 73 pub struct FunctionContext { 74 path: Vec<Symbol>, 75 program: Symbol, 76 pub caller: Value, 77 names: HashMap<Vec<Symbol>, Value>, 78 accumulated_futures: Vec<AsyncExecution>, 79 is_async: bool, 80 } 81 82 /// A stack of contexts, building with the function call stack. 83 #[derive(Clone, Debug, Default)] 84 pub struct ContextStack { 85 contexts: Vec<FunctionContext>, 86 current_len: usize, 87 } 88 89 impl ContextStack { 90 fn len(&self) -> usize { 91 self.current_len 92 } 93 94 fn push( 95 &mut self, 96 path: &[Symbol], 97 program: Symbol, 98 caller: Value, 99 is_async: bool, 100 names: HashMap<Vec<Symbol>, Value>, // a map of variable names that are already known 101 ) { 102 if self.current_len == self.contexts.len() { 103 self.contexts.push(FunctionContext { 104 path: path.to_vec(), 105 program, 106 caller: caller.clone(), 107 names: HashMap::new(), 108 accumulated_futures: Default::default(), 109 is_async, 110 }); 111 } 112 113 self.contexts[self.current_len].path = path.to_vec(); 114 self.contexts[self.current_len].program = program; 115 self.contexts[self.current_len].caller = caller; 116 self.contexts[self.current_len].names = names; 117 self.contexts[self.current_len].accumulated_futures.clear(); 118 self.contexts[self.current_len].is_async = is_async; 119 self.current_len += 1; 120 } 121 122 pub fn pop(&mut self) { 123 // We never actually pop the underlying Vec 124 // so we can reuse the storage of the hash 125 // tables. 126 assert!(self.len() > 0); 127 self.current_len -= 1; 128 self.contexts[self.current_len].names.clear(); 129 } 130 131 /// Get the future accumulated by awaiting futures in the current function call. 132 /// 133 /// If the current code being interpreted is not in an async function, this 134 /// will of course be empty. 135 fn get_future(&mut self) -> Vec<AsyncExecution> { 136 assert!(self.len() > 0); 137 mem::take(&mut self.contexts[self.current_len - 1].accumulated_futures) 138 } 139 140 fn set(&mut self, path: &[Symbol], value: Value) { 141 assert!(self.current_len > 0); 142 self.last_mut().unwrap().names.insert(path.to_vec(), value); 143 } 144 145 pub fn add_future(&mut self, future: Vec<AsyncExecution>) { 146 assert!(self.current_len > 0); 147 self.contexts[self.current_len - 1].accumulated_futures.extend(future); 148 } 149 150 /// Are we currently in an async function? 151 fn is_async(&self) -> bool { 152 assert!(self.current_len > 0); 153 self.last().unwrap().is_async 154 } 155 156 pub fn current_program(&self) -> Option<Symbol> { 157 self.last().map(|c| c.program) 158 } 159 160 pub fn last(&self) -> Option<&FunctionContext> { 161 self.len().checked_sub(1).and_then(|i| self.contexts.get(i)) 162 } 163 164 fn last_mut(&mut self) -> Option<&mut FunctionContext> { 165 self.len().checked_sub(1).and_then(|i| self.contexts.get_mut(i)) 166 } 167 } 168 169 #[derive(Clone, Debug)] 170 pub enum AleoContext { 171 Closure(Closure), 172 Function(SvmFunction), 173 Finalize(Finalize), 174 } 175 176 /// A Leo construct to be evauated. 177 #[derive(Clone, Debug)] 178 pub enum Element { 179 /// A Leo statement. 180 Statement(Statement), 181 182 /// A Leo expression. The optional type is an optional "expected type" for the expression. It helps when trying to 183 /// resolve an unsuffixed literal. 184 Expression(Expression, Option<Type>), 185 186 /// A Leo block. 187 /// 188 /// We have a separate variant for Leo blocks for two reasons: 189 /// 1. In a ConditionalExpression, the `then` block is stored 190 /// as just a Block with no statement, and 191 /// 2. We need to remember if a Block came from a function body, 192 /// so that if such a block ends, we know to push a `Unit` to 193 /// the values stack. 194 Block { 195 block: Block, 196 function_body: bool, 197 }, 198 199 AleoExecution { 200 context: Box<AleoContext>, 201 registers: IndexMap<u64, Value>, 202 instruction_index: usize, 203 }, 204 205 DelayedCall(Location), 206 DelayedAsyncBlock { 207 program: Symbol, 208 block: NodeID, 209 names: HashMap<Vec<Symbol>, Value>, 210 }, 211 } 212 213 impl Element { 214 pub fn span(&self) -> Span { 215 use Element::*; 216 match self { 217 Statement(statement) => statement.span(), 218 Expression(expression, _) => expression.span(), 219 Block { block, .. } => block.span(), 220 AleoExecution { .. } | DelayedCall(..) | DelayedAsyncBlock { .. } => Default::default(), 221 } 222 } 223 } 224 225 /// A frame of execution, keeping track of the Element next to 226 /// be executed and the number of steps we've done so far. 227 #[derive(Clone, Debug)] 228 pub struct Frame { 229 pub step: usize, 230 pub element: Element, 231 pub user_initiated: bool, 232 } 233 234 #[derive(Clone, Debug)] 235 pub enum FunctionVariant { 236 Leo(Function), 237 AleoClosure(Closure), 238 AleoFunction(SvmFunction), 239 } 240 241 /// Tracks the current execution state - a cursor into the running program. 242 #[derive(Clone, Debug)] 243 pub struct Cursor { 244 /// Stack of execution frames, with the one currently to be executed on top. 245 pub frames: Vec<Frame>, 246 247 /// Stack of values from evaluated expressions. 248 /// 249 /// Each time an expression completes evaluation, a value is pushed here. 250 pub values: Vec<Value>, 251 252 /// All functions (or transitions or inlines) in any program being interpreted. 253 pub functions: HashMap<Location, FunctionVariant>, 254 255 /// All the async blocks encountered. We identify them by their `NodeID`. 256 pub async_blocks: HashMap<NodeID, Block>, 257 258 /// Consts are stored here. 259 pub globals: HashMap<Location, Value>, 260 261 pub user_values: HashMap<Vec<Symbol>, Value>, 262 263 pub mappings: HashMap<Location, HashMap<Value, Value>>, 264 265 /// For each struct type, we only need to remember the names of its members, in order. 266 pub composites: HashMap<Vec<Symbol>, IndexMap<Symbol, Type>>, 267 268 /// For each record type, we index by program name and path, and remember its members 269 /// except `owner`. 270 pub records: HashMap<(Symbol, Vec<Symbol>), IndexMap<Symbol, Type>>, 271 272 pub futures: Vec<AsyncExecution>, 273 274 pub contexts: ContextStack, 275 276 // The signer's address. 277 pub signer: Value, 278 279 pub rng: ChaCha20Rng, 280 281 pub block_height: u32, 282 283 pub block_timestamp: i64, 284 285 pub really_async: bool, 286 287 pub program: Option<Symbol>, 288 289 pub network: NetworkName, 290 291 pub private_key: String, 292 } 293 294 impl IntrinsicHelper for Cursor { 295 fn pop_value_impl(&mut self) -> Option<Value> { 296 self.values.pop() 297 } 298 299 fn set_block_height(&mut self, height: u32) { 300 self.block_height = height; 301 } 302 303 fn set_block_timestamp(&mut self, timestamp: i64) { 304 self.block_timestamp = timestamp; 305 } 306 307 fn set_signer(&mut self, private_key: String) -> Result<()> { 308 // Get the address from the private key. 309 let address = match PrivateKey::<TestnetV0>::from_str(&private_key.replace("\"", "")) 310 .and_then(|pk| Address::<TestnetV0>::try_from(&pk)) 311 { 312 Ok(address) => address.into(), 313 Err(_) => halt_no_span!("Invalid private key provided for signer."), 314 }; 315 // Set the private key 316 self.private_key = private_key; 317 // Set the signer. 318 self.signer = address; 319 320 Ok(()) 321 } 322 323 fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> { 324 Cursor::lookup_mapping(self, program, name) 325 } 326 327 fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> { 328 Cursor::lookup_mapping_mut(self, program, name) 329 } 330 331 fn rng(&mut self) -> Option<&mut ChaCha20Rng> { 332 Some(&mut self.rng) 333 } 334 } 335 336 impl Cursor { 337 /// `really_async` indicates we should really delay execution of async function calls until the user runs them. 338 pub fn new( 339 really_async: bool, 340 private_key: String, 341 block_height: u32, 342 block_timestamp: i64, 343 network: NetworkName, 344 ) -> Self { 345 let mut cursor = Cursor { 346 frames: Default::default(), 347 values: Default::default(), 348 functions: Default::default(), 349 async_blocks: Default::default(), 350 globals: Default::default(), 351 user_values: Default::default(), 352 mappings: Default::default(), 353 composites: Default::default(), 354 records: Default::default(), 355 contexts: Default::default(), 356 futures: Default::default(), 357 rng: ChaCha20Rng::from_entropy(), 358 signer: Default::default(), 359 block_height, 360 block_timestamp, 361 really_async, 362 program: None, 363 network, 364 private_key: Default::default(), 365 }; 366 367 // Set the default private key. 368 cursor.set_signer(private_key).expect("The default private key should be valid."); 369 370 cursor 371 } 372 373 // Clears the state of the cursor, but keeps the program definitions. 374 pub fn clear(&mut self) { 375 self.frames.clear(); 376 self.values.clear(); 377 self.mappings.iter_mut().for_each(|(_, map)| map.clear()); 378 self.contexts = Default::default(); 379 self.futures.clear(); 380 } 381 382 fn set_place( 383 new_value: Value, 384 this_value: &mut Value, 385 places: &mut dyn Iterator<Item = &Expression>, 386 indices: &mut dyn Iterator<Item = Value>, 387 ) -> Result<()> { 388 match places.next() { 389 None => *this_value = new_value, 390 Some(Expression::ArrayAccess(_access)) => { 391 let index = indices.next().unwrap(); 392 let index = index.as_u32().unwrap() as usize; 393 394 let mut index_value = this_value.array_index(index).expect("Type"); 395 Self::set_place(new_value, &mut index_value, places, indices)?; 396 397 if this_value.array_index_set(index, index_value).is_none() { 398 halt_no_span!("Invalid array assignment"); 399 } 400 } 401 Some(Expression::TupleAccess(access)) => { 402 let index = access.index.value(); 403 let mut index_value = this_value.tuple_index(index).expect("Type"); 404 Self::set_place(new_value, &mut index_value, places, indices)?; 405 if this_value.tuple_index_set(index, index_value).is_none() { 406 halt_no_span!("Invalid tuple assignment"); 407 } 408 } 409 Some(Expression::MemberAccess(access)) => { 410 let mut access_value = this_value.member_access(access.name.name).expect("Type"); 411 Self::set_place(new_value, &mut access_value, places, indices)?; 412 if this_value.member_set(access.name.name, access_value).is_none() { 413 halt_no_span!("Invalid member set"); 414 } 415 } 416 Some(Expression::Path(_path)) => { 417 Self::set_place(new_value, this_value, places, indices)?; 418 } 419 Some(place) => halt_no_span!("Invalid place for assignment: {place}"), 420 } 421 422 Ok(()) 423 } 424 425 pub fn assign(&mut self, value: Value, place: &Expression, indices: &mut dyn Iterator<Item = Value>) -> Result<()> { 426 let mut places = vec![place]; 427 let indices: Vec<Value> = indices.collect(); 428 429 let path: &Path; 430 431 loop { 432 match places.last().unwrap() { 433 Expression::ArrayAccess(access) => places.push(&access.array), 434 Expression::TupleAccess(access) => places.push(&access.tuple), 435 Expression::MemberAccess(access) => places.push(&access.inner), 436 Expression::Path(path_) => { 437 path = path_; 438 break; 439 } 440 place @ (Expression::Async(..) 441 | Expression::Array(..) 442 | Expression::Binary(..) 443 | Expression::Call(..) 444 | Expression::Intrinsic(..) 445 | Expression::Cast(..) 446 | Expression::Err(..) 447 | Expression::Literal(..) 448 | Expression::Locator(..) 449 | Expression::Repeat(..) 450 | Expression::Composite(..) 451 | Expression::Ternary(..) 452 | Expression::Tuple(..) 453 | Expression::Unary(..) 454 | Expression::Unit(..)) => halt_no_span!("Invalid place for assignment: {place}"), 455 } 456 } 457 458 let full_name = self.to_absolute_path(&path.as_symbols()); 459 460 let mut adl_value = self.lookup(&full_name).unwrap_or(Value::make_unit()); 461 462 // Do an ad hoc evaluation of the lhs of the assignment to determine its type. 463 let mut temp_value = adl_value.clone(); 464 let mut indices_iter = indices.iter(); 465 466 for place in places.iter().rev() { 467 match place { 468 Expression::ArrayAccess(_access) => { 469 let next_index = indices_iter.next().unwrap(); 470 temp_value = temp_value.array_index(next_index.as_u32().unwrap() as usize).unwrap(); 471 } 472 Expression::TupleAccess(access) => { 473 temp_value = temp_value.tuple_index(access.index.value()).unwrap(); 474 } 475 Expression::MemberAccess(access) => { 476 temp_value = temp_value.member_access(access.name.name).unwrap(); 477 } 478 Expression::Path(_path) => 479 // temp_value is already set to adl_value 480 {} 481 _ => panic!("Can't happen."), 482 } 483 } 484 485 let ty = temp_value.get_numeric_type(); 486 let value = value.resolve_if_unsuffixed(&ty, place.span())?; 487 488 Self::set_place(value, &mut adl_value, &mut places.into_iter().rev(), &mut indices.into_iter())?; 489 self.set_variable(&full_name, adl_value); 490 Ok(()) 491 } 492 493 pub fn set_program(&mut self, program: &str) { 494 let p = program.strip_suffix(".alpha").or_else(|| program.strip_suffix(".delta")).unwrap_or(program); 495 self.program = Some(Symbol::intern(p)); 496 } 497 498 pub fn current_program(&self) -> Option<Symbol> { 499 self.contexts.current_program().or(self.program) 500 } 501 502 pub fn increment_step(&mut self) { 503 let Some(Frame { step, .. }) = self.frames.last_mut() else { 504 panic!("frame expected"); 505 }; 506 *step += 1; 507 } 508 509 fn new_caller(&self) -> Value { 510 if let Some(function_context) = self.contexts.last() { 511 let program_id = ProgramID::<TestnetV0>::from_str(&format!("{}.alpha", function_context.program)) 512 .expect("should be able to create ProgramID"); 513 program_id.to_address().expect("should be able to convert to address").into() 514 } else { 515 self.signer.clone() 516 } 517 } 518 519 fn pop_value(&mut self) -> Result<Value> { 520 match self.values.pop() { 521 Some(v) => Ok(v), 522 None => { 523 Err(InterpreterHalt::new("value expected - this may be a bug in the Leo interpreter".to_string()) 524 .into()) 525 } 526 } 527 } 528 529 fn lookup(&self, name: &[Symbol]) -> Option<Value> { 530 if let Some(context) = self.contexts.last() { 531 let option_value = 532 context.names.get(name).or_else(|| self.globals.get(&Location::new(context.program, name.to_vec()))); 533 if option_value.is_some() { 534 return option_value.cloned(); 535 } 536 }; 537 538 self.user_values.get(name).cloned() 539 } 540 541 pub fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> { 542 let Some(program) = program.or_else(|| self.current_program()) else { 543 panic!("no program for mapping lookup"); 544 }; 545 // mappings can only show up in the top level program scope 546 self.mappings.get(&Location::new(program, vec![name])) 547 } 548 549 pub fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> { 550 let Some(program) = program.or_else(|| self.current_program()) else { 551 panic!("no program for mapping lookup"); 552 }; 553 // mappings can only show up in the top level program scope 554 self.mappings.get_mut(&Location::new(program, vec![name])) 555 } 556 557 fn lookup_function(&self, program: Symbol, name: &[Symbol]) -> Option<FunctionVariant> { 558 self.functions.get(&Location::new(program, name.to_vec())).cloned() 559 } 560 561 fn set_variable(&mut self, path: &[Symbol], value: Value) { 562 if self.contexts.len() > 0 { 563 self.contexts.set(path, value); 564 } else { 565 self.user_values.insert(path.to_vec(), value); 566 } 567 } 568 569 /// Execute the whole step of the current Element. 570 /// 571 /// That is, perform a step, and then finish all statements and expressions that have been pushed, 572 /// until we're ready for the next step of the current Element (if there is one). 573 pub fn whole_step(&mut self) -> Result<StepResult> { 574 let frames_len = self.frames.len(); 575 let initial_result = self.step()?; 576 if !initial_result.finished { 577 while self.frames.len() > frames_len { 578 self.step()?; 579 } 580 } 581 Ok(initial_result) 582 } 583 584 /// Step `over` the current Element. 585 /// 586 /// That is, continue executing until the current Element is finished. 587 pub fn over(&mut self) -> Result<StepResult> { 588 let frames_len = self.frames.len(); 589 loop { 590 match self.frames.len().cmp(&frames_len) { 591 Ordering::Greater => { 592 self.step()?; 593 } 594 Ordering::Equal => { 595 let result = self.step()?; 596 if result.finished { 597 return Ok(result); 598 } 599 } 600 Ordering::Less => { 601 // This can happen if, for instance, a `return` was encountered, 602 // which means we exited the function we were evaluating and the 603 // frame stack was truncated. 604 return Ok(StepResult { finished: true, value: None }); 605 } 606 } 607 } 608 } 609 610 pub fn step_block(&mut self, block: &Block, function_body: bool, step: usize) -> bool { 611 let len = self.frames.len(); 612 613 let done = match step { 614 0 => { 615 for statement in block.statements.iter().rev() { 616 self.frames.push(Frame { 617 element: Element::Statement(statement.clone()), 618 step: 0, 619 user_initiated: false, 620 }); 621 } 622 false 623 } 624 1 if function_body => { 625 self.values.push(Value::make_unit()); 626 self.contexts.pop(); 627 true 628 } 629 1 => true, 630 _ => unreachable!(), 631 }; 632 633 if done { 634 assert_eq!(len, self.frames.len()); 635 self.frames.pop(); 636 } else { 637 self.frames[len - 1].step += 1; 638 } 639 640 done 641 } 642 643 /// Returns the full absolute path by prefixing `name` with the current module path. 644 /// If no context is available, returns `name` as-is. 645 fn to_absolute_path(&self, name: &[Symbol]) -> Vec<Symbol> { 646 if let Some(context) = self.contexts.last() { 647 let mut full_name = context.path.clone(); 648 full_name.pop(); // This pops the function name, keeping only the module prefix 649 full_name.extend(name); 650 full_name 651 } else { 652 name.to_vec() 653 } 654 } 655 656 fn step_statement(&mut self, statement: &Statement, step: usize) -> Result<bool> { 657 let len = self.frames.len(); 658 // Push a new expression frame with an optional expected type for the expression 659 let mut push = |expression: &Expression, ty: &Option<Type>| { 660 self.frames.push(Frame { 661 element: Element::Expression(expression.clone(), ty.clone()), 662 step: 0, 663 user_initiated: false, 664 }) 665 }; 666 667 let done = match statement { 668 Statement::Assert(assert) if step == 0 => { 669 match &assert.variant { 670 AssertVariant::Assert(x) => push(x, &Some(Type::Boolean)), 671 AssertVariant::AssertEq(x, y) | AssertVariant::AssertNeq(x, y) => { 672 push(y, &None); 673 push(x, &None); 674 } 675 }; 676 false 677 } 678 Statement::Assert(assert) if step == 1 => { 679 match &assert.variant { 680 AssertVariant::Assert(..) => { 681 let value = self.pop_value()?; 682 match value.try_into() { 683 Ok(true) => {} 684 Ok(false) => halt!(assert.span(), "assert failure"), 685 _ => tc_fail!(), 686 } 687 } 688 AssertVariant::AssertEq(..) => { 689 let x = self.pop_value()?; 690 let y = self.pop_value()?; 691 if !x.eq(&y)? { 692 halt!(assert.span(), "assert failure: {} != {}", y, x); 693 } 694 } 695 696 AssertVariant::AssertNeq(..) => { 697 let x = self.pop_value()?; 698 let y = self.pop_value()?; 699 if x.eq(&y)? { 700 halt!(assert.span(), "assert failure: {} == {}", y, x); 701 } 702 } 703 }; 704 true 705 } 706 Statement::Assign(assign) if step == 0 => { 707 // Step 0: push the expression frame and any array index expression frames. 708 push(&assign.value, &None); 709 let mut place = &assign.place; 710 loop { 711 match place { 712 adl_ast::Expression::ArrayAccess(access) => { 713 push(&access.index, &None); 714 place = &access.array; 715 } 716 adl_ast::Expression::Path(..) => break, 717 adl_ast::Expression::MemberAccess(access) => { 718 place = &access.inner; 719 } 720 adl_ast::Expression::TupleAccess(access) => { 721 place = &access.tuple; 722 } 723 _ => panic!("Can't happen"), 724 } 725 } 726 false 727 } 728 Statement::Assign(assign) if step == 1 => { 729 // Step 1: set the variable (or place). 730 let mut index_count = 0; 731 let mut place = &assign.place; 732 loop { 733 match place { 734 adl_ast::Expression::ArrayAccess(access) => { 735 index_count += 1; 736 place = &access.array; 737 } 738 adl_ast::Expression::Path(..) => break, 739 adl_ast::Expression::MemberAccess(access) => { 740 place = &access.inner; 741 } 742 adl_ast::Expression::TupleAccess(access) => { 743 place = &access.tuple; 744 } 745 _ => panic!("Can't happen"), 746 } 747 } 748 749 // Get the value. 750 let value = self.pop_value()?; 751 let len = self.values.len(); 752 753 // Get the indices. 754 let indices: Vec<Value> = self.values.drain(len - index_count..len).collect(); 755 756 self.assign(value, &assign.place, &mut indices.into_iter())?; 757 758 true 759 } 760 Statement::Block(block) => return Ok(self.step_block(block, false, step)), 761 Statement::Conditional(conditional) if step == 0 => { 762 push(&conditional.condition, &Some(Type::Boolean)); 763 false 764 } 765 Statement::Conditional(conditional) if step == 1 => { 766 match self.pop_value()?.try_into() { 767 Ok(true) => self.frames.push(Frame { 768 step: 0, 769 element: Element::Block { block: conditional.then.clone(), function_body: false }, 770 user_initiated: false, 771 }), 772 Ok(false) => { 773 if let Some(otherwise) = conditional.otherwise.as_ref() { 774 self.frames.push(Frame { 775 step: 0, 776 element: Element::Statement(Statement::clone(otherwise)), 777 user_initiated: false, 778 }) 779 } 780 } 781 _ => tc_fail!(), 782 }; 783 false 784 } 785 Statement::Conditional(_) if step == 2 => true, 786 Statement::Const(const_) if step == 0 => { 787 push(&const_.value, &Some(const_.type_.clone())); 788 false 789 } 790 Statement::Const(const_) if step == 1 => { 791 let value = self.pop_value()?; 792 self.set_variable(&self.to_absolute_path(&[const_.place.name]), value); 793 true 794 } 795 Statement::Definition(definition) if step == 0 => { 796 push(&definition.value, &definition.type_); 797 false 798 } 799 Statement::Definition(definition) if step == 1 => { 800 let value = self.pop_value()?; 801 match &definition.place { 802 DefinitionPlace::Single(id) => self.set_variable(&self.to_absolute_path(&[id.name]), value), 803 DefinitionPlace::Multiple(ids) => { 804 for (i, id) in ids.iter().enumerate() { 805 self.set_variable( 806 &self.to_absolute_path(&[id.name]), 807 value.tuple_index(i).expect("Place for definition should be a tuple."), 808 ); 809 } 810 } 811 } 812 true 813 } 814 Statement::Expression(expression) if step == 0 => { 815 push(&expression.expression, &None); 816 false 817 } 818 Statement::Expression(_) if step == 1 => { 819 self.values.pop(); 820 true 821 } 822 Statement::Iteration(iteration) if step == 0 => { 823 assert!(!iteration.inclusive); 824 push(&iteration.stop, &iteration.type_.clone()); 825 push(&iteration.start, &iteration.type_.clone()); 826 false 827 } 828 Statement::Iteration(iteration) => { 829 // Currently there actually isn't a syntax in Leo for inclusive ranges. 830 let stop = self.pop_value()?; 831 let start = self.pop_value()?; 832 if start.eq(&stop)? { 833 true 834 } else { 835 let new_start = start.inc_wrapping().expect_tc(iteration.span())?; 836 self.set_variable(&self.to_absolute_path(&[iteration.variable.name]), start); 837 self.frames.push(Frame { 838 step: 0, 839 element: Element::Block { block: iteration.block.clone(), function_body: false }, 840 user_initiated: false, 841 }); 842 self.values.push(new_start); 843 self.values.push(stop); 844 false 845 } 846 } 847 Statement::Return(return_) if step == 0 => { 848 // We really only need to care about the type of the output for Leo functions. Aleo functions and 849 // closures don't have to worry about unsuffixed literals 850 let output_type = self.contexts.last().and_then(|ctx| { 851 self.lookup_function(ctx.program, &ctx.path).and_then(|variant| match variant { 852 FunctionVariant::Leo(function) => Some(function.output_type.clone()), 853 _ => None, 854 }) 855 }); 856 857 self.frames.push(Frame { 858 element: Element::Expression(return_.expression.clone(), output_type), 859 step: 0, 860 user_initiated: false, 861 }); 862 863 false 864 } 865 Statement::Return(_) if step == 1 => loop { 866 let last_frame = self.frames.last().expect("a frame should be present"); 867 match last_frame.element { 868 Element::Expression(Expression::Call(_), _) | Element::DelayedCall(_) => { 869 if self.contexts.is_async() { 870 // Get rid of the Unit we previously pushed, and replace it with a Future. 871 self.values.pop(); 872 self.values.push(self.contexts.get_future().into()); 873 } 874 self.contexts.pop(); 875 return Ok(true); 876 } 877 _ => { 878 self.frames.pop(); 879 } 880 } 881 }, 882 _ => unreachable!(), 883 }; 884 885 if done { 886 assert_eq!(len, self.frames.len()); 887 self.frames.pop(); 888 } else { 889 self.frames[len - 1].step += 1; 890 } 891 892 Ok(done) 893 } 894 895 fn step_expression(&mut self, expression: &Expression, expected_ty: &Option<Type>, step: usize) -> Result<bool> { 896 let len = self.frames.len(); 897 898 macro_rules! push { 899 () => { 900 |expression: &Expression, expected_ty: &Option<Type>| { 901 self.frames.push(Frame { 902 element: Element::Expression(expression.clone(), expected_ty.clone()), 903 step: 0, 904 user_initiated: false, 905 }) 906 } 907 }; 908 } 909 910 if let Some(value) = match expression { 911 Expression::ArrayAccess(array) if step == 0 => { 912 push!()(&array.index, &None); 913 push!()(&array.array, &None); 914 None 915 } 916 Expression::ArrayAccess(array_expr) if step == 1 => { 917 let span = array_expr.span(); 918 let index = self.pop_value()?; 919 let array = self.pop_value()?; 920 921 // Local helper function to convert a Value into usize 922 fn to_usize(value: &Value, span: Span) -> Result<usize> { 923 let value = value.resolve_if_unsuffixed(&Some(Type::Integer(adl_ast::IntegerType::U32)), span)?; 924 Ok(value.as_u32().expect_tc(span)? as usize) 925 } 926 927 let index_usize = to_usize(&index, span)?; 928 929 Some(array.array_index(index_usize).expect_tc(span)?) 930 } 931 932 Expression::Async(AsyncExpression { block, .. }) if step == 0 => { 933 // Keep track of the async block, but nothing else to do at this point 934 self.async_blocks.insert(block.id, block.clone()); 935 None 936 } 937 Expression::Async(AsyncExpression { block, .. }) if step == 1 => { 938 // Keep track of this block as a `Future` containing an `AsyncExecution` but nothing else to do here. 939 // The block actually executes when an `await` is called on its future. 940 if let Some(context) = self.contexts.last() { 941 let async_ex = AsyncExecution::AsyncBlock { 942 containing_function: Location::new(context.program, context.path.clone()), 943 block: block.id, 944 names: context.names.clone().into_iter().collect(), 945 }; 946 self.values.push(vec![async_ex].into()); 947 } 948 None 949 } 950 Expression::Async(_) if step == 2 => Some(self.pop_value()?), 951 952 Expression::MemberAccess(access) => match &access.inner { 953 // Otherwise, we just have a normal composite member access. 954 _ if step == 0 => { 955 push!()(&access.inner, &None); 956 None 957 } 958 _ if step == 1 => { 959 let composite = self.values.pop().expect_tc(access.span())?; 960 let value = composite.member_access(access.name.name).expect_tc(access.span())?; 961 Some(value) 962 } 963 _ => unreachable!("we've actually covered all possible patterns above"), 964 }, 965 Expression::TupleAccess(tuple_access) if step == 0 => { 966 push!()(&tuple_access.tuple, &None); 967 None 968 } 969 Expression::TupleAccess(tuple_access) if step == 1 => { 970 let Some(value) = self.values.pop() else { tc_fail!() }; 971 if let Some(result) = value.tuple_index(tuple_access.index.value()) { 972 Some(result) 973 } else { 974 halt!(tuple_access.span(), "Tuple index out of range"); 975 } 976 } 977 Expression::Array(array) if step == 0 => { 978 let element_type = expected_ty.clone().and_then(|ty| match ty { 979 Type::Array(ArrayType { element_type, .. }) => Some(*element_type), 980 _ => None, 981 }); 982 983 array.elements.iter().rev().for_each(|array| push!()(array, &element_type)); 984 None 985 } 986 Expression::Array(array) if step == 1 => { 987 let len = self.values.len(); 988 let array_values = self.values.drain(len - array.elements.len()..); 989 Some(Value::make_array(array_values)) 990 } 991 Expression::Repeat(repeat) if step == 0 => { 992 let element_type = expected_ty.clone().and_then(|ty| match ty { 993 Type::Array(ArrayType { element_type, .. }) => Some(*element_type), 994 _ => None, 995 }); 996 997 push!()(&repeat.count, &None); 998 push!()(&repeat.expr, &element_type); 999 None 1000 } 1001 Expression::Repeat(repeat) if step == 1 => { 1002 let count = self.pop_value()?; 1003 let expr = self.pop_value()?; 1004 let count_resolved = count 1005 .resolve_if_unsuffixed(&Some(Type::Integer(adl_ast::IntegerType::U32)), repeat.count.span())?; 1006 Some(Value::make_array(std::iter::repeat_n( 1007 expr, 1008 count_resolved.as_u32().expect_tc(repeat.span())? as usize, 1009 ))) 1010 } 1011 Expression::Intrinsic(intr) if step == 0 => { 1012 let intrinsic = if intr.name == Symbol::intern("__unresolved_get") { 1013 Intrinsic::MappingGet 1014 } else if intr.name == Symbol::intern("__unresolved_set") { 1015 Intrinsic::MappingSet 1016 } else if let Some(intrinsic) = Intrinsic::from_symbol(intr.name, &intr.type_parameters) { 1017 intrinsic 1018 } else { 1019 halt!(intr.span(), "Unknown intrinsic {}", intr.name); 1020 }; 1021 1022 // We want to push expressions for each of the arguments... except for mappings, 1023 // because we don't look them up as Values. 1024 match intrinsic { 1025 Intrinsic::MappingGet | Intrinsic::MappingRemove | Intrinsic::MappingContains => { 1026 push!()(&intr.arguments[1], &None); 1027 None 1028 } 1029 Intrinsic::MappingGetOrUse | Intrinsic::MappingSet => { 1030 push!()(&intr.arguments[2], &None); 1031 push!()(&intr.arguments[1], &None); 1032 None 1033 } 1034 Intrinsic::GroupGen => Some(Value::generator()), 1035 Intrinsic::SelfSigner => Some(self.signer.clone()), 1036 Intrinsic::SelfCaller => { 1037 if let Some(function_context) = self.contexts.last() { 1038 Some(function_context.caller.clone()) 1039 } else { 1040 Some(self.signer.clone()) 1041 } 1042 } 1043 Intrinsic::SelfAddress => { 1044 // A helper function to convert a program ID string to an address value. 1045 fn program_to_address<N: Network>(program_id: &str) -> Result<Value> { 1046 let Ok(program_id) = ProgramID::<N>::from_str(&format!("{program_id}.alpha")) else { 1047 halt_no_span!("Failed to parse program ID"); 1048 }; 1049 let Ok(address) = program_id.to_address() else { 1050 halt_no_span!("Failed to convert program ID to address"); 1051 }; 1052 let Ok(value) = Value::from_str(&address.to_string()) else { 1053 halt_no_span!("Failed to convert address to value"); 1054 }; 1055 Ok(value) 1056 } 1057 // Get the current program. 1058 let Some(program) = self.current_program() else { 1059 halt_no_span!("No program context for address"); 1060 }; 1061 #[allow(deprecated)] 1062 let result = match self.network { 1063 // ALPHA networks 1064 NetworkName::AlphaTestnetV0 => program_to_address::<TestnetV0>(&program.to_string())?, 1065 NetworkName::AlphaMainnetV0 => program_to_address::<MainnetV0>(&program.to_string())?, 1066 NetworkName::AlphaCanaryV0 => program_to_address::<CanaryV0>(&program.to_string())?, 1067 // DELTA networks 1068 NetworkName::DeltaTestnetV0 => program_to_address::<TestnetV0>(&program.to_string())?, 1069 NetworkName::DeltaMainnetV0 => program_to_address::<MainnetV0>(&program.to_string())?, 1070 NetworkName::DeltaCanaryV0 => program_to_address::<CanaryV0>(&program.to_string())?, 1071 // Legacy Aleo networks (deprecated) 1072 NetworkName::TestnetV0 => program_to_address::<TestnetV0>(&program.to_string())?, 1073 NetworkName::MainnetV0 => program_to_address::<MainnetV0>(&program.to_string())?, 1074 NetworkName::CanaryV0 => program_to_address::<CanaryV0>(&program.to_string())?, 1075 }; 1076 Some(result) 1077 } 1078 Intrinsic::BlockHeight => Some(self.block_height.into()), 1079 Intrinsic::BlockTimestamp => Some(self.block_timestamp.into()), 1080 Intrinsic::CheatCodePrintMapping => { 1081 // Do nothing, as we don't need to evaluate the mapping. 1082 None 1083 } 1084 _ => { 1085 intr.arguments.iter().rev().for_each(|arg| push!()(arg, &None)); 1086 None 1087 } 1088 } 1089 } 1090 Expression::Intrinsic(intr) if step == 1 => { 1091 let intrinsic = if intr.name == Symbol::intern("__unresolved_get") { 1092 Intrinsic::MappingGet 1093 } else if intr.name == Symbol::intern("__unresolved_set") { 1094 Intrinsic::MappingSet 1095 } else if let Some(intrinsic) = Intrinsic::from_symbol(intr.name, &intr.type_parameters) { 1096 intrinsic 1097 } else { 1098 halt!(intr.span(), "Unknown intrinsic {}", intr.name); 1099 }; 1100 1101 let span = intr.span(); 1102 1103 if let Intrinsic::FutureAwait = intrinsic { 1104 let value = self.pop_value()?; 1105 let Some(asyncs) = value.as_future() else { 1106 halt!(span, "Invalid value for await: {value}"); 1107 }; 1108 for async_execution in asyncs { 1109 match async_execution { 1110 AsyncExecution::AsyncFunctionCall { function, arguments } => { 1111 self.values.extend(arguments.iter().cloned()); 1112 self.frames.push(Frame { 1113 step: 0, 1114 element: Element::DelayedCall(function.clone()), 1115 user_initiated: false, 1116 }); 1117 } 1118 AsyncExecution::AsyncBlock { containing_function, block, names, .. } => { 1119 self.frames.push(Frame { 1120 step: 0, 1121 element: Element::DelayedAsyncBlock { 1122 program: containing_function.program, 1123 block: *block, 1124 // Keep track of all the known variables up to this point. 1125 // These are available to use inside the block when we actually execute it. 1126 names: names.clone().into_iter().collect(), 1127 }, 1128 user_initiated: false, 1129 }); 1130 } 1131 } 1132 } 1133 // For an await, we have one extra step - first we must evaluate the delayed call. 1134 None 1135 } else { 1136 let value = evaluate_intrinsic(self, intrinsic.clone(), &intr.arguments, span)?; 1137 assert!(value.is_some()); 1138 value 1139 } 1140 } 1141 Expression::Intrinsic(intr) if step == 2 => { 1142 let intrinsic = if intr.name == Symbol::intern("__unresolved_get") { 1143 Intrinsic::MappingGet 1144 } else if intr.name == Symbol::intern("__unresolved_set") { 1145 Intrinsic::MappingSet 1146 } else if let Some(intrinsic) = Intrinsic::from_symbol(intr.name, &intr.type_parameters) { 1147 intrinsic 1148 } else { 1149 halt!(intr.span(), "Unknown intrinsic {}", intr.name); 1150 }; 1151 assert!(intrinsic == Intrinsic::FutureAwait); 1152 Some(Value::make_unit()) 1153 } 1154 1155 Expression::Binary(binary) if step == 0 => { 1156 use BinaryOperation::*; 1157 1158 // Determine the expected types for the right and left operands based on the operation 1159 let (right_ty, left_ty) = match binary.op { 1160 // Multiplications that return a `Group` can take `Scalar * Group` or `Group * Scalar`. 1161 // No way to know at this stage. 1162 Mul if matches!(expected_ty, Some(Type::Group)) => (None, None), 1163 1164 // Boolean operations don't require expected type propagation 1165 And | Or | Nand | Nor | Eq | Neq | Lt | Gt | Lte | Gte => (None, None), 1166 1167 // Exponentiation (Pow) may require specific typing if expected to be a Field 1168 Pow => { 1169 let right_ty = if matches!(expected_ty, Some(Type::Field)) { 1170 Some(Type::Field) // Enforce Field type on exponent if expected 1171 } else { 1172 None // Otherwise, don't constrain the exponent 1173 }; 1174 (right_ty, expected_ty.clone()) // Pass the expected type to the base 1175 } 1176 1177 // Bitwise shifts and wrapped exponentiation: 1178 // Typically only the left operand should conform to the expected type 1179 Shl | ShlWrapped | Shr | ShrWrapped | PowWrapped => (None, expected_ty.clone()), 1180 1181 // Default case: propagate expected type to both operands 1182 _ => (expected_ty.clone(), expected_ty.clone()), 1183 }; 1184 1185 // Push operands onto the stack for evaluation in right-to-left order 1186 push!()(&binary.right, &right_ty); 1187 push!()(&binary.left, &left_ty); 1188 1189 None 1190 } 1191 Expression::Binary(binary) if step == 1 => { 1192 let rhs = self.pop_value()?; 1193 let lhs = self.pop_value()?; 1194 Some(evaluate_binary(binary.span, binary.op, &lhs, &rhs, expected_ty)?) 1195 } 1196 1197 Expression::Call(call) if step == 0 => { 1198 // Resolve the function's program and name 1199 let (function_program, function_path) = { 1200 let maybe_program = call.program.or_else(|| self.current_program()); 1201 if let Some(program) = maybe_program { 1202 (program, self.to_absolute_path(&call.function.as_symbols())) 1203 } else { 1204 halt!(call.span, "No current program"); 1205 } 1206 }; 1207 1208 // Look up the function variant (Leo, AleoClosure, or AleoFunction) 1209 let Some(function_variant) = self.lookup_function(function_program, &function_path) else { 1210 halt!(call.span, "unknown function {function_program}.alpha/{}", function_path.iter().format("::")); 1211 }; 1212 1213 // Extract const parameter and input types based on the function variant 1214 let (const_param_types, input_types) = match function_variant { 1215 FunctionVariant::Leo(function) => ( 1216 function.const_parameters.iter().map(|p| p.type_.clone()).collect::<Vec<_>>(), 1217 function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>(), 1218 ), 1219 FunctionVariant::AleoClosure(closure) => { 1220 let function = adl_ast::FunctionStub::from_closure(&closure, function_program); 1221 (vec![], function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>()) 1222 } 1223 FunctionVariant::AleoFunction(svm_function) => { 1224 let function = adl_ast::FunctionStub::from_function_core(&svm_function, function_program); 1225 (vec![], function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>()) 1226 } 1227 }; 1228 1229 // Push arguments (in reverse order) with corresponding input types 1230 call.arguments 1231 .iter() 1232 .rev() 1233 .zip(input_types.iter().rev()) 1234 .for_each(|(arg, ty)| push!()(arg, &Some(ty.clone()))); 1235 1236 // Push const arguments (in reverse order) with corresponding const param types 1237 call.const_arguments 1238 .iter() 1239 .rev() 1240 .zip(const_param_types.iter().rev()) 1241 .for_each(|(arg, ty)| push!()(arg, &Some(ty.clone()))); 1242 1243 None 1244 } 1245 1246 Expression::Call(call) if step == 1 => { 1247 let len = self.values.len(); 1248 let (program, path) = { 1249 let maybe_program = call.program.or_else(|| self.current_program()); 1250 if let Some(program) = maybe_program { 1251 (program, call.function.as_symbols()) 1252 } else { 1253 halt!(call.span, "No current program"); 1254 } 1255 }; 1256 // It's a bit cheesy to collect the arguments into a Vec first, but it's the easiest way 1257 // to handle lifetimes here. 1258 let arguments: Vec<Value> = 1259 self.values.drain(len - call.arguments.len() - call.const_arguments.len()..).collect(); 1260 self.do_call( 1261 program, 1262 &self.to_absolute_path(&path), 1263 arguments.into_iter(), 1264 false, // finalize 1265 call.span(), 1266 )?; 1267 None 1268 } 1269 Expression::Call(_call) if step == 2 => Some(self.pop_value()?), 1270 Expression::Cast(cast) if step == 0 => { 1271 push!()(&cast.expression, &None); 1272 None 1273 } 1274 Expression::Cast(cast) if step == 1 => { 1275 let span = cast.span(); 1276 let arg = self.pop_value()?; 1277 match arg.cast(&cast.type_) { 1278 Some(value) => Some(value), 1279 None => return Err(InterpreterHalt::new_spanned("cast failure".to_string(), span).into()), 1280 } 1281 } 1282 Expression::Err(_) => todo!(), 1283 Expression::Path(path) if step == 0 => { 1284 Some(self.lookup(&self.to_absolute_path(&path.as_symbols())).expect_tc(path.span())?) 1285 } 1286 Expression::Literal(literal) if step == 0 => Some(literal_to_value(literal, expected_ty)?), 1287 Expression::Locator(_locator) => todo!(), 1288 Expression::Composite(composite) if step == 0 => { 1289 let members = self 1290 .composites 1291 .get(&self.to_absolute_path(&composite.path.as_symbols())) 1292 .expect_tc(composite.span())?; 1293 for CompositeFieldInitializer { identifier: field_init_name, expression: init, .. } in 1294 &composite.members 1295 { 1296 let Some(type_) = members.get(&field_init_name.name) else { tc_fail!() }; 1297 push!()( 1298 init.as_ref().unwrap_or(&Expression::Path(Path::from(*field_init_name))), 1299 &Some(type_.clone()), 1300 ) 1301 } 1302 1303 None 1304 } 1305 Expression::Composite(composite) if step == 1 => { 1306 // Collect all the key/value pairs into a HashMap. 1307 let mut contents_tmp = HashMap::with_capacity(composite.members.len()); 1308 for initializer in composite.members.iter() { 1309 let name = initializer.identifier.name; 1310 let value = self.pop_value()?; 1311 contents_tmp.insert(name, value); 1312 } 1313 1314 // And now put them into an IndexMap in the correct order. 1315 let members = self 1316 .composites 1317 .get(&self.to_absolute_path(&composite.path.as_symbols())) 1318 .expect_tc(composite.span())?; 1319 let contents = members.iter().map(|(identifier, _)| { 1320 (*identifier, contents_tmp.remove(identifier).expect("we just inserted this")) 1321 }); 1322 1323 // TODO: this only works for composites defined in the top level module.. must figure 1324 // something out for structs defined in modules 1325 Some(Value::make_struct(contents, self.current_program().unwrap(), composite.path.as_symbols())) 1326 } 1327 Expression::Ternary(ternary) if step == 0 => { 1328 push!()(&ternary.condition, &None); 1329 None 1330 } 1331 Expression::Ternary(ternary) if step == 1 => { 1332 let condition = self.pop_value()?; 1333 match condition.try_into() { 1334 Ok(true) => push!()(&ternary.if_true, &None), 1335 Ok(false) => push!()(&ternary.if_false, &None), 1336 _ => halt!(ternary.span(), "Invalid type for ternary expression {ternary}"), 1337 } 1338 None 1339 } 1340 Expression::Ternary(_) if step == 2 => Some(self.pop_value()?), 1341 Expression::Tuple(tuple) if step == 0 => { 1342 tuple.elements.iter().rev().for_each(|t| push!()(t, &None)); 1343 None 1344 } 1345 Expression::Tuple(tuple) if step == 1 => { 1346 let len = self.values.len(); 1347 let tuple_values = self.values.drain(len - tuple.elements.len()..); 1348 Some(Value::make_tuple(tuple_values)) 1349 } 1350 Expression::Unary(unary) if step == 0 => { 1351 use UnaryOperation::*; 1352 1353 // Determine the expected type based on the unary operation 1354 let ty = match unary.op { 1355 Inverse | Square | SquareRoot => Some(Type::Field), // These ops require Field operands 1356 ToXCoordinate | ToYCoordinate => Some(Type::Group), // These ops apply to Group elements 1357 _ => expected_ty.clone(), // Fallback to the externally expected type 1358 }; 1359 1360 // Push the receiver expression with the computed type 1361 push!()(&unary.receiver, &ty); 1362 1363 None 1364 } 1365 Expression::Unary(unary) if step == 1 => { 1366 let value = self.pop_value()?; 1367 Some(evaluate_unary(unary.span, unary.op, &value, expected_ty)?) 1368 } 1369 Expression::Unit(_) if step == 0 => Some(Value::make_unit()), 1370 x => unreachable!("Unexpected expression {x}"), 1371 } { 1372 assert_eq!(self.frames.len(), len); 1373 self.frames.pop(); 1374 self.values.push(value); 1375 Ok(true) 1376 } else { 1377 self.frames[len - 1].step += 1; 1378 Ok(false) 1379 } 1380 } 1381 1382 /// Execute one step of the current element. 1383 /// 1384 /// Many Leo constructs require multiple steps. For instance, when executing a conditional, 1385 /// the first step will push the condition expression to the stack. Once that has executed 1386 /// and we've returned to the conditional, we push the `then` or `otherwise` block to the 1387 /// stack. Once that has executed and we've returned to the conditional, the final step 1388 /// does nothing. 1389 pub fn step(&mut self) -> Result<StepResult> { 1390 if self.frames.is_empty() { 1391 return Err(InterpreterHalt::new("no execution frames available".into()).into()); 1392 } 1393 1394 let Frame { element, step, user_initiated } = self.frames.last().expect("there should be a frame").clone(); 1395 match element { 1396 Element::Block { block, function_body } => { 1397 let finished = self.step_block(&block, function_body, step); 1398 Ok(StepResult { finished, value: None }) 1399 } 1400 Element::Statement(statement) => { 1401 let finished = self.step_statement(&statement, step)?; 1402 Ok(StepResult { finished, value: None }) 1403 } 1404 Element::Expression(expression, expected_ty) => { 1405 let finished = self.step_expression(&expression, &expected_ty, step)?; 1406 let value = match (finished, user_initiated) { 1407 (false, _) => None, 1408 (true, false) => self.values.last().cloned(), 1409 (true, true) => self.values.pop(), 1410 }; 1411 1412 let maybe_future = if let Some(len) = value.as_ref().and_then(|val| val.tuple_len()) { 1413 value.as_ref().unwrap().tuple_index(len - 1) 1414 } else { 1415 value.clone() 1416 }; 1417 1418 if let Some(asyncs) = maybe_future.as_ref().and_then(|fut| fut.as_future()) 1419 && user_initiated 1420 { 1421 self.futures.extend(asyncs.iter().cloned()); 1422 } 1423 1424 Ok(StepResult { finished, value }) 1425 } 1426 Element::AleoExecution { .. } => { 1427 self.step_alpha()?; 1428 Ok(StepResult { finished: true, value: None }) 1429 } 1430 Element::DelayedCall(gid) if step == 0 => { 1431 match self.lookup_function(gid.program, &gid.path).expect("function should exist") { 1432 FunctionVariant::Leo(function) => { 1433 assert!(function.variant == Variant::AsyncFunction); 1434 let len = self.values.len(); 1435 let values: Vec<Value> = self.values.drain(len - function.input.len()..).collect(); 1436 self.contexts.push( 1437 &gid.path, 1438 gid.program, 1439 self.signer.clone(), 1440 true, // is_async 1441 HashMap::new(), 1442 ); 1443 let param_names = function.input.iter().map(|input| input.identifier.name); 1444 for (name, value) in param_names.zip(values) { 1445 self.set_variable(&self.to_absolute_path(&[name]), value); 1446 } 1447 self.frames.last_mut().unwrap().step = 1; 1448 self.frames.push(Frame { 1449 step: 0, 1450 element: Element::Block { block: function.block.clone(), function_body: true }, 1451 user_initiated: false, 1452 }); 1453 Ok(StepResult { finished: false, value: None }) 1454 } 1455 FunctionVariant::AleoFunction(function) => { 1456 let Some(finalize_f) = function.finalize_logic() else { 1457 panic!("must have finalize logic for a delayed call"); 1458 }; 1459 let len = self.values.len(); 1460 let values_iter = self.values.drain(len - finalize_f.inputs().len()..); 1461 self.contexts.push( 1462 &gid.path, 1463 gid.program, 1464 self.signer.clone(), 1465 true, // is_async 1466 HashMap::new(), 1467 ); 1468 self.frames.last_mut().unwrap().step = 1; 1469 self.frames.push(Frame { 1470 step: 0, 1471 element: Element::AleoExecution { 1472 context: AleoContext::Finalize(finalize_f.clone()).into(), 1473 registers: values_iter.enumerate().map(|(i, v)| (i as u64, v)).collect(), 1474 instruction_index: 0, 1475 }, 1476 user_initiated: false, 1477 }); 1478 Ok(StepResult { finished: false, value: None }) 1479 } 1480 FunctionVariant::AleoClosure(..) => panic!("A call to a closure can't be delayed"), 1481 } 1482 } 1483 Element::DelayedCall(_gid) => { 1484 assert_eq!(step, 1); 1485 let value = self.values.pop(); 1486 self.frames.pop(); 1487 Ok(StepResult { finished: true, value }) 1488 } 1489 Element::DelayedAsyncBlock { program, block, names } if step == 0 => { 1490 self.contexts.push( 1491 &[Symbol::intern("")], 1492 program, 1493 self.signer.clone(), 1494 true, 1495 names.clone().into_iter().collect(), // Set the known names to the previously preserved `names`. 1496 ); 1497 self.frames.last_mut().unwrap().step = 1; 1498 self.frames.push(Frame { 1499 step: 0, 1500 element: Element::Block { 1501 block: self.async_blocks.get(&block).unwrap().clone(), 1502 function_body: true, 1503 }, 1504 user_initiated: false, 1505 }); 1506 Ok(StepResult { finished: false, value: None }) 1507 } 1508 Element::DelayedAsyncBlock { .. } => { 1509 assert_eq!(step, 1); 1510 let value = self.values.pop(); 1511 self.frames.pop(); 1512 Ok(StepResult { finished: true, value }) 1513 } 1514 } 1515 } 1516 1517 pub fn do_call( 1518 &mut self, 1519 function_program: Symbol, 1520 function_path: &[Symbol], 1521 arguments: impl Iterator<Item = Value>, 1522 finalize: bool, 1523 span: Span, 1524 ) -> Result<()> { 1525 let Some(function_variant) = self.lookup_function(function_program, function_path) else { 1526 halt!(span, "unknown function {function_program}.alpha/{}", function_path.iter().format("::")); 1527 }; 1528 match function_variant { 1529 FunctionVariant::Leo(function) => { 1530 let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) { 1531 self.new_caller() 1532 } else { 1533 self.signer.clone() 1534 }; 1535 if self.really_async && function.variant == Variant::AsyncFunction { 1536 // Don't actually run the call now. 1537 let async_ex = AsyncExecution::AsyncFunctionCall { 1538 function: Location::new(function_program, function_path.to_vec()), 1539 arguments: arguments.collect(), 1540 }; 1541 self.values.push(vec![async_ex].into()); 1542 } else { 1543 let is_async = function.variant == Variant::AsyncFunction; 1544 self.contexts.push(function_path, function_program, caller, is_async, HashMap::new()); 1545 // Treat const generic parameters as regular inputs 1546 let param_names = function 1547 .const_parameters 1548 .iter() 1549 .map(|param| param.identifier.name) 1550 .chain(function.input.iter().map(|input| input.identifier.name)); 1551 for (name, value) in param_names.zip(arguments) { 1552 self.set_variable(&self.to_absolute_path(&[name]), value); 1553 } 1554 self.frames.push(Frame { 1555 step: 0, 1556 element: Element::Block { block: function.block.clone(), function_body: true }, 1557 user_initiated: false, 1558 }); 1559 } 1560 } 1561 FunctionVariant::AleoClosure(closure) => { 1562 self.contexts.push(function_path, function_program, self.signer.clone(), false, HashMap::new()); 1563 let context = AleoContext::Closure(closure); 1564 self.frames.push(Frame { 1565 step: 0, 1566 element: Element::AleoExecution { 1567 context: context.into(), 1568 registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(), 1569 instruction_index: 0, 1570 }, 1571 user_initiated: false, 1572 }); 1573 } 1574 FunctionVariant::AleoFunction(function) => { 1575 let caller = self.new_caller(); 1576 self.contexts.push(function_path, function_program, caller, false, HashMap::new()); 1577 let context = if finalize { 1578 let Some(finalize_f) = function.finalize_logic() else { 1579 panic!("finalize call with no finalize logic"); 1580 }; 1581 AleoContext::Finalize(finalize_f.clone()) 1582 } else { 1583 AleoContext::Function(function) 1584 }; 1585 self.frames.push(Frame { 1586 step: 0, 1587 element: Element::AleoExecution { 1588 context: context.into(), 1589 registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(), 1590 instruction_index: 0, 1591 }, 1592 user_initiated: false, 1593 }); 1594 } 1595 } 1596 1597 Ok(()) 1598 } 1599 } 1600 1601 #[derive(Clone, Debug)] 1602 pub struct StepResult { 1603 /// Has this element completely finished running? 1604 pub finished: bool, 1605 1606 /// If the element was an expression, here's its value. 1607 pub value: Option<Value>, 1608 }