Skip to main content

compiler/
vm.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt;
4use std::rc::Rc;
5
6use byteorder::{BigEndian, ByteOrder};
7use object::builtins::BuiltIns;
8
9use object::Object::ClosureObj;
10use object::{BoundMethodObject, BuiltinFunc, ClassObject, Closure, InstanceObject, Object};
11
12use crate::compiler::Bytecode;
13use crate::frame::Frame;
14use crate::op_code::Opcode;
15
16const STACK_SIZE: usize = 2048;
17pub const GLOBAL_SIZE: usize = 65536;
18const MAX_FRAMES: usize = 1024;
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
21pub enum VmRuntimeErrorKind {
22    Arithmetic,
23    Call,
24    Index,
25    Property,
26    Stack,
27    Type,
28}
29
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct VmRuntimeError {
32    pub kind: VmRuntimeErrorKind,
33    pub message: String,
34}
35
36impl VmRuntimeError {
37    fn new(kind: VmRuntimeErrorKind, message: impl Into<String>) -> Self {
38        Self {
39            kind,
40            message: message.into(),
41        }
42    }
43}
44
45impl fmt::Display for VmRuntimeError {
46    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47        formatter.write_str(&self.message)
48    }
49}
50
51impl std::error::Error for VmRuntimeError {}
52
53type VmResult<T> = Result<T, VmRuntimeError>;
54
55pub struct VM {
56    constants: Vec<Rc<Object>>,
57
58    stack: Vec<Rc<Object>>,
59    sp: usize, // stack pointer. Always point to the next value. Top of the stack is stack[sp -1]
60
61    pub globals: Vec<Rc<Object>>,
62
63    frames: Vec<Frame>,
64    frame_index: usize,
65    last_error: Option<VmRuntimeError>,
66}
67
68impl VM {
69    pub fn new(bytecode: Bytecode) -> VM {
70        // it's rust, it's verbose. You can't just grow your vector size.
71        let empty_frame = Frame::new(
72            Closure {
73                func: Rc::from(object::CompiledFunction {
74                    name: String::new(),
75                    instructions: vec![],
76                    num_locals: 0,
77                    num_parameters: 0,
78                }),
79                free: vec![],
80            },
81            0,
82        );
83
84        let main_fn = Rc::from(object::CompiledFunction {
85            name: String::new(),
86            instructions: bytecode.instructions.data,
87            num_locals: 0,
88            num_parameters: 0,
89        });
90        let main_closure = Closure {
91            func: main_fn,
92            free: vec![],
93        };
94        let main_frame = Frame::new(main_closure, 0);
95        let mut frames = vec![empty_frame; MAX_FRAMES];
96        frames[0] = main_frame;
97
98        let null = Rc::new(Object::Null);
99        return VM {
100            constants: bytecode.constants,
101            stack: vec![Rc::clone(&null); STACK_SIZE],
102            sp: 0,
103            globals: vec![null; GLOBAL_SIZE],
104            frames,
105            frame_index: 1,
106            last_error: None,
107        };
108    }
109
110    pub fn new_with_global_store(bytecode: Bytecode, globals: Vec<Rc<Object>>) -> VM {
111        let mut vm = VM::new(bytecode);
112        vm.globals = globals;
113        return vm;
114    }
115
116    /// Run bytecode while retaining the error for callers of the original API.
117    /// New code should prefer [`Self::run_checked`] so failures cannot be ignored.
118    pub fn run(&mut self) {
119        let _ = self.run_checked();
120    }
121
122    pub fn run_checked(&mut self) -> VmResult<()> {
123        self.last_error = None;
124        let result = self.run_inner();
125        if let Err(error) = &result {
126            self.last_error = Some(error.clone());
127        }
128        result
129    }
130
131    pub fn last_error(&self) -> Option<&VmRuntimeError> {
132        self.last_error.as_ref()
133    }
134
135    fn run_inner(&mut self) -> VmResult<()> {
136        let mut ip: usize;
137        let mut ins: Vec<u8>;
138        while self.current_frame().ip
139            < self.current_frame().instructions().data.clone().len() as i32 - 1
140        {
141            self.current_frame().ip += 1;
142            ip = self.current_frame().ip as usize;
143            ins = self.current_frame().instructions().data.clone();
144
145            let op: u8 = *ins.get(ip).unwrap();
146            let opcode = Opcode::from_repr(op).expect("unknown opcode in compiled bytecode");
147
148            match opcode {
149                Opcode::OpConst => {
150                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
151                    self.current_frame().ip += 2;
152                    self.push(Rc::clone(&self.constants[const_index]))?;
153                }
154                Opcode::OpAdd | Opcode::OpSub | Opcode::OpMul | Opcode::OpDiv => {
155                    self.execute_binary_operation(opcode)?;
156                }
157                Opcode::OpPop => {
158                    self.pop();
159                }
160                Opcode::OpTrue => {
161                    self.push(Rc::new(Object::Boolean(true)))?;
162                }
163                Opcode::OpFalse => {
164                    self.push(Rc::new(Object::Boolean(false)))?;
165                }
166                Opcode::OpEqual
167                | Opcode::OpNotEqual
168                | Opcode::OpGreaterThan
169                | Opcode::OpLessThan => {
170                    self.execute_comparison(opcode)?;
171                }
172                Opcode::OpMinus => {
173                    self.execute_minus_operation(opcode)?;
174                }
175                Opcode::OpBang => {
176                    self.execute_bang_operation()?;
177                }
178                Opcode::OpJump => {
179                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
180                    self.current_frame().ip = pos as i32 - 1;
181                }
182                Opcode::OpJumpNotTruthy => {
183                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
184                    self.current_frame().ip += 2;
185                    let condition = self.pop();
186                    if !self.is_truthy(condition) {
187                        self.current_frame().ip = pos as i32 - 1;
188                    }
189                }
190                Opcode::OpNull => {
191                    self.push(Rc::new(Object::Null))?;
192                }
193                Opcode::OpGetGlobal => {
194                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
195                    self.current_frame().ip += 2;
196                    self.push(Rc::clone(&self.globals[global_index]))?;
197                }
198                Opcode::OpSetGlobal => {
199                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
200                    self.current_frame().ip += 2;
201                    self.globals[global_index] = self.pop();
202                }
203                Opcode::OpArray => {
204                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
205                    self.current_frame().ip += 2;
206                    let elements = self.build_array(self.sp - count, self.sp);
207                    self.sp -= count;
208                    self.push(Rc::new(Object::Array(elements)))?;
209                }
210                Opcode::OpHash => {
211                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
212                    self.current_frame().ip += 2;
213                    #[allow(clippy::mutable_key_type)]
214                    let elements = self.build_hash(self.sp - count, self.sp)?;
215                    self.sp -= count;
216                    self.push(Rc::new(Object::Hash(elements)))?;
217                }
218                Opcode::OpIndex => {
219                    let index = self.pop();
220                    let left = self.pop();
221                    self.execute_index_operation(left, index)?;
222                }
223                Opcode::OpReturnValue => {
224                    let return_value = self.pop();
225                    if self.frame_index == 1 {
226                        // A top-level return ends the program with this value
227                        // as its result, matching the interpreter backend.
228                        self.stack[0] = return_value;
229                        self.sp = 0;
230                        break;
231                    }
232                    let frame = self.pop_frame();
233                    self.sp = frame.base_pointer - 1;
234                    self.push(return_value)?;
235                }
236                Opcode::OpReturn => {
237                    if self.frame_index == 1 {
238                        self.stack[0] = Rc::new(object::Object::Null);
239                        self.sp = 0;
240                        break;
241                    }
242                    let frame = self.pop_frame();
243                    self.sp = frame.base_pointer - 1;
244                    self.push(Rc::new(object::Object::Null))?;
245                }
246                Opcode::OpCall => {
247                    let num_args = ins[ip + 1] as usize;
248                    self.current_frame().ip += 1;
249                    self.execute_call(num_args)?;
250                }
251                Opcode::OpSetLocal => {
252                    let local_index = ins[ip + 1] as usize;
253                    self.current_frame().ip += 1;
254                    let base = self.current_frame().base_pointer;
255                    self.stack[base + local_index] = self.pop();
256                }
257                Opcode::OpGetLocal => {
258                    let local_index = ins[ip + 1] as usize;
259                    self.current_frame().ip += 1;
260                    let base = self.current_frame().base_pointer;
261                    self.push(Rc::clone(&self.stack[base + local_index]))?;
262                }
263                Opcode::OpGetBuiltin => {
264                    let built_index = ins[ip + 1] as usize;
265                    self.current_frame().ip += 1;
266                    let definition = BuiltIns.get(built_index).unwrap().function;
267                    self.push(Rc::new(Object::Builtin(definition)))?;
268                }
269                Opcode::OpClosure => {
270                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
271                    let num_free = ins[ip + 3] as usize;
272                    self.current_frame().ip += 3;
273                    self.push_closure(const_index, num_free)?;
274                }
275                Opcode::OpGetFree => {
276                    let free_index = ins[ip + 1] as usize;
277                    self.current_frame().ip += 1;
278                    let current_closure = self.current_frame().cl.clone();
279                    self.push(current_closure.free[free_index].clone())?;
280                }
281                Opcode::OpCurrentClosure => {
282                    let current_closure = self.current_frame().cl.clone();
283                    self.push(Rc::new(Object::ClosureObj(current_closure)))?;
284                }
285                Opcode::OpClass => {
286                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
287                    self.current_frame().ip += 2;
288                    let name = self.constant_string(name_index);
289                    self.push(Rc::new(Object::Class(Rc::new(RefCell::new(ClassObject {
290                        name,
291                        constructor: None,
292                        methods: HashMap::new(),
293                    })))))?;
294                }
295                Opcode::OpMethod => {
296                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
297                    let kind = ins[ip + 3];
298                    self.current_frame().ip += 3;
299                    let name = self.constant_string(name_index);
300                    let method = self.pop();
301                    let class = match &*self.stack[self.sp - 1] {
302                        Object::Class(class) => Rc::clone(class),
303                        value => panic!("cannot install method on {}", value),
304                    };
305                    if kind == 1 {
306                        class.borrow_mut().constructor = Some(method);
307                    } else {
308                        class.borrow_mut().methods.insert(name, method);
309                    }
310                }
311                Opcode::OpGetProperty => {
312                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
313                    self.current_frame().ip += 2;
314                    let name = self.constant_string(name_index);
315                    let receiver = self.pop();
316                    let value = self.get_property(&receiver, &name)?;
317                    self.push(value)?;
318                }
319                Opcode::OpSetProperty => {
320                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
321                    self.current_frame().ip += 2;
322                    let name = self.constant_string(name_index);
323                    let value = self.pop();
324                    let receiver = self.pop();
325                    self.set_property(&receiver, name, value)?;
326                }
327                Opcode::OpNew => {
328                    let num_args = ins[ip + 1] as usize;
329                    self.current_frame().ip += 1;
330                    self.execute_new(num_args)?;
331                }
332                Opcode::OpDebugger => {
333                    // Recording debugger snapshots is the GC VM's job; here
334                    // the statement is a no-op with no stack effect.
335                }
336            }
337        }
338        Ok(())
339    }
340
341    fn execute_binary_operation(&mut self, opcode: Opcode) -> VmResult<()> {
342        let right = self.pop();
343        let left = self.pop();
344        match (left.as_ref(), right.as_ref()) {
345            (Object::Integer(l), Object::Integer(r)) => {
346                let result = match opcode {
347                    Opcode::OpAdd => l.checked_add(*r).ok_or_else(|| {
348                        VmRuntimeError::new(
349                            VmRuntimeErrorKind::Arithmetic,
350                            "integer overflow in addition",
351                        )
352                    }),
353                    Opcode::OpSub => l.checked_sub(*r).ok_or_else(|| {
354                        VmRuntimeError::new(
355                            VmRuntimeErrorKind::Arithmetic,
356                            "integer overflow in subtraction",
357                        )
358                    }),
359                    Opcode::OpMul => l.checked_mul(*r).ok_or_else(|| {
360                        VmRuntimeError::new(
361                            VmRuntimeErrorKind::Arithmetic,
362                            "integer overflow in multiplication",
363                        )
364                    }),
365                    Opcode::OpDiv if *r == 0 => {
366                        Err(VmRuntimeError::new(VmRuntimeErrorKind::Arithmetic, "division by zero"))
367                    }
368                    Opcode::OpDiv => l.checked_div(*r).ok_or_else(|| {
369                        VmRuntimeError::new(
370                            VmRuntimeErrorKind::Arithmetic,
371                            "integer overflow in division",
372                        )
373                    }),
374                    _ => unreachable!("compiler emitted non-binary opcode"),
375                }?;
376                self.push(Rc::from(Object::Integer(result)))
377            }
378            (Object::String(l), Object::String(r)) if opcode == Opcode::OpAdd => {
379                self.push(Rc::from(Object::String(l.to_string() + r)))
380            }
381            _ => Err(VmRuntimeError::new(
382                VmRuntimeErrorKind::Type,
383                format!("unsupported binary operation for {} and {}", left, right),
384            )),
385        }
386    }
387
388    fn execute_comparison(&mut self, opcode: Opcode) -> VmResult<()> {
389        let right = self.pop();
390        let left = self.pop();
391        if opcode == Opcode::OpEqual || opcode == Opcode::OpNotEqual {
392            let equal = left.as_ref() == right.as_ref();
393            return self.push(Rc::new(Object::Boolean(if opcode == Opcode::OpEqual {
394                equal
395            } else {
396                !equal
397            })));
398        }
399        match (left.as_ref(), right.as_ref()) {
400            (Object::Integer(l), Object::Integer(r)) => {
401                let result = match opcode {
402                    Opcode::OpGreaterThan => l > r,
403                    Opcode::OpLessThan => l < r,
404                    _ => unreachable!("compiler emitted non-comparison opcode"),
405                };
406                self.push(Rc::from(Object::Boolean(result)))
407            }
408            _ => Err(VmRuntimeError::new(
409                VmRuntimeErrorKind::Type,
410                format!("unsupported comparison for {} and {}", left, right),
411            )),
412        }
413    }
414
415    fn execute_minus_operation(&mut self, opcode: Opcode) -> VmResult<()> {
416        let operand = self.pop();
417        match operand.as_ref() {
418            Object::Integer(value) => value
419                .checked_neg()
420                .ok_or_else(|| {
421                    VmRuntimeError::new(
422                        VmRuntimeErrorKind::Arithmetic,
423                        "integer overflow in negation",
424                    )
425                })
426                .and_then(|value| self.push(Rc::from(Object::Integer(value)))),
427            _ => Err(VmRuntimeError::new(
428                VmRuntimeErrorKind::Type,
429                format!("unsupported type for negation {:?}: {}", opcode, operand),
430            )),
431        }
432    }
433
434    fn execute_bang_operation(&mut self) -> VmResult<()> {
435        let operand = self.pop();
436        match operand.as_ref() {
437            Object::Boolean(l) => self.push(Rc::from(Object::Boolean(!*l))),
438            _ => self.push(Rc::from(Object::Boolean(false))),
439        }
440    }
441
442    pub fn last_popped_stack_elm(&self) -> Option<Rc<Object>> {
443        self.stack.get(self.sp).cloned()
444    }
445
446    fn pop(&mut self) -> Rc<Object> {
447        let o = Rc::clone(&self.stack[self.sp - 1]);
448        self.sp -= 1;
449        return o;
450    }
451
452    fn push(&mut self, o: Rc<Object>) -> VmResult<()> {
453        if self.sp >= STACK_SIZE {
454            return Err(VmRuntimeError::new(VmRuntimeErrorKind::Stack, "stack limit exceeded"));
455        }
456        self.stack[self.sp] = o;
457        self.sp += 1;
458        Ok(())
459    }
460    fn is_truthy(&self, condition: Rc<Object>) -> bool {
461        match condition.as_ref() {
462            Object::Boolean(b) => *b,
463            Object::Null => false,
464            _ => true,
465        }
466    }
467    fn build_array(&self, start: usize, end: usize) -> Vec<Rc<Object>> {
468        let mut elements = Vec::with_capacity(end - start);
469        for i in start..end {
470            elements.push(Rc::clone(&self.stack[i]));
471        }
472        return elements;
473    }
474
475    // Object's Hash impl only covers Integer/Boolean/String, which have no
476    // interior mutability, so the keys are effectively immutable.
477    #[allow(clippy::mutable_key_type)]
478    fn build_hash(&self, start: usize, end: usize) -> VmResult<HashMap<Rc<Object>, Rc<Object>>> {
479        let mut elements = HashMap::new();
480        for i in (start..end).step_by(2) {
481            let key = Rc::clone(&self.stack[i]);
482            if !key.is_hashable() {
483                return Err(VmRuntimeError::new(
484                    VmRuntimeErrorKind::Index,
485                    format!("hash key must be hashable, got {}", key),
486                ));
487            }
488            let value = Rc::clone(&self.stack[i + 1]);
489            elements.insert(key, value);
490        }
491        Ok(elements)
492    }
493
494    fn execute_index_operation(&mut self, left: Rc<Object>, index: Rc<Object>) -> VmResult<()> {
495        match (left.as_ref(), index.as_ref()) {
496            (Object::Array(l), Object::Integer(i)) => self.execute_array_index(l, *i),
497            (Object::Hash(l), _) => self.execute_hash_index(l, index),
498            _ => Err(VmRuntimeError::new(
499                VmRuntimeErrorKind::Index,
500                format!("unsupported index operation for {} with {}", left, index),
501            )),
502        }
503    }
504
505    fn execute_array_index(&mut self, array: &[Rc<Object>], index: i64) -> VmResult<()> {
506        if index < array.len() as i64 && index >= 0 {
507            self.push(Rc::clone(&array[index as usize]))
508        } else {
509            self.push(Rc::new(Object::Null))
510        }
511    }
512
513    #[allow(clippy::mutable_key_type)]
514    fn execute_hash_index(
515        &mut self,
516        hash: &HashMap<Rc<Object>, Rc<Object>>,
517        index: Rc<Object>,
518    ) -> VmResult<()> {
519        match &*index {
520            Object::Integer(_) | Object::Boolean(_) | Object::String(_) => match hash.get(&index) {
521                Some(el) => self.push(Rc::clone(el)),
522                None => self.push(Rc::new(Object::Null)),
523            },
524            _ => Err(VmRuntimeError::new(
525                VmRuntimeErrorKind::Index,
526                format!("unsupported hash index key {}", index),
527            )),
528        }
529    }
530
531    fn current_frame(&mut self) -> &mut Frame {
532        &mut self.frames[self.frame_index - 1]
533    }
534
535    fn push_frame(&mut self, frame: Frame) -> VmResult<()> {
536        if self.frame_index >= MAX_FRAMES {
537            return Err(VmRuntimeError::new(VmRuntimeErrorKind::Stack, "frame limit exceeded"));
538        }
539        self.frames[self.frame_index] = frame;
540        self.frame_index += 1;
541        Ok(())
542    }
543
544    fn pop_frame(&mut self) -> Frame {
545        self.frame_index -= 1;
546        return self.frames[self.frame_index].clone();
547    }
548
549    fn execute_call(&mut self, num_args: usize) -> VmResult<()> {
550        let callee = Rc::clone(&self.stack[self.sp - 1 - num_args]);
551        match &*callee {
552            Object::ClosureObj(cf) => self.call_closure(cf.clone(), num_args),
553            Object::Builtin(bt) => self.call_builtin(*bt, num_args),
554            Object::BoundMethod(bound) => self.call_bound_method(bound.clone(), num_args),
555            Object::Class(class) => Err(VmRuntimeError::new(
556                VmRuntimeErrorKind::Call,
557                format!("class {} must be constructed with new", class.borrow().name),
558            )),
559            _ => Err(VmRuntimeError::new(VmRuntimeErrorKind::Call, "calling non-closure")),
560        }
561    }
562
563    fn call_closure(&mut self, cl: Closure, num_args: usize) -> VmResult<()> {
564        if cl.func.num_parameters != num_args {
565            return Err(VmRuntimeError::new(
566                VmRuntimeErrorKind::Call,
567                format!(
568                    "wrong number of arguments: want={}, got={}",
569                    cl.func.num_parameters, num_args
570                ),
571            ));
572        }
573
574        let frame = Frame::new(cl.clone(), self.sp - num_args);
575        let next_sp = frame
576            .base_pointer
577            .checked_add(cl.func.num_locals)
578            .filter(|next_sp| *next_sp <= STACK_SIZE)
579            .ok_or_else(|| {
580                VmRuntimeError::new(VmRuntimeErrorKind::Stack, "stack limit exceeded")
581            })?;
582        self.push_frame(frame)?;
583        self.sp = next_sp;
584        Ok(())
585    }
586
587    fn call_builtin(&mut self, bt: BuiltinFunc, num_args: usize) -> VmResult<()> {
588        let args = self.stack[self.sp - num_args..self.sp].to_vec();
589        let result = bt(args);
590        self.sp = self.sp - num_args - 1;
591        self.push(result)
592    }
593
594    fn push_closure(&mut self, const_index: usize, num_free: usize) -> VmResult<()> {
595        match &*self.constants[const_index] {
596            Object::CompiledFunction(f) => {
597                let mut free = Vec::with_capacity(num_free);
598                for i in 0..num_free {
599                    let f = self.stack[self.sp - num_free + i].clone();
600                    free.push(f);
601                }
602                self.sp -= num_free;
603                let closure = ClosureObj(Closure {
604                    func: f.clone(),
605                    free,
606                });
607                self.push(Rc::new(closure))
608            }
609            o => {
610                panic!("not a function {}", o);
611            }
612        }
613    }
614
615    fn constant_string(&self, index: usize) -> String {
616        match &*self.constants[index] {
617            Object::String(value) => value.clone(),
618            value => panic!("expected string constant, got {}", value),
619        }
620    }
621
622    fn get_property(&self, receiver: &Rc<Object>, name: &str) -> VmResult<Rc<Object>> {
623        let Object::Instance(instance) = &**receiver else {
624            return Err(VmRuntimeError::new(
625                VmRuntimeErrorKind::Property,
626                format!("cannot read property '{}' of {}", name, receiver),
627            ));
628        };
629        if let Some(value) = instance.borrow().fields.get(name).cloned() {
630            return Ok(value);
631        }
632        let (class_name, method) = {
633            let instance_object = instance.borrow();
634            let class = instance_object.class.borrow();
635            (class.name.clone(), class.methods.get(name).cloned())
636        };
637        match method {
638            Some(method) => Ok(Rc::new(Object::BoundMethod(Rc::new(BoundMethodObject {
639                receiver: Rc::clone(instance),
640                method,
641                name: name.to_string(),
642            })))),
643            None => Err(VmRuntimeError::new(
644                VmRuntimeErrorKind::Property,
645                format!("property '{}' does not exist on {}", name, class_name),
646            )),
647        }
648    }
649
650    fn set_property(&self, receiver: &Rc<Object>, name: String, value: Rc<Object>) -> VmResult<()> {
651        let Object::Instance(instance) = &**receiver else {
652            return Err(VmRuntimeError::new(
653                VmRuntimeErrorKind::Property,
654                format!("cannot set property '{}' of {}", name, receiver),
655            ));
656        };
657        instance.borrow_mut().fields.insert(name, value);
658        Ok(())
659    }
660
661    fn execute_new(&mut self, num_args: usize) -> VmResult<()> {
662        let base = self.sp - num_args - 1;
663        let class = match &*self.stack[base] {
664            Object::Class(class) => Rc::clone(class),
665            value => {
666                return Err(VmRuntimeError::new(
667                    VmRuntimeErrorKind::Call,
668                    format!("cannot construct {}", value),
669                ))
670            }
671        };
672        let instance = Rc::new(RefCell::new(InstanceObject {
673            class: Rc::clone(&class),
674            fields: HashMap::new(),
675        }));
676        let instance_value = Rc::new(Object::Instance(instance));
677        let constructor = class.borrow().constructor.clone();
678        let Some(constructor) = constructor else {
679            if num_args != 0 {
680                return Err(VmRuntimeError::new(
681                    VmRuntimeErrorKind::Call,
682                    format!(
683                        "wrong number of arguments for {}.constructor: want=0, got={}",
684                        class.borrow().name,
685                        num_args
686                    ),
687                ));
688            }
689            self.sp = base;
690            self.push(instance_value)?;
691            return Ok(());
692        };
693
694        let closure = match &*constructor {
695            Object::ClosureObj(closure) => closure.clone(),
696            value => panic!("constructor is not a closure: {}", value),
697        };
698        let expected = closure.func.num_parameters.saturating_sub(1);
699        if expected != num_args {
700            return Err(VmRuntimeError::new(
701                VmRuntimeErrorKind::Call,
702                format!(
703                    "wrong number of arguments for {}.constructor: want={}, got={}",
704                    class.borrow().name,
705                    expected,
706                    num_args
707                ),
708            ));
709        }
710        self.rewrite_receiver_call(constructor, instance_value, num_args)?;
711        self.call_closure(closure, num_args + 1)
712    }
713
714    fn call_bound_method(&mut self, bound: Rc<BoundMethodObject>, num_args: usize) -> VmResult<()> {
715        let closure = match &*bound.method {
716            Object::ClosureObj(closure) => closure.clone(),
717            value => panic!("bound method is not a closure: {}", value),
718        };
719        let expected = closure.func.num_parameters.saturating_sub(1);
720        if expected != num_args {
721            let class_name = bound.receiver.borrow().class.borrow().name.clone();
722            return Err(VmRuntimeError::new(
723                VmRuntimeErrorKind::Call,
724                format!(
725                    "wrong number of arguments for {}.{}: want={}, got={}",
726                    class_name, bound.name, expected, num_args
727                ),
728            ));
729        }
730        let receiver = Rc::new(Object::Instance(Rc::clone(&bound.receiver)));
731        self.rewrite_receiver_call(Rc::clone(&bound.method), receiver, num_args)?;
732        self.call_closure(closure, num_args + 1)
733    }
734
735    fn rewrite_receiver_call(
736        &mut self,
737        callable: Rc<Object>,
738        receiver: Rc<Object>,
739        num_args: usize,
740    ) -> VmResult<()> {
741        if self.sp >= STACK_SIZE {
742            return Err(VmRuntimeError::new(VmRuntimeErrorKind::Stack, "stack limit exceeded"));
743        }
744        let base = self.sp - num_args - 1;
745        for index in (base + 1..self.sp).rev() {
746            self.stack[index + 1] = Rc::clone(&self.stack[index]);
747        }
748        self.stack[base] = callable;
749        self.stack[base + 1] = receiver;
750        self.sp += 1;
751        Ok(())
752    }
753}