datex_core/runtime/execution/
execution_input.rs

1use crate::runtime::RuntimeInternal;
2use crate::runtime::execution::ExecutionError;
3use crate::runtime::execution::execution_loop::execution_loop;
4use crate::runtime::execution::execution_loop::interrupts::{
5    ExternalExecutionInterrupt, InterruptProvider,
6};
7use crate::runtime::execution::execution_loop::state::{
8    ExecutionLoopState, RuntimeExecutionState,
9};
10use crate::stdlib::boxed::Box;
11use crate::stdlib::rc::Rc;
12use core::cell::RefCell;
13
14#[derive(Debug, Clone, Default)]
15pub struct ExecutionOptions {
16    pub verbose: bool,
17}
18
19/// Input required to execute a DXB program.
20#[derive(Debug, Default)]
21pub struct ExecutionInput<'a> {
22    /// Options for execution.
23    pub options: ExecutionOptions,
24    /// The DXB program body containing raw bytecode.
25    pub dxb_body: &'a [u8],
26    /// For persisting execution state across multiple executions (e.g., for REPL scenarios).
27    pub loop_state: Option<ExecutionLoopState>,
28    pub runtime: Option<Rc<RuntimeInternal>>,
29}
30
31impl<'a> ExecutionInput<'a> {
32    pub fn new(
33        dxb_body: &'a [u8],
34        options: ExecutionOptions,
35        runtime: Option<Rc<RuntimeInternal>>,
36    ) -> Self {
37        Self {
38            options,
39            dxb_body,
40            loop_state: None,
41            runtime,
42        }
43    }
44
45    pub fn execution_loop(
46        mut self,
47    ) -> (
48        InterruptProvider,
49        impl Iterator<Item = Result<ExternalExecutionInterrupt, ExecutionError>>,
50    ) {
51        // use execution iterator if one already exists from previous execution
52        let mut loop_state = if let Some(existing_loop_state) =
53            self.loop_state.take()
54        {
55            // update dxb so that instruction iterator can continue with next instructions
56            *existing_loop_state.dxb_body.borrow_mut() = self.dxb_body.to_vec();
57            existing_loop_state
58        }
59        // otherwise start a new execution loop
60        else {
61            let state = RuntimeExecutionState {
62                runtime_internal: self.runtime.clone(),
63                source_id: 0, // TODO #640: set proper source ID
64                ..Default::default()
65            };
66            // TODO #641: optimize, don't clone the whole DXB body every time here
67            let dxb_rc = Rc::new(RefCell::new(self.dxb_body.to_vec()));
68            let interrupt_provider = InterruptProvider::new();
69            ExecutionLoopState {
70                dxb_body: dxb_rc.clone(),
71                iterator: Box::new(execution_loop(
72                    state,
73                    dxb_rc,
74                    interrupt_provider.clone(),
75                )),
76                interrupt_provider,
77            }
78        };
79        let interrupt_provider = loop_state.interrupt_provider.clone();
80
81        // proxy the iterator, storing it back into state if interrupted to await more instructions
82        let iterator = gen move {
83            loop {
84                let item = loop_state.iterator.next();
85                if item.is_none() {
86                    break;
87                }
88                let item = item.unwrap();
89
90                match item {
91                    Err(ExecutionError::IntermediateResultWithState(
92                        intermediate_result,
93                        _,
94                    )) => {
95                        return yield Err(
96                            ExecutionError::IntermediateResultWithState(
97                                intermediate_result,
98                                Some(loop_state),
99                            ),
100                        );
101                    }
102                    _ => yield item,
103                }
104            }
105        };
106
107        (interrupt_provider, iterator)
108    }
109}