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}