miden_testing/
executor.rs

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