miden_testing/
executor.rs

1use alloc::{borrow::ToOwned, sync::Arc};
2
3use miden_lib::transaction::TransactionKernel;
4use miden_objects::assembly::SourceManager;
5use vm_processor::{
6    AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, Host, Process, Program, StackInputs,
7};
8
9// MOCK CODE EXECUTOR
10// ================================================================================================
11
12/// Helper for executing arbitrary code within arbitrary hosts.
13pub struct CodeExecutor<H> {
14    host: H,
15    stack_inputs: Option<StackInputs>,
16    advice_inputs: AdviceInputs,
17}
18
19impl<H: Host> CodeExecutor<H> {
20    // CONSTRUCTOR
21    // --------------------------------------------------------------------------------------------
22    pub(crate) fn new(host: H) -> Self {
23        Self {
24            host,
25            stack_inputs: None,
26            advice_inputs: AdviceInputs::default(),
27        }
28    }
29
30    pub fn extend_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
31        self.advice_inputs.extend(advice_inputs);
32        self
33    }
34
35    pub fn stack_inputs(mut self, stack_inputs: StackInputs) -> Self {
36        self.stack_inputs = Some(stack_inputs);
37        self
38    }
39
40    /// Compiles and runs the desired code in the host and returns the [`Process`] state.
41    ///
42    /// To improve the error message quality, convert the returned [`ExecutionError`] into a
43    /// [`Report`](miden_objects::assembly::diagnostics::Report).
44    pub fn run(self, code: &str) -> Result<Process, ExecutionError> {
45        let assembler = TransactionKernel::testing_assembler().with_debug_mode(true);
46        let source_manager = assembler.source_manager();
47
48        // Virtual file name should be unique.
49        let virtual_source_file = source_manager.load("_user_code", code.to_owned());
50        let program = assembler.assemble_program(virtual_source_file).unwrap();
51
52        self.execute_program(program, source_manager)
53    }
54
55    /// Executes the provided [`Program`] and returns the [`Process`] state.
56    ///
57    /// To improve the error message quality, convert the returned [`ExecutionError`] into a
58    /// [`Report`](miden_objects::assembly::diagnostics::Report).
59    pub fn execute_program(
60        mut self,
61        program: Program,
62        source_manager: Arc<dyn SourceManager>,
63    ) -> Result<Process, ExecutionError> {
64        let mut process =
65            Process::new_debug(program.kernel().clone(), self.stack_inputs.unwrap_or_default())
66                .with_source_manager(source_manager);
67        process.execute(&program, &mut self.host)?;
68
69        Ok(process)
70    }
71}
72
73impl<A> CodeExecutor<DefaultHost<A>>
74where
75    A: AdviceProvider,
76{
77    pub fn with_advice_provider(adv_provider: A) -> Self {
78        let mut host = DefaultHost::new(adv_provider);
79
80        let test_lib = TransactionKernel::kernel_as_library();
81        host.load_mast_forest(test_lib.mast_forest().clone()).unwrap();
82
83        CodeExecutor::new(host)
84    }
85}