1use std::{
2 mem,
3 cell::RefCell,
4 cmp::Ordering,
5 rc::Rc,
6};
7
8use crate::common::data::Data;
9
10use crate::vm::{
11 tag::Tagged,
12 slot::{Slot, Suspend},
13};
14
15#[derive(Debug)]
23pub struct Stack {
24 pub frames: Vec<usize>,
25 pub stack: Vec<Tagged>
26}
27
28impl Stack {
29 pub fn init() -> Stack {
31 Stack {
32 frames: vec![0],
33 stack: vec![Tagged::frame()],
34 }
35 }
36
37 #[inline]
39 fn frame_index(&self) -> usize {
40 *self.frames.last().unwrap()
41 }
42
43 #[inline]
45 fn pop(&mut self) -> Tagged {
46 self.stack.pop()
47 .expect("VM tried to pop empty stack, stack should never be empty")
48 }
49
50 #[inline]
52 fn swap(&mut self, index: usize, tagged: Tagged) -> Tagged {
53 mem::replace(&mut self.stack[index], tagged)
54 }
55
56 #[inline]
58 pub fn push_data(&mut self, data: Data) {
59 self.stack.push(Tagged::new(Slot::Data(data)))
60 }
61
62 #[inline]
64 pub fn push_tagged(&mut self, tagged: Tagged) {
65 self.stack.push(tagged)
66 }
67
68 #[inline]
71 pub fn pop_data(&mut self) -> Data {
72 let value = self.stack.pop()
73 .expect("VM tried to pop empty stack, stack should never be empty");
74
75 match value.slot().data() {
76 Data::Heaped(h) => h.borrow().clone(),
77 d => d,
78 }
79 }
80
81 #[inline]
84 pub fn pop_frame(&mut self) -> Suspend {
85 if let Slot::Frame = self.pop().slot() {} else {
86 unreachable!("Expected frame on top of stack");
87 }
88
89 self.frames.pop();
90 let old_slot = self.swap(self.frame_index(), Tagged::frame()).slot();
91
92 if let Slot::Suspend(s) = old_slot {
93 s
94 } else {
95 unreachable!("Expected frame on top of stack");
96 }
97 }
98
99 #[inline]
102 pub fn push_frame(&mut self, suspend: Suspend) {
103 let frame_index = self.frame_index();
104 self.stack[frame_index] = Tagged::new(Slot::Suspend(suspend));
105 self.frames.push(self.stack.len());
106 self.stack.push(Tagged::frame());
107 }
108
109 #[inline]
111 pub fn push_not_init(&mut self) {
112 self.stack.push(Tagged::not_init());
113 }
114
115 #[inline]
117 pub fn declare(&mut self, decls: usize) {
118 for _ in 0..decls { self.push_not_init(); }
119 }
120
121 #[inline]
124 pub fn heapify(&mut self, index: usize) {
125 let local_index = self.frame_index() + index + 1;
126
127 let data = self.swap(local_index, Tagged::not_init()).slot().data();
128 let heaped = Slot::Data(Data::Heaped(Rc::new(RefCell::new(data))));
129 mem::drop(mem::replace(&mut self.stack[local_index], Tagged::new(heaped)));
130 }
131
132 #[inline]
135 pub fn unwind_frame(&mut self) -> bool {
136 self.stack.truncate(self.frame_index() + 1);
137 self.frames.len() > 1
138 }
139
140 pub fn local_slot(&mut self, index: usize) -> Slot {
142 let local_index = self.frame_index() + index + 1;
143
144 let slot = self.swap(local_index, Tagged::not_init()).slot();
147 let copy = slot.clone();
148 mem::drop(self.swap(local_index, Tagged::new(slot)));
149
150 copy
151 }
152
153 pub fn local_data(&mut self, index: usize) -> Data {
155 let local_index = self.frame_index() + index + 1;
156
157 let data = self.swap(local_index, Tagged::not_init()).slot().data();
160 let copy = data.clone();
161 mem::drop(self.swap(local_index, Tagged::new(Slot::Data(data))));
162
163 copy
164 }
165
166 pub fn set_local(&mut self, index: usize) {
171 let local_index = self.frame_index() + index + 1;
172
173 match (self.stack.len() - 1).cmp(&local_index) {
174 Ordering::Greater => {
175 let slot = self.swap(local_index, Tagged::not_init()).slot();
177
178 let tagged = match slot {
180 Slot::Frame => unreachable!("Expected data, found frame"),
181 Slot::Data(Data::Heaped(ref cell)) => {
183 mem::drop(cell.replace(self.pop_data()));
185 Tagged::new(slot)
186 }
187 _ => self.stack.pop().unwrap(),
190 };
191
192 mem::drop(self.swap(local_index, tagged))
193 },
194 Ordering::Less => {
195 unreachable!("Can not set local that is not yet on stack");
197 },
198 _ => {
199 }
201 }
202 }
203}