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