1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::{
mem,
rc::Rc,
cell::RefCell
};
use crate::common::data::Data;
use crate::vm::{
tag::Tagged,
linked::Linked,
};
#[derive(Debug)]
pub struct Stack {
pub frames: Linked,
pub stack: Vec<Tagged>
}
impl Stack {
pub fn init() -> Stack {
Stack {
frames: Linked::new(0),
stack: vec![Tagged::frame()],
}
}
#[inline]
pub fn push_data(&mut self, data: Data) {
self.stack.push(Tagged::new(data))
}
#[inline]
pub fn push_tagged(&mut self, tagged: Tagged) {
self.stack.push(tagged)
}
#[inline]
pub fn pop_data(&mut self) -> Data {
let value = self.stack.pop()
.expect("VM tried to pop empty stack, stack should never be empty");
match value.data() {
Data::Frame => unreachable!("tried to pop data, Frame is not data"),
Data::Heaped(r) => r.borrow().clone(),
data => data,
}
}
#[inline]
pub fn pop_frame(&mut self) {
let index = self.frames.prepop();
if self.stack.len() - 1 == index {
self.stack.pop();
} else {
unreachable!("Expected frame on top of stack, found data")
}
}
#[inline]
pub fn push_frame(&mut self) {
self.frames.prepend(self.stack.len());
self.stack.push(Tagged::frame());
}
#[inline]
pub fn heapify(&mut self, index: usize) -> Rc<RefCell<Data>> {
let local_index = self.frames.peek() + index + 1;
let data = mem::replace(&mut self.stack[local_index], Tagged::frame()).data();
let reference = Rc::new(RefCell::new(data));
let heaped = Data::Heaped(reference.clone());
mem::drop(mem::replace(&mut self.stack[local_index], Tagged::new(heaped)));
return reference;
}
pub fn get_local(&mut self, index: usize) {
let local_index = self.frames.peek() + index + 1;
let data = mem::replace(&mut self.stack[local_index], Tagged::frame()).data();
let copy = data.clone();
mem::drop(mem::replace(&mut self.stack[local_index], Tagged::new(data)));
self.push_data(copy);
}
pub fn set_local(&mut self, index: usize) {
let local_index = self.frames.peek() + index + 1;
if self.stack.len() - 1 == local_index {
return;
} else if self.stack.len() <= local_index {
unreachable!("Can not set local that is not yet on stack");
} else {
let data = mem::replace(&mut self.stack[local_index], Tagged::frame()).data();
let tagged = match data {
Data::Frame => unreachable!(),
Data::Heaped(ref cell) => {
mem::drop(cell.replace(self.pop_data()));
Tagged::new(data)
}
_ => self.stack.pop().unwrap(),
};
mem::drop(mem::replace(&mut self.stack[local_index], tagged))
}
}
}