1use super::stack::{Scope, ScopeStack};
2
3use crate::ast::assignment_operation::AssignmentOperator;
4use crate::ast::binary_operation::{
5 ArithmeticOperator, BinaryOperator, BitwiseOperator, LogicalOperator,
6};
7use crate::ast::comparison_operation::ComparisonOperator;
8use crate::ast::unary_operation::{
9 ArithmeticUnaryOperator, BitwiseUnaryOperator, LogicalUnaryOperator,
10 ReferenceUnaryOperator, UnaryOperator,
11};
12use crate::compiler::compile_value;
13use crate::compiler::error::CompilerError;
14use crate::global::instruction_codes::InstructionCode;
15use crate::global::protocol_structures::instructions::*;
16use crate::global::slots::InternalSlot;
17use crate::libs::core::{CoreLibPointerId, get_core_lib_type_reference};
18use crate::network::com_hub::ResponseError;
19use crate::parser::body;
20use crate::parser::body::DXBParserError;
21use crate::references::reference::{AssignmentError, ReferenceCreationError};
22use crate::runtime::RuntimeInternal;
23use crate::runtime::execution_context::RemoteExecutionContext;
24use crate::traits::apply::Apply;
25use crate::traits::identity::Identity;
26use crate::traits::structural_eq::StructuralEq;
27use crate::traits::value_eq::ValueEq;
28use crate::types::error::IllegalTypeError;
29use crate::types::type_container::TypeContainer;
30use crate::utils::buffers::append_u32;
31use crate::values::core_value::CoreValue;
32use crate::values::core_values::decimal::Decimal;
33use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
34use crate::values::core_values::integer::Integer;
35use crate::values::core_values::list::List;
36use crate::values::core_values::map::Map;
37use crate::values::core_values::r#type::Type;
38use crate::values::pointer::PointerAddress;
39use crate::values::value::Value;
40use crate::values::value_container::{ValueContainer, ValueError};
41use datex_core::decompiler::{DecompileOptions, decompile_value};
42use datex_core::references::reference::Reference;
43use itertools::Itertools;
44use log::info;
45use num_enum::TryFromPrimitive;
46use std::cell::RefCell;
47use std::collections::HashMap;
48use std::fmt::Display;
49use std::rc::Rc;
50
51#[derive(Debug, Clone, Default)]
52pub struct ExecutionOptions {
53 pub verbose: bool,
54}
55
56#[derive(Debug, Clone)]
57pub struct ExecutionInput<'a> {
58 pub options: ExecutionOptions,
59 pub dxb_body: &'a [u8],
60 pub end_execution: bool,
61 pub context: Rc<RefCell<RuntimeExecutionContext>>,
62}
63
64pub struct MemoryDump {
83 pub slots: Vec<(u32, Option<ValueContainer>)>,
84}
85
86impl Display for MemoryDump {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 for (address, value) in &self.slots {
89 match value {
90 Some(vc) => {
91 let decompiled =
92 decompile_value(vc, DecompileOptions::colorized());
93 writeln!(f, "#{address}: {decompiled}")?
94 }
95 None => writeln!(f, "#{address}: <uninitialized>")?,
96 }
97 }
98 if self.slots.is_empty() {
99 writeln!(f, "<no slots allocated>")?;
100 }
101 Ok(())
102 }
103}
104
105impl Default for ExecutionInput<'_> {
106 fn default() -> Self {
107 Self {
108 options: ExecutionOptions::default(),
109 dxb_body: &[],
110 context: Rc::new(RefCell::new(RuntimeExecutionContext::default())),
111 end_execution: true,
112 }
113 }
114}
115
116impl<'a> ExecutionInput<'a> {
117 pub fn new_with_dxb_and_options(
118 dxb_body: &'a [u8],
119 options: ExecutionOptions,
120 ) -> Self {
121 Self {
122 options,
123 dxb_body,
124 context: Rc::new(RefCell::new(RuntimeExecutionContext::default())),
125 end_execution: true,
126 }
127 }
128}
129
130#[derive(Debug, Clone, Default)]
131pub struct RuntimeExecutionContext {
132 index: usize,
133 scope_stack: ScopeStack,
134 slots: RefCell<HashMap<u32, Option<ValueContainer>>>,
135 pop_next_scope: bool,
137 runtime_internal: Option<Rc<RuntimeInternal>>,
138}
139
140impl RuntimeExecutionContext {
141 pub fn new(runtime_internal: Rc<RuntimeInternal>) -> Self {
142 Self {
143 runtime_internal: Some(runtime_internal),
144 ..Default::default()
145 }
146 }
147
148 pub fn reset_index(&mut self) {
149 self.index = 0;
150 }
151
152 pub fn runtime_internal(&self) -> &Option<Rc<RuntimeInternal>> {
153 &self.runtime_internal
154 }
155
156 pub fn set_runtime_internal(
157 &mut self,
158 runtime_internal: Rc<RuntimeInternal>,
159 ) {
160 self.runtime_internal = Some(runtime_internal);
161 }
162
163 fn allocate_slot(&self, address: u32, value: Option<ValueContainer>) {
165 self.slots.borrow_mut().insert(address, value);
166 }
167
168 fn drop_slot(
171 &self,
172 address: u32,
173 ) -> Result<Option<ValueContainer>, ExecutionError> {
174 self.slots
175 .borrow_mut()
176 .remove(&address)
177 .ok_or(())
178 .map_err(|_| ExecutionError::SlotNotAllocated(address))
179 }
180
181 fn set_slot_value(
184 &self,
185 address: u32,
186 value: ValueContainer,
187 ) -> Result<Option<ValueContainer>, ExecutionError> {
188 self.slots
189 .borrow_mut()
190 .insert(address, Some(value))
191 .ok_or(())
192 .map_err(|_| ExecutionError::SlotNotAllocated(address))
193 }
194
195 fn get_slot_value(
198 &self,
199 address: u32,
200 ) -> Result<Option<ValueContainer>, ExecutionError> {
201 self.slots
202 .borrow_mut()
203 .get(&address)
204 .cloned()
205 .ok_or(())
206 .map_err(|_| ExecutionError::SlotNotAllocated(address))
207 }
208
209 pub fn memory_dump(&self) -> MemoryDump {
211 MemoryDump {
212 slots: self
213 .slots
214 .borrow()
215 .iter()
216 .map(|(k, v)| (*k, v.clone()))
217 .sorted_by_key(|(k, _)| *k)
218 .collect(),
219 }
220 }
221}
222
223pub fn execute_dxb_sync(
224 input: ExecutionInput,
225) -> Result<Option<ValueContainer>, ExecutionError> {
226 let interrupt_provider = Rc::new(RefCell::new(None));
227 let runtime_internal =
228 input.context.borrow_mut().runtime_internal().clone();
229
230 for output in execute_loop(input, interrupt_provider.clone()) {
231 match output? {
232 ExecutionStep::Return(result) => return Ok(result),
233 ExecutionStep::ResolvePointer(address) => {
234 *interrupt_provider.borrow_mut() =
235 Some(InterruptProvider::Result(get_pointer_value(
236 &runtime_internal,
237 address,
238 )?));
239 }
240 ExecutionStep::ResolveLocalPointer(address) => {
241 *interrupt_provider.borrow_mut() =
243 Some(InterruptProvider::Result(get_local_pointer_value(
244 &runtime_internal,
245 address,
246 )?));
247 }
248 ExecutionStep::ResolveInternalPointer(address) => {
249 *interrupt_provider.borrow_mut() =
250 Some(InterruptProvider::Result(
251 get_internal_pointer_value(address)?,
252 ));
253 }
254 ExecutionStep::GetInternalSlot(slot) => {
255 *interrupt_provider.borrow_mut() =
256 Some(InterruptProvider::Result(get_internal_slot_value(
257 &runtime_internal,
258 slot,
259 )?));
260 }
261 _ => return Err(ExecutionError::RequiresAsyncExecution),
262 }
263 }
264
265 Err(ExecutionError::RequiresAsyncExecution)
266}
267
268pub async fn execute_dxb(
269 input: ExecutionInput<'_>,
270) -> Result<Option<ValueContainer>, ExecutionError> {
271 let interrupt_provider = Rc::new(RefCell::new(None));
272 let runtime_internal =
273 input.context.borrow_mut().runtime_internal().clone();
274
275 for output in execute_loop(input, interrupt_provider.clone()) {
276 match output? {
277 ExecutionStep::Return(result) => return Ok(result),
278 ExecutionStep::ResolvePointer(address) => {
279 *interrupt_provider.borrow_mut() =
280 Some(InterruptProvider::Result(get_pointer_value(
281 &runtime_internal,
282 address,
283 )?));
284 }
285 ExecutionStep::ResolveLocalPointer(address) => {
286 *interrupt_provider.borrow_mut() =
288 Some(InterruptProvider::Result(get_local_pointer_value(
289 &runtime_internal,
290 address,
291 )?));
292 }
293 ExecutionStep::ResolveInternalPointer(address) => {
294 *interrupt_provider.borrow_mut() =
295 Some(InterruptProvider::Result(
296 get_internal_pointer_value(address)?,
297 ));
298 }
299 ExecutionStep::RemoteExecution(receivers, body) => {
300 if let Some(runtime) = &runtime_internal {
301 let receiver_endpoint = receivers
304 .to_value()
305 .borrow()
306 .cast_to_endpoint()
307 .unwrap();
308 let mut remote_execution_context =
309 RemoteExecutionContext::new(receiver_endpoint, true);
310 let res = RuntimeInternal::execute_remote(
311 runtime.clone(),
312 &mut remote_execution_context,
313 body,
314 )
315 .await?;
316 *interrupt_provider.borrow_mut() =
317 Some(InterruptProvider::Result(res));
318 } else {
319 return Err(ExecutionError::RequiresRuntime);
320 }
321 }
322 ExecutionStep::GetInternalSlot(slot) => {
323 *interrupt_provider.borrow_mut() =
324 Some(InterruptProvider::Result(get_internal_slot_value(
325 &runtime_internal,
326 slot,
327 )?));
328 }
329 _ => todo!("#99 Undescribed by author."),
330 }
331 }
332
333 unreachable!("Execution loop should always return a result");
334}
335
336fn get_internal_slot_value(
337 runtime_internal: &Option<Rc<RuntimeInternal>>,
338 slot: u32,
339) -> Result<Option<ValueContainer>, ExecutionError> {
340 if let Some(runtime) = &runtime_internal {
341 let slot = InternalSlot::try_from_primitive(slot)
343 .map_err(|_| ExecutionError::SlotNotAllocated(slot))?;
344 let res = match slot {
345 InternalSlot::ENDPOINT => {
346 Some(ValueContainer::from(runtime.endpoint.clone()))
347 }
348 };
349 Ok(res)
350 } else {
351 Err(ExecutionError::RequiresRuntime)
352 }
353}
354
355fn get_pointer_value(
356 runtime_internal: &Option<Rc<RuntimeInternal>>,
357 address: RawFullPointerAddress,
358) -> Result<Option<ValueContainer>, ExecutionError> {
359 if let Some(runtime) = &runtime_internal {
360 let memory = runtime.memory.borrow();
361 let resolved_address =
362 memory.get_pointer_address_from_raw_full_address(address);
363 Ok(memory
365 .get_reference(&resolved_address)
366 .map(|r| ValueContainer::Reference(r.clone())))
367 } else {
368 Err(ExecutionError::RequiresRuntime)
369 }
370}
371
372fn get_internal_pointer_value(
373 address: RawInternalPointerAddress,
374) -> Result<Option<ValueContainer>, ExecutionError> {
375 let core_lib_id =
376 CoreLibPointerId::try_from(&PointerAddress::Internal(address.id));
377 core_lib_id
378 .map_err(|_| ExecutionError::ReferenceNotFound)
379 .map(|id| {
380 Some(ValueContainer::Reference(Reference::TypeReference(
381 get_core_lib_type_reference(id),
382 )))
383 })
384}
385
386fn get_local_pointer_value(
387 runtime_internal: &Option<Rc<RuntimeInternal>>,
388 address: RawLocalPointerAddress,
389) -> Result<Option<ValueContainer>, ExecutionError> {
390 if let Some(runtime) = &runtime_internal {
391 Ok(runtime
393 .memory
394 .borrow()
395 .get_reference(&PointerAddress::Local(address.id))
396 .map(|r| ValueContainer::Reference(r.clone())))
397 } else {
398 Err(ExecutionError::RequiresRuntime)
399 }
400}
401
402#[derive(Debug, Clone, PartialEq, Eq)]
403pub enum InvalidProgramError {
404 InvalidScopeClose,
405 InvalidKeyValuePair,
406 UnterminatedSequence,
408 MissingRemoteExecutionReceiver,
409}
410
411impl Display for InvalidProgramError {
412 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413 match self {
414 InvalidProgramError::InvalidScopeClose => {
415 write!(f, "Invalid scope close")
416 }
417 InvalidProgramError::InvalidKeyValuePair => {
418 write!(f, "Invalid key-value pair")
419 }
420 InvalidProgramError::UnterminatedSequence => {
421 write!(f, "Unterminated sequence")
422 }
423 InvalidProgramError::MissingRemoteExecutionReceiver => {
424 write!(f, "Missing remote execution receiver")
425 }
426 }
427 }
428}
429
430#[derive(Debug)]
431pub enum ExecutionError {
432 DXBParserError(DXBParserError),
433 ValueError(ValueError),
434 InvalidProgram(InvalidProgramError),
435 Unknown,
436 NotImplemented(String),
437 SlotNotAllocated(u32),
438 SlotNotInitialized(u32),
439 RequiresAsyncExecution,
440 RequiresRuntime,
441 ResponseError(ResponseError),
442 CompilerError(CompilerError),
443 IllegalTypeError(IllegalTypeError),
444 ReferenceNotFound,
445 DerefOfNonReference,
446 InvalidTypeCast,
447 AssignmentError(AssignmentError),
448 ReferenceFromValueContainerError(ReferenceCreationError),
449}
450impl From<ReferenceCreationError> for ExecutionError {
451 fn from(error: ReferenceCreationError) -> Self {
452 ExecutionError::ReferenceFromValueContainerError(error)
453 }
454}
455
456impl From<DXBParserError> for ExecutionError {
457 fn from(error: DXBParserError) -> Self {
458 ExecutionError::DXBParserError(error)
459 }
460}
461
462impl From<ValueError> for ExecutionError {
463 fn from(error: ValueError) -> Self {
464 ExecutionError::ValueError(error)
465 }
466}
467
468impl From<IllegalTypeError> for ExecutionError {
469 fn from(error: IllegalTypeError) -> Self {
470 ExecutionError::IllegalTypeError(error)
471 }
472}
473
474impl From<InvalidProgramError> for ExecutionError {
475 fn from(error: InvalidProgramError) -> Self {
476 ExecutionError::InvalidProgram(error)
477 }
478}
479
480impl From<ResponseError> for ExecutionError {
481 fn from(error: ResponseError) -> Self {
482 ExecutionError::ResponseError(error)
483 }
484}
485
486impl From<CompilerError> for ExecutionError {
487 fn from(error: CompilerError) -> Self {
488 ExecutionError::CompilerError(error)
489 }
490}
491
492impl From<AssignmentError> for ExecutionError {
493 fn from(error: AssignmentError) -> Self {
494 ExecutionError::AssignmentError(error)
495 }
496}
497
498impl Display for ExecutionError {
499 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
500 match self {
501 ExecutionError::ReferenceFromValueContainerError(err) => {
502 write!(f, "Reference from value container error: {err}")
503 }
504 ExecutionError::ReferenceNotFound => {
505 write!(f, "Reference not found")
506 }
507 ExecutionError::CompilerError(err) => {
508 write!(f, "Compiler error: {err}")
509 }
510 ExecutionError::DXBParserError(err) => {
511 write!(f, "Parser error: {err}")
512 }
513 ExecutionError::Unknown => write!(f, "Unknown execution error"),
514 ExecutionError::ValueError(err) => write!(f, "Value error: {err}"),
515 ExecutionError::InvalidProgram(err) => {
516 write!(f, "Invalid program error: {err}")
517 }
518 ExecutionError::NotImplemented(msg) => {
519 write!(f, "Not implemented: {msg}")
520 }
521 ExecutionError::SlotNotAllocated(address) => {
522 write!(
523 f,
524 "Tried to access unallocated slot at address {address}"
525 )
526 }
527 ExecutionError::SlotNotInitialized(address) => {
528 write!(
529 f,
530 "Tried to access uninitialized slot at address {address}"
531 )
532 }
533 ExecutionError::RequiresAsyncExecution => {
534 write!(f, "Program must be executed asynchronously")
535 }
536 ExecutionError::RequiresRuntime => {
537 write!(f, "Execution requires a runtime to be set")
538 }
539 ExecutionError::ResponseError(err) => {
540 write!(f, "Response error: {err}")
541 }
542 ExecutionError::IllegalTypeError(err) => {
543 write!(f, "Illegal type: {err}")
544 }
545 ExecutionError::DerefOfNonReference => {
546 write!(f, "Tried to dereference a non-reference value")
547 }
548 ExecutionError::AssignmentError(err) => {
549 write!(f, "Assignment error: {err}")
550 }
551 ExecutionError::InvalidTypeCast => {
552 write!(f, "Invalid type cast")
553 }
554 }
555 }
556}
557
558#[derive(Debug)]
559pub enum ExecutionStep {
560 InternalReturn(Option<ValueContainer>),
561 InternalTypeReturn(Option<TypeContainer>),
562 Return(Option<ValueContainer>),
563 ResolvePointer(RawFullPointerAddress),
564 ResolveLocalPointer(RawLocalPointerAddress),
565 ResolveInternalPointer(RawInternalPointerAddress),
566 GetInternalSlot(u32),
567 RemoteExecution(ValueContainer, Vec<u8>),
568 Pause,
569}
570
571#[derive(Debug)]
572pub enum InterruptProvider {
573 Result(Option<ValueContainer>),
574}
575
576#[macro_export]
577macro_rules! interrupt {
578 ($input:expr, $arg:expr) => {{
579 yield Ok($arg);
580 $input.take().unwrap()
581 }};
582}
583
584#[macro_export]
585macro_rules! interrupt_with_result {
586 ($input:expr, $arg:expr) => {{
587 yield Ok($arg);
588 let res = $input.take().unwrap();
589 match res {
590 InterruptProvider::Result(value) => value,
591 }
592 }};
593}
594
595#[macro_export]
596macro_rules! yield_unwrap {
597 ($e:expr) => {{
598 let res = $e;
599 if let Ok(res) = res {
600 res
601 } else {
602 return yield Err(res.unwrap_err().into());
603 }
604 }};
605}
606
607pub fn execute_loop(
608 input: ExecutionInput,
609 interrupt_provider: Rc<RefCell<Option<InterruptProvider>>>,
610) -> impl Iterator<Item = Result<ExecutionStep, ExecutionError>> {
611 gen move {
612 let dxb_body = input.dxb_body;
613 let end_execution = input.end_execution;
614 let context = input.context;
615
616 let instruction_iterator = body::iterate_instructions(dxb_body);
617
618 for instruction in instruction_iterator {
619 let instruction = yield_unwrap!(instruction);
621 if input.options.verbose {
622 info!("[Exec]: {instruction}");
623 }
624
625 let mut result_value = None;
627
628 for output in get_result_value_from_instruction(
629 context.clone(),
630 instruction,
631 interrupt_provider.clone(),
632 ) {
633 match yield_unwrap!(output) {
634 ExecutionStep::InternalReturn(result) => {
635 result_value = result;
636 }
637 ExecutionStep::InternalTypeReturn(result) => {
638 result_value = result.map(ValueContainer::from);
639 }
640 step => {
641 *interrupt_provider.borrow_mut() =
642 Some(interrupt!(interrupt_provider, step));
643 }
644 }
645 }
646
647 loop {
650 let mut context_mut = context.borrow_mut();
651 context_mut.pop_next_scope = false;
652 if let Some(value) = result_value {
653 let res = handle_value(&mut context_mut, value);
654 drop(context_mut);
655 yield_unwrap!(res);
656 } else {
657 drop(context_mut);
658 }
659
660 let mut context_mut = context.borrow_mut();
661
662 if context_mut.pop_next_scope {
663 let res = context_mut.scope_stack.pop();
664 drop(context_mut);
665 result_value = yield_unwrap!(res);
666 } else {
667 break;
668 }
669 }
670 }
671
672 if end_execution {
673 let res = match context.borrow_mut().scope_stack.pop_active_value()
684 {
685 None => ExecutionStep::Return(None),
686 Some(val) => ExecutionStep::Return(Some(val)),
687 };
688 yield Ok(res);
689 } else {
690 yield Ok(ExecutionStep::Pause);
691 }
692 }
693}
694
695#[inline]
696fn get_result_value_from_instruction(
697 context: Rc<RefCell<RuntimeExecutionContext>>,
698 instruction: Instruction,
699 interrupt_provider: Rc<RefCell<Option<InterruptProvider>>>,
700) -> impl Iterator<Item = Result<ExecutionStep, ExecutionError>> {
701 gen move {
702 yield Ok(ExecutionStep::InternalReturn(match instruction {
703 Instruction::True => Some(true.into()),
705 Instruction::False => Some(false.into()),
706
707 Instruction::Int8(integer) => Some(Integer::from(integer.0).into()),
709 Instruction::Int16(integer) => {
710 Some(Integer::from(integer.0).into())
711 }
712 Instruction::Int32(integer) => {
713 Some(Integer::from(integer.0).into())
714 }
715 Instruction::Int64(integer) => {
716 Some(Integer::from(integer.0).into())
717 }
718 Instruction::Int128(integer) => {
719 Some(Integer::from(integer.0).into())
720 }
721
722 Instruction::UInt8(integer) => {
724 Some(Integer::from(integer.0).into())
725 }
726 Instruction::UInt16(integer) => {
727 Some(Integer::from(integer.0).into())
728 }
729 Instruction::UInt32(integer) => {
730 Some(Integer::from(integer.0).into())
731 }
732 Instruction::UInt64(integer) => {
733 Some(Integer::from(integer.0).into())
734 }
735 Instruction::UInt128(integer) => {
736 Some(Integer::from(integer.0).into())
737 }
738
739 Instruction::BigInteger(IntegerData(integer)) => {
741 Some(integer.into())
742 }
743
744 Instruction::DecimalF32(Float32Data(f32)) => {
746 Some(TypedDecimal::from(f32).into())
747 }
748 Instruction::DecimalF64(Float64Data(f64)) => {
749 Some(TypedDecimal::from(f64).into())
750 }
751
752 Instruction::DecimalAsInt16(FloatAsInt16Data(i16)) => {
754 Some(Decimal::from(i16 as f32).into())
755 }
756 Instruction::DecimalAsInt32(FloatAsInt32Data(i32)) => {
757 Some(Decimal::from(i32 as f32).into())
758 }
759 Instruction::Decimal(DecimalData(big_decimal)) => {
760 Some(big_decimal.into())
761 }
762
763 Instruction::Endpoint(endpoint) => Some(endpoint.into()),
765
766 Instruction::Null => Some(Value::null().into()),
768
769 Instruction::ShortText(ShortTextData(text)) => Some(text.into()),
771 Instruction::Text(TextData(text)) => Some(text.into()),
772
773 Instruction::Add
775 | Instruction::Subtract
776 | Instruction::Multiply
777 | Instruction::Divide => {
778 context.borrow_mut().scope_stack.create_scope(
779 Scope::BinaryOperation {
780 operator: BinaryOperator::from(instruction),
781 },
782 );
783 None
784 }
785
786 Instruction::UnaryPlus => {
788 context.borrow_mut().scope_stack.create_scope(
789 Scope::UnaryOperation {
790 operator: UnaryOperator::Arithmetic(
791 ArithmeticUnaryOperator::Plus,
792 ),
793 },
794 );
795 None
796 }
797 Instruction::UnaryMinus => {
798 context.borrow_mut().scope_stack.create_scope(
799 Scope::UnaryOperation {
800 operator: UnaryOperator::Arithmetic(
801 ArithmeticUnaryOperator::Minus,
802 ),
803 },
804 );
805 None
806 }
807 Instruction::BitwiseNot => {
808 context.borrow_mut().scope_stack.create_scope(
809 Scope::UnaryOperation {
810 operator: UnaryOperator::Bitwise(
811 BitwiseUnaryOperator::Negation,
812 ),
813 },
814 );
815 None
816 }
817
818 Instruction::Is
820 | Instruction::Matches
821 | Instruction::StructuralEqual
822 | Instruction::Equal
823 | Instruction::NotStructuralEqual
824 | Instruction::NotEqual => {
825 context.borrow_mut().scope_stack.create_scope(
826 Scope::ComparisonOperation {
827 operator: ComparisonOperator::from(instruction),
828 },
829 );
830 None
831 }
832
833 Instruction::ExecutionBlock(block) => {
834 let mut buffer = Vec::with_capacity(256);
837 for (addr, local_slot) in
838 block.injected_slots.into_iter().enumerate()
839 {
840 buffer.push(InstructionCode::ALLOCATE_SLOT as u8);
841 append_u32(&mut buffer, addr as u32);
842
843 if let Some(vc) = yield_unwrap!(
844 context.borrow().get_slot_value(local_slot).map_err(
845 |_| ExecutionError::SlotNotAllocated(local_slot),
846 )
847 ) {
848 buffer.extend_from_slice(&yield_unwrap!(
849 compile_value(&vc)
850 ));
851 } else {
852 return yield Err(ExecutionError::SlotNotInitialized(
853 local_slot,
854 ));
855 }
856 }
857 buffer.extend_from_slice(&block.body);
858
859 let maybe_receivers =
860 context.borrow_mut().scope_stack.pop_active_value();
861
862 if let Some(receivers) = maybe_receivers {
863 interrupt_with_result!(
864 interrupt_provider,
865 ExecutionStep::RemoteExecution(receivers, buffer)
866 )
867 } else {
868 yield Err(ExecutionError::InvalidProgram(
870 InvalidProgramError::MissingRemoteExecutionReceiver,
871 ));
872 None
873 }
874 }
875
876 Instruction::CloseAndStore => {
877 let _ = context.borrow_mut().scope_stack.pop_active_value();
878 None
879 }
880
881 Instruction::Apply(ApplyData { arg_count }) => {
882 context.borrow_mut().scope_stack.create_scope(Scope::Apply {
883 arg_count,
884 args: vec![],
885 });
886 None
887 }
888
889 Instruction::ScopeStart => {
890 context
891 .borrow_mut()
892 .scope_stack
893 .create_scope(Scope::Default);
894 None
895 }
896
897 Instruction::ListStart => {
898 context
899 .borrow_mut()
900 .scope_stack
901 .create_scope_with_active_value(
902 Scope::Collection,
903 List::default().into(),
904 );
905 None
906 }
907
908 Instruction::MapStart => {
909 context
910 .borrow_mut()
911 .scope_stack
912 .create_scope_with_active_value(
913 Scope::Collection,
914 Map::default().into(),
915 );
916 None
917 }
918
919 Instruction::KeyValueShortText(ShortTextData(key)) => {
920 context
921 .borrow_mut()
922 .scope_stack
923 .create_scope_with_active_value(
924 Scope::KeyValuePair,
925 key.into(),
926 );
927 None
928 }
929
930 Instruction::KeyValueDynamic => {
931 context
932 .borrow_mut()
933 .scope_stack
934 .create_scope(Scope::KeyValuePair);
935 None
936 }
937
938 Instruction::ScopeEnd => {
939 yield_unwrap!(context.borrow_mut().scope_stack.pop())
941 }
942
943 Instruction::AllocateSlot(SlotAddress(address)) => {
945 let mut context = context.borrow_mut();
946 context.allocate_slot(address, None);
947 context
948 .scope_stack
949 .create_scope(Scope::SlotAssignment { address });
950 None
951 }
952 Instruction::GetSlot(SlotAddress(address)) => {
953 if address >= 0xffffff00 {
955 interrupt_with_result!(
956 interrupt_provider,
957 ExecutionStep::GetInternalSlot(address)
958 )
959 }
960 else {
962 let res = context.borrow_mut().get_slot_value(address);
963 let slot_value = yield_unwrap!(res);
965 if slot_value.is_none() {
966 return yield Err(ExecutionError::SlotNotInitialized(
967 address,
968 ));
969 }
970 slot_value
971 }
972 }
973 Instruction::SetSlot(SlotAddress(address)) => {
974 context
975 .borrow_mut()
976 .scope_stack
977 .create_scope(Scope::SlotAssignment { address });
978 None
979 }
980
981 Instruction::AssignToReference(operator) => {
982 context.borrow_mut().scope_stack.create_scope(
983 Scope::AssignToReference {
984 reference: None,
985 operator,
986 },
987 );
988 None
989 }
990
991 Instruction::Deref => {
992 context.borrow_mut().scope_stack.create_scope(Scope::Deref);
993 None
994 }
995
996 Instruction::GetRef(address) => {
997 interrupt_with_result!(
998 interrupt_provider,
999 ExecutionStep::ResolvePointer(address)
1000 )
1001 }
1002
1003 Instruction::GetLocalRef(address) => {
1004 interrupt_with_result!(
1005 interrupt_provider,
1006 ExecutionStep::ResolveLocalPointer(address)
1007 )
1008 }
1009
1010 Instruction::GetInternalRef(address) => {
1011 interrupt_with_result!(
1012 interrupt_provider,
1013 ExecutionStep::ResolveInternalPointer(address)
1014 )
1015 }
1016
1017 Instruction::AddAssign(SlotAddress(address)) => {
1018 context.borrow_mut().scope_stack.create_scope(
1019 Scope::AssignmentOperation {
1020 address,
1021 operator: AssignmentOperator::AddAssign,
1022 },
1023 );
1024 None
1025 }
1026
1027 Instruction::SubtractAssign(SlotAddress(address)) => {
1028 context.borrow_mut().scope_stack.create_scope(
1029 Scope::AssignmentOperation {
1030 address,
1031 operator: AssignmentOperator::SubtractAssign,
1032 },
1033 );
1034 None
1035 }
1036
1037 Instruction::CreateRef => {
1039 context.borrow_mut().scope_stack.create_scope(
1040 Scope::UnaryOperation {
1041 operator: UnaryOperator::Reference(
1042 ReferenceUnaryOperator::CreateRef,
1043 ),
1044 },
1045 );
1046 None
1047 }
1048
1049 Instruction::CreateRefMut => {
1050 context.borrow_mut().scope_stack.create_scope(
1051 Scope::UnaryOperation {
1052 operator: UnaryOperator::Reference(
1053 ReferenceUnaryOperator::CreateRefMut,
1054 ),
1055 },
1056 );
1057 None
1058 }
1059
1060 Instruction::CreateRefFinal => {
1061 context.borrow_mut().scope_stack.create_scope(
1062 Scope::UnaryOperation {
1063 operator: UnaryOperator::Reference(
1064 ReferenceUnaryOperator::CreateRefFinal,
1065 ),
1066 },
1067 );
1068 None
1069 }
1070
1071 Instruction::RemoteExecution => {
1073 context
1074 .borrow_mut()
1075 .scope_stack
1076 .create_scope(Scope::RemoteExecution);
1077 None
1078 }
1079
1080 Instruction::DropSlot(SlotAddress(address)) => {
1081 let res = context.borrow_mut().drop_slot(address);
1083 yield_unwrap!(res);
1084 None
1085 }
1086
1087 Instruction::TypeInstructions(instructions) => {
1088 for output in
1089 iterate_type_instructions(interrupt_provider, instructions)
1090 {
1091 yield output;
1093 }
1094 return;
1095 }
1096
1097 Instruction::TypeExpression(instructions) => {
1099 for output in
1100 iterate_type_instructions(interrupt_provider, instructions)
1101 {
1102 yield output;
1103 }
1104 return;
1105 }
1106
1107 i => {
1108 return yield Err(ExecutionError::NotImplemented(
1109 format!("Instruction {i}").to_string(),
1110 ));
1111 }
1112 }))
1113 }
1114}
1115
1116fn iterate_type_instructions(
1117 interrupt_provider: Rc<RefCell<Option<InterruptProvider>>>,
1118 instructions: Vec<TypeInstruction>,
1119) -> impl Iterator<Item = Result<ExecutionStep, ExecutionError>> {
1120 gen move {
1121 for instruction in instructions {
1122 match instruction {
1123 TypeInstruction::ListStart => {
1125 interrupt_with_result!(
1126 interrupt_provider,
1127 ExecutionStep::Pause
1128 );
1129 }
1130 TypeInstruction::LiteralInteger(integer) => {
1131 yield Ok(ExecutionStep::InternalTypeReturn(Some(
1132 TypeContainer::Type(Type::structural(integer.0)),
1133 )));
1134 }
1135 _ => todo!("#405 Undescribed by author."),
1136 }
1137 }
1138 }
1139}
1140
1141fn handle_value(
1143 context: &mut RuntimeExecutionContext,
1144 value_container: ValueContainer,
1145) -> Result<(), ExecutionError> {
1146 let scope_container = context.scope_stack.get_current_scope_mut();
1147
1148 let result_value = match &mut scope_container.scope {
1149 Scope::KeyValuePair => {
1150 let key = &scope_container.active_value;
1151 match key {
1152 None => Some(value_container),
1154
1155 Some(_) => {
1157 let key = context.scope_stack.pop()?.unwrap();
1158 match context.scope_stack.get_active_value_mut() {
1159 Some(collector) => {
1160 handle_key_value_pair(
1162 collector,
1163 key,
1164 value_container,
1165 )?;
1166 }
1167 None => unreachable!(
1168 "Expected active value for key-value pair, but got None"
1169 ),
1170 }
1171 None
1172 }
1173 }
1174 }
1175
1176 Scope::SlotAssignment { address } => {
1177 let address = *address;
1179 context.set_slot_value(address, value_container.clone())?;
1180 Some(value_container)
1181 }
1182
1183 Scope::Deref => {
1184 if let ValueContainer::Reference(reference) = value_container {
1186 Some(reference.value_container())
1187 } else {
1188 return Err(ExecutionError::DerefOfNonReference);
1189 }
1190 }
1191
1192 Scope::AssignToReference {
1193 operator,
1194 reference,
1195 } => {
1196 if (reference.is_none()) {
1197 if let ValueContainer::Reference(new_reference) =
1199 value_container
1200 {
1201 reference.replace(new_reference);
1202 None
1203 } else {
1204 return Err(ExecutionError::DerefOfNonReference);
1205 }
1206 } else {
1207 let operator = *operator;
1208 let reference = reference.as_ref().unwrap();
1209 let lhs = reference.value_container();
1210 let res = handle_assignment_operation(
1211 lhs,
1212 value_container,
1213 operator,
1214 )?;
1215 reference.set_value_container(res)?;
1216 Some(ValueContainer::Reference(reference.clone()))
1217 }
1218 }
1219
1220 Scope::Apply { args, arg_count } => {
1221 if scope_container.active_value.is_none() {
1223 if *arg_count == 0 {
1225 context.pop_next_scope = true;
1226 handle_apply(&value_container, args)?
1227 }
1228 else {
1230 Some(value_container)
1231 }
1232 } else {
1233 let callee = scope_container.active_value.as_ref().unwrap();
1234 args.push(value_container);
1236
1237 if args.len() == *arg_count as usize {
1239 context.pop_next_scope = true;
1240 handle_apply(callee, args)?
1241 } else {
1242 Some(callee.clone())
1243 }
1244 }
1245 }
1246
1247 Scope::AssignmentOperation { operator, address } => {
1248 let operator = *operator;
1249 let address = *address;
1250 let lhs = if let Ok(Some(val)) = context.get_slot_value(address) {
1251 val
1252 } else {
1253 return Err(ExecutionError::SlotNotInitialized(address));
1254 };
1255 let res =
1256 handle_assignment_operation(lhs, value_container, operator)?;
1257 context.set_slot_value(address, res.clone())?;
1258 Some(res)
1259 }
1260
1261 Scope::UnaryOperation { operator } => {
1262 let operator = *operator;
1263 context.pop_next_scope = true;
1264 let result = handle_unary_operation(operator, value_container);
1265 if let Ok(val) = result {
1266 Some(val)
1267 } else {
1268 return Err(result.unwrap_err());
1270 }
1271 }
1272
1273 Scope::BinaryOperation { operator } => {
1274 let active_value = &scope_container.active_value;
1275 match active_value {
1276 Some(active_value_container) => {
1277 let res = handle_binary_operation(
1278 active_value_container,
1279 value_container,
1280 *operator,
1281 );
1282 if let Ok(val) = res {
1283 context.pop_next_scope = true;
1285 Some(val)
1286 } else {
1287 return Err(res.unwrap_err());
1289 }
1290 }
1291 None => Some(value_container),
1292 }
1293 }
1294
1295 Scope::ComparisonOperation { operator } => {
1296 let active_value = &scope_container.active_value;
1297 match active_value {
1298 Some(active_value_container) => {
1299 let res = handle_comparison_operation(
1300 active_value_container,
1301 value_container,
1302 *operator,
1303 );
1304 if let Ok(val) = res {
1305 context.pop_next_scope = true;
1307 Some(val)
1308 } else {
1309 return Err(res.unwrap_err());
1311 }
1312 }
1313 None => Some(value_container),
1314 }
1315 }
1316
1317 Scope::Collection => {
1318 let active_value = &mut scope_container.active_value;
1319 match active_value {
1320 Some(active_value_container) => {
1321 handle_collector(active_value_container, value_container);
1323 None
1324 }
1325 None => {
1326 unreachable!(
1327 "Expected active value for collection scope, but got None"
1328 );
1329 }
1330 }
1331 }
1332
1333 _ => Some(value_container),
1334 };
1335
1336 if let Some(result_value) = result_value {
1337 context.scope_stack.set_active_value_container(result_value);
1338 }
1339
1340 Ok(())
1341}
1342
1343fn handle_apply(
1344 callee: &ValueContainer,
1345 args: &[ValueContainer],
1346) -> Result<Option<ValueContainer>, ExecutionError> {
1347 Ok(if args.len() == 1 {
1350 callee.apply_single(&args[0])?
1351 } else {
1352 callee.apply(args)?
1353 })
1354}
1355
1356fn handle_collector(collector: &mut ValueContainer, value: ValueContainer) {
1357 match collector {
1358 ValueContainer::Value(Value {
1359 inner: CoreValue::List(list),
1360 ..
1361 }) => {
1362 list.push(value);
1364 }
1365 ValueContainer::Value(Value {
1366 inner: CoreValue::Map(map),
1367 ..
1368 }) => {
1369 panic!("append {:?}", value);
1371 }
1372 _ => {
1373 unreachable!("Unsupported collector for collection scope");
1374 }
1375 }
1376}
1377
1378fn handle_key_value_pair(
1379 active_container: &mut ValueContainer,
1380 key: ValueContainer,
1381 value: ValueContainer,
1382) -> Result<(), ExecutionError> {
1383 match active_container {
1385 ValueContainer::Value(Value {
1387 inner: CoreValue::Map(map),
1388 ..
1389 }) => {
1390 map.try_set(key, value)
1392 .expect("Failed to set key-value pair in map");
1393 }
1394 _ => {
1395 unreachable!(
1396 "Expected active value that can collect key value pairs, but got: {}",
1397 active_container
1398 );
1399 }
1400 }
1401
1402 Ok(())
1403}
1404
1405fn handle_unary_reference_operation(
1406 operator: ReferenceUnaryOperator,
1407 value_container: ValueContainer,
1408) -> Result<ValueContainer, ExecutionError> {
1409 Ok(match operator {
1410 ReferenceUnaryOperator::CreateRef => {
1411 ValueContainer::Reference(Reference::from(value_container))
1412 }
1413 ReferenceUnaryOperator::CreateRefFinal => ValueContainer::Reference(
1414 Reference::try_final_from(value_container)?,
1415 ),
1416 ReferenceUnaryOperator::CreateRefMut => {
1417 ValueContainer::Reference(Reference::try_mut_from(value_container)?)
1418 }
1419 ReferenceUnaryOperator::Deref => {
1420 if let ValueContainer::Reference(reference) = value_container {
1421 reference.value_container()
1422 } else {
1423 return Err(ExecutionError::DerefOfNonReference);
1424 }
1425 }
1426 })
1427}
1428fn handle_unary_logical_operation(
1429 operator: LogicalUnaryOperator,
1430 value_container: ValueContainer,
1431) -> Result<ValueContainer, ExecutionError> {
1432 unimplemented!(
1433 "Logical unary operations are not implemented yet: {operator:?}"
1434 )
1435}
1436fn handle_unary_arithmetic_operation(
1437 operator: ArithmeticUnaryOperator,
1438 value_container: ValueContainer,
1439) -> Result<ValueContainer, ExecutionError> {
1440 match operator {
1441 ArithmeticUnaryOperator::Minus => Ok((-value_container)?),
1442 ArithmeticUnaryOperator::Plus => Ok(value_container),
1443 _ => unimplemented!(
1444 "Arithmetic unary operations are not implemented yet: {operator:?}"
1445 ),
1446 }
1447}
1448
1449fn handle_unary_operation(
1450 operator: UnaryOperator,
1451 value_container: ValueContainer,
1452) -> Result<ValueContainer, ExecutionError> {
1453 match operator {
1454 UnaryOperator::Reference(reference) => {
1455 handle_unary_reference_operation(reference, value_container)
1456 }
1457 UnaryOperator::Logical(logical) => {
1458 handle_unary_logical_operation(logical, value_container)
1459 }
1460 UnaryOperator::Arithmetic(arithmetic) => {
1461 handle_unary_arithmetic_operation(arithmetic, value_container)
1462 }
1463 _ => todo!("#102 Unary instruction not implemented: {operator:?}"),
1464 }
1465}
1466
1467fn handle_comparison_operation(
1468 active_value_container: &ValueContainer,
1469 value_container: ValueContainer,
1470 operator: ComparisonOperator,
1471) -> Result<ValueContainer, ExecutionError> {
1472 match operator {
1474 ComparisonOperator::StructuralEqual => {
1475 let val = active_value_container.structural_eq(&value_container);
1476 Ok(ValueContainer::from(val))
1477 }
1478 ComparisonOperator::Equal => {
1479 let val = active_value_container.value_eq(&value_container);
1480 Ok(ValueContainer::from(val))
1481 }
1482 ComparisonOperator::NotStructuralEqual => {
1483 let val = !active_value_container.structural_eq(&value_container);
1484 Ok(ValueContainer::from(val))
1485 }
1486 ComparisonOperator::NotEqual => {
1487 let val = !active_value_container.value_eq(&value_container);
1488 Ok(ValueContainer::from(val))
1489 }
1490 ComparisonOperator::Is => {
1491 let val = active_value_container.identical(&value_container);
1496 Ok(ValueContainer::from(val))
1497 }
1498 ComparisonOperator::Matches => {
1499 let v_type = value_container.actual_type(); let val = v_type.value_matches(active_value_container);
1502 Ok(ValueContainer::from(val))
1503 }
1504 _ => {
1505 unreachable!("Instruction {:?} is not a valid operation", operator);
1506 }
1507 }
1508}
1509
1510fn handle_assignment_operation(
1511 lhs: ValueContainer,
1512 rhs: ValueContainer,
1513 operator: AssignmentOperator,
1514) -> Result<ValueContainer, ExecutionError> {
1515 match operator {
1517 AssignmentOperator::AddAssign => Ok((lhs + rhs)?),
1518 AssignmentOperator::SubtractAssign => Ok((lhs - rhs)?),
1519 _ => {
1520 unreachable!("Instruction {:?} is not a valid operation", operator);
1521 }
1522 }
1523}
1524
1525fn handle_arithmetic_operation(
1526 active_value_container: &ValueContainer,
1527 value_container: ValueContainer,
1528 operator: ArithmeticOperator,
1529) -> Result<ValueContainer, ExecutionError> {
1530 match operator {
1532 ArithmeticOperator::Add => {
1533 Ok((active_value_container + &value_container)?)
1534 }
1535 ArithmeticOperator::Subtract => {
1536 Ok((active_value_container - &value_container)?)
1537 }
1538 _ => {
1545 todo!("#408 Implement arithmetic operation for {:?}", operator);
1546 }
1547 }
1548}
1549
1550fn handle_bitwise_operation(
1551 active_value_container: &ValueContainer,
1552 value_container: ValueContainer,
1553 operator: BitwiseOperator,
1554) -> Result<ValueContainer, ExecutionError> {
1555 {
1557 todo!("#409 Implement bitwise operation for {:?}", operator);
1558 }
1559}
1560
1561fn handle_logical_operation(
1562 active_value_container: &ValueContainer,
1563 value_container: ValueContainer,
1564 operator: LogicalOperator,
1565) -> Result<ValueContainer, ExecutionError> {
1566 {
1568 todo!("#410 Implement logical operation for {:?}", operator);
1569 }
1570}
1571
1572fn handle_binary_operation(
1573 active_value_container: &ValueContainer,
1574 value_container: ValueContainer,
1575 operator: BinaryOperator,
1576) -> Result<ValueContainer, ExecutionError> {
1577 match operator {
1578 BinaryOperator::Arithmetic(arith_op) => handle_arithmetic_operation(
1579 active_value_container,
1580 value_container,
1581 arith_op,
1582 ),
1583 BinaryOperator::Bitwise(bitwise_op) => handle_bitwise_operation(
1584 active_value_container,
1585 value_container,
1586 bitwise_op,
1587 ),
1588 BinaryOperator::Logical(logical_op) => handle_logical_operation(
1589 active_value_container,
1590 value_container,
1591 logical_op,
1592 ),
1593 BinaryOperator::VariantAccess => {
1594 todo!("#411 Implement variant access operation")
1595 }
1596 }
1597}
1598
1599#[cfg(test)]
1600mod tests {
1601 use std::assert_matches::assert_matches;
1602 use std::vec;
1603
1604 use super::*;
1605 use crate::compiler::{CompileOptions, compile_script};
1606 use crate::global::instruction_codes::InstructionCode;
1607 use crate::logger::init_logger_debug;
1608 use crate::traits::structural_eq::StructuralEq;
1609 use crate::{assert_structural_eq, assert_value_eq, datex_list};
1610 use datex_core::values::core_values::integer::typed_integer::TypedInteger;
1611 use log::debug;
1612
1613 fn execute_datex_script_debug(
1614 datex_script: &str,
1615 ) -> Option<ValueContainer> {
1616 let (dxb, _) =
1617 compile_script(datex_script, CompileOptions::default()).unwrap();
1618 let context = ExecutionInput::new_with_dxb_and_options(
1619 &dxb,
1620 ExecutionOptions { verbose: true },
1621 );
1622 execute_dxb_sync(context).unwrap_or_else(|err| {
1623 panic!("Execution failed: {err}");
1624 })
1625 }
1626
1627 fn execute_datex_script_debug_with_error(
1628 datex_script: &str,
1629 ) -> Result<Option<ValueContainer>, ExecutionError> {
1630 let (dxb, _) =
1631 compile_script(datex_script, CompileOptions::default()).unwrap();
1632 let context = ExecutionInput::new_with_dxb_and_options(
1633 &dxb,
1634 ExecutionOptions { verbose: true },
1635 );
1636 execute_dxb_sync(context)
1637 }
1638
1639 fn execute_datex_script_debug_with_result(
1640 datex_script: &str,
1641 ) -> ValueContainer {
1642 execute_datex_script_debug(datex_script).unwrap()
1643 }
1644
1645 fn execute_dxb_debug(
1646 dxb_body: &[u8],
1647 ) -> Result<Option<ValueContainer>, ExecutionError> {
1648 let context = ExecutionInput::new_with_dxb_and_options(
1649 dxb_body,
1650 ExecutionOptions { verbose: true },
1651 );
1652 execute_dxb_sync(context)
1653 }
1654
1655 #[test]
1656 fn empty_script() {
1657 assert_eq!(execute_datex_script_debug(""), None);
1658 }
1659
1660 #[test]
1661 fn empty_script_semicolon() {
1662 assert_eq!(execute_datex_script_debug(";;;"), None);
1663 }
1664
1665 #[test]
1666 fn single_value() {
1667 assert_eq!(
1668 execute_datex_script_debug_with_result("42"),
1669 Integer::from(42i8).into()
1670 );
1671 }
1672
1673 #[test]
1674 fn single_value_semicolon() {
1675 assert_eq!(execute_datex_script_debug("42;"), None)
1676 }
1677
1678 #[test]
1679 fn is() {
1680 let result = execute_datex_script_debug_with_result("1 is 1");
1681 assert_eq!(result, false.into());
1682 assert_structural_eq!(result, ValueContainer::from(false));
1683 }
1684
1685 #[test]
1686 fn equality() {
1687 let result = execute_datex_script_debug_with_result("1 == 1");
1688 assert_eq!(result, true.into());
1689 assert_structural_eq!(result, ValueContainer::from(true));
1690
1691 let result = execute_datex_script_debug_with_result("1 == 2");
1692 assert_eq!(result, false.into());
1693 assert_structural_eq!(result, ValueContainer::from(false));
1694
1695 let result = execute_datex_script_debug_with_result("1 != 2");
1696 assert_eq!(result, true.into());
1697 assert_structural_eq!(result, ValueContainer::from(true));
1698
1699 let result = execute_datex_script_debug_with_result("1 != 1");
1700 assert_eq!(result, false.into());
1701 assert_structural_eq!(result, ValueContainer::from(false));
1702 let result = execute_datex_script_debug_with_result("1 === 1");
1703 assert_eq!(result, true.into());
1704
1705 assert_structural_eq!(result, ValueContainer::from(true));
1706 let result = execute_datex_script_debug_with_result("1 !== 2");
1707 assert_eq!(result, true.into());
1708 assert_structural_eq!(result, ValueContainer::from(true));
1709
1710 let result = execute_datex_script_debug_with_result("1 !== 1");
1711 assert_eq!(result, false.into());
1712 assert_structural_eq!(result, ValueContainer::from(false));
1713 }
1714
1715 #[test]
1716 fn single_value_scope() {
1717 let result = execute_datex_script_debug_with_result("(42)");
1718 assert_eq!(result, Integer::from(42i8).into());
1719 assert_structural_eq!(result, ValueContainer::from(42_u128));
1720 }
1721
1722 #[test]
1723 fn add() {
1724 let result = execute_datex_script_debug_with_result("1 + 2");
1725 assert_eq!(result, Integer::from(3i8).into());
1726 assert_structural_eq!(result, ValueContainer::from(3i8));
1727 }
1728
1729 #[test]
1730 fn nested_scope() {
1731 let result = execute_datex_script_debug_with_result("1 + (2 + 3)");
1732 assert_eq!(result, Integer::from(6i8).into());
1733 }
1734
1735 #[test]
1736 fn invalid_scope_close() {
1737 let result = execute_dxb_debug(&[
1738 InstructionCode::SCOPE_START.into(),
1739 InstructionCode::SCOPE_END.into(),
1740 InstructionCode::SCOPE_END.into(),
1741 ]);
1742 assert!(matches!(
1743 result,
1744 Err(ExecutionError::InvalidProgram(
1745 InvalidProgramError::InvalidScopeClose
1746 ))
1747 ));
1748 }
1749
1750 #[test]
1751 fn empty_list() {
1752 let result = execute_datex_script_debug_with_result("[]");
1753 let list: List = result.to_value().borrow().cast_to_list().unwrap();
1754 assert_eq!(list.len(), 0);
1755 assert_eq!(result, Vec::<ValueContainer>::new().into());
1756 assert_eq!(result, ValueContainer::from(Vec::<ValueContainer>::new()));
1757 }
1758
1759 #[test]
1760 fn list() {
1761 let result = execute_datex_script_debug_with_result("[1, 2, 3]");
1762 let list: List = result.to_value().borrow().cast_to_list().unwrap();
1763 let expected = datex_list![
1764 Integer::from(1i8),
1765 Integer::from(2i8),
1766 Integer::from(3i8)
1767 ];
1768 assert_eq!(list.len(), 3);
1769 assert_eq!(result, expected.into());
1770 assert_ne!(result, ValueContainer::from(vec![1, 2, 3]));
1771 assert_structural_eq!(result, ValueContainer::from(vec![1, 2, 3]));
1772 }
1773
1774 #[test]
1775 fn list_with_nested_scope() {
1776 init_logger_debug();
1777 let result = execute_datex_script_debug_with_result("[1, (2 + 3), 4]");
1778 let expected = datex_list![
1779 Integer::from(1i8),
1780 Integer::from(5i8),
1781 Integer::from(4i8)
1782 ];
1783
1784 assert_eq!(result, expected.into());
1785 assert_ne!(result, ValueContainer::from(vec![1_u8, 5_u8, 4_u8]));
1786 assert_structural_eq!(
1787 result,
1788 ValueContainer::from(vec![1_u8, 5_u8, 4_u8])
1789 );
1790 }
1791
1792 #[test]
1793 fn boolean() {
1794 let result = execute_datex_script_debug_with_result("true");
1795 assert_eq!(result, true.into());
1796 assert_structural_eq!(result, ValueContainer::from(true));
1797
1798 let result = execute_datex_script_debug_with_result("false");
1799 assert_eq!(result, false.into());
1800 assert_structural_eq!(result, ValueContainer::from(false));
1801 }
1802
1803 #[test]
1804 fn decimal() {
1805 let result = execute_datex_script_debug_with_result("1.5");
1806 assert_eq!(result, Decimal::from_string("1.5").unwrap().into());
1807 assert_structural_eq!(result, ValueContainer::from(1.5));
1808 }
1809
1810 #[test]
1811 fn decimal_and_integer() {
1812 let result = execute_datex_script_debug_with_result("-2341324.0");
1813 assert_eq!(result, Decimal::from_string("-2341324").unwrap().into());
1814 assert!(!result.structural_eq(&ValueContainer::from(-2341324)));
1815 }
1816
1817 #[test]
1818 fn integer() {
1819 init_logger_debug();
1820 let result = execute_datex_script_debug_with_result("2");
1821 assert_eq!(result, Integer::from(2).into());
1822 assert_ne!(result, 2_u8.into());
1823 assert_structural_eq!(result, ValueContainer::from(2_i8));
1824 }
1825
1826 #[test]
1827 fn typed_integer() {
1828 init_logger_debug();
1829 let result = execute_datex_script_debug_with_result("-2i16");
1830 assert_eq!(result, TypedInteger::from(-2i16).into());
1831 assert_structural_eq!(result, ValueContainer::from(-2_i16));
1832
1833 let result = execute_datex_script_debug_with_result("2i32");
1834 assert_eq!(result, TypedInteger::from(2i32).into());
1835 assert_structural_eq!(result, ValueContainer::from(2_i32));
1836
1837 let result = execute_datex_script_debug_with_result("-2i64");
1838 assert_eq!(result, TypedInteger::from(-2i64).into());
1839 assert_structural_eq!(result, ValueContainer::from(-2_i64));
1840
1841 let result = execute_datex_script_debug_with_result("2i128");
1842 assert_eq!(result, TypedInteger::from(2i128).into());
1843 assert_structural_eq!(result, ValueContainer::from(2_i128));
1844
1845 let result = execute_datex_script_debug_with_result("2u8");
1846 assert_eq!(result, TypedInteger::from(2_u8).into());
1847 assert_structural_eq!(result, ValueContainer::from(2_u8));
1848
1849 let result = execute_datex_script_debug_with_result("2u16");
1850 assert_eq!(result, TypedInteger::from(2_u16).into());
1851 assert_structural_eq!(result, ValueContainer::from(2_u16));
1852
1853 let result = execute_datex_script_debug_with_result("2u32");
1854 assert_eq!(result, TypedInteger::from(2_u32).into());
1855 assert_structural_eq!(result, ValueContainer::from(2_u32));
1856
1857 let result = execute_datex_script_debug_with_result("2u64");
1858 assert_eq!(result, TypedInteger::from(2_u64).into());
1859 assert_structural_eq!(result, ValueContainer::from(2_u64));
1860
1861 let result = execute_datex_script_debug_with_result("2u128");
1862 assert_eq!(result, TypedInteger::from(2_u128).into());
1863 assert_structural_eq!(result, ValueContainer::from(2_u128));
1864
1865 let result = execute_datex_script_debug_with_result("2big");
1866 assert_eq!(result, TypedInteger::Big(Integer::from(2)).into());
1867 assert_structural_eq!(result, ValueContainer::from(2));
1868 }
1869
1870 #[test]
1871 fn null() {
1872 let result = execute_datex_script_debug_with_result("null");
1873 assert_eq!(result, ValueContainer::from(CoreValue::Null));
1874 assert_eq!(result, CoreValue::Null.into());
1875 assert_structural_eq!(result, ValueContainer::from(CoreValue::Null));
1876 }
1877
1878 #[test]
1879 fn map() {
1880 init_logger_debug();
1881 let result =
1882 execute_datex_script_debug_with_result("{x: 1, y: 2, z: 42}");
1883 let map: CoreValue = result.clone().to_value().borrow().clone().inner;
1884 let map: Map = map.try_into().unwrap();
1885
1886 assert_eq!(map.to_string(), "{\"x\": 1, \"y\": 2, \"z\": 42}");
1888 assert_eq!(map.size(), 3);
1889
1890 info!("Map: {:?}", map);
1891
1892 assert_eq!(map.get(&"x".into()), Some(&Integer::from(1i8).into()));
1894 assert_eq!(map.get(&"y".into()), Some(&Integer::from(2i8).into()));
1895 assert_eq!(map.get(&"z".into()), Some(&Integer::from(42i8).into()));
1896
1897 let expected_se: Map = Map::from(vec![
1899 ("x".to_string(), 1.into()),
1900 ("y".to_string(), 2.into()),
1901 ("z".to_string(), 42.into()),
1902 ]);
1903 assert_structural_eq!(map, expected_se);
1904
1905 let expected_strict: Map = Map::from(vec![
1907 ("x".to_string(), Integer::from(1_u32).into()),
1908 ("y".to_string(), Integer::from(2_u32).into()),
1909 ("z".to_string(), Integer::from(42_u32).into()),
1910 ]);
1911 debug!("Expected map: {expected_strict}");
1912 debug!("Map result: {map}");
1913 }
1916
1917 #[test]
1918 fn val_assignment() {
1919 init_logger_debug();
1920 let result = execute_datex_script_debug_with_result("const x = 42; x");
1921 assert_eq!(result, Integer::from(42i8).into());
1922 }
1923
1924 #[test]
1925 fn val_assignment_with_addition() {
1926 init_logger_debug();
1927 let result =
1928 execute_datex_script_debug_with_result("const x = 1 + 2; x");
1929 assert_eq!(result, Integer::from(3i8).into());
1930 }
1931
1932 #[test]
1933 fn val_assignment_inside_scope() {
1934 init_logger_debug();
1935 let result =
1937 execute_datex_script_debug_with_result("[const x = 42, 2, x]");
1938 let expected = datex_list![
1939 Integer::from(42i8),
1940 Integer::from(2i8),
1941 Integer::from(42i8)
1942 ];
1943 assert_eq!(result, expected.into());
1944 }
1945
1946 #[test]
1947 fn deref() {
1948 init_logger_debug();
1949 let result =
1950 execute_datex_script_debug_with_result("const x = &42; *x");
1951 assert_eq!(result, ValueContainer::from(Integer::from(42i8)));
1952 }
1953
1954 #[test]
1955 fn ref_assignment() {
1956 init_logger_debug();
1957 let result =
1958 execute_datex_script_debug_with_result("const x = &mut 42; x");
1959 assert_matches!(result, ValueContainer::Reference(..));
1960 assert_value_eq!(result, ValueContainer::from(Integer::from(42i8)));
1961 }
1962
1963 #[test]
1964 fn ref_add_assignment() {
1965 init_logger_debug();
1966 let result = execute_datex_script_debug_with_result(
1967 "const x = &mut 42; *x += 1",
1968 );
1969 assert_value_eq!(result, ValueContainer::from(Integer::from(43i8)));
1970
1971 let result = execute_datex_script_debug_with_result(
1972 "const x = &mut 42; *x += 1; x",
1973 );
1974
1975 assert_value_eq!(result, ValueContainer::from(Integer::from(43i8)));
1979 }
1980
1981 #[test]
1982 fn ref_sub_assignment() {
1983 init_logger_debug();
1984 let result = execute_datex_script_debug_with_result(
1985 "const x = &mut 42; *x -= 1",
1986 );
1987 assert_value_eq!(result, ValueContainer::from(Integer::from(41i8)));
1988
1989 let result = execute_datex_script_debug_with_result(
1990 "const x = &mut 42; *x -= 1; x",
1991 );
1992
1993 assert_value_eq!(result, ValueContainer::from(Integer::from(41i8)));
1997 }
1998
1999 #[test]
2000 fn endpoint_slot() {
2001 init_logger_debug();
2002 let result = execute_datex_script_debug_with_error("#endpoint");
2003 assert_matches!(result.unwrap_err(), ExecutionError::RequiresRuntime);
2004 }
2005
2006 #[test]
2007 fn shebang() {
2008 init_logger_debug();
2009 let result = execute_datex_script_debug_with_result("#!datex\n42");
2010 assert_eq!(result, Integer::from(42i8).into());
2011 }
2012
2013 #[test]
2014 fn single_line_comment() {
2015 init_logger_debug();
2016 let result =
2017 execute_datex_script_debug_with_result("// this is a comment\n42");
2018 assert_eq!(result, Integer::from(42i8).into());
2019
2020 let result = execute_datex_script_debug_with_result(
2021 "// this is a comment\n// another comment\n42",
2022 );
2023 assert_eq!(result, Integer::from(42i8).into());
2024 }
2025
2026 #[test]
2027 fn multi_line_comment() {
2028 init_logger_debug();
2029 let result = execute_datex_script_debug_with_result(
2030 "/* this is a comment */\n42",
2031 );
2032 assert_eq!(result, Integer::from(42i8).into());
2033
2034 let result = execute_datex_script_debug_with_result(
2035 "/* this is a comment\n with multiple lines */\n42",
2036 );
2037 assert_eq!(result, Integer::from(42i8).into());
2038
2039 let result = execute_datex_script_debug_with_result("[1, /* 2, */ 3]");
2040 let expected = datex_list![Integer::from(1i8), Integer::from(3i8)];
2041 assert_eq!(result, expected.into());
2042 }
2043}