Skip to main content

datex_core/runtime/execution/execution_loop/
mod.rs

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