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