1use crate::compiler::error::CompilerError;
2use crate::compiler::scope::CompilationScope;
3use crate::compiler::{CompileOptions, compile_template};
4use crate::decompiler::{DecompileOptions, decompile_body};
5use crate::global::dxb_block::OutgoingContextId;
6use crate::runtime::RuntimeInternal;
7use crate::runtime::execution::{
8 ExecutionError, ExecutionInput, ExecutionOptions, MemoryDump,
9 RuntimeExecutionContext, execute_dxb, execute_dxb_sync,
10};
11use crate::values::core_values::endpoint::Endpoint;
12use crate::values::value_container::ValueContainer;
13use std::cell::RefCell;
14use std::fmt::Display;
15use std::rc::Rc;
16
17#[derive(Debug)]
18pub enum ScriptExecutionError {
19 CompilerError(CompilerError),
20 ExecutionError(ExecutionError),
21}
22
23impl From<CompilerError> for ScriptExecutionError {
24 fn from(err: CompilerError) -> Self {
25 ScriptExecutionError::CompilerError(err)
26 }
27}
28
29impl From<ExecutionError> for ScriptExecutionError {
30 fn from(err: ExecutionError) -> Self {
31 ScriptExecutionError::ExecutionError(err)
32 }
33}
34
35impl Display for ScriptExecutionError {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 ScriptExecutionError::CompilerError(err) => {
39 write!(f, "Compiler Error: {}", err)
40 }
41 ScriptExecutionError::ExecutionError(err) => {
42 write!(f, "Execution Error: {}", err)
43 }
44 }
45 }
46}
47
48#[derive(Debug, Clone, Default)]
49pub struct RemoteExecutionContext {
50 pub compile_scope: CompilationScope,
51 pub endpoint: Endpoint,
52 pub context_id: Option<OutgoingContextId>,
53}
54
55impl RemoteExecutionContext {
56 pub fn new(endpoint: impl Into<Endpoint>, once: bool) -> Self {
58 RemoteExecutionContext {
59 compile_scope: CompilationScope::new(once),
60 endpoint: endpoint.into(),
61 context_id: None,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Default)]
67pub struct LocalExecutionContext {
68 compile_scope: CompilationScope,
69 runtime_execution_context: Rc<RefCell<RuntimeExecutionContext>>,
70 execution_options: ExecutionOptions,
71 verbose: bool,
72}
73
74impl LocalExecutionContext {
75 pub fn new(once: bool) -> Self {
76 LocalExecutionContext {
77 compile_scope: CompilationScope::new(once),
78 runtime_execution_context: Rc::new(RefCell::new(
79 RuntimeExecutionContext::default(),
80 )),
81 execution_options: ExecutionOptions::default(),
82 verbose: false,
83 }
84 }
85
86 pub fn debug(once: bool) -> Self {
88 LocalExecutionContext {
89 compile_scope: CompilationScope::new(once),
90 execution_options: ExecutionOptions { verbose: true },
91 verbose: true,
92 ..Default::default()
93 }
94 }
95
96 pub fn debug_with_runtime_internal(
97 runtime_internal: Rc<RuntimeInternal>,
98 once: bool,
99 ) -> Self {
100 LocalExecutionContext {
101 compile_scope: CompilationScope::new(once),
102 runtime_execution_context: Rc::new(RefCell::new(
103 RuntimeExecutionContext::new(runtime_internal),
104 )),
105 execution_options: ExecutionOptions { verbose: true },
106 verbose: true,
107 }
108 }
109
110 pub fn new_with_runtime_internal(
111 runtime_internal: Rc<RuntimeInternal>,
112 once: bool,
113 ) -> Self {
114 LocalExecutionContext {
115 compile_scope: CompilationScope::new(once),
116 runtime_execution_context: Rc::new(RefCell::new(
117 RuntimeExecutionContext::new(runtime_internal),
118 )),
119 ..Default::default()
120 }
121 }
122
123 pub fn set_runtime_internal(
124 &mut self,
125 runtime_internal: Rc<RuntimeInternal>,
126 ) {
127 self.runtime_execution_context
128 .borrow_mut()
129 .set_runtime_internal(runtime_internal);
130 }
131
132 pub fn memory_dump(&self) -> MemoryDump {
134 self.runtime_execution_context.borrow().memory_dump()
135 }
136}
137
138#[derive(Debug, Clone)]
142pub enum ExecutionContext {
143 Local(LocalExecutionContext),
144 Remote(RemoteExecutionContext),
145}
146
147impl ExecutionContext {
148 pub fn local_once() -> Self {
150 ExecutionContext::Local(LocalExecutionContext::new(true))
151 }
152
153 pub fn local() -> Self {
155 ExecutionContext::Local(LocalExecutionContext::new(false))
156 }
157
158 pub fn local_with_runtime_internal(
160 runtime_internal: Rc<RuntimeInternal>,
161 once: bool,
162 ) -> Self {
163 ExecutionContext::Local(
164 LocalExecutionContext::new_with_runtime_internal(
165 runtime_internal,
166 once,
167 ),
168 )
169 }
170
171 pub fn local_debug(once: bool) -> Self {
174 ExecutionContext::Local(LocalExecutionContext::debug(once))
175 }
176
177 pub fn local_debug_with_runtime_internal(
179 runtime_internal: Rc<RuntimeInternal>,
180 once: bool,
181 ) -> Self {
182 ExecutionContext::Local(
183 LocalExecutionContext::debug_with_runtime_internal(
184 runtime_internal,
185 once,
186 ),
187 )
188 }
189
190 pub fn remote_once(endpoint: impl Into<Endpoint>) -> Self {
191 ExecutionContext::Remote(RemoteExecutionContext::new(endpoint, true))
192 }
193
194 pub fn remote(endpoint: impl Into<Endpoint>) -> Self {
195 ExecutionContext::Remote(RemoteExecutionContext::new(endpoint, false))
196 }
197
198 fn compile_scope(&self) -> &CompilationScope {
199 match self {
200 ExecutionContext::Local(LocalExecutionContext {
201 compile_scope,
202 ..
203 }) => compile_scope,
204 ExecutionContext::Remote(RemoteExecutionContext {
205 compile_scope,
206 ..
207 }) => compile_scope,
208 }
209 }
210
211 fn set_compile_scope(&mut self, new_compile_scope: CompilationScope) {
212 match self {
213 ExecutionContext::Local(LocalExecutionContext {
214 compile_scope,
215 ..
216 }) => *compile_scope = new_compile_scope,
217 ExecutionContext::Remote(RemoteExecutionContext {
218 compile_scope,
219 ..
220 }) => *compile_scope = new_compile_scope,
221 }
222 }
223
224 pub fn compile(
226 &mut self,
227 script: &str,
228 inserted_values: &[ValueContainer],
229 ) -> Result<Vec<u8>, CompilerError> {
230 let compile_scope = self.compile_scope();
231 let res = compile_template(
233 script,
234 inserted_values,
235 CompileOptions::new_with_scope(compile_scope.clone()),
236 );
237 match res {
238 Ok((bytes, compile_scope)) => {
239 self.set_compile_scope(compile_scope);
240 Ok(bytes)
241 }
242 Err(err) => Err(err),
243 }
244 }
245
246 fn print_dxb_debug(&self, dxb: &[u8]) -> Result<(), ExecutionError> {
247 println!(
248 "\x1b[32m[Compiled Bytecode] {}",
249 dxb.iter()
250 .map(|b| format!("{b:02x}"))
251 .collect::<Vec<_>>()
252 .join(", ")
253 );
254
255 let decompiled = decompile_body(dxb, DecompileOptions::colorized());
256 if let Err(e) = decompiled {
257 println!("\x1b[31m[Decompiler Error] {e}\x1b[0m");
258 } else {
259 let decompiled = decompiled?;
260 println!("[Decompiled]: {decompiled}");
261 }
262
263 Ok(())
264 }
265
266 fn get_local_execution_input<'a>(
267 &'a mut self,
268 dxb: &'a [u8],
269 end_execution: bool,
270 ) -> Result<ExecutionInput<'a>, ExecutionError> {
271 let (local_execution_context, execution_options, verbose) = match &self
272 {
273 ExecutionContext::Local(LocalExecutionContext {
274 runtime_execution_context: local_execution_context,
275 execution_options,
276 verbose,
277 ..
278 }) => (local_execution_context, execution_options, *verbose),
279 ExecutionContext::Remote(_) => {
281 panic!("Remote execution requires a Runtime");
282 }
283 };
284
285 if verbose {
287 self.print_dxb_debug(dxb)?;
288 }
289
290 local_execution_context.borrow_mut().reset_index();
291 Ok(ExecutionInput {
292 context: (*local_execution_context).clone(),
294 options: (*execution_options).clone(),
295 dxb_body: dxb,
296 end_execution,
297 })
298 }
299
300 pub fn execute_dxb_sync(
302 &mut self,
303 dxb: &[u8],
304 end_execution: bool,
305 ) -> Result<Option<ValueContainer>, ExecutionError> {
306 let execution_input =
307 self.get_local_execution_input(dxb, end_execution)?;
308 execute_dxb_sync(execution_input)
309 }
310
311 pub fn execute_sync(
313 &mut self,
314 script: &str,
315 inserted_values: &[ValueContainer],
316 ) -> Result<Option<ValueContainer>, ScriptExecutionError> {
317 let dxb = self.compile(script, inserted_values)?;
318 self.execute_dxb_sync(&dxb, true)
319 .map_err(ScriptExecutionError::from)
320 }
321
322 pub async fn execute_dxb(
323 &mut self,
324 dxb: &[u8],
325 end_execution: bool,
326 ) -> Result<Option<ValueContainer>, ExecutionError> {
327 match self {
328 ExecutionContext::Local { .. } => {
329 let execution_input =
330 self.get_local_execution_input(dxb, end_execution)?;
331 execute_dxb(execution_input).await
332 }
333 ExecutionContext::Remote { .. } => {
335 panic!("Remote execution requires a Runtime");
336 }
337 }
338 }
339
340 pub async fn execute(
341 &mut self,
342 script: &str,
343 inserted_values: &[ValueContainer],
344 ) -> Result<Option<ValueContainer>, ScriptExecutionError> {
345 let dxb = self.compile(script, inserted_values)?;
346 self.execute_dxb(&dxb, true)
347 .await
348 .map_err(ScriptExecutionError::from)
349 }
350
351 pub fn memory_dump(&self) -> Option<MemoryDump> {
353 match self {
354 ExecutionContext::Local(local_context) => {
355 Some(local_context.memory_dump())
356 }
357 ExecutionContext::Remote(_) => None,
359 }
360 }
361}