1use super::stack::{Scope, ScopeStack};
2use crate::compiler::ast_parser::{BinaryOperator, UnaryOperator};
3use crate::compiler::compile_value;
4use crate::compiler::error::CompilerError;
5use crate::global::binary_codes::{InstructionCode, InternalSlot};
6use crate::global::protocol_structures::instructions::*;
7use crate::network::com_hub::ResponseError;
8use crate::parser::body;
9use crate::parser::body::DXBParserError;
10use crate::utils::buffers::append_u32;
11use crate::values::core_value::CoreValue;
12use crate::values::core_values::array::Array;
13use crate::values::core_values::decimal::decimal::Decimal;
14use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
15use crate::values::core_values::integer::integer::Integer;
16use crate::values::core_values::object::Object;
17use crate::values::core_values::tuple::Tuple;
18use crate::values::reference::Reference;
19use crate::values::traits::identity::Identity;
20use crate::values::traits::structural_eq::StructuralEq;
21use crate::values::traits::value_eq::ValueEq;
22use crate::values::value::Value;
23use crate::values::value_container::{ValueContainer, ValueError};
24use std::cell::RefCell;
25use std::collections::HashMap;
26use std::fmt::Display;
27use std::rc::Rc;
28use log::info;
29use num_enum::TryFromPrimitive;
30use crate::runtime::execution_context::RemoteExecutionContext;
31use crate::runtime::RuntimeInternal;
32
33#[derive(Debug, Clone, Default)]
34pub struct ExecutionOptions {
35 pub verbose: bool,
36}
37
38#[derive(Debug, Clone)]
39pub struct ExecutionInput<'a> {
40 pub options: ExecutionOptions,
41 pub dxb_body: &'a [u8],
42 pub end_execution: bool,
43 pub context: Rc<RefCell<RuntimeExecutionContext>>,
44}
45
46impl Default for ExecutionInput<'_> {
65 fn default() -> Self {
66 Self {
67 options: ExecutionOptions::default(),
68 dxb_body: &[],
69 context: Rc::new(RefCell::new(RuntimeExecutionContext::default())),
70 end_execution: true,
71 }
72 }
73}
74
75impl<'a> ExecutionInput<'a> {
76 pub fn new_with_dxb_and_options(
77 dxb_body: &'a [u8],
78 options: ExecutionOptions,
79 ) -> Self {
80 Self {
81 options,
82 dxb_body,
83 context: Rc::new(RefCell::new(RuntimeExecutionContext::default())),
84 end_execution: true,
85 }
86 }
87}
88
89#[derive(Debug, Clone, Default)]
90pub struct RuntimeExecutionContext {
91 index: usize,
92 scope_stack: ScopeStack,
93 slots: RefCell<HashMap<u32, Option<ValueContainer>>>,
94 pop_next_scope: bool,
96 runtime_internal: Option<Rc<RuntimeInternal>>,
97}
98
99impl RuntimeExecutionContext {
100
101 pub fn new(runtime_internal: Rc<RuntimeInternal>) -> Self {
102 Self {
103 runtime_internal: Some(runtime_internal),
104 ..Default::default()
105 }
106 }
107
108 pub fn reset_index(&mut self) {
109 self.index = 0;
110 }
111
112 pub fn runtime_internal(&self) -> &Option<Rc<RuntimeInternal>> {
113 &self.runtime_internal
114 }
115
116 pub fn set_runtime_internal(
117 &mut self,
118 runtime_internal: Rc<RuntimeInternal>,
119 ) {
120 self.runtime_internal = Some(runtime_internal);
121 }
122
123 fn allocate_slot(&self, address: u32, value: Option<ValueContainer>) {
125 self.slots.borrow_mut().insert(address, value);
126 }
127
128 fn drop_slot(
131 &self,
132 address: u32,
133 ) -> Result<Option<ValueContainer>, ExecutionError> {
134 self.slots
135 .borrow_mut()
136 .remove(&address)
137 .ok_or(())
138 .map_err(|_| ExecutionError::SlotNotAllocated(address))
139 }
140
141 fn set_slot_value(
144 &self,
145 address: u32,
146 value: ValueContainer,
147 ) -> Result<Option<ValueContainer>, ExecutionError> {
148 self.slots
149 .borrow_mut()
150 .insert(address, Some(value))
151 .ok_or(())
152 .map_err(|_| ExecutionError::SlotNotAllocated(address))
153 }
154
155 fn get_slot_value(
158 &self,
159 address: u32,
160 ) -> Result<Option<ValueContainer>, ExecutionError> {
161 self.slots
162 .borrow_mut()
163 .get(&address)
164 .cloned()
165 .ok_or(())
166 .map_err(|_| ExecutionError::SlotNotAllocated(address))
167 }
168}
169
170pub fn execute_dxb_sync(
171 input: ExecutionInput,
172) -> Result<Option<ValueContainer>, ExecutionError> {
173 let interrupt_provider = Rc::new(RefCell::new(None));
174 let runtime_internal = input.context.borrow_mut().runtime_internal().clone();
175
176 for output in execute_loop(input, interrupt_provider.clone()) {
177 match output? {
178 ExecutionStep::Return(result) => return Ok(result),
179 ExecutionStep::ResolvePointer(_pointer_id) => {
180 *interrupt_provider.borrow_mut() =
181 Some(InterruptProvider::Result(Some(ValueContainer::from(42))));
182 }
183 ExecutionStep::GetInternalSlot(slot) => {
184 *interrupt_provider.borrow_mut() =
185 Some(InterruptProvider::Result(get_internal_slot_value(&runtime_internal, slot)?));
186 }
187 _ => return Err(ExecutionError::RequiresAsyncExecution),
188 }
189 }
190
191 Err(ExecutionError::RequiresAsyncExecution)
192}
193
194fn get_internal_slot_value(runtime_internal: &Option<Rc<RuntimeInternal>>, slot: u32) -> Result<Option<ValueContainer>, ExecutionError> {
195 if let Some(runtime) = &runtime_internal {
196 let slot = InternalSlot::try_from_primitive(slot).map_err(|_| {
198 ExecutionError::SlotNotAllocated(slot)
199 })?;
200 let res = match slot {
201 InternalSlot::ENDPOINT => {
202 Some(ValueContainer::from(runtime.endpoint.clone()))
203 }
204 };
205 Ok(res)
206 }
207 else {
208 Err(ExecutionError::RequiresRuntime)
209 }
210}
211
212pub async fn get_pointer_test() {}
213
214pub async fn execute_dxb(
215 input: ExecutionInput<'_>,
216) -> Result<Option<ValueContainer>, ExecutionError> {
217 let interrupt_provider = Rc::new(RefCell::new(None));
218 let runtime_internal = input.context.borrow_mut().runtime_internal().clone();
219
220 for output in execute_loop(input, interrupt_provider.clone()) {
221 match output? {
222 ExecutionStep::Return(result) => return Ok(result),
223 ExecutionStep::ResolvePointer(_pointer_id) => {
224 get_pointer_test().await;
225 *interrupt_provider.borrow_mut() =
226 Some(InterruptProvider::Result(Some(ValueContainer::from(42))));
227 }
228 ExecutionStep::RemoteExecution(receivers, body) => {
229 if let Some(runtime) = &runtime_internal {
230 let receiver_endpoint = receivers.to_value().borrow().cast_to_endpoint().unwrap();
233 let mut remote_execution_context = RemoteExecutionContext::new(
234 receiver_endpoint,
235 true
236 );
237 let res = RuntimeInternal::execute_remote(runtime.clone(), &mut remote_execution_context, body).await?;
238 *interrupt_provider.borrow_mut() =
239 Some(InterruptProvider::Result(res));
240 }
241 else {
242 return Err(ExecutionError::RequiresRuntime);
243 }
244 }
245 ExecutionStep::GetInternalSlot(slot) => {
246 *interrupt_provider.borrow_mut() =
247 Some(InterruptProvider::Result(get_internal_slot_value(&runtime_internal, slot)?));
248 }
249 _ => todo!("#99 Undescribed by author."),
250 }
251 }
252
253 unreachable!("Execution loop should always return a result");
254}
255
256#[derive(Debug, Clone, PartialEq, Eq)]
257pub enum InvalidProgramError {
258 InvalidScopeClose,
259 InvalidKeyValuePair,
260 UnterminatedSequence,
262 MissingRemoteExecutionReceiver,
263}
264
265impl Display for InvalidProgramError {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 match self {
268 InvalidProgramError::InvalidScopeClose => {
269 write!(f, "Invalid scope close")
270 }
271 InvalidProgramError::InvalidKeyValuePair => {
272 write!(f, "Invalid key-value pair")
273 }
274 InvalidProgramError::UnterminatedSequence => {
275 write!(f, "Unterminated sequence")
276 }
277 InvalidProgramError::MissingRemoteExecutionReceiver => {
278 write!(f, "Missing remote execution receiver")
279 }
280 }
281 }
282}
283
284#[derive(Debug)]
285pub enum ExecutionError {
286 ParserError(DXBParserError),
287 ValueError(ValueError),
288 InvalidProgram(InvalidProgramError),
289 Unknown,
290 NotImplemented(String),
291 SlotNotAllocated(u32),
292 SlotNotInitialized(u32),
293 RequiresAsyncExecution,
294 RequiresRuntime,
295 ResponseError(ResponseError),
296 CompilerError(CompilerError),
297}
298
299impl From<DXBParserError> for ExecutionError {
300 fn from(error: DXBParserError) -> Self {
301 ExecutionError::ParserError(error)
302 }
303}
304
305impl From<ValueError> for ExecutionError {
306 fn from(error: ValueError) -> Self {
307 ExecutionError::ValueError(error)
308 }
309}
310
311impl From<InvalidProgramError> for ExecutionError {
312 fn from(error: InvalidProgramError) -> Self {
313 ExecutionError::InvalidProgram(error)
314 }
315}
316
317impl From<ResponseError> for ExecutionError {
318 fn from(error: ResponseError) -> Self {
319 ExecutionError::ResponseError(error)
320 }
321}
322
323impl From<CompilerError> for ExecutionError {
324 fn from(error: CompilerError) -> Self {
325 ExecutionError::CompilerError(error)
326 }
327}
328
329impl Display for ExecutionError {
330 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331 match self {
332 ExecutionError::CompilerError(err) => {
333 write!(f, "Compiler error: {err}")
334 }
335 ExecutionError::ParserError(err) => {
336 write!(f, "Parser error: {err}")
337 }
338 ExecutionError::Unknown => write!(f, "Unknown execution error"),
339 ExecutionError::ValueError(err) => write!(f, "Value error: {err}"),
340 ExecutionError::InvalidProgram(err) => {
341 write!(f, "Invalid program error: {err}")
342 }
343 ExecutionError::NotImplemented(msg) => {
344 write!(f, "Not implemented: {msg}")
345 }
346 ExecutionError::SlotNotAllocated(address) => {
347 write!(
348 f,
349 "Tried to access unallocated slot at address {address}"
350 )
351 }
352 ExecutionError::SlotNotInitialized(address) => {
353 write!(
354 f,
355 "Tried to access uninitialized slot at address {address}"
356 )
357 }
358 ExecutionError::RequiresAsyncExecution => {
359 write!(f, "Program must be executed asynchronously")
360 }
361 ExecutionError::RequiresRuntime => {
362 write!(f, "Execution requires a runtime to be set")
363 }
364 ExecutionError::ResponseError(err) => {
365 write!(f, "Response error: {err}")
366 }
367 }
368 }
369}
370
371#[derive(Debug)]
372pub enum ExecutionStep {
373 InternalReturn(Option<ValueContainer>),
374 Return(Option<ValueContainer>),
375 ResolvePointer(u64),
376 GetInternalSlot(u32),
377 RemoteExecution(ValueContainer, Vec<u8>),
378 Pause,
379}
380
381#[derive(Debug)]
382pub enum InterruptProvider {
383 Result(Option<ValueContainer>),
384}
385
386#[macro_export]
387macro_rules! interrupt {
388 ($input:expr, $arg:expr) => {{
389 yield Ok($arg);
390 $input.take().unwrap()
391 }};
392}
393
394#[macro_export]
395macro_rules! interrupt_with_result {
396 ($input:expr, $arg:expr) => {{
397 yield Ok($arg);
398 let res = $input.take().unwrap();
399 match res {
400 InterruptProvider::Result(value) => value,
401 }
402 }};
403}
404
405#[macro_export]
406macro_rules! yield_unwrap {
407 ($e:expr) => {{
408 let res = $e;
409 if let Ok(res) = res {
410 res
411 } else {
412 return yield Err(res.unwrap_err().into());
413 }
414 }};
415}
416
417pub fn execute_loop(
418 input: ExecutionInput,
419 interrupt_provider: Rc<RefCell<Option<InterruptProvider>>>,
420) -> impl Iterator<Item = Result<ExecutionStep, ExecutionError>> {
421 gen move {
422 let dxb_body = input.dxb_body;
423 let end_execution = input.end_execution;
424 let context = input.context;
425
426 let instruction_iterator = body::iterate_instructions(dxb_body);
427
428 for instruction in instruction_iterator {
429 let instruction = yield_unwrap!(instruction);
431 if input.options.verbose {
432 info!("[Exec]: {instruction}");
433 }
434
435 let mut result_value = None;
437
438 for output in get_result_value_from_instruction(
439 context.clone(),
440 instruction,
441 interrupt_provider.clone(),
442 ) {
443 match yield_unwrap!(output) {
444 ExecutionStep::InternalReturn(result) => {
445 result_value = result;
446 }
447 step => {
448 *interrupt_provider.borrow_mut() =
449 Some(interrupt!(interrupt_provider, step));
450 }
451 }
452 }
453
454 loop {
457 let mut context_mut = context.borrow_mut();
458 context_mut.pop_next_scope = false;
459 if let Some(value) = result_value {
460 let res = handle_value(&mut context_mut, value);
461 drop(context_mut);
462 yield_unwrap!(res);
463 } else {
464 drop(context_mut);
465 }
466
467 let mut context_mut = context.borrow_mut();
468
469 if context_mut.pop_next_scope {
470 let res = context_mut.scope_stack.pop();
471 drop(context_mut);
472 result_value = yield_unwrap!(res);
473 } else {
474 break;
475 }
476 }
477 }
478
479 if end_execution {
480 let res = match context.borrow_mut().scope_stack.pop_active_value()
491 {
492 None => ExecutionStep::Return(None),
493 Some(val) => ExecutionStep::Return(Some(val)),
494 };
495 yield Ok(res);
496 } else {
497 yield Ok(ExecutionStep::Pause);
498 }
499 }
500}
501
502#[inline]
503fn get_result_value_from_instruction(
504 context: Rc<RefCell<RuntimeExecutionContext>>,
505 instruction: Instruction,
506 interrupt_provider: Rc<RefCell<Option<InterruptProvider>>>,
507) -> impl Iterator<Item = Result<ExecutionStep, ExecutionError>> {
508 gen move {
509 yield Ok(ExecutionStep::InternalReturn(match instruction {
510 Instruction::True => Some(true.into()),
512 Instruction::False => Some(false.into()),
513
514 Instruction::Int8(integer) => Some(Integer::from(integer.0).into()),
516 Instruction::Int16(integer) => {
517 Some(Integer::from(integer.0).into())
518 }
519 Instruction::Int32(integer) => {
520 Some(Integer::from(integer.0).into())
521 }
522 Instruction::Int64(integer) => {
523 Some(Integer::from(integer.0).into())
524 }
525 Instruction::Int128(integer) => {
526 Some(Integer::from(integer.0).into())
527 }
528
529 Instruction::UInt128(integer) => {
531 Some(Integer::from(integer.0).into())
532 }
533
534 Instruction::DecimalF32(Float32Data(f32)) => {
536 Some(TypedDecimal::from(f32).into())
537 }
538 Instruction::DecimalF64(Float64Data(f64)) => {
539 Some(TypedDecimal::from(f64).into())
540 }
541
542 Instruction::DecimalAsInt16(FloatAsInt16Data(i16)) => {
544 Some(Decimal::from(i16 as f32).into())
545 }
546 Instruction::DecimalAsInt32(FloatAsInt32Data(i32)) => {
547 Some(Decimal::from(i32 as f32).into())
548 }
549 Instruction::Decimal(DecimalData(big_decimal)) => {
550 Some(big_decimal.into())
551 }
552
553 Instruction::Endpoint(endpoint) => Some(endpoint.into()),
555
556 Instruction::Null => Some(Value::null().into()),
558
559 Instruction::ShortText(ShortTextData(text)) => Some(text.into()),
561 Instruction::Text(TextData(text)) => Some(text.into()),
562
563 Instruction::Add
565 | Instruction::Subtract
566 | Instruction::Multiply
567 | Instruction::Divide
568 | Instruction::Is
569 | Instruction::StructuralEqual
570 | Instruction::Equal
571 | Instruction::NotStructuralEqual
572 | Instruction::NotEqual => {
573 context.borrow_mut().scope_stack.create_scope(
574 Scope::BinaryOperation {
575 operator: BinaryOperator::from(instruction),
576 },
577 );
578 None
579 }
580
581 Instruction::ExecutionBlock(block) => {
582 let mut buffer = Vec::with_capacity(256);
585 for (addr, local_slot) in
586 block.injected_slots.into_iter().enumerate()
587 {
588 buffer.push(InstructionCode::ALLOCATE_SLOT as u8);
589 append_u32(&mut buffer, addr as u32);
590
591 if let Some(vc) = yield_unwrap!(
592 context.borrow().get_slot_value(local_slot).map_err(
593 |_| ExecutionError::SlotNotAllocated(local_slot),
594 )
595 ) {
596 buffer.extend_from_slice(&yield_unwrap!(
597 compile_value(&vc)
598 ));
599 } else {
600 return yield Err(ExecutionError::SlotNotInitialized(
601 local_slot,
602 ));
603 }
604 }
605 buffer.extend_from_slice(&block.body);
606
607 let maybe_receivers =
608 context.borrow_mut().scope_stack.pop_active_value();
609
610 if let Some(receivers) = maybe_receivers {
611 interrupt_with_result!(
612 interrupt_provider,
613 ExecutionStep::RemoteExecution(receivers, buffer)
614 )
615 } else {
616 yield Err(ExecutionError::InvalidProgram(
618 InvalidProgramError::MissingRemoteExecutionReceiver,
619 ));
620 None
621 }
622 }
623
624 Instruction::CloseAndStore => {
625 let _ = context.borrow_mut().scope_stack.pop_active_value();
626 None
627 }
628
629 Instruction::ScopeStart => {
630 context
631 .borrow_mut()
632 .scope_stack
633 .create_scope(Scope::Default);
634 None
635 }
636
637 Instruction::ArrayStart => {
638 context
639 .borrow_mut()
640 .scope_stack
641 .create_scope_with_active_value(
642 Scope::Collection,
643 Array::default().into(),
644 );
645 None
646 }
647
648 Instruction::ObjectStart => {
649 context
650 .borrow_mut()
651 .scope_stack
652 .create_scope_with_active_value(
653 Scope::Collection,
654 Object::default().into(),
655 );
656 None
657 }
658
659 Instruction::TupleStart => {
660 context
661 .borrow_mut()
662 .scope_stack
663 .create_scope_with_active_value(
664 Scope::Collection,
665 Tuple::default().into(),
666 );
667 None
668 }
669
670 Instruction::KeyValueShortText(ShortTextData(key)) => {
671 context
672 .borrow_mut()
673 .scope_stack
674 .create_scope_with_active_value(
675 Scope::KeyValuePair,
676 key.into(),
677 );
678 None
679 }
680
681 Instruction::KeyValueDynamic => {
682 context
683 .borrow_mut()
684 .scope_stack
685 .create_scope(Scope::KeyValuePair);
686 None
687 }
688
689 Instruction::ScopeEnd => {
690 yield_unwrap!(context.borrow_mut().scope_stack.pop())
692 }
693
694 Instruction::AllocateSlot(SlotAddress(address)) => {
696 let mut context = context.borrow_mut();
697 context.allocate_slot(address, None);
698 context
699 .scope_stack
700 .create_scope(Scope::SlotAssignment { address });
701 None
702 }
703 Instruction::GetSlot(SlotAddress(address)) => {
704
705 if address >= 0xffffff00 {
707 interrupt_with_result!(
708 interrupt_provider,
709 ExecutionStep::GetInternalSlot(address)
710 )
711 }
712
713 else {
715 let res = context.borrow_mut().get_slot_value(address);
716 let slot_value = yield_unwrap!(res);
718 if slot_value.is_none() {
719 return yield Err(ExecutionError::SlotNotInitialized(
720 address,
721 ));
722 }
723 slot_value
724 }
725 }
726 Instruction::SetSlot(SlotAddress(address)) => {
727 context
728 .borrow_mut()
729 .scope_stack
730 .create_scope(Scope::SlotAssignment { address });
731 None
732 }
733
734 Instruction::CreateRef => {
736 context.borrow_mut().scope_stack.create_scope(
737 Scope::UnaryOperation {
738 operator: UnaryOperator::CreateRef,
739 },
740 );
741 None
742 }
743
744 Instruction::RemoteExecution => {
746 context
747 .borrow_mut()
748 .scope_stack
749 .create_scope(Scope::RemoteExecution);
750 None
751 }
752
753 Instruction::DropSlot(SlotAddress(address)) => {
754 let res = context.borrow_mut().drop_slot(address);
756 yield_unwrap!(res);
757 None
758 }
759
760 i => {
761 return yield Err(ExecutionError::NotImplemented(
762 format!("Instruction {i}").to_string(),
763 ));
764 }
765 }))
766 }
767}
768
769fn handle_value(
771 context: &mut RuntimeExecutionContext,
772 value_container: ValueContainer,
773) -> Result<(), ExecutionError> {
774 let scope_container = context.scope_stack.get_current_scope_mut();
775
776 let result_value = match &scope_container.scope {
777 Scope::KeyValuePair => {
778 let key = &scope_container.active_value;
779 match key {
780 None => Some(value_container),
782
783 Some(_) => {
785 let key = context.scope_stack.pop()?.unwrap();
786 match context.scope_stack.get_active_value_mut() {
787 Some(collector) => {
788 handle_key_value_pair(
790 collector,
791 key,
792 value_container,
793 )?;
794 }
795 None => unreachable!(
796 "Expected active value for key-value pair, but got None"
797 ),
798 }
799 None
800 }
801 }
802 }
803
804 Scope::SlotAssignment { address } => {
805 let address = *address;
807 context.set_slot_value(address, value_container.clone())?;
808 Some(value_container)
809 }
810
811 Scope::UnaryOperation { operator } => {
812 let operator = *operator;
813 context.pop_next_scope = true;
814 Some(handle_unary_operation(operator, value_container))
815 }
816
817 Scope::BinaryOperation { operator } => {
818 let active_value = &scope_container.active_value;
819 match active_value {
820 Some(active_value_container) => {
821 let res = handle_binary_operation(
822 active_value_container,
823 value_container,
824 *operator,
825 );
826 if let Ok(val) = res {
827 context.pop_next_scope = true;
829 Some(val)
830 } else {
831 return Err(res.unwrap_err());
833 }
834 }
835 None => Some(value_container),
836 }
837 }
838
839 Scope::Collection => {
840 let active_value = &mut scope_container.active_value;
841 match active_value {
842 Some(active_value_container) => {
843 handle_collector(active_value_container, value_container);
845 None
846 }
847 None => {
848 unreachable!(
849 "Expected active value for collection scope, but got None"
850 );
851 }
852 }
853 }
854
855 _ => Some(value_container),
856 };
857
858 if let Some(result_value) = result_value {
859 context.scope_stack.set_active_value_container(result_value);
860 }
861
862 Ok(())
863}
864
865fn handle_collector(collector: &mut ValueContainer, value: ValueContainer) {
866 match collector {
867 ValueContainer::Value(Value {
868 inner: CoreValue::Array(array),
869 ..
870 }) => {
871 array.push(value);
873 }
874 ValueContainer::Value(Value {
875 inner: CoreValue::Tuple(tuple),
876 ..
877 }) => {
878 let index = CoreValue::Integer(Integer::from(tuple.next_int_key()));
880 tuple.set(index, value);
881 }
882 _ => {
883 unreachable!(
884 "Expected active value in array scope to be an array, but got: {}",
885 collector
886 );
887 }
888 }
889}
890
891fn handle_key_value_pair(
892 active_container: &mut ValueContainer,
893 key: ValueContainer,
894 value: ValueContainer,
895) -> Result<(), ExecutionError> {
896 match active_container {
898 ValueContainer::Value(Value {
900 inner: CoreValue::Object(object),
901 ..
902 }) => {
903 match key {
905 ValueContainer::Value(Value {
906 inner: CoreValue::Text(key_str),
907 ..
908 }) => {
909 object.set(&key_str.0, value);
910 }
911 _ => {
912 return Err(ExecutionError::InvalidProgram(
913 InvalidProgramError::InvalidKeyValuePair,
914 ));
915 }
916 }
917 }
918 ValueContainer::Value(Value {
920 inner: CoreValue::Tuple(tuple),
921 ..
922 }) => {
923 tuple.set(key, value);
925 }
926 _ => {
927 unreachable!(
928 "Expected active value object or tuple to collect key value pairs, but got: {}",
929 active_container
930 );
931 }
932 }
933
934 Ok(())
935}
936
937fn handle_unary_operation(
938 operator: UnaryOperator,
939 value_container: ValueContainer,
940) -> ValueContainer {
941 match operator {
942 UnaryOperator::CreateRef => {
943 ValueContainer::Reference(Reference::from(value_container))
944 }
945 _ => todo!("#102 Unary instruction not implemented: {operator:?}"),
946 }
947}
948
949fn handle_binary_operation(
950 active_value_container: &ValueContainer,
951 value_container: ValueContainer,
952 operator: BinaryOperator,
953) -> Result<ValueContainer, ExecutionError> {
954 match operator {
956 BinaryOperator::Add => Ok((active_value_container + &value_container)?),
957 BinaryOperator::Subtract => {
958 Ok((active_value_container - &value_container)?)
959 }
960 BinaryOperator::StructuralEqual => {
961 let val = active_value_container.structural_eq(&value_container);
962 Ok(ValueContainer::from(val))
963 }
964 BinaryOperator::Equal => {
965 let val = active_value_container.value_eq(&value_container);
966 Ok(ValueContainer::from(val))
967 }
968 BinaryOperator::NotStructuralEqual => {
969 let val = !active_value_container.structural_eq(&value_container);
970 Ok(ValueContainer::from(val))
971 }
972 BinaryOperator::NotEqual => {
973 let val = !active_value_container.value_eq(&value_container);
974 Ok(ValueContainer::from(val))
975 }
976 BinaryOperator::Is => {
977 let val = active_value_container.identical(&value_container);
982 Ok(ValueContainer::from(val))
983 }
984 _ => {
985 unreachable!("Instruction {:?} is not a valid operation", operator);
986 }
987 }
988}
989
990#[cfg(test)]
991mod tests {
992 use std::assert_matches::assert_matches;
993 use std::vec;
994
995 use log::debug;
996
997 use super::*;
998 use crate::compiler::{CompileOptions, compile_script};
999 use crate::global::binary_codes::InstructionCode;
1000 use crate::logger::init_logger_debug;
1001 use crate::values::traits::structural_eq::StructuralEq;
1002 use crate::{assert_structural_eq, assert_value_eq, datex_array};
1003
1004 fn execute_datex_script_debug(
1005 datex_script: &str,
1006 ) -> Option<ValueContainer> {
1007 let (dxb, _) =
1008 compile_script(datex_script, CompileOptions::default()).unwrap();
1009 let context = ExecutionInput::new_with_dxb_and_options(
1010 &dxb,
1011 ExecutionOptions { verbose: true },
1012 );
1013 execute_dxb_sync(context).unwrap_or_else(|err| {
1014 panic!("Execution failed: {err}");
1015 })
1016 }
1017
1018 fn execute_datex_script_debug_with_error(
1019 datex_script: &str,
1020 ) -> Result<Option<ValueContainer>, ExecutionError> {
1021 let (dxb, _) =
1022 compile_script(datex_script, CompileOptions::default()).unwrap();
1023 let context = ExecutionInput::new_with_dxb_and_options(
1024 &dxb,
1025 ExecutionOptions { verbose: true },
1026 );
1027 execute_dxb_sync(context)
1028 }
1029
1030 fn execute_datex_script_debug_with_result(
1031 datex_script: &str,
1032 ) -> ValueContainer {
1033 execute_datex_script_debug(datex_script).unwrap()
1034 }
1035
1036 fn execute_dxb_debug(
1037 dxb_body: &[u8],
1038 ) -> Result<Option<ValueContainer>, ExecutionError> {
1039 let context = ExecutionInput::new_with_dxb_and_options(
1040 dxb_body,
1041 ExecutionOptions { verbose: true },
1042 );
1043 execute_dxb_sync(context)
1044 }
1045
1046 #[test]
1047 fn test_empty_script() {
1048 assert_eq!(execute_datex_script_debug(""), None);
1049 }
1050
1051 #[test]
1052 fn test_empty_script_semicolon() {
1053 assert_eq!(execute_datex_script_debug(";;;"), None);
1054 }
1055
1056 #[test]
1057 fn test_single_value() {
1058 assert_eq!(
1059 execute_datex_script_debug_with_result("42"),
1060 Integer::from(42).into()
1061 );
1062 }
1063
1064 #[test]
1065 fn test_single_value_semicolon() {
1066 assert_eq!(execute_datex_script_debug("42;"), None)
1067 }
1068
1069 #[test]
1070 fn test_is() {
1071 let result = execute_datex_script_debug_with_result("1 is 1");
1072 assert_eq!(result, false.into());
1073 assert_structural_eq!(result, ValueContainer::from(false));
1074 }
1075
1076 #[test]
1077 fn test_equality() {
1078 let result = execute_datex_script_debug_with_result("1 == 1");
1079 assert_eq!(result, true.into());
1080 assert_structural_eq!(result, ValueContainer::from(true));
1081
1082 let result = execute_datex_script_debug_with_result("1 == 2");
1083 assert_eq!(result, false.into());
1084 assert_structural_eq!(result, ValueContainer::from(false));
1085
1086 let result = execute_datex_script_debug_with_result("1 != 2");
1087 assert_eq!(result, true.into());
1088 assert_structural_eq!(result, ValueContainer::from(true));
1089
1090 let result = execute_datex_script_debug_with_result("1 != 1");
1091 assert_eq!(result, false.into());
1092 assert_structural_eq!(result, ValueContainer::from(false));
1093 let result = execute_datex_script_debug_with_result("1 === 1");
1094 assert_eq!(result, true.into());
1095
1096 assert_structural_eq!(result, ValueContainer::from(true));
1097 let result = execute_datex_script_debug_with_result("1 !== 2");
1098 assert_eq!(result, true.into());
1099 assert_structural_eq!(result, ValueContainer::from(true));
1100
1101 let result = execute_datex_script_debug_with_result("1 !== 1");
1102 assert_eq!(result, false.into());
1103 assert_structural_eq!(result, ValueContainer::from(false));
1104 }
1105
1106 #[test]
1107 fn test_single_value_scope() {
1108 let result = execute_datex_script_debug_with_result("(42)");
1109 assert_eq!(result, Integer::from(42).into());
1110 assert_structural_eq!(result, ValueContainer::from(42_u128));
1111 }
1112
1113 #[test]
1114 fn test_add() {
1115 let result = execute_datex_script_debug_with_result("1 + 2");
1116 assert_structural_eq!(result, ValueContainer::from(3_u128));
1117 assert_eq!(result, Integer::from(3).into());
1118 }
1119
1120 #[test]
1121 fn test_nested_scope() {
1122 let result = execute_datex_script_debug_with_result("1 + (2 + 3)");
1123 assert_eq!(result, Integer::from(6).into());
1124 }
1125
1126 #[test]
1127 fn test_invalid_scope_close() {
1128 let result = execute_dxb_debug(&[
1129 InstructionCode::SCOPE_START.into(),
1130 InstructionCode::SCOPE_END.into(),
1131 InstructionCode::SCOPE_END.into(),
1132 ]);
1133 assert!(matches!(
1134 result,
1135 Err(ExecutionError::InvalidProgram(
1136 InvalidProgramError::InvalidScopeClose
1137 ))
1138 ));
1139 }
1140
1141 #[test]
1142 fn test_empty_array() {
1143 let result = execute_datex_script_debug_with_result("[]");
1144 let array: Array = result.to_value().borrow().cast_to_array().unwrap();
1145 assert_eq!(array.len(), 0);
1146 assert_eq!(result, Vec::<ValueContainer>::new().into());
1147 assert_eq!(result, ValueContainer::from(Vec::<ValueContainer>::new()));
1148 }
1149
1150 #[test]
1151 fn test_array() {
1152 let result = execute_datex_script_debug_with_result("[1, 2, 3]");
1153 let array: Array = result.to_value().borrow().cast_to_array().unwrap();
1154 let expected =
1155 datex_array![Integer::from(1), Integer::from(2), Integer::from(3)];
1156 assert_eq!(array.len(), 3);
1157 assert_eq!(result, expected.into());
1158 assert_ne!(result, ValueContainer::from(vec![1, 2, 3]));
1159 assert_structural_eq!(result, ValueContainer::from(vec![1, 2, 3]));
1160 }
1161
1162 #[test]
1163 fn test_array_with_nested_scope() {
1164 init_logger_debug();
1165 let result = execute_datex_script_debug_with_result("[1, (2 + 3), 4]");
1166 let expected =
1167 datex_array![Integer::from(1), Integer::from(5), Integer::from(4)];
1168
1169 assert_eq!(result, expected.into());
1170 assert_ne!(result, ValueContainer::from(vec![1_u8, 5_u8, 4_u8]));
1171 assert_structural_eq!(
1172 result,
1173 ValueContainer::from(vec![1_u8, 5_u8, 4_u8])
1174 );
1175 }
1176
1177 #[test]
1178 fn test_boolean() {
1179 let result = execute_datex_script_debug_with_result("true");
1180 assert_eq!(result, true.into());
1181 assert_structural_eq!(result, ValueContainer::from(true));
1182
1183 let result = execute_datex_script_debug_with_result("false");
1184 assert_eq!(result, false.into());
1185 assert_structural_eq!(result, ValueContainer::from(false));
1186 }
1187
1188 #[test]
1189 fn test_decimal() {
1190 let result = execute_datex_script_debug_with_result("1.5");
1191 assert_eq!(result, Decimal::from_string("1.5").into());
1192 assert_structural_eq!(result, ValueContainer::from(1.5));
1193 }
1194
1195 #[test]
1196 fn test_decimal_and_integer() {
1197 let result = execute_datex_script_debug_with_result("-2341324.0");
1198 assert_eq!(result, Decimal::from_string("-2341324").into());
1199 assert!(!result.structural_eq(&ValueContainer::from(-2341324)));
1200 }
1201
1202 #[test]
1203 fn test_integer_2() {
1204 init_logger_debug();
1205 let result = execute_datex_script_debug_with_result("2");
1206 assert_eq!(result, Integer::from(2).into());
1207 assert_ne!(result, 2_u8.into());
1208 assert_structural_eq!(result, ValueContainer::from(2_u8));
1209 }
1210
1211 #[test]
1212 fn test_null() {
1213 let result = execute_datex_script_debug_with_result("null");
1214 assert_eq!(result, ValueContainer::from(CoreValue::Null));
1215 assert_eq!(result, CoreValue::Null.into());
1216 assert_structural_eq!(result, ValueContainer::from(CoreValue::Null));
1217 }
1218
1219 #[test]
1220 fn test_tuple() {
1221 init_logger_debug();
1222 let result = execute_datex_script_debug_with_result("(x: 1, 2, 42)");
1223 let tuple: CoreValue = result.clone().to_value().borrow().clone().inner;
1224 let tuple: Tuple = tuple.try_into().unwrap();
1225
1226 assert_eq!(tuple.to_string(), "(\"x\": 1, 0: 2, 1: 42)");
1228 assert_eq!(tuple.size(), 3);
1229
1230 assert_eq!(tuple.get(&"x".into()), Some(&Integer::from(1).into()));
1232 assert_eq!(
1233 tuple.get(&Integer::from(0_u32).into()),
1234 Some(&Integer::from(2).into())
1235 );
1236 assert_eq!(
1237 tuple.get(&Integer::from(1_u32).into()),
1238 Some(&Integer::from(42).into())
1239 );
1240
1241 let expected_se: Tuple = Tuple::from(vec![
1243 ("x".into(), 1.into()),
1244 (0.into(), 2.into()),
1245 (1.into(), 42.into()),
1246 ]);
1247 assert_structural_eq!(tuple, expected_se);
1248
1249 let expected_strict: Tuple = Tuple::from(vec![
1251 ("x".into(), Integer::from(1_u32).into()),
1252 (0_u32.into(), Integer::from(2_u32).into()),
1253 (1_u32.into(), Integer::from(42_u32).into()),
1254 ]);
1255 debug!("Expected tuple: {expected_strict}");
1256 debug!("Tuple result: {tuple}");
1257 }
1260
1261 #[test]
1262 fn test_val_assignment() {
1263 init_logger_debug();
1264 let result = execute_datex_script_debug_with_result("const x = 42; x");
1265 assert_eq!(result, Integer::from(42).into());
1266 }
1267
1268 #[test]
1269 fn test_val_assignment_with_addition() {
1270 init_logger_debug();
1271 let result = execute_datex_script_debug_with_result("const x = 1 + 2; x");
1272 assert_eq!(result, Integer::from(3).into());
1273 }
1274
1275 #[test]
1276 fn test_val_assignment_inside_scope() {
1277 init_logger_debug();
1278 let result =
1279 execute_datex_script_debug_with_result("[const x = 42, 2, x]");
1280 let expected = datex_array![
1281 Integer::from(42),
1282 Integer::from(2),
1283 Integer::from(42)
1284 ];
1285 assert_eq!(result, expected.into());
1286 }
1287
1288 #[test]
1289 fn test_ref_assignment() {
1290 init_logger_debug();
1291 let result = execute_datex_script_debug_with_result("const mut x = 42; x");
1292 assert_matches!(result, ValueContainer::Reference(..));
1293 assert_value_eq!(result, ValueContainer::from(Integer::from(42)));
1294 }
1295
1296 #[test]
1297 fn test_endpoint_slot() {
1298 init_logger_debug();
1299 let result = execute_datex_script_debug_with_error("#endpoint");
1300 assert_matches!(result.unwrap_err(), ExecutionError::RequiresRuntime);
1301 }
1302
1303 #[test]
1304 fn test_shebang() {
1305 init_logger_debug();
1306 let result = execute_datex_script_debug_with_result("#!datex\n42");
1307 assert_eq!(result, Integer::from(42).into());
1308 }
1309
1310 #[test]
1311 fn test_single_line_comment() {
1312 init_logger_debug();
1313 let result =
1314 execute_datex_script_debug_with_result("// this is a comment\n42");
1315 assert_eq!(result, Integer::from(42).into());
1316
1317 let result = execute_datex_script_debug_with_result(
1318 "// this is a comment\n// another comment\n42",
1319 );
1320 assert_eq!(result, Integer::from(42).into());
1321 }
1322
1323 #[test]
1324 fn test_multi_line_comment() {
1325 init_logger_debug();
1326 let result = execute_datex_script_debug_with_result(
1327 "/* this is a comment */\n42",
1328 );
1329 assert_eq!(result, Integer::from(42).into());
1330
1331 let result = execute_datex_script_debug_with_result(
1332 "/* this is a comment\n with multiple lines */\n42",
1333 );
1334 assert_eq!(result, Integer::from(42).into());
1335
1336 let result = execute_datex_script_debug_with_result("[1, /* 2, */ 3]");
1337 let expected = datex_array![Integer::from(1), Integer::from(3)];
1338 assert_eq!(result, expected.into());
1339 }
1340}