1use crate::{
2 global::protocol_structures::instructions::*,
3 libs::core::{CoreLibPointerId, get_core_lib_value},
4 runtime::{
5 RuntimeInternal,
6 execution::{
7 context::{ExecutionMode, RemoteExecutionContext},
8 execution_loop::interrupts::{
9 ExternalExecutionInterrupt, InterruptResult,
10 },
11 },
12 },
13 traits::apply::Apply,
14 values::{pointer::PointerAddress, value_container::ValueContainer},
15};
16
17use crate::prelude::*;
18use core::{result::Result, unreachable};
19pub use errors::*;
20pub use execution_input::{ExecutionInput, ExecutionOptions};
21pub use memory_dump::*;
22
23pub mod context;
24mod errors;
25mod execution_input;
26pub mod execution_loop;
27pub mod macros;
28mod memory_dump;
29
30#[cfg(all(test, feature = "std"))]
31mod test_remote_execution;
32
33pub fn execute_dxb_sync(
34 input: ExecutionInput,
35) -> Result<Option<ValueContainer>, ExecutionError> {
36 let runtime_internal = input.runtime.clone();
37 let (interrupt_provider, execution_loop) = input.execution_loop();
38
39 for output in execution_loop {
40 match output? {
41 ExternalExecutionInterrupt::Result(result) => return Ok(result),
42 ExternalExecutionInterrupt::ResolvePointer(address) => {
43 interrupt_provider.provide_result(
44 InterruptResult::ResolvedValue(get_pointer_value(
45 &runtime_internal,
46 address,
47 )?),
48 )
49 }
50 ExternalExecutionInterrupt::ResolveLocalPointer(address) => {
51 interrupt_provider.provide_result(
53 InterruptResult::ResolvedValue(get_local_pointer_value(
54 &runtime_internal,
55 address,
56 )?),
57 );
58 }
59 ExternalExecutionInterrupt::ResolveInternalPointer(address) => {
60 interrupt_provider.provide_result(
61 InterruptResult::ResolvedValue(Some(
62 get_internal_pointer_value(&runtime_internal, address)?,
63 )),
64 );
65 }
66 ExternalExecutionInterrupt::Apply(callee, args) => {
67 let res = handle_apply(&callee, &args)?;
68 interrupt_provider
69 .provide_result(InterruptResult::ResolvedValue(res));
70 }
71 _ => return Err(ExecutionError::RequiresAsyncExecution),
72 }
73 }
74
75 Err(ExecutionError::RequiresAsyncExecution)
76}
77
78pub async fn execute_dxb(
79 input: ExecutionInput<'_>,
80) -> Result<Option<ValueContainer>, ExecutionError> {
81 let runtime_internal = input.runtime.clone();
82 let (interrupt_provider, execution_loop) = input.execution_loop();
83
84 for output in execution_loop {
85 match output? {
86 ExternalExecutionInterrupt::Result(result) => return Ok(result),
87 ExternalExecutionInterrupt::ResolvePointer(address) => {
88 interrupt_provider.provide_result(
89 InterruptResult::ResolvedValue(get_pointer_value(
90 &runtime_internal,
91 address,
92 )?),
93 );
94 }
95 ExternalExecutionInterrupt::ResolveLocalPointer(address) => {
96 interrupt_provider.provide_result(
98 InterruptResult::ResolvedValue(get_local_pointer_value(
99 &runtime_internal,
100 address,
101 )?),
102 );
103 }
104 ExternalExecutionInterrupt::ResolveInternalPointer(address) => {
105 interrupt_provider.provide_result(
106 InterruptResult::ResolvedValue(Some(
107 get_internal_pointer_value(&runtime_internal, address)?,
108 )),
109 );
110 }
111 ExternalExecutionInterrupt::RemoteExecution(receivers, body) => {
112 if let Some(runtime) = &runtime_internal {
113 let receiver_endpoint = receivers
116 .to_value()
117 .borrow()
118 .cast_to_endpoint()
119 .unwrap();
120 let mut remote_execution_context =
121 RemoteExecutionContext::new(
122 receiver_endpoint,
123 ExecutionMode::Static,
124 );
125 let res = RuntimeInternal::execute_remote(
126 runtime.clone(),
127 &mut remote_execution_context,
128 body,
129 )
130 .await?;
131 interrupt_provider
132 .provide_result(InterruptResult::ResolvedValue(res));
133 } else {
134 return Err(ExecutionError::RequiresRuntime);
135 }
136 }
137 ExternalExecutionInterrupt::Apply(callee, args) => {
138 let res = handle_apply(&callee, &args)?;
139 interrupt_provider
140 .provide_result(InterruptResult::ResolvedValue(res));
141 }
142 }
143 }
144
145 unreachable!("Execution loop should always return a result");
146}
147
148fn handle_apply(
149 callee: &ValueContainer,
150 args: &[ValueContainer],
151) -> Result<Option<ValueContainer>, ExecutionError> {
152 Ok(if args.len() == 1 {
155 callee.apply_single(&args[0])?
156 } else {
157 callee.apply(args)?
158 })
159}
160
161fn get_pointer_value(
162 runtime_internal: &Option<Rc<RuntimeInternal>>,
163 address: RawFullPointerAddress,
164) -> Result<Option<ValueContainer>, ExecutionError> {
165 if let Some(runtime) = &runtime_internal {
166 let memory = runtime.memory.borrow();
167 let resolved_address =
168 memory.get_pointer_address_from_raw_full_address(address);
169 Ok(memory
171 .get_reference(&resolved_address)
172 .map(|r| ValueContainer::Reference(r.clone())))
173 } else {
174 Err(ExecutionError::RequiresRuntime)
175 }
176}
177
178fn get_internal_pointer_value(
179 runtime_internal: &Option<Rc<RuntimeInternal>>,
180 address: RawInternalPointerAddress,
181) -> Result<ValueContainer, ExecutionError> {
182 if let Some(runtime_internal) = runtime_internal
184 && let Ok(core_lib_id) =
185 get_internal_pointer_value_from_memory(runtime_internal, &address)
186 {
187 return Ok(core_lib_id);
188 }
189
190 let core_lib_id =
191 CoreLibPointerId::try_from(&PointerAddress::Internal(address.id));
192 core_lib_id
193 .map_err(|_| ExecutionError::ReferenceNotFound)
194 .map(|id| {
195 get_core_lib_value(id).ok_or(ExecutionError::ReferenceNotFound)
196 })?
197}
198
199fn get_internal_pointer_value_from_memory(
200 runtime_internal: &Rc<RuntimeInternal>,
201 address: &RawInternalPointerAddress,
202) -> Result<ValueContainer, ExecutionError> {
203 let pointer_address = PointerAddress::Internal(address.id);
204 let memory = runtime_internal.memory.borrow();
205 if let Some(reference) = memory.get_reference(&pointer_address) {
206 Ok(ValueContainer::Reference(reference.clone()))
207 } else {
208 Err(ExecutionError::ReferenceNotFound)
209 }
210}
211
212fn get_local_pointer_value(
213 runtime_internal: &Option<Rc<RuntimeInternal>>,
214 address: RawLocalPointerAddress,
215) -> Result<Option<ValueContainer>, ExecutionError> {
216 if let Some(runtime) = &runtime_internal {
217 Ok(runtime
219 .memory
220 .borrow()
221 .get_reference(&PointerAddress::Local(address.id))
222 .map(|r| ValueContainer::Reference(r.clone())))
223 } else {
224 Err(ExecutionError::RequiresRuntime)
225 }
226}
227
228#[cfg(test)]
229#[cfg(feature = "compiler")]
230mod tests {
231 use core::assert_matches;
232
233 use super::*;
234 use crate::{
235 assert_structural_eq, assert_value_eq,
236 compiler::{CompileOptions, compile_script, scope::CompilationScope},
237 datex_list,
238 global::instruction_codes::InstructionCode,
239 libs::core::get_core_lib_type_reference,
240 references::reference::Reference,
241 runtime::{
242 RuntimeConfig, RuntimeRunner,
243 execution::{
244 context::{ExecutionContext, LocalExecutionContext},
245 execution_input::ExecutionOptions,
246 },
247 },
248 traits::{structural_eq::StructuralEq, value_eq::ValueEq},
249 values::{
250 core_value::CoreValue,
251 core_values::{
252 decimal::Decimal,
253 integer::{Integer, typed_integer::TypedInteger},
254 list::List,
255 map::Map,
256 },
257 },
258 };
259 use log::{debug, info};
260
261 fn execute_datex_script_debug(
262 datex_script: &str,
263 ) -> Option<ValueContainer> {
264 let (dxb, _) =
265 compile_script(datex_script, CompileOptions::default()).unwrap();
266 let context =
267 ExecutionInput::new(&dxb, ExecutionOptions { verbose: true }, None);
268 execute_dxb_sync(context).unwrap_or_else(|err| {
269 core::panic!("Execution failed: {err}");
270 })
271 }
272
273 fn execute_datex_script_debug_unbounded(
274 datex_script_parts: impl Iterator<Item = &'static str>,
275 ) -> impl Iterator<Item = Result<Option<ValueContainer>, ExecutionError>>
276 {
277 gen move {
278 let datex_script_parts = datex_script_parts.collect::<Vec<_>>();
279 let mut execution_context = ExecutionContext::Local(
280 LocalExecutionContext::new(ExecutionMode::unbounded()),
281 );
282 let mut compilation_scope =
283 CompilationScope::new(ExecutionMode::unbounded());
284
285 let len = datex_script_parts.len();
286 for (index, script_part) in
287 datex_script_parts.into_iter().enumerate()
288 {
289 if index == len - 1 {
291 compilation_scope.mark_as_last_execution();
292 }
293
294 let (dxb, new_compilation_scope) = compile_script(
295 script_part,
296 CompileOptions::new_with_scope(compilation_scope),
297 )
298 .unwrap();
299 compilation_scope = new_compilation_scope;
300 yield execution_context.execute_dxb_sync(&dxb)
301 }
302 }
303 }
304
305 fn assert_unbounded_input_matches_output(
306 input: Vec<&'static str>,
307 expected_output: Vec<Option<ValueContainer>>,
308 ) {
309 let input = input.into_iter();
310 let expected_output = expected_output.into_iter();
311 for (result, expected) in
312 execute_datex_script_debug_unbounded(input.into_iter())
313 .zip(expected_output.into_iter())
314 {
315 let result = result.unwrap();
316 assert_eq!(result, expected);
317 }
318 }
319
320 fn execute_datex_script_debug_with_error(
321 datex_script: &str,
322 ) -> Result<Option<ValueContainer>, ExecutionError> {
323 let (dxb, _) =
324 compile_script(datex_script, CompileOptions::default()).unwrap();
325 let context =
326 ExecutionInput::new(&dxb, ExecutionOptions { verbose: true }, None);
327 execute_dxb_sync(context)
328 }
329
330 fn execute_datex_script_debug_with_result(
331 datex_script: &str,
332 ) -> ValueContainer {
333 execute_datex_script_debug(datex_script).unwrap()
334 }
335
336 fn execute_dxb_debug(
337 dxb_body: &[u8],
338 ) -> Result<Option<ValueContainer>, ExecutionError> {
339 let context = ExecutionInput::new(
340 dxb_body,
341 ExecutionOptions { verbose: true },
342 None,
343 );
344 execute_dxb_sync(context)
345 }
346
347 async fn execute_datex_script_with_runtime(
348 config: RuntimeConfig,
349 datex_script: &str,
350 ) -> Result<Option<ValueContainer>, ExecutionError> {
351 RuntimeRunner::new(config)
352 .run(async |runtime| {
353 let (dxb, _) =
354 compile_script(datex_script, CompileOptions::default())
355 .unwrap();
356 let context = ExecutionInput::new(
357 &dxb,
358 ExecutionOptions { verbose: true },
359 Some(runtime.internal),
360 );
361 execute_dxb(context).await
362 })
363 .await
364 }
365
366 #[test]
367 fn empty_script() {
368 assert_eq!(execute_datex_script_debug(""), None);
369 }
370
371 #[test]
372 fn empty_script_semicolon() {
373 assert_eq!(execute_datex_script_debug(";;;"), None);
374 }
375
376 #[test]
377 fn single_value() {
378 assert_eq!(
379 execute_datex_script_debug_with_result("42"),
380 Integer::from(42i8).into()
381 );
382 }
383
384 #[test]
385 fn single_value_semicolon() {
386 assert_eq!(execute_datex_script_debug("42;"), None)
387 }
388
389 #[test]
390 fn is() {
391 let result = execute_datex_script_debug_with_result("1 is 1");
392 assert_eq!(result, false.into());
393 assert_structural_eq!(result, ValueContainer::from(false));
394 }
395
396 #[test]
397 fn equality() {
398 let result = execute_datex_script_debug_with_result("1 == 1");
399 assert_eq!(result, true.into());
400 assert_structural_eq!(result, ValueContainer::from(true));
401
402 let result = execute_datex_script_debug_with_result("1 == 2");
403 assert_eq!(result, false.into());
404 assert_structural_eq!(result, ValueContainer::from(false));
405
406 let result = execute_datex_script_debug_with_result("1 != 2");
407 assert_eq!(result, true.into());
408 assert_structural_eq!(result, ValueContainer::from(true));
409
410 let result = execute_datex_script_debug_with_result("1 != 1");
411 assert_eq!(result, false.into());
412 assert_structural_eq!(result, ValueContainer::from(false));
413 let result = execute_datex_script_debug_with_result("1 === 1");
414 assert_eq!(result, true.into());
415
416 assert_structural_eq!(result, ValueContainer::from(true));
417 let result = execute_datex_script_debug_with_result("1 !== 2");
418 assert_eq!(result, true.into());
419 assert_structural_eq!(result, ValueContainer::from(true));
420
421 let result = execute_datex_script_debug_with_result("1 !== 1");
422 assert_eq!(result, false.into());
423 assert_structural_eq!(result, ValueContainer::from(false));
424 }
425
426 #[test]
427 fn single_value_scope() {
428 let result = execute_datex_script_debug_with_result("(42)");
429 assert_eq!(result, Integer::from(42i8).into());
430 assert_structural_eq!(result, ValueContainer::from(42_u128));
431 }
432
433 #[test]
434 fn add() {
435 let result = execute_datex_script_debug_with_result("1 + 2");
436 assert_eq!(result, Integer::from(3i8).into());
437 assert_structural_eq!(result, ValueContainer::from(3i8));
438 }
439
440 #[test]
441 fn nested_scope() {
442 let result = execute_datex_script_debug_with_result("1 + (2 + 3)");
443 assert_eq!(result, Integer::from(6i8).into());
444 }
445
446 #[test]
447 fn empty_list() {
448 let result = execute_datex_script_debug_with_result("[]");
449 let list: List = result.to_value().borrow().cast_to_list().unwrap();
450 assert_eq!(list.len(), 0);
451 assert_eq!(result, Vec::<ValueContainer>::new().into());
452 assert_eq!(result, ValueContainer::from(Vec::<ValueContainer>::new()));
453 }
454
455 #[test]
456 fn list() {
457 let result = execute_datex_script_debug_with_result("[1, 2, 3]");
458 let list: List = result.to_value().borrow().cast_to_list().unwrap();
459 let expected = datex_list![
460 Integer::from(1i8),
461 Integer::from(2i8),
462 Integer::from(3i8)
463 ];
464 assert_eq!(list.len(), 3);
465 assert_eq!(result, expected.into());
466 assert_ne!(result, ValueContainer::from(vec![1, 2, 3]));
467 assert_structural_eq!(result, ValueContainer::from(vec![1, 2, 3]));
468 }
469
470 #[test]
471 fn list_with_nested_scope() {
472 let result = execute_datex_script_debug_with_result("[1, (2 + 3), 4]");
473 let expected = datex_list![
474 Integer::from(1i8),
475 Integer::from(5i8),
476 Integer::from(4i8)
477 ];
478
479 assert_eq!(result, expected.into());
480 assert_ne!(result, ValueContainer::from(vec![1_u8, 5_u8, 4_u8]));
481 assert_structural_eq!(
482 result,
483 ValueContainer::from(vec![1_u8, 5_u8, 4_u8])
484 );
485 }
486
487 #[test]
488 fn boolean() {
489 let result = execute_datex_script_debug_with_result("true");
490 assert_eq!(result, true.into());
491 assert_structural_eq!(result, ValueContainer::from(true));
492
493 let result = execute_datex_script_debug_with_result("false");
494 assert_eq!(result, false.into());
495 assert_structural_eq!(result, ValueContainer::from(false));
496 }
497
498 #[test]
499 fn decimal() {
500 let result = execute_datex_script_debug_with_result("1.5");
501 assert_eq!(result, Decimal::from_string("1.5").unwrap().into());
502 assert_structural_eq!(result, ValueContainer::from(1.5));
503 }
504
505 #[test]
506 fn decimal_and_integer() {
507 let result = execute_datex_script_debug_with_result("-2341324.0");
508 assert_eq!(result, Decimal::from_string("-2341324").unwrap().into());
509 assert!(!result.structural_eq(&ValueContainer::from(-2341324)));
510 }
511
512 #[test]
513 fn integer() {
514 let result = execute_datex_script_debug_with_result("2");
515 assert_eq!(result, Integer::from(2).into());
516 assert_ne!(result, 2_u8.into());
517 assert_structural_eq!(result, ValueContainer::from(2_i8));
518 }
519
520 #[test]
521 fn typed_integer() {
522 let result = execute_datex_script_debug_with_result("-2i16");
523 assert_eq!(result, TypedInteger::from(-2i16).into());
524 assert_structural_eq!(result, ValueContainer::from(-2_i16));
525
526 let result = execute_datex_script_debug_with_result("2i32");
527 assert_eq!(result, TypedInteger::from(2i32).into());
528 assert_structural_eq!(result, ValueContainer::from(2_i32));
529
530 let result = execute_datex_script_debug_with_result("-2i64");
531 assert_eq!(result, TypedInteger::from(-2i64).into());
532 assert_structural_eq!(result, ValueContainer::from(-2_i64));
533
534 let result = execute_datex_script_debug_with_result("2i128");
535 assert_eq!(result, TypedInteger::from(2i128).into());
536 assert_structural_eq!(result, ValueContainer::from(2_i128));
537
538 let result = execute_datex_script_debug_with_result("2u8");
539 assert_eq!(result, TypedInteger::from(2_u8).into());
540 assert_structural_eq!(result, ValueContainer::from(2_u8));
541
542 let result = execute_datex_script_debug_with_result("2u16");
543 assert_eq!(result, TypedInteger::from(2_u16).into());
544 assert_structural_eq!(result, ValueContainer::from(2_u16));
545
546 let result = execute_datex_script_debug_with_result("2u32");
547 assert_eq!(result, TypedInteger::from(2_u32).into());
548 assert_structural_eq!(result, ValueContainer::from(2_u32));
549
550 let result = execute_datex_script_debug_with_result("2u64");
551 assert_eq!(result, TypedInteger::from(2_u64).into());
552 assert_structural_eq!(result, ValueContainer::from(2_u64));
553
554 let result = execute_datex_script_debug_with_result("2u128");
555 assert_eq!(result, TypedInteger::from(2_u128).into());
556 assert_structural_eq!(result, ValueContainer::from(2_u128));
557
558 let result = execute_datex_script_debug_with_result("2ibig");
559 assert_eq!(result, TypedInteger::IBig(Integer::from(2)).into());
560 assert_structural_eq!(result, ValueContainer::from(2));
561 }
562
563 #[test]
564 fn null() {
565 let result = execute_datex_script_debug_with_result("null");
566 assert_eq!(result, ValueContainer::from(CoreValue::Null));
567 assert_eq!(result, CoreValue::Null.into());
568 assert_structural_eq!(result, ValueContainer::from(CoreValue::Null));
569 }
570
571 #[test]
572 fn map() {
573 let result =
574 execute_datex_script_debug_with_result("{x: 1, y: 2, z: 42}");
575 let map: CoreValue = result.clone().to_value().borrow().clone().inner;
576 let map: Map = map.try_into().unwrap();
577
578 assert_eq!(map.to_string(), "{\"x\": 1, \"y\": 2, \"z\": 42}");
580 assert_eq!(map.size(), 3);
581
582 info!("Map: {:?}", map);
583
584 assert_eq!(map.get("x"), Ok(&Integer::from(1).into()));
586 assert_eq!(map.get("y"), Ok(&Integer::from(2).into()));
587 assert_eq!(map.get("z"), Ok(&Integer::from(42).into()));
588
589 let expected_se: Map = Map::from(vec![
591 ("x".to_string(), 1.into()),
592 ("y".to_string(), 2.into()),
593 ("z".to_string(), 42.into()),
594 ]);
595 assert_structural_eq!(map, expected_se);
596
597 let expected_strict: Map = Map::from(vec![
599 ("x".to_string(), Integer::from(1).into()),
600 ("y".to_string(), Integer::from(2).into()),
601 ("z".to_string(), Integer::from(42).into()),
602 ]);
603 debug!("Expected map: {expected_strict}");
604 debug!("Map result: {map}");
605 }
608
609 #[test]
610 fn empty_map() {
611 let result = execute_datex_script_debug_with_result("{}");
612 let map: CoreValue = result.clone().to_value().borrow().clone().inner;
613 let map: Map = map.try_into().unwrap();
614
615 assert_eq!(map.to_string(), "{}");
617 assert_eq!(map.size(), 0);
618
619 info!("Map: {:?}", map);
620 }
621
622 #[test]
623 fn statements() {
624 let result = execute_datex_script_debug_with_result("1; 2; 3");
625 assert_eq!(result, Integer::from(3).into());
626 }
627
628 #[test]
629 fn single_terminated_statement() {
630 let result = execute_datex_script_debug("1;");
631 assert_eq!(result, None);
632 }
633
634 #[test]
635 fn const_declaration() {
636 let result = execute_datex_script_debug_with_result("const x = 42; x");
637 assert_eq!(result, Integer::from(42).into());
638 }
639
640 #[test]
641 fn const_declaration_with_addition() {
642 let result =
643 execute_datex_script_debug_with_result("const x = 1 + 2; x");
644 assert_eq!(result, Integer::from(3).into());
645 }
646
647 #[test]
648 fn deref() {
649 let result =
650 execute_datex_script_debug_with_result("const x = &42; *x");
651 assert_eq!(result, ValueContainer::from(Integer::from(42)));
652 }
653
654 #[test]
655 fn ref_assignment() {
656 let result =
657 execute_datex_script_debug_with_result("const x = &mut 42; x");
658 assert_matches!(result, ValueContainer::Reference(..));
659 assert_value_eq!(result, ValueContainer::from(Integer::from(42)));
660 }
661
662 #[test]
663 fn ref_add_assignment() {
664 let result = execute_datex_script_debug_with_result(
665 "const x = &mut 42; *x += 1",
666 );
667 assert_value_eq!(result, ValueContainer::from(Integer::from(43)));
668
669 let result = execute_datex_script_debug_with_result(
670 "const x = &mut 42; *x += 1; x",
671 );
672
673 assert_matches!(result, ValueContainer::Reference(..));
674 assert_value_eq!(result, ValueContainer::from(Integer::from(43)));
675 }
676
677 #[test]
678 fn ref_sub_assignment() {
679 let result = execute_datex_script_debug_with_result(
680 "const x = &mut 42; *x -= 1",
681 );
682 assert_value_eq!(result, ValueContainer::from(Integer::from(41)));
683
684 let result = execute_datex_script_debug_with_result(
685 "const x = &mut 42; *x -= 1; x",
686 );
687
688 assert_value_eq!(result, ValueContainer::from(Integer::from(41)));
692 }
693
694 #[test]
695 fn endpoint_slot_no_runtime() {
696 let result = execute_datex_script_debug_with_error("#endpoint");
697 assert_matches!(result.unwrap_err(), ExecutionError::RequiresRuntime);
698 }
699
700 #[test]
701 fn env_slot_no_runtime() {
702 let result = execute_datex_script_debug_with_error("#env");
703 assert_matches!(result.unwrap_err(), ExecutionError::RequiresRuntime);
704 }
705
706 #[tokio::test]
707 async fn env_slot() {
708 let res = execute_datex_script_with_runtime(
709 RuntimeConfig {
710 env: Some(HashMap::from([(
711 "TEST_ENV_VAR".to_string(),
712 "test_value".to_string(),
713 )])),
714 ..Default::default()
715 },
716 "#env",
717 )
718 .await
719 .unwrap();
720 assert!(res.is_some());
721 let env = res.unwrap().to_value().borrow().cast_to_map().unwrap();
722 assert_eq!(env.get("TEST_ENV_VAR"), Ok(&"test_value".into()));
723 }
724
725 #[test]
726 fn shebang() {
727 let result = execute_datex_script_debug_with_result("#!datex\n42");
728 assert_eq!(result, Integer::from(42).into());
729 }
730
731 #[test]
732 fn single_line_comment() {
733 let result =
734 execute_datex_script_debug_with_result("// this is a comment\n42");
735 assert_eq!(result, Integer::from(42).into());
736
737 let result = execute_datex_script_debug_with_result(
738 "// this is a comment\n// another comment\n42",
739 );
740 assert_eq!(result, Integer::from(42).into());
741 }
742
743 #[test]
744 fn multi_line_comment() {
745 let result = execute_datex_script_debug_with_result(
746 "/* this is a comment */\n42",
747 );
748 assert_eq!(result, Integer::from(42).into());
749
750 let result = execute_datex_script_debug_with_result(
751 "/* this is a comment\n with multiple lines */\n42",
752 );
753 assert_eq!(result, Integer::from(42).into());
754
755 let result = execute_datex_script_debug_with_result("[1, /* 2, */ 3]");
756 let expected = datex_list![Integer::from(1), Integer::from(3)];
757 assert_eq!(result, expected.into());
758 }
759
760 #[test]
761 fn continuous_execution() {
762 assert_unbounded_input_matches_output(
763 vec!["1", "2"],
764 vec![Some(Integer::from(1).into()), Some(Integer::from(2).into())],
765 )
766 }
767
768 #[test]
769 fn continuous_execution_multiple_external_interrupts() {
770 assert_unbounded_input_matches_output(
771 vec!["1", "integer", "integer"],
772 vec![
773 Some(Integer::from(1).into()),
774 Some(ValueContainer::Reference(Reference::TypeReference(
775 get_core_lib_type_reference(CoreLibPointerId::Integer(
776 None,
777 )),
778 ))),
779 Some(ValueContainer::Reference(Reference::TypeReference(
780 get_core_lib_type_reference(CoreLibPointerId::Integer(
781 None,
782 )),
783 ))),
784 ],
785 )
786 }
787}