datex_core/runtime/execution/execution_loop/
mod.rs

1pub mod interrupts;
2mod operations;
3mod runtime_value;
4mod slots;
5pub mod state;
6
7use crate::core_compiler::value_compiler::compile_value_container;
8use crate::dxb_parser::body::{DXBParserError, iterate_instructions};
9use crate::dxb_parser::instruction_collector::{
10    CollectedResults, CollectionResultsPopper, FullOrPartialResult,
11    InstructionCollector, LastUnboundedResultCollector, ResultCollector,
12    StatementResultCollectionStrategy,
13};
14use crate::global::instruction_codes::InstructionCode;
15use crate::global::operators::{
16    AssignmentOperator, BinaryOperator, ComparisonOperator, UnaryOperator,
17};
18use crate::global::protocol_structures::instructions::{
19    ApplyData, DecimalData, Float32Data, Float64Data, FloatAsInt16Data,
20    FloatAsInt32Data, Instruction, IntegerData, RawPointerAddress,
21    RegularInstruction, ShortTextData, SlotAddress, TextData, TypeInstruction,
22};
23use crate::references::reference::{Reference, ReferenceMutability};
24use crate::runtime::execution::execution_loop::interrupts::{
25    ExecutionInterrupt, ExternalExecutionInterrupt, InterruptProvider,
26    InterruptResult,
27};
28use crate::runtime::execution::execution_loop::operations::{
29    handle_assignment_operation, handle_binary_operation,
30    handle_comparison_operation, handle_unary_operation, set_property,
31};
32use crate::runtime::execution::execution_loop::runtime_value::RuntimeValue;
33use crate::runtime::execution::execution_loop::slots::get_internal_slot_value;
34use crate::runtime::execution::execution_loop::state::RuntimeExecutionState;
35use crate::runtime::execution::macros::{
36    interrupt, interrupt_with_maybe_value, interrupt_with_value, yield_unwrap,
37};
38use crate::runtime::execution::{ExecutionError, InvalidProgramError};
39use crate::stdlib::boxed::Box;
40use crate::stdlib::rc::Rc;
41use crate::stdlib::vec::Vec;
42use crate::types::definition::TypeDefinition;
43use crate::utils::buffers::append_u32;
44use crate::values::core_value::CoreValue;
45use crate::values::core_values::decimal::Decimal;
46use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
47use crate::values::core_values::integer::typed_integer::TypedInteger;
48use crate::values::core_values::list::List;
49use crate::values::core_values::map::{Map, MapKey};
50use crate::values::core_values::r#type::Type;
51use crate::values::pointer::PointerAddress;
52use crate::values::value::Value;
53use crate::values::value_container::{OwnedValueKey, ValueContainer};
54use core::cell::RefCell;
55use datex_core::runtime::execution::execution_loop::slots::get_slot_value;
56
57#[derive(Debug)]
58enum CollectedExecutionResult {
59    /// contains an optional runtime value that is intercepted by the consumer of a value or passed as the final result at the end of execution
60    Value(Option<RuntimeValue>),
61    /// contains a Type that is intercepted by a consumer of a type value
62    Type(Type),
63    /// contains a key-value pair that is intercepted by a map construction operation
64    KeyValuePair((MapKey, ValueContainer)),
65}
66
67impl From<Option<RuntimeValue>> for CollectedExecutionResult {
68    fn from(value: Option<RuntimeValue>) -> Self {
69        CollectedExecutionResult::Value(value)
70    }
71}
72impl From<RuntimeValue> for CollectedExecutionResult {
73    fn from(value: RuntimeValue) -> Self {
74        CollectedExecutionResult::Value(Some(value))
75    }
76}
77impl From<Type> for CollectedExecutionResult {
78    fn from(value: Type) -> Self {
79        CollectedExecutionResult::Type(value)
80    }
81}
82impl From<(MapKey, ValueContainer)> for CollectedExecutionResult {
83    fn from(value: (MapKey, ValueContainer)) -> Self {
84        CollectedExecutionResult::KeyValuePair(value)
85    }
86}
87
88impl
89    CollectionResultsPopper<
90        CollectedExecutionResult,
91        Option<RuntimeValue>,
92        MapKey,
93        ValueContainer,
94        Type,
95    > for CollectedResults<CollectedExecutionResult>
96{
97    fn try_extract_value_result(
98        result: CollectedExecutionResult,
99    ) -> Option<Option<RuntimeValue>> {
100        match result {
101            CollectedExecutionResult::Value(val) => Some(val),
102            _ => None,
103        }
104    }
105
106    fn try_extract_type_result(
107        result: CollectedExecutionResult,
108    ) -> Option<Type> {
109        match result {
110            CollectedExecutionResult::Type(ty) => Some(ty),
111            _ => None,
112        }
113    }
114
115    fn try_extract_key_value_pair_result(
116        result: CollectedExecutionResult,
117    ) -> Option<(MapKey, ValueContainer)> {
118        match result {
119            CollectedExecutionResult::KeyValuePair((key, value)) => {
120                Some((key, value))
121            }
122            _ => None,
123        }
124    }
125}
126
127impl CollectedResults<CollectedExecutionResult> {
128    fn collect_value_container_results_assert_existing(
129        mut self,
130        state: &RuntimeExecutionState,
131    ) -> Result<Vec<ValueContainer>, ExecutionError> {
132        let count = self.len();
133        let mut expressions = Vec::with_capacity(count);
134        for _ in 0..count {
135            expressions.push(
136                self.pop_cloned_value_container_result_assert_existing(state)?,
137            );
138        }
139        expressions.reverse();
140        Ok(expressions)
141    }
142
143    /// Pops a runtime value result, returning an error if none exists
144    fn pop_runtime_value_result_assert_existing(
145        &mut self,
146    ) -> Result<RuntimeValue, ExecutionError> {
147        self.pop_value_result()
148            .ok_or(ExecutionError::InvalidProgram(
149                InvalidProgramError::ExpectedValue,
150            ))
151    }
152
153    /// Pops a value container result, returning an error if none exists.
154    /// If the value is a slot address, it is resolved to a cloned value container.
155    /// Do not use this method if you want to work on the actual value without cloning it.
156    fn pop_cloned_value_container_result_assert_existing(
157        &mut self,
158        state: &RuntimeExecutionState,
159    ) -> Result<ValueContainer, ExecutionError> {
160        self.pop_runtime_value_result_assert_existing()?
161            .into_cloned_value_container(state)
162    }
163
164    fn collect_key_value_pair_results_assert_existing(
165        mut self,
166    ) -> Result<Vec<(MapKey, ValueContainer)>, ExecutionError> {
167        let count = self.len();
168        let mut pairs = Vec::with_capacity(count);
169        for _ in 0..count {
170            let (key, value) = self.pop_key_value_pair_result();
171            pairs.push((key, value));
172        }
173        pairs.reverse();
174        Ok(pairs)
175    }
176}
177
178/// Main execution loop that drives the execution of the DXB body
179/// The interrupt_provider is used to provide results for synchronous or asynchronous I/O operations
180pub fn execution_loop(
181    state: RuntimeExecutionState,
182    dxb_body: Rc<RefCell<Vec<u8>>>,
183    interrupt_provider: InterruptProvider,
184) -> impl Iterator<Item = Result<ExternalExecutionInterrupt, ExecutionError>> {
185    gen move {
186        let mut active_value: Option<ValueContainer> = None;
187
188        for interrupt in
189            inner_execution_loop(dxb_body, interrupt_provider.clone(), state)
190        {
191            match interrupt {
192                Ok(interrupt) => match interrupt {
193                    ExecutionInterrupt::External(external_interrupt) => {
194                        yield Ok(external_interrupt);
195                    }
196                    ExecutionInterrupt::SetActiveValue(value) => {
197                        active_value = value;
198                    }
199                },
200                Err(err) => {
201                    match err {
202                        ExecutionError::DXBParserError(
203                            DXBParserError::ExpectingMoreInstructions,
204                        ) => {
205                            yield Err(
206                                ExecutionError::IntermediateResultWithState(
207                                    active_value.take(),
208                                    None,
209                                ),
210                            );
211                            // assume that when continuing after this yield, more instructions will have been loaded
212                            // so we run the loop again to try to get the next instruction
213                            continue;
214                        }
215                        _ => {
216                            yield Err(err);
217                        }
218                    }
219                }
220            }
221        }
222    }
223}
224
225pub fn inner_execution_loop(
226    dxb_body: Rc<RefCell<Vec<u8>>>,
227    interrupt_provider: InterruptProvider,
228    mut state: RuntimeExecutionState,
229) -> impl Iterator<Item = Result<ExecutionInterrupt, ExecutionError>> {
230    gen move {
231        let mut collector =
232            InstructionCollector::<CollectedExecutionResult>::default();
233
234        for instruction_result in iterate_instructions(dxb_body) {
235            let instruction = match instruction_result {
236                Ok(instruction) => instruction,
237                Err(DXBParserError::ExpectingMoreInstructions) => {
238                    yield Err(DXBParserError::ExpectingMoreInstructions.into());
239                    // assume that when continuing after this yield, more instructions will have been loaded
240                    // so we run the loop again to try to get the next instruction
241                    continue;
242                }
243                Err(err) => {
244                    return yield Err(err.into());
245                }
246            };
247
248            let result = match instruction {
249                // handle regular instructions
250                Instruction::RegularInstruction(regular_instruction) => {
251                    let regular_instruction = collector
252                        .default_regular_instruction_collection(
253                            regular_instruction,
254                            StatementResultCollectionStrategy::Last,
255                        );
256
257                    let expr: Option<Option<RuntimeValue>> = if let Some(
258                        regular_instruction,
259                    ) =
260                        regular_instruction
261                    {
262                        Some(match regular_instruction {
263                            // boolean
264                            RegularInstruction::True => Some(ValueContainer::from(true).into()),
265                            RegularInstruction::False => Some(ValueContainer::from(false).into()),
266
267                            // integers
268                            RegularInstruction::Int8(integer) => {
269                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
270                            }
271                            RegularInstruction::Int16(integer) => {
272                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
273                            }
274                            RegularInstruction::Int32(integer) => {
275                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
276                            }
277                            RegularInstruction::Int64(integer) => {
278                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
279                            }
280                            RegularInstruction::Int128(integer) => {
281                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
282                            }
283
284                            // unsigned integers
285                            RegularInstruction::UInt8(integer) => {
286                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
287                            }
288                            RegularInstruction::UInt16(integer) => {
289                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
290                            }
291                            RegularInstruction::UInt32(integer) => {
292                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
293                            }
294                            RegularInstruction::UInt64(integer) => {
295                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
296                            }
297                            RegularInstruction::UInt128(integer) => {
298                                Some(ValueContainer::from(TypedInteger::from(integer.0)).into())
299                            }
300
301                            // big integers
302                            RegularInstruction::BigInteger(IntegerData(integer)) => {
303                                Some(ValueContainer::from(TypedInteger::IBig(integer)).into())
304                            }
305
306                            // default integer
307                            RegularInstruction::Integer(IntegerData(i8)) => {
308                                Some(ValueContainer::from(i8).into())
309                            }
310
311                            // specific floats
312                            RegularInstruction::DecimalF32(Float32Data(f32)) => {
313                                Some(ValueContainer::from(TypedDecimal::from(f32)).into())
314                            }
315                            RegularInstruction::DecimalF64(Float64Data(f64)) => {
316                                Some(ValueContainer::from(TypedDecimal::from(f64)).into())
317                            }
318                            // big decimal
319                            RegularInstruction::BigDecimal(DecimalData(big_decimal)) => {
320                                Some(ValueContainer::from(TypedDecimal::Decimal(big_decimal)).into())
321                            }
322
323                            // default decimals
324                            RegularInstruction::DecimalAsInt16(FloatAsInt16Data(i16)) => {
325                                Some(ValueContainer::from(Decimal::from(i16 as f32)).into())
326                            }
327                            RegularInstruction::DecimalAsInt32(FloatAsInt32Data(i32)) => {
328                                Some(ValueContainer::from(Decimal::from(i32 as f32)).into())
329                            }
330                            RegularInstruction::Decimal(DecimalData(big_decimal)) => {
331                                Some(ValueContainer::from(big_decimal).into())
332                            }
333
334                            // endpoint
335                            RegularInstruction::Endpoint(endpoint) => Some(ValueContainer::from(endpoint).into()),
336
337                            // null
338                            RegularInstruction::Null => Some(ValueContainer::from(Value::null()).into()),
339
340                            // text
341                            RegularInstruction::ShortText(ShortTextData(text)) => {
342                                Some(ValueContainer::from(text).into())
343                            }
344                            RegularInstruction::Text(TextData(text)) => Some(ValueContainer::from(text).into()),
345
346                            RegularInstruction::GetRef(address) => Some(interrupt_with_value!(
347                                    interrupt_provider,
348                                    ExecutionInterrupt::External(
349                                        ExternalExecutionInterrupt::ResolvePointer(address)
350                                    )
351                                ).into()),
352                            RegularInstruction::GetLocalRef(address) => {
353                                Some(interrupt_with_value!(
354                                    interrupt_provider,
355                                    ExecutionInterrupt::External(
356                                        ExternalExecutionInterrupt::ResolveLocalPointer(
357                                            address
358                                        )
359                                    )
360                                ).into())
361                            }
362                            RegularInstruction::GetInternalRef(address) => {
363                                Some(interrupt_with_value!(
364                                    interrupt_provider,
365                                    ExecutionInterrupt::External(
366                                        ExternalExecutionInterrupt::ResolveInternalPointer(
367                                            address
368                                        )
369                                    )
370                                ).into())
371                            }
372
373                            RegularInstruction::GetSlot(SlotAddress(address)) => {
374                                Some(RuntimeValue::SlotAddress(address))
375                            }
376
377                            RegularInstruction::GetInternalSlot(SlotAddress(address)) => {
378                                Some(RuntimeValue::ValueContainer(yield_unwrap!(
379                                    get_internal_slot_value(
380                                        &state,
381                                        address,
382                                    )
383                                )))
384                            }
385
386
387                            RegularInstruction::DropSlot(SlotAddress(address)) => {
388                                yield_unwrap!(state.slots.drop_slot(address));
389                                None
390                            }
391
392                            // NOTE: make sure that each possible match case is either implemented in the default collection or here
393                            // If an instruction is implemented in the default collection, it should be marked as unreachable!() here
394                            RegularInstruction::Statements(_) |
395                            RegularInstruction::ShortStatements(_) |
396                            RegularInstruction::UnboundedStatements |
397                            RegularInstruction::UnboundedStatementsEnd(_) |
398                            RegularInstruction::List(_) |
399                            RegularInstruction::ShortList(_)  |
400                            RegularInstruction::Map(_) |
401                            RegularInstruction::ShortMap(_) |
402                            RegularInstruction::KeyValueDynamic |
403                            RegularInstruction::KeyValueShortText(_) |
404                            RegularInstruction::Add |
405                            RegularInstruction::Subtract |
406                            RegularInstruction::Multiply |
407                            RegularInstruction::Divide |
408                            RegularInstruction::UnaryMinus |
409                            RegularInstruction::UnaryPlus |
410                            RegularInstruction::BitwiseNot |
411                            RegularInstruction::Apply(_) |
412                            RegularInstruction::GetPropertyText(_) |
413                            RegularInstruction::GetPropertyIndex(_) |
414                            RegularInstruction::GetPropertyDynamic |
415                            RegularInstruction::SetPropertyText(_) |
416                            RegularInstruction::SetPropertyIndex(_) |
417                            RegularInstruction::SetPropertyDynamic |
418                            RegularInstruction::Is |
419                            RegularInstruction::Matches |
420                            RegularInstruction::StructuralEqual |
421                            RegularInstruction::Equal |
422                            RegularInstruction::NotStructuralEqual |
423                            RegularInstruction::NotEqual |
424                            RegularInstruction::AddAssign(_) |
425                            RegularInstruction::SubtractAssign(_) |
426                            RegularInstruction::MultiplyAssign(_) |
427                            RegularInstruction::DivideAssign(_) |
428                            RegularInstruction::CreateRef |
429                            RegularInstruction::CreateRefMut |
430                            RegularInstruction::GetOrCreateRef(_) |
431                            RegularInstruction::GetOrCreateRefMut(_) |
432                            RegularInstruction::AllocateSlot(_) |
433                            RegularInstruction::SetSlot(_) |
434                            RegularInstruction::SetReferenceValue(_) |
435                            RegularInstruction::Deref |
436                            RegularInstruction::TypedValue |
437                            RegularInstruction::RemoteExecution(_) |
438                            RegularInstruction::TypeExpression => unreachable!()
439                        })
440                    } else {
441                        None
442                    };
443
444                    expr.map(CollectedExecutionResult::from)
445                }
446                Instruction::TypeInstruction(type_instruction) => {
447                    let type_instruction = collector
448                        .default_type_instruction_collection(type_instruction);
449
450                    let type_expression: Option<Type> = if let Some(
451                        type_instruction,
452                    ) = type_instruction
453                    {
454                        Some(match type_instruction {
455                            TypeInstruction::LiteralInteger(integer) => {
456                                Type::structural(integer.0)
457                            }
458                            TypeInstruction::LiteralText(text_data) => {
459                                Type::structural(text_data.0)
460                            }
461
462                            TypeInstruction::TypeReference(type_ref) => {
463                                let metadata = type_ref.metadata;
464                                let val = interrupt_with_maybe_value!(
465                                    interrupt_provider,
466                                    match type_ref.address {
467                                        RawPointerAddress::Local(address) => {
468                                            ExecutionInterrupt::External(
469                                                ExternalExecutionInterrupt::ResolveLocalPointer(
470                                                    address,
471                                                ),
472                                            )
473                                        }
474                                        RawPointerAddress::Internal(
475                                            address,
476                                        ) => {
477                                            ExecutionInterrupt::External(ExternalExecutionInterrupt::ResolveInternalPointer(address))
478                                        }
479                                        RawPointerAddress::Full(address) => {
480                                            ExecutionInterrupt::External(
481                                                ExternalExecutionInterrupt::ResolvePointer(
482                                                    address,
483                                                ),
484                                            )
485                                        }
486                                    }
487                                );
488
489                                match val {
490                                    // simple Type value
491                                    Some(ValueContainer::Value(Value {
492                                        inner: CoreValue::Type(ty),
493                                        ..
494                                    })) => ty,
495                                    // Type Reference
496                                    Some(ValueContainer::Reference(
497                                        Reference::TypeReference(type_ref),
498                                    )) => Type::new(
499                                        TypeDefinition::Reference(type_ref),
500                                        metadata.mutability.into(),
501                                    ),
502                                    _ => {
503                                        return yield Err(
504                                            ExecutionError::ExpectedTypeValue,
505                                        );
506                                    }
507                                }
508                            }
509
510                            // NOTE: make sure that each possible match case is either implemented in the default collection or here
511                            // If an instruction is implemented in the default collection, it should be marked as unreachable!() here
512                            TypeInstruction::List(_)
513                            | TypeInstruction::ImplType(_) => unreachable!(),
514                        })
515                    } else {
516                        None
517                    };
518
519                    type_expression
520                        .map(|ty_expr| CollectedExecutionResult::from(ty_expr))
521                }
522            };
523
524            if let Some(result) = result {
525                collector.push_result(result);
526            }
527
528            // handle collecting nested expressions
529            while let Some(result) = collector.try_pop_collected() {
530                let expr: CollectedExecutionResult = match result {
531                    FullOrPartialResult::Full(
532                        instruction,
533                        mut collected_results,
534                    ) => {
535                        match instruction {
536                            Instruction::RegularInstruction(
537                                regular_instruction,
538                            ) => match regular_instruction {
539                                RegularInstruction::List(_)
540                                | RegularInstruction::ShortList(_) => {
541                                    let elements = yield_unwrap!(collected_results.collect_value_container_results_assert_existing(&state));
542                                    RuntimeValue::ValueContainer(
543                                        ValueContainer::from(List::new(
544                                            elements,
545                                        )),
546                                    )
547                                    .into()
548                                }
549                                RegularInstruction::Map(_)
550                                | RegularInstruction::ShortMap(_) => {
551                                    let entries = yield_unwrap!(collected_results.collect_key_value_pair_results_assert_existing());
552                                    RuntimeValue::ValueContainer(
553                                        ValueContainer::from(Map::from(
554                                            entries,
555                                        )),
556                                    )
557                                    .into()
558                                }
559
560                                RegularInstruction::KeyValueDynamic => {
561                                    let value = yield_unwrap!(
562                                        collected_results.pop_cloned_value_container_result_assert_existing(&state)
563                                    );
564                                    let key = yield_unwrap!(
565                                        collected_results
566                                            .pop_cloned_value_container_result_assert_existing(&state)
567                                    );
568                                    CollectedExecutionResult::KeyValuePair((
569                                        MapKey::Value(key),
570                                        value,
571                                    ))
572                                }
573
574                                RegularInstruction::KeyValueShortText(
575                                    short_text_data,
576                                ) => {
577                                    let value = yield_unwrap!(
578                                        collected_results.pop_cloned_value_container_result_assert_existing(&state)
579                                    );
580                                    let key = MapKey::Text(short_text_data.0);
581                                    CollectedExecutionResult::KeyValuePair((
582                                        key, value,
583                                    ))
584                                }
585
586                                RegularInstruction::Add
587                                | RegularInstruction::Subtract
588                                | RegularInstruction::Multiply
589                                | RegularInstruction::Divide => {
590                                    let right = yield_unwrap!(
591                                        collected_results
592                                            .pop_cloned_value_container_result_assert_existing(&state)
593                                    );
594                                    let left = yield_unwrap!(
595                                        collected_results
596                                            .pop_cloned_value_container_result_assert_existing(&state)
597                                    );
598
599                                    let res = handle_binary_operation(
600                                        BinaryOperator::from(
601                                            regular_instruction,
602                                        ),
603                                        &left,
604                                        &right,
605                                    );
606                                    RuntimeValue::ValueContainer(yield_unwrap!(
607                                        res
608                                    ))
609                                    .into()
610                                }
611
612                                RegularInstruction::Is
613                                | RegularInstruction::StructuralEqual
614                                | RegularInstruction::Equal
615                                | RegularInstruction::NotStructuralEqual
616                                | RegularInstruction::NotEqual => {
617                                    let right = yield_unwrap!(
618                                        collected_results
619                                            .pop_cloned_value_container_result_assert_existing(&state)
620                                    );
621                                    let left = yield_unwrap!(
622                                        collected_results
623                                            .pop_cloned_value_container_result_assert_existing(&state)
624                                    );
625
626                                    let res = handle_comparison_operation(
627                                        ComparisonOperator::from(
628                                            regular_instruction,
629                                        ),
630                                        &left,
631                                        &right,
632                                    );
633                                    RuntimeValue::ValueContainer(yield_unwrap!(
634                                        res
635                                    ))
636                                    .into()
637                                }
638
639                                RegularInstruction::Matches => {
640                                    let target = yield_unwrap!(
641                                        collected_results
642                                            .pop_runtime_value_result_assert_existing()
643                                    );
644                                    let type_pattern =
645                                        collected_results.pop_type_result();
646
647                                    todo!("#645 Undescribed by author.")
648                                }
649
650                                RegularInstruction::UnaryMinus
651                                | RegularInstruction::UnaryPlus
652                                | RegularInstruction::BitwiseNot
653                                | RegularInstruction::CreateRef
654                                | RegularInstruction::CreateRefMut
655                                | RegularInstruction::Deref => {
656                                    let mut target = yield_unwrap!(
657                                        collected_results
658                                            .pop_runtime_value_result_assert_existing()
659                                    );
660                                    let res = target.with_mut_value_container(
661                                        &mut state,
662                                        |target| {
663                                            handle_unary_operation(
664                                                UnaryOperator::from(
665                                                    regular_instruction,
666                                                ),
667                                                target.clone(), // TODO #646: is unary operation supposed to take ownership?
668                                            )
669                                        },
670                                    );
671                                    RuntimeValue::ValueContainer(yield_unwrap!(
672                                        yield_unwrap!(res)
673                                    ))
674                                    .into()
675                                }
676
677                                RegularInstruction::TypedValue => {
678                                    let mut value_container = yield_unwrap!(
679                                        collected_results
680                                            .pop_cloned_value_container_result_assert_existing(&state)
681                                    );
682                                    let ty =
683                                        collected_results.pop_type_result();
684
685                                    match &mut value_container {
686                                        ValueContainer::Value(value) => {
687                                            // FIXME #647: only using type definition here, refactor and/or add checks
688                                            value.actual_type =
689                                                Box::new(ty.type_definition);
690                                        }
691                                        _ => panic!(
692                                            "Expected ValueContainer::Value for type casting"
693                                        ),
694                                    }
695                                    RuntimeValue::ValueContainer(
696                                        value_container,
697                                    )
698                                    .into()
699                                }
700
701                                // type(...)
702                                RegularInstruction::TypeExpression => {
703                                    let ty =
704                                        collected_results.pop_type_result();
705                                    RuntimeValue::ValueContainer(
706                                        ValueContainer::Value(Value {
707                                            inner: CoreValue::Type(ty),
708                                            actual_type: Box::new(
709                                                TypeDefinition::Unknown,
710                                            ), // TODO #648: type for type
711                                        }),
712                                    )
713                                    .into()
714                                }
715
716                                RegularInstruction::AddAssign(SlotAddress(
717                                    address,
718                                ))
719                                | RegularInstruction::MultiplyAssign(
720                                    SlotAddress(address),
721                                )
722                                | RegularInstruction::DivideAssign(
723                                    SlotAddress(address),
724                                )
725                                | RegularInstruction::SubtractAssign(
726                                    SlotAddress(address),
727                                ) => {
728                                    let slot_value = yield_unwrap!(
729                                        get_slot_value(&state, address)
730                                    );
731                                    let value = yield_unwrap!(
732                                            collected_results
733                                                .pop_cloned_value_container_result_assert_existing(&state)
734                                        );
735
736                                    let new_val = yield_unwrap!(
737                                        handle_assignment_operation(
738                                            AssignmentOperator::from(
739                                                regular_instruction
740                                            ),
741                                            &slot_value,
742                                            value,
743                                        )
744                                    );
745                                    yield_unwrap!(
746                                        state
747                                            .slots
748                                            .set_slot_value(address, new_val)
749                                    );
750                                    None.into()
751                                }
752
753                                RegularInstruction::SetReferenceValue(
754                                    operator,
755                                ) => {
756                                    let value_container = yield_unwrap!(
757                                        collected_results
758                                            .pop_cloned_value_container_result_assert_existing(&state)
759                                    );
760                                    let ref_value_container = yield_unwrap!(
761                                        collected_results
762                                            .pop_cloned_value_container_result_assert_existing(&state)
763                                    );
764
765                                    // assignment value must be a reference
766                                    if let Some(reference) =
767                                        ref_value_container.maybe_reference()
768                                    {
769                                        let lhs = reference.value_container();
770                                        let res = yield_unwrap!(
771                                            handle_assignment_operation(
772                                                operator,
773                                                &lhs,
774                                                value_container,
775                                            )
776                                        );
777                                        yield_unwrap!(
778                                            reference.set_value_container(res)
779                                        );
780                                        RuntimeValue::ValueContainer(
781                                            ref_value_container,
782                                        )
783                                        .into()
784                                    } else {
785                                        return yield Err(
786                                            ExecutionError::DerefOfNonReference,
787                                        );
788                                    }
789                                }
790
791                                RegularInstruction::SetSlot(SlotAddress(
792                                    address,
793                                )) => {
794                                    let value = yield_unwrap!(
795                                        collected_results
796                                            .pop_cloned_value_container_result_assert_existing(&state)
797                                    );
798                                    yield_unwrap!(
799                                        state
800                                            .slots
801                                            .set_slot_value(address, value)
802                                    );
803                                    None.into()
804                                }
805
806                                RegularInstruction::AllocateSlot(
807                                    SlotAddress(address),
808                                ) => {
809                                    let value = yield_unwrap!(
810                                        collected_results
811                                            .pop_cloned_value_container_result_assert_existing(&state)
812                                    );
813                                    state
814                                        .slots
815                                        .allocate_slot(address, Some(value));
816
817                                    None.into()
818                                }
819
820                                RegularInstruction::GetPropertyText(
821                                    property_data,
822                                ) => {
823                                    let mut target = yield_unwrap!(
824                                        collected_results
825                                            .pop_runtime_value_result_assert_existing()
826                                    );
827                                    let property_name = property_data.0;
828
829                                    let res = target.with_mut_value_container(
830                                        &mut state,
831                                        |target| {
832                                            target.try_get_property(
833                                                &property_name,
834                                            )
835                                        },
836                                    );
837                                    RuntimeValue::ValueContainer(yield_unwrap!(
838                                        yield_unwrap!(res)
839                                    ))
840                                    .into()
841                                }
842
843                                RegularInstruction::GetPropertyIndex(
844                                    property_data,
845                                ) => {
846                                    let mut target = yield_unwrap!(
847                                        collected_results
848                                            .pop_runtime_value_result_assert_existing()
849                                    );
850                                    let property_index = property_data.0;
851
852                                    let res = target.with_mut_value_container(
853                                        &mut state,
854                                        |target| {
855                                            target.try_get_property(
856                                                property_index,
857                                            )
858                                        },
859                                    );
860                                    RuntimeValue::ValueContainer(yield_unwrap!(
861                                        yield_unwrap!(res)
862                                    ))
863                                    .into()
864                                }
865
866                                RegularInstruction::GetPropertyDynamic => {
867                                    let key = yield_unwrap!(
868                                        collected_results
869                                            .pop_cloned_value_container_result_assert_existing(&state)
870                                    );
871                                    let mut target = yield_unwrap!(
872                                        collected_results
873                                            .pop_runtime_value_result_assert_existing()
874                                    );
875
876                                    let res = target.with_mut_value_container(
877                                        &mut state,
878                                        |target| target.try_get_property(&key),
879                                    );
880                                    RuntimeValue::ValueContainer(yield_unwrap!(
881                                        yield_unwrap!(res)
882                                    ))
883                                    .into()
884                                }
885
886                                RegularInstruction::SetPropertyText(
887                                    property_data,
888                                ) => {
889                                    let mut target = yield_unwrap!(
890                                        collected_results
891                                            .pop_runtime_value_result_assert_existing()
892                                    );
893                                    let value = yield_unwrap!(
894                                        collected_results
895                                            .pop_cloned_value_container_result_assert_existing(&state)
896                                    );
897                                    let runtime_internal =
898                                        state.runtime_internal.clone();
899                                    let res = target.with_mut_value_container(
900                                        &mut state,
901                                        |target| {
902                                            set_property(
903                                                &runtime_internal,
904                                                target,
905                                                OwnedValueKey::Text(
906                                                    property_data.0,
907                                                ),
908                                                value,
909                                            )
910                                        },
911                                    );
912                                    yield_unwrap!(yield_unwrap!(res));
913                                    None.into()
914                                }
915
916                                RegularInstruction::SetPropertyIndex(
917                                    property_data,
918                                ) => {
919                                    let mut target = yield_unwrap!(
920                                        collected_results
921                                            .pop_runtime_value_result_assert_existing()
922                                    );
923                                    let value = yield_unwrap!(
924                                        collected_results
925                                            .pop_cloned_value_container_result_assert_existing(&state)
926                                    );
927
928                                    let runtime_internal =
929                                        state.runtime_internal.clone();
930                                    let res = target.with_mut_value_container(
931                                        &mut state,
932                                        |target| {
933                                            set_property(
934                                                &runtime_internal,
935                                                target,
936                                                OwnedValueKey::Index(
937                                                    property_data.0 as i64,
938                                                ),
939                                                value,
940                                            )
941                                        },
942                                    );
943                                    yield_unwrap!(yield_unwrap!(res));
944                                    None.into()
945                                }
946
947                                RegularInstruction::SetPropertyDynamic => {
948                                    let mut target = yield_unwrap!(
949                                        collected_results
950                                            .pop_runtime_value_result_assert_existing()
951                                    );
952                                    let value = yield_unwrap!(
953                                        collected_results
954                                            .pop_cloned_value_container_result_assert_existing(&state)
955                                    );
956                                    let key = yield_unwrap!(
957                                        collected_results
958                                            .pop_cloned_value_container_result_assert_existing(&state)
959                                    );
960
961                                    let runtime_internal =
962                                        state.runtime_internal.clone();
963                                    let res = target.with_mut_value_container(
964                                        &mut state,
965                                        |target| {
966                                            set_property(
967                                                &runtime_internal,
968                                                target,
969                                                OwnedValueKey::Value(key),
970                                                value,
971                                            )
972                                        },
973                                    );
974                                    yield_unwrap!(yield_unwrap!(res));
975                                    None.into()
976                                }
977
978                                RegularInstruction::RemoteExecution(
979                                    exec_block_data,
980                                ) => {
981                                    // build dxb
982                                    let mut buffer = Vec::with_capacity(256);
983                                    for (addr, local_slot) in exec_block_data
984                                        .injected_slots
985                                        .into_iter()
986                                        .enumerate()
987                                    {
988                                        buffer.push(
989                                            InstructionCode::ALLOCATE_SLOT
990                                                as u8,
991                                        );
992                                        append_u32(&mut buffer, addr as u32);
993
994                                        let slot_value = yield_unwrap!(
995                                            get_slot_value(&state, local_slot,)
996                                        );
997                                        buffer.extend_from_slice(
998                                            &compile_value_container(
999                                                &slot_value,
1000                                            ),
1001                                        );
1002                                    }
1003                                    buffer.extend_from_slice(
1004                                        &exec_block_data.body,
1005                                    );
1006
1007                                    let receivers = yield_unwrap!(
1008                                        collected_results
1009                                            .pop_cloned_value_container_result_assert_existing(&state)
1010                                    );
1011
1012                                    interrupt_with_maybe_value!(
1013                                        interrupt_provider,
1014                                        ExecutionInterrupt::External(
1015                                            ExternalExecutionInterrupt::RemoteExecution(
1016                                                receivers, buffer
1017                                            )
1018                                        )
1019                                    )
1020                                        .map(|val| RuntimeValue::ValueContainer(val))
1021                                        .into()
1022                                }
1023
1024                                RegularInstruction::Apply(ApplyData {
1025                                    ..
1026                                }) => {
1027                                    let mut args = yield_unwrap!(collected_results.collect_value_container_results_assert_existing(&state));
1028                                    // last argument is the callee
1029                                    let callee = args.remove(args.len() - 1);
1030                                    interrupt_with_maybe_value!(
1031                                        interrupt_provider,
1032                                        ExecutionInterrupt::External(
1033                                            ExternalExecutionInterrupt::Apply(
1034                                                callee, args
1035                                            )
1036                                        )
1037                                    )
1038                                    .map(|val| {
1039                                        RuntimeValue::ValueContainer(val)
1040                                    })
1041                                    .into()
1042                                }
1043
1044                                RegularInstruction::UnboundedStatementsEnd(
1045                                    terminated,
1046                                ) => {
1047                                    let result = yield_unwrap!(collector.try_pop_unbounded().ok_or(DXBParserError::NotInUnboundedRegularScopeError));
1048                                    if let FullOrPartialResult::Partial(
1049                                        _,
1050                                        mut collected_result,
1051                                    ) = result
1052                                    {
1053                                        if terminated {
1054                                            CollectedExecutionResult::Value(
1055                                                None,
1056                                            )
1057                                        } else {
1058                                            match collected_result {
1059                                                Some(CollectedExecutionResult::Value(val)) => val.into(),
1060                                                None => CollectedExecutionResult::Value(None),
1061                                                _ => unreachable!(),
1062                                            }
1063                                        }
1064                                    } else {
1065                                        unreachable!()
1066                                    }
1067                                }
1068
1069                                e => {
1070                                    todo!(
1071                                        "Unhandled collected regular instruction: {:?}",
1072                                        e
1073                                    );
1074                                }
1075                            },
1076
1077                            Instruction::TypeInstruction(type_instruction) => {
1078                                match type_instruction {
1079                                    TypeInstruction::ImplType(
1080                                        impl_type_data,
1081                                    ) => {
1082                                        let mutability: Option<
1083                                            ReferenceMutability,
1084                                        > = impl_type_data
1085                                            .metadata
1086                                            .mutability
1087                                            .into();
1088                                        let base_type =
1089                                            collected_results.pop_type_result();
1090                                        Type::new(
1091                                            TypeDefinition::ImplType(
1092                                                Box::new(base_type),
1093                                                impl_type_data
1094                                                    .impls
1095                                                    .iter()
1096                                                    .map(PointerAddress::from)
1097                                                    .collect(),
1098                                            ),
1099                                            mutability.clone(),
1100                                        )
1101                                        .into()
1102                                    }
1103                                    _ => todo!("#649 Undescribed by author."),
1104                                }
1105                            }
1106                        }
1107                    }
1108                    FullOrPartialResult::Partial(
1109                        instruction,
1110                        collected_result,
1111                    ) => match instruction {
1112                        Instruction::RegularInstruction(
1113                            regular_instruction,
1114                        ) => match regular_instruction {
1115                            RegularInstruction::Statements(statements_data) => {
1116                                if statements_data.terminated {
1117                                    CollectedExecutionResult::Value(None)
1118                                } else {
1119                                    match collected_result {
1120                                        Some(
1121                                            CollectedExecutionResult::Value(
1122                                                val,
1123                                            ),
1124                                        ) => val.into(),
1125                                        None => {
1126                                            CollectedExecutionResult::Value(
1127                                                None,
1128                                            )
1129                                        }
1130                                        _ => unreachable!(),
1131                                    }
1132                                }
1133                            }
1134                            _ => unreachable!(),
1135                        },
1136
1137                        Instruction::TypeInstruction(data) => unreachable!(),
1138                    },
1139                };
1140
1141                collector.push_result(expr);
1142            }
1143
1144            // if in unbounded statements, propagate active value via interrupt
1145            if let Some(ResultCollector::LastUnbounded(
1146                LastUnboundedResultCollector {
1147                    last_result:
1148                        Some(CollectedExecutionResult::Value(last_result)),
1149                    ..
1150                },
1151            )) = collector.last()
1152            {
1153                let active_value = yield_unwrap!(
1154                    last_result
1155                        .clone()
1156                        .map(|v| v.into_cloned_value_container(&state))
1157                        .transpose()
1158                );
1159
1160                interrupt!(
1161                    interrupt_provider,
1162                    ExecutionInterrupt::SetActiveValue(active_value)
1163                );
1164            }
1165        }
1166
1167        if let Some(result) = collector.take_root_result() {
1168            yield Ok(ExecutionInterrupt::External(
1169                ExternalExecutionInterrupt::Result(match result {
1170                    CollectedExecutionResult::Value(value) => {
1171                        let value = yield_unwrap!(
1172                            value
1173                                .map(|v| v.into_cloned_value_container(&state))
1174                                .transpose()
1175                        );
1176
1177                        value
1178                    }
1179                    _ => unreachable!("Expected root result"),
1180                }),
1181            ));
1182        } else {
1183            panic!("Execution finished without root result");
1184        }
1185    }
1186}