datex_core/runtime/execution/context/
mod.rs1#[cfg(feature = "compiler")]
2use crate::compiler::{
3 CompileOptions, compile_template, error::SpannedCompilerError,
4 scope::CompilationScope,
5};
6use crate::{
7 runtime::execution::{
8 ExecutionError, ExecutionInput, MemoryDump, execute_dxb,
9 execute_dxb_sync,
10 },
11 values::value_container::ValueContainer,
12};
13
14use crate::prelude::*;
15pub use local::*;
16use log::info;
17pub use remote::*;
18pub use script::*;
19
20mod local;
21mod remote;
22mod script;
23
24#[derive(Debug)]
28pub enum ExecutionContext {
29 Local(LocalExecutionContext),
30 Remote(RemoteExecutionContext),
31}
32
33impl ExecutionContext {
34 #[cfg(feature = "compiler")]
35 fn compile_scope(&self) -> &CompilationScope {
36 match self {
37 ExecutionContext::Local(LocalExecutionContext {
38 compile_scope,
39 ..
40 }) => compile_scope,
41 ExecutionContext::Remote(RemoteExecutionContext {
42 compile_scope,
43 ..
44 }) => compile_scope,
45 }
46 }
47
48 #[cfg(feature = "compiler")]
49 fn set_compile_scope(&mut self, new_compile_scope: CompilationScope) {
50 match self {
51 ExecutionContext::Local(LocalExecutionContext {
52 compile_scope,
53 ..
54 }) => *compile_scope = new_compile_scope,
55 ExecutionContext::Remote(RemoteExecutionContext {
56 compile_scope,
57 ..
58 }) => *compile_scope = new_compile_scope,
59 }
60 }
61
62 #[cfg(feature = "compiler")]
64 pub fn compile(
65 &mut self,
66 script: &str,
67 inserted_values: &[ValueContainer],
68 ) -> Result<Vec<u8>, SpannedCompilerError> {
69 let compile_scope = self.compile_scope();
70 let res = compile_template(
72 script,
73 inserted_values
74 .iter()
75 .cloned()
76 .map(Some)
77 .collect::<Vec<_>>()
78 .as_slice(),
79 CompileOptions::new_with_scope(compile_scope.clone()),
80 );
81 match res {
82 Ok((bytes, compile_scope)) => {
83 self.set_compile_scope(compile_scope);
84 Ok(bytes)
85 }
86 Err(err) => Err(err),
87 }
88 }
89
90 fn print_dxb_debug(&self, dxb: &[u8]) -> Result<(), ExecutionError> {
91 info!(
92 "\x1b[32m[Compiled Bytecode] {}",
93 dxb.iter()
94 .map(|b| format!("{b:02x}"))
95 .collect::<Vec<_>>()
96 .join(" ")
97 );
98
99 #[cfg(feature = "decompiler")]
100 {
101 let decompiled = crate::decompiler::decompile_body(
102 dxb,
103 crate::decompiler::DecompileOptions::colorized(),
104 );
105 if let Err(e) = decompiled {
106 info!("\x1b[31m[Decompiler Error] {e}\x1b[0m");
107 } else {
108 let decompiled = decompiled?;
109 info!("[Decompiled]: {decompiled}");
110 }
111 }
112
113 Ok(())
114 }
115
116 fn get_local_execution_input<'a>(
117 &'a mut self,
118 dxb: &'a [u8],
119 ) -> Result<ExecutionInput<'a>, ExecutionError> {
120 match self {
121 ExecutionContext::Remote(_) => {
122 core::panic!("Remote execution requires a Runtime");
123 }
124 ExecutionContext::Local(LocalExecutionContext {
125 runtime,
126 loop_state,
127 execution_options,
128 verbose,
129 ..
130 }) => {
131 let input = ExecutionInput {
132 runtime: runtime.clone(),
133 loop_state: loop_state.take(),
134 options: (*execution_options).clone(),
135 dxb_body: dxb,
136 };
137
138 if *verbose {
140 self.print_dxb_debug(dxb)?;
141 }
142
143 Ok(input)
144 }
145 }
146 }
147
148 pub fn execute_dxb_sync(
150 &mut self,
151 dxb: &[u8],
152 ) -> Result<Option<ValueContainer>, ExecutionError> {
153 let execution_input = self.get_local_execution_input(dxb)?;
154 let res = execute_dxb_sync(execution_input);
155 self.intercept_intermediate_result(res)
156 }
157
158 #[cfg(feature = "compiler")]
160 pub fn execute_sync(
161 &mut self,
162 script: &str,
163 inserted_values: &[ValueContainer],
164 ) -> Result<Option<ValueContainer>, ScriptExecutionError> {
165 let dxb = self.compile(script, inserted_values)?;
166 self.execute_dxb_sync(&dxb)
167 .map_err(ScriptExecutionError::from)
168 }
169
170 pub async fn execute_dxb(
171 &mut self,
172 dxb: &[u8],
173 ) -> Result<Option<ValueContainer>, ExecutionError> {
174 match self {
175 ExecutionContext::Local(..) => {
176 let res = {
177 let execution_input =
178 self.get_local_execution_input(dxb)?;
179 execute_dxb(execution_input).await
180 };
181 self.intercept_intermediate_result(res)
182 }
183 ExecutionContext::Remote(..) => {
185 core::panic!("Remote execution requires a Runtime");
186 }
187 }
188 }
189
190 fn intercept_intermediate_result(
194 &mut self,
195 execution_result: Result<Option<ValueContainer>, ExecutionError>,
196 ) -> Result<Option<ValueContainer>, ExecutionError> {
197 match execution_result {
198 Err(ExecutionError::IntermediateResultWithState(
199 intermediate_result,
200 Some(state),
201 )) => {
202 match self {
203 ExecutionContext::Local(LocalExecutionContext {
204 loop_state,
205 ..
206 }) => {
207 loop_state.replace(state);
208 Ok(intermediate_result)
209 }
210 _ => unreachable!(), }
212 }
213 _ => execution_result,
214 }
215 }
216
217 #[cfg(feature = "compiler")]
218 pub async fn execute(
219 &mut self,
220 script: &str,
221 inserted_values: &[ValueContainer],
222 ) -> Result<Option<ValueContainer>, ScriptExecutionError> {
223 let dxb = self.compile(script, inserted_values)?;
224 self.execute_dxb(&dxb)
225 .await
226 .map_err(ScriptExecutionError::from)
227 }
228
229 pub fn memory_dump(&self) -> Option<MemoryDump> {
231 match self {
232 ExecutionContext::Local(_local_context) => {
233 todo!("#650 Undescribed by author.")
234 }
236 ExecutionContext::Remote(_) => None,
238 }
239 }
240}