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, 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 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 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 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 }
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 #[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}