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