swamp_vm/
range.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::{Vm, get_reg, i16_from_u8s, set_reg};
6use std::ptr;
7use swamp_vm_isa::{RangeHeader, RangeIterator};
8
9impl Vm {
10    #[inline]
11    #[must_use]
12    pub fn get_range_header_ptr_from_reg(&self, range_reg: u8) -> *mut RangeHeader {
13        self.get_ptr_from_reg(range_reg) as *mut RangeHeader
14    }
15
16    #[inline]
17    #[must_use]
18    pub fn range_header_from_reg(&self, range_reg: u8) -> RangeHeader {
19        unsafe { *(self.get_const_ptr_from_reg(range_reg) as *const RangeHeader) }
20    }
21
22    pub fn range_iterator_ptr_from_reg(&self, range_iterator_reg: u8) -> *mut RangeIterator {
23        self.get_ptr_from_reg(range_iterator_reg) as *mut RangeIterator
24    }
25
26    #[inline]
27    pub fn execute_range_init(
28        &mut self,
29        range_target_reg: u8,
30        min_reg: u8,
31        max_reg: u8,
32        is_inclusive: u8,
33    ) {
34        let range_header = self.get_range_header_ptr_from_reg(range_target_reg);
35
36        unsafe {
37            (*range_header).min = get_reg!(self, min_reg) as i32;
38            (*range_header).max = get_reg!(self, max_reg) as i32;
39            (*range_header).inclusive = get_reg!(self, is_inclusive) as i32 != 0;
40        }
41    }
42
43    #[inline]
44    pub fn execute_range_iter_init(&mut self, target_iterator_reg: u8, range_header_reg: u8) {
45        let range_header = self.range_header_from_reg(range_header_reg);
46
47        let extra = i32::from(range_header.inclusive);
48
49        let (start, end, direction) = if range_header.min <= range_header.max {
50            // Ascending range: [min, max] or [min, max)
51            (
52                range_header.min,
53                range_header.max + extra, // End is one past max for inclusive, or exactly max for exclusive
54                1,
55            )
56        } else {
57            // Descending range: [min, max] or [min, max)
58            // Here, min is the starting higher value, max is the ending lower value
59            (
60                range_header.min,
61                range_header.max - extra, // End is one below max for inclusive, or exactly max for exclusive
62                -1,
63            )
64        };
65
66        #[cfg(feature = "debug_vm")]
67        {}
68
69        let iterator_target_ptr = self.range_iterator_ptr_from_reg(target_iterator_reg);
70
71        unsafe {
72            let range_iterator = RangeIterator {
73                index: start,
74                end,
75                direction,
76            };
77
78            ptr::write(iterator_target_ptr, range_iterator);
79        }
80    }
81
82    #[inline]
83    pub fn execute_range_iter_next(
84        &mut self,
85        target_iterator_reg: u8,
86        target_int_reg: u8,
87        jmp_offset_lower: u8,
88        jmp_offset_upper: u8,
89    ) {
90        let range_iterator = self.range_iterator_ptr_from_reg(target_iterator_reg);
91        unsafe {
92            #[cfg(feature = "debug_vm")]
93            {
94                if self.debug_operations_enabled {
95                    eprintln!(
96                        "range_iterator: index={}, end={}, direction={}",
97                        (*range_iterator).index,
98                        (*range_iterator).end,
99                        (*range_iterator).direction
100                    );
101                }
102            }
103
104            if (*range_iterator).index == (*range_iterator).end {
105                let jump_offset = i16_from_u8s!(jmp_offset_lower, jmp_offset_upper);
106                #[cfg(feature = "debug_vm")]
107                {
108                    if self.debug_operations_enabled {
109                        eprintln!("range_iter_next complete. jumping with offset {jump_offset}");
110                    }
111                }
112                self.pc = (self.pc as i32 + jump_offset as i32) as usize;
113            } else {
114                set_reg!(self, target_int_reg, (*range_iterator).index);
115                (*range_iterator).index += (*range_iterator).direction;
116            }
117        }
118    }
119}