Skip to main content

compiler/
vm.rs

1use std::borrow::Borrow;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use byteorder::{BigEndian, ByteOrder};
6use object::builtins::BuiltIns;
7
8use object::Object::ClosureObj;
9use object::{BuiltinFunc, Closure, CompiledFunction, Object};
10
11use crate::compiler::Bytecode;
12use crate::frame::Frame;
13use crate::op_code::{cast_u8_to_opcode, Opcode};
14
15const STACK_SIZE: usize = 2048;
16pub const GLOBAL_SIZE: usize = 65536;
17const MAX_FRAMES: usize = 1024;
18
19pub struct VM {
20    constants: Vec<Rc<Object>>,
21
22    stack: Vec<Rc<Object>>,
23    sp: usize, // stack pointer. Always point to the next value. Top of the stack is stack[sp -1]
24
25    pub globals: Vec<Rc<Object>>,
26
27    frames: Vec<Frame>,
28    frame_index: usize,
29}
30
31impl VM {
32    pub fn new(bytecode: Bytecode) -> VM {
33        // it's rust, it's verbose. You can't just grow your vector size.
34        let empty_frame = Frame::new(
35            Closure {
36                func: Rc::from(object::CompiledFunction {
37                    instructions: vec![],
38                    num_locals: 0,
39                    num_parameters: 0,
40                }),
41                free: vec![],
42            },
43            0,
44        );
45
46        let main_fn = Rc::from(object::CompiledFunction {
47            instructions: bytecode.instructions.data,
48            num_locals: 0,
49            num_parameters: 0,
50        });
51        let main_closure = Closure {
52            func: main_fn,
53            free: vec![],
54        };
55        let main_frame = Frame::new(main_closure, 0);
56        let mut frames = vec![empty_frame; MAX_FRAMES];
57        frames[0] = main_frame;
58
59        return VM {
60            constants: bytecode.constants,
61            stack: vec![Rc::new(Object::Null); STACK_SIZE],
62            sp: 0,
63            globals: vec![Rc::new(Object::Null); GLOBAL_SIZE],
64            frames,
65            frame_index: 1,
66        };
67    }
68
69    pub fn new_with_global_store(bytecode: Bytecode, globals: Vec<Rc<Object>>) -> VM {
70        let mut vm = VM::new(bytecode);
71        vm.globals = globals;
72        return vm;
73    }
74
75    pub fn run(&mut self) {
76        let mut ip = 0;
77        let mut ins: Vec<u8>;
78        while self.current_frame().ip
79            < self.current_frame().instructions().data.clone().len() as i32 - 1
80        {
81            self.current_frame().ip += 1;
82            ip = self.current_frame().ip as usize;
83            ins = self.current_frame().instructions().data.clone();
84
85            let op: u8 = *ins.get(ip).unwrap();
86            let opcode = cast_u8_to_opcode(op);
87
88            match opcode {
89                Opcode::OpConst => {
90                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
91                    self.current_frame().ip += 2;
92                    self.push(Rc::clone(&self.constants[const_index]))
93                }
94                Opcode::OpAdd | Opcode::OpSub | Opcode::OpMul | Opcode::OpDiv => {
95                    self.execute_binary_operation(opcode);
96                }
97                Opcode::OpPop => {
98                    self.pop();
99                }
100                Opcode::OpTrue => {
101                    self.push(Rc::new(Object::Boolean(true)));
102                }
103                Opcode::OpFalse => {
104                    self.push(Rc::new(Object::Boolean(false)));
105                }
106                Opcode::OpEqual | Opcode::OpNotEqual | Opcode::OpGreaterThan => {
107                    self.execute_comparison(opcode);
108                }
109                Opcode::OpMinus => {
110                    self.execute_minus_operation(opcode);
111                }
112                Opcode::OpBang => {
113                    self.execute_bang_operation();
114                }
115                Opcode::OpJump => {
116                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
117                    self.current_frame().ip = pos as i32 - 1;
118                }
119                Opcode::OpJumpNotTruthy => {
120                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
121                    self.current_frame().ip += 2;
122                    let condition = self.pop();
123                    if !self.is_truthy(condition) {
124                        self.current_frame().ip = pos as i32 - 1;
125                    }
126                }
127                Opcode::OpNull => {
128                    self.push(Rc::new(Object::Null));
129                }
130                Opcode::OpGetGlobal => {
131                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
132                    self.current_frame().ip += 2;
133                    self.push(Rc::clone(&self.globals[global_index]));
134                }
135                Opcode::OpSetGlobal => {
136                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
137                    self.current_frame().ip += 2;
138                    self.globals[global_index] = self.pop();
139                }
140                Opcode::OpArray => {
141                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
142                    self.current_frame().ip += 2;
143                    let elements = self.build_array(self.sp - count, self.sp);
144                    self.sp = self.sp - count;
145                    self.push(Rc::new(Object::Array(elements)));
146                }
147                Opcode::OpHash => {
148                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
149                    self.current_frame().ip += 2;
150                    let elements = self.build_hash(self.sp - count, self.sp);
151                    self.sp = self.sp - count;
152                    self.push(Rc::new(Object::Hash(elements)));
153                }
154                Opcode::OpIndex => {
155                    let index = self.pop();
156                    let left = self.pop();
157                    self.execute_index_operation(left, index);
158                }
159                Opcode::OpReturnValue => {
160                    let return_value = self.pop();
161                    let frame = self.pop_frame();
162                    self.sp = frame.base_pointer - 1;
163                    self.push(return_value);
164                }
165                Opcode::OpReturn => {
166                    let frame = self.pop_frame();
167                    self.sp = frame.base_pointer - 1;
168                    self.push(Rc::new(object::Object::Null));
169                }
170                Opcode::OpCall => {
171                    let num_args = ins[ip + 1] as usize;
172                    self.current_frame().ip += 1;
173                    self.execute_call(num_args);
174                }
175                Opcode::OpSetLocal => {
176                    let local_index = ins[ip + 1] as usize;
177                    self.current_frame().ip += 1;
178                    let base = self.current_frame().base_pointer;
179                    self.stack[base + local_index] = self.pop();
180                }
181                Opcode::OpGetLocal => {
182                    let local_index = ins[ip + 1] as usize;
183                    self.current_frame().ip += 1;
184                    let base = self.current_frame().base_pointer;
185                    self.push(Rc::clone(&self.stack[base + local_index]));
186                }
187                Opcode::OpGetBuiltin => {
188                    let built_index = ins[ip + 1] as usize;
189                    self.current_frame().ip += 1;
190                    let definition = BuiltIns.get(built_index).unwrap().1;
191                    self.push(Rc::new(Object::Builtin(definition)));
192                }
193                Opcode::OpClosure => {
194                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
195                    let num_free = ins[ip + 3] as usize;
196                    self.current_frame().ip += 3;
197                    self.push_closure(const_index, num_free);
198                }
199                Opcode::OpGetFree => {
200                    let free_index = ins[ip + 1] as usize;
201                    self.current_frame().ip += 1;
202                    let current_closure = self.current_frame().cl.clone();
203                    self.push(current_closure.free[free_index].clone());
204                }
205                Opcode::OpCurrentClosure => {
206                    let current_closure = self.current_frame().cl.clone();
207                    self.push(Rc::new(Object::ClosureObj(current_closure)));
208                }
209            }
210        }
211    }
212
213    fn execute_binary_operation(&mut self, opcode: Opcode) {
214        let right = self.pop();
215        let left = self.pop();
216        match (left.borrow(), right.borrow()) {
217            (Object::Integer(l), Object::Integer(r)) => {
218                let result = match opcode {
219                    Opcode::OpAdd => l + r,
220                    Opcode::OpSub => l - r,
221                    Opcode::OpMul => l * r,
222                    Opcode::OpDiv => l / r,
223                    _ => panic!("Unknown opcode for int"),
224                };
225                self.push(Rc::from(Object::Integer(result)));
226            }
227            (Object::String(l), Object::String(r)) => {
228                let result = match opcode {
229                    Opcode::OpAdd => l.to_string() + &r.to_string(),
230                    _ => panic!("Unknown opcode for string"),
231                };
232                self.push(Rc::from(Object::String(result)));
233            }
234            _ => {
235                panic!("unsupported add for those types")
236            }
237        }
238    }
239
240    fn execute_comparison(&mut self, opcode: Opcode) {
241        let right = self.pop();
242        let left = self.pop();
243        match (left.borrow(), right.borrow()) {
244            (Object::Integer(l), Object::Integer(r)) => {
245                let result = match opcode {
246                    Opcode::OpEqual => l == r,
247                    Opcode::OpNotEqual => l != r,
248                    Opcode::OpGreaterThan => l > r,
249                    _ => panic!("Unknown opcode for comparing int"),
250                };
251                self.push(Rc::from(Object::Boolean(result)));
252            }
253            (Object::Boolean(l), Object::Boolean(r)) => {
254                let result = match opcode {
255                    Opcode::OpEqual => l == r,
256                    Opcode::OpNotEqual => l != r,
257                    _ => panic!("Unknown opcode for comparing boolean"),
258                };
259                self.push(Rc::from(Object::Boolean(result)));
260            }
261            _ => {
262                panic!("unsupported comparison for those types")
263            }
264        }
265    }
266
267    fn execute_minus_operation(&mut self, opcode: Opcode) {
268        let operand = self.pop();
269        match operand.borrow() {
270            Object::Integer(l) => {
271                self.push(Rc::from(Object::Integer(-*l)));
272            }
273            _ => {
274                panic!("unsupported types for negation {:?}", opcode)
275            }
276        }
277    }
278    fn execute_bang_operation(&mut self) {
279        let operand = self.pop();
280        match operand.borrow() {
281            Object::Boolean(l) => {
282                self.push(Rc::from(Object::Boolean(!*l)));
283            }
284            _ => {
285                self.push(Rc::from(Object::Boolean(false)));
286            }
287        }
288    }
289
290    pub fn last_popped_stack_elm(&self) -> Option<Rc<Object>> {
291        self.stack.get(self.sp).cloned()
292    }
293
294    fn pop(&mut self) -> Rc<Object> {
295        let o = Rc::clone(&self.stack[self.sp - 1]);
296        self.sp -= 1;
297        return o;
298    }
299
300    fn push(&mut self, o: Rc<Object>) {
301        if self.sp >= STACK_SIZE {
302            panic!("Stack overflow");
303        };
304        self.stack[self.sp] = o;
305        self.sp += 1;
306    }
307    fn is_truthy(&self, condition: Rc<Object>) -> bool {
308        match condition.borrow() {
309            Object::Boolean(b) => *b,
310            Object::Null => false,
311            _ => true,
312        }
313    }
314    fn build_array(&self, start: usize, end: usize) -> Vec<Rc<Object>> {
315        let mut elements = Vec::with_capacity(end - start);
316        for i in start..end {
317            elements.push(Rc::clone(&self.stack[i]));
318        }
319        return elements;
320    }
321
322    fn build_hash(&self, start: usize, end: usize) -> HashMap<Rc<Object>, Rc<Object>> {
323        let mut elements = HashMap::new();
324        for i in (start..end).step_by(2) {
325            let key = Rc::clone(&self.stack[i]);
326            let value = Rc::clone(&self.stack[i + 1]);
327            elements.insert(key, value);
328        }
329        return elements;
330    }
331
332    fn execute_index_operation(&mut self, left: Rc<Object>, index: Rc<Object>) {
333        match (left.borrow(), index.borrow()) {
334            (Object::Array(l), Object::Integer(i)) => {
335                self.execute_array_index(l, *i);
336            }
337            (Object::Hash(l), _) => {
338                self.execute_hash_index(l, index);
339            }
340            _ => {
341                panic!("unsupported index operation for those types")
342            }
343        }
344    }
345
346    fn execute_array_index(&mut self, array: &Vec<Rc<Object>>, index: i64) {
347        if index < array.len() as i64 && index >= 0 {
348            self.push(Rc::clone(&array[index as usize]));
349        } else {
350            self.push(Rc::new(Object::Null));
351        }
352    }
353
354    fn execute_hash_index(&mut self, hash: &HashMap<Rc<Object>, Rc<Object>>, index: Rc<Object>) {
355        match &*index {
356            Object::Integer(_) | Object::Boolean(_) | Object::String(_) => match hash.get(&index) {
357                Some(el) => {
358                    self.push(Rc::clone(el));
359                }
360                None => {
361                    self.push(Rc::new(Object::Null));
362                }
363            },
364            _ => {
365                panic!("unsupported hash index operation for those types {}", index)
366            }
367        }
368    }
369
370    fn current_frame(&mut self) -> &mut Frame {
371        &mut self.frames[self.frame_index - 1]
372    }
373
374    fn push_frame(&mut self, frame: Frame) {
375        self.frames[self.frame_index] = frame;
376        self.frame_index += 1;
377    }
378
379    fn pop_frame(&mut self) -> Frame {
380        self.frame_index -= 1;
381        return self.frames[self.frame_index].clone();
382    }
383
384    fn execute_call(&mut self, num_args: usize) {
385        let callee = &*self.stack[self.sp - 1 - num_args];
386        match callee {
387            Object::ClosureObj(cf) => {
388                self.call_closure(cf.clone(), num_args);
389            }
390            Object::Builtin(bt) => {
391                self.call_builtin(bt.clone(), num_args);
392            }
393            _ => {
394                panic!("calling non-closure")
395            }
396        }
397    }
398    fn call_closure(&mut self, cl: Closure, num_args: usize) {
399        if cl.func.num_parameters != num_args {
400            panic!("wrong number of arguments: want={}, got={}", cl.func.num_parameters, num_args);
401        }
402
403        let frame = Frame::new(cl.clone(), self.sp - num_args);
404        self.sp = frame.base_pointer + cl.func.num_locals;
405        self.push_frame(frame);
406    }
407
408    fn call_builtin(&mut self, bt: BuiltinFunc, num_args: usize) {
409        let args = self.stack[self.sp - num_args..self.sp].to_vec();
410        let result = bt(args);
411        self.sp = self.sp - num_args - 1;
412        self.push(result);
413    }
414
415    fn push_closure(&mut self, const_index: usize, num_free: usize) {
416        match &*self.constants[const_index] {
417            Object::CompiledFunction(f) => {
418                let mut free = Vec::with_capacity(num_free);
419                for i in 0..num_free {
420                    let f = self.stack[self.sp - num_free + i].clone();
421                    free.push(f);
422                }
423                self.sp = self.sp - num_free;
424                let closure = ClosureObj(Closure {
425                    func: f.clone(),
426                    free,
427                });
428                self.push(Rc::new(closure));
429            }
430            o => {
431                panic!("not a function {}", o);
432            }
433        }
434    }
435}