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