datex_core/runtime/
execution.rs

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
64// TODO #229: do we want a DatexProgram input enum like this for execution?
65// #[derive(Debug, Clone)]
66// pub enum DatexProgram {
67//     Dxb(Vec<u8>),
68//     Script(String),
69// }
70
71// impl From<Vec<u8>> for DatexProgram {
72//     fn from(dxb: Vec<u8>) -> Self {
73//         DatexProgram::Dxb(dxb)
74//     }
75// }
76// impl From<String> for DatexProgram {
77//     fn from(script: String) -> Self {
78//         DatexProgram::Script(script)
79//     }
80// }
81
82pub 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    // if set to true, the execution loop will pop the current scope before continuing with the next instruction
136    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    /// Allocates a new slot with the given slot address.
164    fn allocate_slot(&self, address: u32, value: Option<ValueContainer>) {
165        self.slots.borrow_mut().insert(address, value);
166    }
167
168    /// Drops a slot by its address, returning the value if it existed.
169    /// If the slot is not allocated, it returns an error.
170    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    /// Sets the value of a slot, returning the previous value if it existed.
182    /// If the slot is not allocated, it returns an error.
183    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    /// Retrieves the value of a slot by its address.
196    /// If the slot is not allocated, it returns an error.
197    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    /// Returns a memory dump of the current slots and their values.
210    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                // TODO #401: in the future, local pointer addresses should be relative to the block sender, not the local runtime
242                *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                // TODO #402: in the future, local pointer addresses should be relative to the block sender, not the local runtime
287                *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                    // assert that receivers is a single endpoint
302                    // TODO #230: support advanced receivers
303                    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        // convert slot to InternalSlot enum
342        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        // convert slot to InternalSlot enum
364        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        // convert slot to InternalSlot enum
392        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    // any unterminated sequence, e.g. missing key in key-value pair
407    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            // TODO #100: use ? operator instead of yield_unwrap once supported in gen blocks
620            let instruction = yield_unwrap!(instruction);
621            if input.options.verbose {
622                info!("[Exec]: {instruction}");
623            }
624
625            // get initial value from instruction
626            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            // 1. if value is Some, handle it
648            // 2. while pop_next_scope is true: pop current scope and repeat
649            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            // cleanup...
674            // TODO #101: check for other unclosed stacks
675            // if we have an active key here, this is invalid and leads to an error
676            // if context.scope_stack.get_active_key().is_some() {
677            //     return Err(ExecutionError::InvalidProgram(
678            //         InvalidProgramError::UnterminatedSequence,
679            //     ));
680            // }
681
682            // removes the current active value from the scope stack
683            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            // boolean
704            Instruction::True => Some(true.into()),
705            Instruction::False => Some(false.into()),
706
707            // integers
708            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            // unsigned integers
723            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            // big integers
740            Instruction::BigInteger(IntegerData(integer)) => {
741                Some(integer.into())
742            }
743
744            // specific floats
745            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            // default decimals (big decimals)
753            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            // endpoint
764            Instruction::Endpoint(endpoint) => Some(endpoint.into()),
765
766            // null
767            Instruction::Null => Some(Value::null().into()),
768
769            // text
770            Instruction::ShortText(ShortTextData(text)) => Some(text.into()),
771            Instruction::Text(TextData(text)) => Some(text.into()),
772
773            // binary operations
774            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            // unary operations
787            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            // equality operations
819            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                // build dxb
835
836                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                    // should not happen, receivers must be set
869                    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                // pop scope and return value
940                yield_unwrap!(context.borrow_mut().scope_stack.pop())
941            }
942
943            // slots
944            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 is >= 0xffffff00, resolve internal slot
954                if address >= 0xffffff00 {
955                    interrupt_with_result!(
956                        interrupt_provider,
957                        ExecutionStep::GetInternalSlot(address)
958                    )
959                }
960                // else handle normal slot
961                else {
962                    let res = context.borrow_mut().get_slot_value(address);
963                    // get value from slot
964                    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            // refs
1038            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            // remote execution
1072            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                // remove slot from slots
1082                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                    // TODO #403: handle type here
1092                    yield output;
1093                }
1094                return;
1095            }
1096
1097            // type(...)
1098            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                // TODO #404: Implement type instructions iteration
1124                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
1141/// Takes a produced value and handles it according to the current scope
1142fn 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                // set key as active_value for key-value pair (for dynamic keys)
1153                None => Some(value_container),
1154
1155                // set value for key-value pair
1156                Some(_) => {
1157                    let key = context.scope_stack.pop()?.unwrap();
1158                    match context.scope_stack.get_active_value_mut() {
1159                        Some(collector) => {
1160                            // handle active value collector
1161                            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            // set value for slot
1178            let address = *address;
1179            context.set_slot_value(address, value_container.clone())?;
1180            Some(value_container)
1181        }
1182
1183        Scope::Deref => {
1184            // set value for slot
1185            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                // set value for slot
1198                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            // collect callee as active value if not set yet and we have args to collect
1222            if scope_container.active_value.is_none() {
1223                // directly apply if no args to collect
1224                if *arg_count == 0 {
1225                    context.pop_next_scope = true;
1226                    handle_apply(&value_container, args)?
1227                }
1228                // set callee as active value
1229                else {
1230                    Some(value_container)
1231                }
1232            } else {
1233                let callee = scope_container.active_value.as_ref().unwrap();
1234                // callee already exists, collect args
1235                args.push(value_container);
1236
1237                // all args collected, apply function
1238                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                // handle error
1269                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                        // set val as active value
1284                        context.pop_next_scope = true;
1285                        Some(val)
1286                    } else {
1287                        // handle error
1288                        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                        // set val as active value
1306                        context.pop_next_scope = true;
1307                        Some(val)
1308                    } else {
1309                        // handle error
1310                        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 active value collector
1322                    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    // callee is guaranteed to be Some here
1348    // apply_single if one arg, apply otherwise
1349    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            // append value to list
1363            list.push(value);
1364        }
1365        ValueContainer::Value(Value {
1366            inner: CoreValue::Map(map),
1367            ..
1368        }) => {
1369            // TODO #406: Implement map collector for optimized structural maps
1370            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    // insert key value pair into active map
1384    match active_container {
1385        // Map
1386        ValueContainer::Value(Value {
1387            inner: CoreValue::Map(map),
1388            ..
1389        }) => {
1390            // make sure key is a string
1391            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    // apply operation to active value
1473    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            // TODO #103 we should throw a runtime error when one of lhs or rhs is a value
1492            // instead of a ref. Identity checks using the is operator shall be only allowed
1493            // for references.
1494            // @benstre: or keep as always false ? - maybe a compiler check would be better
1495            let val = active_value_container.identical(&value_container);
1496            Ok(ValueContainer::from(val))
1497        }
1498        ComparisonOperator::Matches => {
1499            // TODO #407: Fix matches, rhs will always be a type, so actual_type() call is wrong
1500            let v_type = value_container.actual_type(); // Type::try_from(value_container)?;
1501            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    // apply operation to active value
1516    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    // apply operation to active value
1531    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        // ArithmeticOperator::Multiply => {
1539        //     Ok((active_value_container * &value_container)?)
1540        // }
1541        // ArithmeticOperator::Divide => {
1542        //     Ok((active_value_container / &value_container)?)
1543        // }
1544        _ => {
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    // apply operation to active value
1556    {
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    // apply operation to active value
1567    {
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        // form and size
1887        assert_eq!(map.to_string(), "{\"x\": 1, \"y\": 2, \"z\": 42}");
1888        assert_eq!(map.size(), 3);
1889
1890        info!("Map: {:?}", map);
1891
1892        // access by key
1893        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        // structural equality checks
1898        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        // strict equality checks
1906        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        // FIXME #104 type information gets lost on compile
1914        // assert_eq!(result, expected.into());
1915    }
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        // FIXME #412: This should be probably disallowed (we can not use x in this scope due to hoisting behavior)
1936        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        // FIXME #413 due to addition the resulting value container of the slot
1976        // is no longer a reference but a value what is incorrect.
1977        // assert_matches!(result, ValueContainer::Reference(..));
1978        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        // FIXME #414 due to addition the resulting value container of the slot
1994        // is no longer a reference but a value what is incorrect.
1995        // assert_matches!(result, ValueContainer::Reference(..));
1996        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}