slvm/
vm.rs

1use std::alloc;
2use std::alloc::Layout;
3use std::sync::Arc;
4
5use crate::{
6    CallFrame, CallFunc, CallFuncSig, Chunk, Globals, HALT, Handle, Heap, Interner, VMError,
7    VMErrorObj, VMResult, Value, from_i56,
8};
9
10mod cons;
11mod storage;
12#[macro_use]
13pub mod macros;
14mod call;
15mod call_collection;
16mod exec_loop;
17
18/// Size (in elements/Values) of the stack.
19pub const STACK_CAP: usize = 1024;
20
21const DEAD_CODE: [u8; 3] = [HALT, HALT, HALT];
22
23/// Hold state of the VM, this is for making re-entrant calls on the VM.
24struct VmState {
25    stack_top: usize,
26    stack_max: usize,
27    ip: *const u8,
28    current_ip: *const u8,
29    this_fn: Option<Value>,
30    on_error: Option<Value>,
31    defers: Vec<Value>,
32}
33
34pub struct GVm<ENV> {
35    interner: Interner,
36    heap: Option<Heap>,
37    //stack: [Value; STACK_CAP],
38    stack: *mut Value,
39    registers: *mut Value,
40    globals: Globals,
41    builtins: Vec<CallFunc<ENV>>,
42    this_fn: Option<Value>,
43    on_error: Option<Value>,
44
45    err_frame: Option<CallFrame>,
46    stack_top: usize,
47    k_stack_top: Option<usize>, // Used for continuation/defer interaction.
48    stack_max: usize,
49    ip_ptr: *const u8,
50    current_ip_ptr: *const u8,
51    callframe_id: usize,
52    defers: Vec<Value>,
53    env: ENV,
54}
55
56pub type Vm = GVm<()>;
57
58impl Default for GVm<()> {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64impl GVm<()> {
65    pub fn new() -> Self {
66        GVm::new_with_env(())
67    }
68}
69
70impl<ENV> GVm<ENV> {
71    pub fn new_with_env(env: ENV) -> Self {
72        let globals = Globals::new();
73        let stack_layout =
74            Layout::array::<Value>(STACK_CAP).expect("Failed to get memory layout for stack!");
75        let stack = unsafe { alloc::alloc(stack_layout) } as *mut Value;
76        if stack.is_null() {
77            // Out of memory...
78            panic!("Unable to allocate a stack!");
79        }
80        // Initialize the stack else it will contain garbage.
81        for i in 0..STACK_CAP {
82            let val = unsafe { stack.add(i).as_mut().expect("cant be null!") };
83            *val = Value::Undefined;
84        }
85        Self {
86            interner: Interner::with_capacity(8192),
87            heap: Some(Heap::new()),
88            stack, //: [Value::Undefined; STACK_CAP],
89            registers: stack,
90            globals,
91            builtins: Vec::new(),
92            this_fn: None,
93            on_error: None,
94            err_frame: None,
95            stack_top: 0,
96            k_stack_top: None,
97            stack_max: 0,
98            ip_ptr: DEAD_CODE.as_ptr(),
99            current_ip_ptr: DEAD_CODE.as_ptr(),
100            callframe_id: 0,
101            defers: Vec::new(),
102            env,
103        }
104    }
105
106    pub fn this_fn(&self) -> Option<Value> {
107        self.this_fn
108    }
109
110    pub fn stack(&self, idx: usize) -> Value {
111        unsafe { *self.stack.add(idx) }
112    }
113
114    pub fn stack_mut(&mut self, idx: usize) -> &mut Value {
115        unsafe { self.stack.add(idx).as_mut().expect("cant be null!") }
116    }
117
118    pub fn stack_slice(&self) -> &[Value] {
119        unsafe { std::slice::from_raw_parts(self.stack, STACK_CAP) }
120    }
121
122    pub fn stack_slice_mut(&mut self) -> &mut [Value] {
123        unsafe { std::slice::from_raw_parts_mut(self.stack, STACK_CAP) }
124    }
125
126    /// Return the register for idx.
127    pub fn register(&self, idx: usize) -> Value {
128        unsafe { *self.registers.add(idx).as_mut().expect("cant be null!") }
129    }
130
131    pub fn register_slice<'b>(&self) -> &'b [Value] {
132        unsafe {
133            std::slice::from_raw_parts(self.stack.add(self.stack_top), STACK_CAP - self.stack_top)
134        }
135    }
136
137    /// Return the int representation of register idx or error if not an integral type.
138    pub fn register_int(&self, idx: usize) -> VMResult<i64> {
139        let reg = self.register(idx);
140        match reg {
141            Value::Byte(b) => Ok(b as i64),
142            Value::Int(i) => Ok(from_i56(&i)),
143            _ => Err(VMError::new_value(format!(
144                "Not an integer: {}",
145                reg.display_value(self)
146            ))),
147        }
148    }
149
150    /// Return the current register for idx, if it is stored on heap then dereference it first.
151    pub fn register_unref(&self, idx: usize) -> Value {
152        let reg = self.register(idx);
153        match reg {
154            Value::Value(handle) => self.heap().get_value(handle),
155            _ => reg,
156        }
157    }
158
159    pub fn register_mut<'b>(&self, idx: usize) -> &'b mut Value {
160        unsafe { self.registers.add(idx).as_mut().expect("cant be null!") }
161    }
162
163    pub fn env(&self) -> &ENV {
164        &self.env
165    }
166
167    pub fn env_mut(&mut self) -> &mut ENV {
168        &mut self.env
169    }
170
171    fn heap(&self) -> &Heap {
172        self.heap.as_ref().expect("VM must have a Heap!")
173    }
174
175    fn heap_mut(&mut self) -> &mut Heap {
176        self.heap.as_mut().expect("VM must have a Heap!")
177    }
178
179    /// Set the internal registers pointer, do this when the registers start position changes.
180    fn make_registers(&mut self) {
181        unsafe {
182            self.registers = self.stack.add(self.stack_top);
183        }
184    }
185
186    fn mk_str(&mut self, reg1: u16, reg2: u16) -> VMResult<Value> {
187        let mut val = String::new();
188        for reg in reg1..=reg2 {
189            let v = self.register_unref(reg as usize);
190            val.push_str(&v.pretty_value(self));
191        }
192        let val = self.alloc_string(val);
193        Ok(val)
194    }
195
196    fn is_identical(&self, reg1: u16, reg2: u16) -> VMResult<Value> {
197        let mut val = Value::False;
198        if reg1 == reg2 {
199            val = Value::True;
200        } else {
201            let mut val1 = self.register_unref(reg1 as usize);
202            for reg in reg1..reg2 {
203                let val2 = self.register_unref(reg as usize + 1);
204                if val1 == val2 {
205                    val = Value::True;
206                } else {
207                    val = Value::False;
208                    break;
209                }
210                val1 = val2;
211            }
212        };
213        Ok(val)
214    }
215
216    pub fn add_builtin(&mut self, func: CallFuncSig<ENV>) -> Value {
217        let result = self.builtins.len();
218        self.builtins.push(CallFunc { func });
219        Value::Builtin(result as u32)
220    }
221
222    /// Return the builtin function at idx.
223    /// Note, will panic if idx is not a valid builtin index.
224    pub fn get_builtin(&self, idx: u32) -> &CallFuncSig<ENV> {
225        &self.builtins[idx as usize].func
226    }
227
228    pub fn is_equal_pair(&self, val1: Value, val2: Value) -> VMResult<Value> {
229        let mut val = Value::False;
230        match (val1, val2) {
231            (Value::Float(f1), Value::Float(f2))
232                if f1.roughly_equal_using_relative_difference(&f2) =>
233            {
234                val = Value::True
235            }
236            (_, _) if val1 == val2 => val = Value::True,
237            (Value::Int(i), Value::Byte(b)) | (Value::Byte(b), Value::Int(i))
238                if from_i56(&i) == i64::from(b) =>
239            {
240                val = Value::True
241            }
242            (Value::StringConst(s1), Value::CharCluster(l, c)) => {
243                let s2 = format!("{}", String::from_utf8_lossy(&c[0..l as usize]));
244                let s1 = self.get_interned(s1);
245                if s1 == s2 {
246                    val = Value::True;
247                }
248            }
249            (Value::StringConst(s1), Value::CodePoint(c)) => {
250                let s2 = format!("{c}");
251                let s1 = self.get_interned(s1);
252                if s1 == s2 {
253                    val = Value::True;
254                }
255            }
256            (Value::StringConst(s1), Value::String(h2) | Value::CharClusterLong(h2)) => {
257                let s1 = self.get_interned(s1);
258                if s1 == self.get_string(h2) {
259                    val = Value::True;
260                }
261            }
262            (Value::String(h1) | Value::CharClusterLong(h1), Value::StringConst(s2)) => {
263                let s1 = self.get_string(h1);
264                if s1 == self.get_interned(s2) {
265                    val = Value::True;
266                }
267            }
268            (Value::String(h1) | Value::CharClusterLong(h1), Value::CodePoint(c)) => {
269                let s1 = self.get_string(h1);
270                let s2 = format!("{c}");
271                if s1 == s2 {
272                    val = Value::True;
273                }
274            }
275            (Value::String(h1) | Value::CharClusterLong(h1), Value::CharCluster(l, c)) => {
276                let s1 = self.get_string(h1);
277                let s2 = format!("{}", String::from_utf8_lossy(&c[0..l as usize]));
278                if s1 == s2 {
279                    val = Value::True;
280                }
281            }
282            (
283                Value::String(h1) | Value::CharClusterLong(h1),
284                Value::CharClusterLong(h2) | Value::String(h2),
285            ) => {
286                let s1 = self.get_string(h1);
287                if s1 == self.get_string(h2) {
288                    val = Value::True;
289                }
290            }
291            (Value::Vector(h1), Value::Vector(h2)) => {
292                let v1 = self.heap().get_vector(h1);
293                let v2 = self.heap().get_vector(h2);
294                if v1.len() == v2.len() {
295                    if v1.is_empty() {
296                        val = Value::True;
297                    } else {
298                        for i in 0..v1.len() {
299                            val = self.is_equal_pair(v1[i], v2[i])?;
300                            if val == Value::False {
301                                break;
302                            }
303                        }
304                    }
305                }
306            }
307            (Value::Bytes(h1), Value::Bytes(h2)) => {
308                let b1 = self.heap().get_bytes(h1);
309                let b2 = self.heap().get_bytes(h2);
310                if b1.len() == b2.len() {
311                    if b1.is_empty() {
312                        val = Value::True;
313                    } else {
314                        for i in 0..b1.len() {
315                            if b1[i] == b2[i] {
316                                val = Value::True;
317                            } else {
318                                val = Value::False;
319                                break;
320                            }
321                        }
322                    }
323                }
324            }
325            (Value::Pair(_) | Value::List(_, _), Value::Pair(_) | Value::List(_, _)) => {
326                // XXX use iterators to reduce recursion?
327                // Make sure pair iter will work for non-lists...
328                let (car1, cdr1) = val1.get_pair(self).expect("Must be a pair or list!");
329                let (car2, cdr2) = val2.get_pair(self).expect("Must be a pair or list!");
330                val = self.is_equal_pair(car1, car2)?;
331                if val == Value::True {
332                    val = self.is_equal_pair(cdr1, cdr2)?;
333                }
334            }
335            (Value::Map(m1), Value::Map(m2)) => {
336                let m1 = self.heap().get_map(m1);
337                let m2 = self.heap().get_map(m2);
338                if m1.len() == m2.len() {
339                    if m1.is_empty() {
340                        val = Value::True;
341                    } else {
342                        // must set val to false in two instances because
343                        // its possible a previous iteration set val to true.
344                        for (k, v) in m1.iter() {
345                            if let Some(v2) = m2.get(self, k) {
346                                if self.is_equal_pair(v, v2)? == Value::False {
347                                    val = Value::False;
348                                    break;
349                                } else {
350                                    val = Value::True;
351                                }
352                            } else {
353                                val = Value::False;
354                                break;
355                            }
356                        }
357                    }
358                }
359            }
360            (Value::Value(h1), Value::Value(h2)) => {
361                let v1 = self.get_value(h1);
362                let v2 = self.get_value(h2);
363                val = self.is_equal_pair(v1, v2)?;
364            }
365            (val1, Value::Value(h2)) => {
366                let v2 = self.get_value(h2);
367                val = self.is_equal_pair(val1, v2)?;
368            }
369            (Value::Value(v1), val2) => {
370                let v1 = self.get_value(v1);
371                val = self.is_equal_pair(v1, val2)?;
372            }
373            (Value::Nil, Value::True) => val = Value::False,
374            (Value::Nil, Value::False) => val = Value::True,
375            (Value::True, Value::Nil) => val = Value::False,
376            (Value::False, Value::Nil) => val = Value::True,
377            (Value::Error(e1), Value::Error(e2)) => {
378                let err1 = self.get_error(e1);
379                let err2 = self.get_error(e2);
380                if self.get_interned(err1.keyword) == self.get_interned(err2.keyword) {
381                    val = self.is_equal_pair(err1.data, err2.data)?;
382                }
383            }
384            (Value::Undefined, _) => {
385                panic!("is_equal_pair: internal error, given left hand value is Undefined.")
386            }
387            (_, Value::Undefined) => {
388                panic!("is_equal_pair: internal error, given right hand value is Undefined.")
389            }
390            (_, _) => {}
391        }
392        Ok(val)
393    }
394
395    /// test if the operands are = (more lenient than identical)
396    fn is_equal(&self, reg1: u16, reg2: u16) -> VMResult<Value> {
397        let mut val = Value::False;
398        if reg1 == reg2 {
399            val = Value::True
400        } else {
401            let mut val1 = self.register_unref(reg1 as usize);
402            for reg in reg1..reg2 {
403                let val2 = self.register_unref(reg as usize + 1);
404                val = self.is_equal_pair(val1, val2)?;
405                if val == Value::False {
406                    break;
407                }
408                val1 = val2;
409            }
410        }
411        Ok(val)
412    }
413
414    /// Return the current VM state (for re-entrant VM calls).
415    fn save_state(&mut self) -> VmState {
416        VmState {
417            stack_top: self.stack_top,
418            stack_max: self.stack_max,
419            ip: self.ip_ptr,
420            current_ip: self.current_ip_ptr,
421            this_fn: self.this_fn,
422            on_error: self.on_error,
423            defers: std::mem::take(&mut self.defers),
424        }
425    }
426
427    /// Restore saved VM state (for cleaning up after re-entrant VM calls).
428    fn restore_state(&mut self, state: &mut VmState) {
429        self.stack_top = state.stack_top;
430        self.stack_max = state.stack_max;
431        self.ip_ptr = state.ip;
432        self.current_ip_ptr = state.current_ip;
433        self.this_fn = state.this_fn;
434        self.on_error = state.on_error;
435        self.defers = std::mem::take(&mut state.defers);
436    }
437
438    /// Runs a lambda.  Will save and restore the VM state even on error, chunk is expected to be a
439    /// callable with params and any captures (closure) in caps.
440    /// This is useful for macro expansion, eval and things like that.  It can be safely used while
441    /// the VM is currently executing bytecode.
442    pub fn do_call(
443        &mut self,
444        chunk: Arc<Chunk>,
445        params: &[Value],
446        caps: Option<&[Handle]>,
447    ) -> VMResult<Value> {
448        let mut vm_state = self.save_state();
449        self.this_fn = None;
450        self.on_error = None;
451        self.stack_top = self.stack_max + 1;
452
453        self.stack_max = self.stack_top + chunk.input_regs + chunk.extra_regs;
454
455        // We don't have a call frame, this will cause RET/SRET to return control back when called.
456        *self.stack_mut(self.stack_top) = Value::Undefined;
457        if !params.is_empty() {
458            let r = self.stack_top + 1..self.stack_top + 1 + params.len();
459            self.stack_slice_mut()[r].copy_from_slice(params);
460        }
461        self.make_registers();
462        if chunk.rest {
463            let (rest_reg, h) = self.setup_rest(&chunk, 0, params.len() as u16);
464            if let Some(caps) = caps {
465                let cap_first = (chunk.args + chunk.opt_args + 1) as usize;
466                for (i, c) in caps.iter().enumerate() {
467                    mov_register!(self, cap_first + i, Value::Value(*c));
468                }
469            }
470            mov_register!(self, rest_reg, h);
471        } else if let Some(caps) = caps {
472            let cap_first = (chunk.args + chunk.opt_args + 1) as usize;
473            for (i, c) in caps.iter().enumerate() {
474                mov_register!(self, cap_first + i, Value::Value(*c));
475            }
476        }
477        let res = self.execute2(chunk).map(|_| self.stack(self.stack_top));
478        self.restore_state(&mut vm_state);
479        res
480    }
481
482    /// Executes chunk.  Will save the current VM state and restore on success or leave it on error.
483    /// This allows a debugger to work with the "broken" image.
484    pub fn execute(&mut self, chunk: Arc<Chunk>) -> VMResult<Value> {
485        let stack_top = self.stack_top;
486        let stack_max = self.stack_max;
487        let ip = self.ip_ptr;
488        let this_fn = self.this_fn;
489        let on_error = self.on_error;
490        self.this_fn = None;
491        self.stack_top = self.stack_max;
492        self.stack_max = self.stack_top + chunk.input_regs + chunk.extra_regs;
493
494        // Return on error without resetting the VM.
495        // This is to allow debugging a live image/vm.
496        self.execute2(chunk)?;
497        let res = self.stack(self.stack_top);
498
499        self.stack_top = stack_top;
500        self.stack_max = stack_max;
501        self.ip_ptr = ip;
502        self.this_fn = this_fn;
503        self.on_error = on_error;
504        Ok(res)
505    }
506
507    /// Reset the VM to default settings.  Useful for cleaning up if you want to abort an execute()
508    /// that errored out.
509    pub fn reset(&mut self) {
510        self.this_fn = None;
511        self.on_error = None;
512        self.err_frame = None;
513        self.stack_top = 0;
514        self.stack_max = 0;
515        self.ip_ptr = DEAD_CODE.as_ptr();
516        self.current_ip_ptr = DEAD_CODE.as_ptr();
517        self.callframe_id = 0;
518        // XXX TODO- should probably run any defers before the reset.
519        self.defers = Vec::new();
520    }
521
522    fn execute2(&mut self, chunk: Arc<Chunk>) -> VMResult<()> {
523        let mut chunk = chunk;
524
525        let mut done = false;
526        let mut result = Ok(());
527        let mut skip_init = false;
528        while !done {
529            result = if let Err((e, echunk)) = self.exec_loop(chunk.clone(), skip_init) {
530                skip_init = false;
531                if self.err_frame.is_none() {
532                    self.err_frame = Some(CallFrame {
533                        id: 0,
534                        chunk: echunk,
535                        stack_top: self.stack_top,
536                        ip: self.ip_ptr,
537                        current_ip: self.current_ip_ptr,
538                        this_fn: self.this_fn,
539                        defers: std::mem::take(&mut self.defers),
540                        on_error: self.on_error,
541                        called: Value::Undefined,
542                    });
543                }
544                if let Some(on_error) = self.on_error {
545                    self.make_registers();
546                    let keyword = self.intern(e.key);
547                    let data = match &e.obj {
548                        VMErrorObj::Message(msg) => Value::StringConst(self.intern(msg)),
549                        VMErrorObj::Object(v) => *v,
550                    };
551                    *self.register_mut(1) = self.alloc_error(crate::Error { keyword, data });
552                    self.on_error = None;
553                    match self.make_call(on_error, chunk.clone(), 0, 1, true) {
554                        Ok(c) => {
555                            chunk = c;
556                            if let Value::Continuation(_) = on_error {
557                                // Make sure to leave the new stack and ip_ptr alone when calling exec_loop().
558                                skip_init = true;
559                            }
560                            Err(e)
561                        }
562                        Err((ne, _c)) => {
563                            done = true;
564                            Err(ne)
565                        }
566                    }
567                } else {
568                    done = true;
569                    Err(e)
570                }
571            } else {
572                self.err_frame = None;
573                done = true;
574                Ok(())
575            };
576        }
577
578        result
579    }
580}
581
582#[cfg(test)]
583mod tests {
584    use super::*;
585    use crate::opcodes::*;
586
587    fn get_int(_vm: &Vm, val: &Value) -> VMResult<i64> {
588        if let Value::Int(i) = val {
589            Ok(from_i56(i))
590        } else {
591            Err(VMError::new_vm("Not an int"))
592        }
593    }
594
595    fn is_nil(_vm: &Vm, val: &Value) -> VMResult<bool> {
596        if let Value::Nil = val {
597            Ok(true)
598        } else {
599            Ok(false)
600        }
601    }
602
603    #[test]
604    fn test_list() -> VMResult<()> {
605        let mut chunk = Chunk::new("no_file", 1);
606        let line = 1;
607        chunk.add_constant(1.into());
608        chunk.add_constant(2.into());
609        chunk.add_constant(3.into());
610        chunk.add_constant(4.into());
611        chunk.add_constant(Value::Nil);
612        chunk.encode2(CONST, 0, 0, Some(line)).unwrap();
613        chunk.encode2(CONST, 1, 1, Some(line)).unwrap();
614        chunk.encode3(CONS, 1, 0, 1, Some(line)).unwrap();
615        chunk.encode2(CDR, 0, 1, Some(line)).unwrap();
616        chunk.encode0(RET, Some(line))?;
617        let mut vm = Vm::new();
618        chunk.add_constant(Value::Nil);
619        let chunk = Arc::new(chunk);
620        vm.execute(chunk.clone())?;
621        let result = vm.stack(0).get_int(&vm)?;
622        assert!(result == 2);
623
624        let mut chunk = Arc::try_unwrap(chunk).unwrap();
625        chunk.code.clear();
626        chunk.encode2(CAR, 0, 1, Some(line)).unwrap();
627        chunk.encode0(RET, Some(line))?;
628        let chunk = Arc::new(chunk);
629        vm.execute(chunk.clone())?;
630        let result = vm.stack(0).get_int(&vm)?;
631        assert!(result == 1);
632
633        // car with nil
634        let mut chunk = Arc::try_unwrap(chunk).unwrap();
635        chunk.code.clear();
636        chunk.encode2(CONST, 2, 4, Some(line)).unwrap();
637        chunk.encode2(CAR, 0, 2, Some(line)).unwrap();
638        chunk.encode0(RET, Some(line))?;
639        let chunk = Arc::new(chunk);
640        vm.execute(chunk.clone())?;
641        assert!(vm.stack(0).is_nil());
642
643        // car with nil on heap
644        let mut chunk = Arc::try_unwrap(chunk).unwrap();
645        chunk.code.clear();
646        chunk.encode2(CONST, 2, 4, Some(line)).unwrap();
647        chunk.encode2(CAR, 0, 2, Some(line)).unwrap();
648        chunk.encode0(RET, Some(line))?;
649        let chunk = Arc::new(chunk);
650        vm.execute(chunk.clone())?;
651        assert!(vm.stack(0).is_nil());
652
653        // cdr with nil
654        let mut chunk = Arc::try_unwrap(chunk).unwrap();
655        chunk.code.clear();
656        chunk.encode2(CDR, 0, 2, Some(line)).unwrap();
657        chunk.encode0(RET, Some(line))?;
658        let chunk = Arc::new(chunk);
659        vm.execute(chunk.clone())?;
660        assert!(vm.stack(0).is_nil());
661
662        // cdr with nil on heap
663        let mut chunk = Arc::try_unwrap(chunk).unwrap();
664        chunk.code.clear();
665        chunk.encode2(CONST, 2, 4, Some(line)).unwrap();
666        chunk.encode2(CDR, 0, 2, Some(line)).unwrap();
667        chunk.encode0(RET, Some(line))?;
668        let chunk = Arc::new(chunk);
669        vm.execute(chunk.clone())?;
670        assert!(vm.stack(0).is_nil());
671
672        let mut chunk = Arc::try_unwrap(chunk).unwrap();
673        chunk.code.clear();
674        chunk.encode2(CONST, 2, 2, Some(line)).unwrap();
675        chunk.encode2(XAR, 1, 2, Some(line)).unwrap();
676        chunk.encode2(CAR, 0, 1, Some(line)).unwrap();
677        chunk.encode0(RET, Some(line))?;
678        let chunk = Arc::new(chunk);
679        vm.execute(chunk.clone())?;
680        let result = vm.stack(0).get_int(&vm)?;
681        assert!(result == 3);
682
683        let mut chunk = Arc::try_unwrap(chunk).unwrap();
684        chunk.code.clear();
685        chunk.encode2(CONST, 2, 3, Some(line)).unwrap();
686        chunk.encode2(XDR, 1, 2, Some(line)).unwrap();
687        chunk.encode2(CDR, 0, 1, Some(line)).unwrap();
688        chunk.encode0(RET, Some(line))?;
689        let chunk = Arc::new(chunk);
690        vm.execute(chunk.clone())?;
691        let result = vm.stack(0).get_int(&vm)?;
692        assert!(result == 4);
693
694        let mut chunk = Arc::try_unwrap(chunk).unwrap();
695        chunk.code.clear();
696        chunk.encode2(CONST, 2, 4, Some(line)).unwrap();
697        chunk.encode2(CONST, 3, 2, Some(line)).unwrap();
698        chunk.encode2(XAR, 2, 3, Some(line)).unwrap();
699        chunk.encode2(CAR, 0, 2, Some(line)).unwrap();
700        chunk.encode2(CDR, 3, 2, Some(line)).unwrap();
701        chunk.encode0(RET, Some(line))?;
702        let mut chunk = Arc::new(chunk);
703        assert!(
704            vm.execute(chunk.clone()).is_err(),
705            "XAR on Nil is an error."
706        );
707
708        // Previous error stashed a clone of chunk so make a new one.
709        Arc::make_mut(&mut chunk);
710        let mut chunk = Arc::try_unwrap(chunk).unwrap();
711        chunk.code.clear();
712        chunk.encode2(CONST, 2, 4, Some(line)).unwrap();
713        chunk.encode2(CONST, 3, 3, Some(line)).unwrap();
714        chunk.encode2(XDR, 2, 3, Some(line)).unwrap();
715        chunk.encode2(CDR, 0, 2, Some(line)).unwrap();
716        chunk.encode2(CAR, 3, 2, Some(line)).unwrap();
717        chunk.encode0(RET, Some(line))?;
718        let mut chunk = Arc::new(chunk);
719        assert!(vm.execute(chunk.clone()).is_err(), "Can not XDR Nil");
720
721        // Previous error stashed a clone of chunk so make a new one.
722        Arc::make_mut(&mut chunk);
723        // Test a list with elements.
724        let mut chunk = Arc::try_unwrap(chunk).unwrap();
725        chunk.code.clear();
726        chunk.encode2(CONST, 0, 0, Some(line)).unwrap();
727        chunk.encode2(CONST, 1, 1, Some(line)).unwrap();
728        chunk.encode2(CONST, 2, 2, Some(line)).unwrap();
729        chunk.encode3(LIST, 0, 0, 2, Some(line)).unwrap();
730        chunk.encode0(RET, Some(line))?;
731        let chunk = Arc::new(chunk);
732        vm.execute(chunk.clone())?;
733        let result = vm.stack(0);
734        if let Value::Pair(h) = result {
735            let (car, cdr) = vm.heap().get_pair(h);
736            assert!(get_int(&vm, &car)? == 1);
737            if let Value::Pair(h2) = cdr {
738                let (car, cdr) = vm.heap().get_pair(h2);
739                assert!(get_int(&vm, &car)? == 2);
740                if let Value::Pair(h3) = cdr {
741                    let (car, cdr) = vm.heap().get_pair(h3);
742                    assert!(get_int(&vm, &car)? == 3);
743                    assert!(is_nil(&vm, &cdr)?);
744                } else {
745                    panic!();
746                }
747            } else {
748                panic!();
749            }
750        } else {
751            panic!();
752        }
753
754        let mut chunk = Arc::try_unwrap(chunk).unwrap();
755        chunk.code.clear();
756        chunk.encode3(LIST, 0, 1, 0, Some(line)).unwrap();
757        chunk.encode0(RET, Some(line))?;
758        let chunk = Arc::new(chunk);
759        vm.execute(chunk)?;
760        let result = vm.stack(0);
761        assert!(result.is_nil());
762        Ok(())
763    }
764
765    #[test]
766    fn test_store() -> VMResult<()> {
767        let mut chunk = Chunk::new("no_file", 1);
768        let line = 1;
769        for i in 0..257 {
770            chunk.add_constant(i.into());
771        }
772        chunk.encode2(CONST, 0, 0, Some(line)).unwrap();
773        chunk.encode2(CONST, 1, 255, Some(line)).unwrap();
774        chunk.encode2(ADD, 0, 1, Some(line)).unwrap();
775        chunk.encode0(RET, Some(line))?;
776
777        let mut vm = Vm::new();
778        let chunk = Arc::new(chunk);
779        vm.execute(chunk.clone())?;
780        let result = vm.stack(0).get_int(&vm)?;
781        assert!(result == 255);
782
783        let mut chunk = Arc::try_unwrap(chunk).unwrap();
784        chunk.code.clear();
785        chunk.encode2(CONST, 1, 256, Some(line)).unwrap();
786        chunk.encode2(ADD, 0, 1, Some(line)).unwrap();
787        chunk.encode0(RET, Some(line))?;
788
789        let chunk = Arc::new(chunk);
790        vm.execute(chunk.clone())?;
791        let result = vm.stack(0).get_int(&vm)?;
792        assert!(result == 255 + 256);
793
794        let mut chunk = Arc::try_unwrap(chunk).unwrap();
795        chunk.code.clear();
796        chunk.encode2(MOV, 1, 0, Some(line)).unwrap();
797        chunk.encode0(RET, Some(line))?;
798        let result = vm.stack(1).get_int(&vm)?;
799        assert!(result == 256);
800        let chunk = Arc::new(chunk);
801        vm.execute(chunk.clone())?;
802        let result = vm.stack(1).get_int(&vm)?;
803        assert!(result == 255 + 256);
804
805        let mut vm = Vm::new();
806        *vm.stack_mut(0) = vm.new_upval(1.into());
807        *vm.stack_mut(1) = 10.into();
808        *vm.stack_mut(2) = 1.into();
809        let mut chunk = Arc::try_unwrap(chunk).unwrap();
810        chunk.code.clear();
811        chunk.encode2(MOV, 1, 0, Some(line)).unwrap();
812        chunk.encode2(ADD, 1, 2, Some(line)).unwrap();
813        chunk.encode2(ADD, 1, 2, Some(line)).unwrap();
814        chunk.encode2(ADD, 1, 2, Some(line)).unwrap();
815        chunk.encode0(RET, Some(line))?;
816        let chunk = Arc::new(chunk);
817        vm.execute(chunk)?;
818        let result = vm.stack(0).unref(&vm).get_int(&vm)?;
819        assert!(result == 1);
820        let result = vm.stack(1).unref(&vm).get_int(&vm)?;
821        assert!(result == 4);
822
823        Ok(())
824    }
825
826    #[test]
827    fn test_global() -> VMResult<()> {
828        let mut chunk = Chunk::new("no_file", 1);
829        let line = 1;
830        let mut vm = Vm::new();
831        let slot = vm.globals.reserve();
832        let slot2 = vm.globals.reserve();
833        let const2 = chunk.add_constant(42.into()) as u16;
834        vm.globals.set(slot, 11.into());
835        chunk.encode_refi(1, slot, Some(line))?;
836        chunk.encode0(RET, Some(line))?;
837        let chunk = Arc::new(chunk);
838        vm.execute(chunk.clone())?;
839        assert!(vm.stack(1).unref(&vm).get_int(&vm)? == 11);
840
841        let mut chunk = Arc::try_unwrap(chunk).unwrap();
842        chunk.code.clear();
843        chunk.encode2(CONST, 1, const2, Some(line))?;
844        chunk.encode_def(1, slot2, Some(line), false)?;
845        chunk.encode_refi(2, slot2, Some(line))?;
846        chunk.encode0(RET, Some(line))?;
847        let chunk = Arc::new(chunk);
848        vm.execute(chunk.clone())?;
849        assert!(vm.stack(2).unref(&vm).get_int(&vm)? == 42);
850
851        let mut chunk = Arc::try_unwrap(chunk).unwrap();
852        chunk.code.clear();
853        vm.globals.set(slot, 11.into());
854        let const2 = chunk.add_constant(43.into()) as u16;
855        let const3 = chunk.add_constant(53.into()) as u16;
856        chunk.encode2(CONST, 1, const2, Some(line))?;
857        chunk.encode2(CONST, 3, const3, Some(line))?;
858        chunk.encode_def(1, slot2, Some(line), false)?;
859        chunk.encode_def(3, slot2, Some(line), true)?;
860        chunk.encode_refi(2, slot2, Some(line))?;
861        chunk.encode0(RET, Some(line))?;
862        let chunk = Arc::new(chunk);
863        vm.execute(chunk.clone())?;
864        assert!(vm.stack(2).unref(&vm).get_int(&vm)? == 43);
865
866        let mut chunk = Arc::try_unwrap(chunk).unwrap();
867        chunk.code.clear();
868        vm.globals.set(slot2, 11.into());
869        assert!(vm.globals.get(slot2).get_int(&vm)? == 11);
870        let const2 = chunk.add_constant(43.into()) as u16;
871        let const3 = chunk.add_constant(53.into()) as u16;
872        chunk.encode2(CONST, 1, const2, Some(line))?;
873        chunk.encode2(CONST, 3, const3, Some(line))?;
874        chunk.encode_def(1, slot, Some(line), false)?;
875        chunk.encode_def(3, slot, Some(line), true)?;
876        chunk.encode_refi(2, slot, Some(line))?;
877        chunk.encode_refi(5, slot, Some(line))?;
878        chunk.encode2(SET, 5, 3, Some(line))?;
879        chunk.encode0(RET, Some(line))?;
880        let chunk = Arc::new(chunk);
881        vm.execute(chunk.clone())?;
882        assert!(vm.stack(2).unref(&vm).get_int(&vm)? == 43);
883        assert!(vm.stack(5).unref(&vm).get_int(&vm)? == 53);
884        assert_eq!(vm.globals.get(slot).get_int(&vm)?, 43);
885
886        let mut vm = Vm::new();
887        let mut chunk = Arc::try_unwrap(chunk).unwrap();
888        chunk.code.clear();
889        let slot = vm.globals.reserve();
890        let const2 = chunk.add_constant(44.into()) as u16;
891        let const3 = chunk.add_constant(53.into()) as u16;
892        chunk.encode2(CONST, 2, const2, Some(line))?;
893        chunk.encode2(CONST, 3, const3, Some(line))?;
894        chunk.encode_def(2, slot, Some(line), true)?;
895        chunk.encode_def(3, slot, Some(line), true)?;
896        chunk.encode_refi(0, slot, Some(line))?;
897        chunk.encode0(RET, Some(line))?;
898        let chunk = Arc::new(chunk);
899        vm.execute(chunk.clone())?;
900        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 44);
901
902        let mut vm = Vm::new();
903        let mut chunk = Arc::try_unwrap(chunk).unwrap();
904        chunk.code.clear();
905        let slot = vm.globals.reserve();
906        let const2 = chunk.add_constant(45.into()) as u16;
907        let const3 = chunk.add_constant(55.into()) as u16;
908        chunk.encode2(CONST, 2, const2, Some(line))?;
909        chunk.encode2(CONST, 3, const3, Some(line))?;
910        chunk.encode_def(2, slot, Some(line), true)?;
911        chunk.encode_def(3, slot, Some(line), false)?;
912        chunk.encode_refi(0, slot, Some(line))?;
913        chunk.encode0(RET, Some(line))?;
914        let chunk = Arc::new(chunk);
915        vm.execute(chunk.clone())?;
916        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 55);
917
918        let mut vm = Vm::new();
919        let mut chunk = Arc::try_unwrap(chunk).unwrap();
920        chunk.code.clear();
921        let slot = vm.globals.reserve();
922        let const2 = chunk.add_constant(45.into()) as u16;
923        let const3 = chunk.add_constant(1.into()) as u16;
924        chunk.encode2(CONST, 2, const2, Some(line))?;
925        chunk.encode2(CONST, 3, const3, Some(line))?;
926        chunk.encode_def(2, slot, Some(line), true)?;
927        chunk.encode_def(3, slot, Some(line), false)?;
928        chunk.encode_refi(0, slot, Some(line))?;
929        chunk.encode2(MOV, 5, 0, Some(line))?;
930        chunk.encode2(SET, 5, 3, Some(line))?;
931        chunk.encode2(ADD, 5, 3, Some(line))?;
932        chunk.encode2(ADD, 5, 3, Some(line))?;
933        chunk.encode0(RET, Some(line))?;
934        let chunk = Arc::new(chunk);
935        vm.execute(chunk)?;
936        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 1);
937        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 1);
938        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 1);
939        assert!(vm.stack(0).unref(&vm).get_int(&vm)? == 1);
940        assert!(vm.stack(5).unref(&vm).get_int(&vm)? == 3);
941        assert!(vm.globals.get(slot).get_int(&vm)? == 1);
942
943        Ok(())
944    }
945
946    #[test]
947    fn test_lambda() -> VMResult<()> {
948        let mut vm = Vm::new();
949        let mut chunk = Chunk::new("no_file", 1);
950        let line = 1;
951        chunk.encode2(ADD, 1, 2, Some(line)).unwrap();
952        chunk.encode2(MOV, 3, 1, Some(line)).unwrap();
953        chunk.encode1(SRET, 3, Some(line))?;
954        chunk.args = 2;
955        let add = vm.alloc_lambda(Arc::new(chunk));
956
957        let mut chunk = Chunk::new("no_file", 1);
958        let line = 1;
959        let const1 = chunk.add_constant(10.into()) as u16;
960        chunk.encode2(CONST, 2, const1, Some(line)).unwrap();
961        chunk.encode2(ADD, 1, 2, Some(line)).unwrap();
962        chunk.encode2(MOV, 3, 1, Some(line)).unwrap();
963        chunk.encode1(SRET, 3, Some(line))?;
964        chunk.args = 1;
965        let add_ten = vm.alloc_lambda(Arc::new(chunk));
966
967        let mut chunk = Chunk::new("no_file", 1);
968        let line = 1;
969        *vm.stack_mut(0) = add;
970        *vm.stack_mut(1) = add_ten;
971        *vm.stack_mut(3) = 5.into();
972        *vm.stack_mut(4) = 2.into();
973        *vm.stack_mut(6) = 2.into();
974        chunk.encode3(CALL, 0, 2, 2, Some(line)).unwrap();
975        chunk.encode3(CALL, 1, 1, 5, Some(line)).unwrap();
976        chunk.encode0(RET, Some(line))?;
977
978        let chunk = Arc::new(chunk);
979        vm.execute(chunk)?;
980        let result = vm.stack(2).get_int(&vm)?;
981        assert!(result == 7);
982        let result = vm.stack(5).get_int(&vm)?;
983        assert!(result == 12);
984        let result = vm.stack(7).get_int(&vm)?;
985        assert!(result == 10);
986
987        Ok(())
988    }
989
990    #[test]
991    fn test_tcall() -> VMResult<()> {
992        let mut vm = Vm::new();
993        let mut chunk = Chunk::new("no_file", 1);
994        let line = 1;
995        chunk.encode2(MOV, 3, 2, Some(line)).unwrap();
996        chunk.encode2(ADD, 3, 1, Some(line)).unwrap();
997        chunk.encode1(SRET, 3, Some(line))?;
998        chunk.args = 2;
999        let add = vm.alloc_lambda(Arc::new(chunk));
1000
1001        let mut chunk = Chunk::new("no_file", 1);
1002        let line = 1;
1003        let const1 = chunk.add_constant(10.into()) as u16;
1004        let const2 = chunk.add_constant(add) as u16;
1005        chunk.encode2(CONST, 2, const1, Some(line)).unwrap();
1006        chunk.encode2(CONST, 3, const2, Some(line)).unwrap();
1007        chunk.encode2(TCALL, 3, 2, Some(line)).unwrap();
1008        // The TCALL will keep HALT from executing.
1009        chunk.encode0(HALT, Some(line))?;
1010        chunk.args = 1;
1011        let add_ten = vm.alloc_lambda(Arc::new(chunk));
1012
1013        let mut chunk = Chunk::new("no_file", 1);
1014        let line = 1;
1015        *vm.stack_mut(1) = 5.into();
1016        *vm.stack_mut(2) = 2.into();
1017        *vm.stack_mut(4) = 2.into();
1018        *vm.stack_mut(50) = add;
1019        *vm.stack_mut(60) = add_ten;
1020        chunk.encode3(CALL, 60, 1, 3, Some(line)).unwrap();
1021        // tail call at the top level does not make sense
1022        //chunk.encode2(TCALL, 50, 2, Some(line)).unwrap();
1023        chunk.encode0(RET, Some(line))?;
1024
1025        let chunk = Arc::new(chunk);
1026        vm.execute(chunk)?;
1027        //let result = vm.stack(0).get_int(&vm)?;
1028        //assert!(result == 7);
1029        let result = vm.stack(3).get_int(&vm)?;
1030        assert!(result == 12);
1031
1032        Ok(())
1033    }
1034
1035    #[test]
1036    fn test_builtin() -> VMResult<()> {
1037        fn add_b(vm: &mut Vm, registers: &[Value]) -> VMResult<Value> {
1038            if registers.len() != 2 {
1039                return Err(VMError::new_vm("test add: wrong number of args."));
1040            }
1041            Ok((registers[0].get_int(vm)? + registers[1].get_int(vm)?).into())
1042        }
1043        fn add_10(vm: &mut Vm, registers: &[Value]) -> VMResult<Value> {
1044            if registers.len() != 1 {
1045                return Err(VMError::new_vm("test add_10: wrong number of args."));
1046            }
1047            Ok((registers[0].get_int(vm)? + 10).into())
1048        }
1049        fn make_str(vm: &mut Vm, registers: &[Value]) -> VMResult<Value> {
1050            if !registers.is_empty() {
1051                return Err(VMError::new_vm("test make_str: wrong number of args."));
1052            }
1053            let s = vm.alloc_string("builtin hello".into());
1054            Ok(s)
1055        }
1056        let mut vm = Vm::new();
1057        let mut chunk = Chunk::new("no_file", 1);
1058        let line = 1;
1059        let const1 = chunk.add_constant(vm.add_builtin(add_b)) as u16;
1060        chunk.encode2(CONST, 10, const1, Some(line)).unwrap();
1061        chunk.encode2(MOV, 4, 1, Some(line)).unwrap();
1062        chunk.encode2(MOV, 5, 2, Some(line)).unwrap();
1063        chunk.encode3(CALL, 10, 2, 3, Some(line)).unwrap();
1064        chunk.encode1(SRET, 3, Some(line))?;
1065        chunk.args = 2;
1066        let add = vm.alloc_lambda(Arc::new(chunk));
1067
1068        let mut chunk = Chunk::new("no_file", 1);
1069        let line = 1;
1070        let const1 = chunk.add_constant(vm.add_builtin(add_b)) as u16;
1071        chunk.encode2(CONST, 10, const1, Some(line)).unwrap();
1072        chunk.encode2(TCALL, 10, 2, Some(line)).unwrap();
1073        chunk.encode0(RET, Some(line))?;
1074        chunk.args = 2;
1075        let tadd = vm.alloc_lambda(Arc::new(chunk));
1076
1077        let mut chunk = Chunk::new("no_file", 1);
1078        let line = 1;
1079        let const1 = chunk.add_constant(vm.add_builtin(add_10)) as u16;
1080        chunk.encode2(CONST, 4, const1, Some(line)).unwrap();
1081        chunk.encode2(MOV, 3, 1, Some(line)).unwrap();
1082        chunk.encode3(CALL, 4, 1, 2, Some(line)).unwrap();
1083        chunk.encode1(SRET, 2, Some(line))?;
1084        chunk.args = 1;
1085        let add_ten = vm.alloc_lambda(Arc::new(chunk));
1086
1087        let mut chunk = Chunk::new("no_file", 1);
1088        let line = 1;
1089        *vm.stack_mut(0) = add;
1090        *vm.stack_mut(1) = add_ten;
1091        *vm.stack_mut(3) = 6.into();
1092        *vm.stack_mut(4) = 3.into();
1093        *vm.stack_mut(8) = 12.into();
1094        let const1 = chunk.add_constant(vm.add_builtin(make_str)) as u16;
1095        chunk.encode3(CALL, 0, 2, 2, Some(line)).unwrap();
1096        chunk.encode3(CALL, 1, 1, 7, Some(line)).unwrap();
1097        chunk.encode2(CONST, 15, const1, Some(line)).unwrap();
1098        chunk.encode3(CALL, 15, 0, 15, Some(line)).unwrap();
1099        chunk.encode0(RET, Some(line))?;
1100        let chunk = Arc::new(chunk);
1101        vm.execute(chunk)?;
1102        let result = vm.stack(2).get_int(&vm)?;
1103        assert!(result == 9);
1104        let result = vm.stack(7).get_int(&vm)?;
1105        assert!(result == 22);
1106        match vm.stack(15) {
1107            Value::String(h) => assert!(vm.heap().get_string(h) == "builtin hello"),
1108            _ => panic!("bad make_str call"),
1109        }
1110
1111        let mut chunk = Chunk::new("no_file", 1);
1112        let line = 1;
1113        for i in 0..100 {
1114            *vm.stack_mut(i) = Value::Undefined;
1115        }
1116        *vm.stack_mut(0) = tadd;
1117        *vm.stack_mut(1) = add_ten;
1118        *vm.stack_mut(3) = 6.into();
1119        *vm.stack_mut(4) = 3.into();
1120        *vm.stack_mut(6) = 12.into();
1121        let const1 = chunk.add_constant(vm.add_builtin(make_str)) as u16;
1122        chunk.encode3(CALL, 0, 2, 2, Some(line)).unwrap();
1123        chunk.encode3(CALL, 1, 1, 5, Some(line)).unwrap();
1124        chunk.encode2(CONST, 10, const1, Some(line)).unwrap();
1125        chunk.encode3(CALL, 10, 0, 11, Some(line)).unwrap();
1126        chunk.encode0(RET, Some(line))?;
1127        let chunk = Arc::new(chunk);
1128        vm.execute(chunk)?;
1129        let result = vm.stack(2).get_int(&vm)?;
1130        assert!(result == 9);
1131        let result = vm.stack(5).get_int(&vm)?;
1132        assert!(result == 22);
1133        match vm.stack(11) {
1134            Value::String(h) => assert!(vm.heap().get_string(h) == "builtin hello"),
1135            _ => panic!("bad make_str call"),
1136        }
1137
1138        Ok(())
1139    }
1140
1141    #[test]
1142    fn test_jumps() -> VMResult<()> {
1143        let mut vm = Vm::new();
1144        let mut chunk = Chunk::new("no_file", 1);
1145        let const0 = chunk.add_constant(2.into()) as u16;
1146        let const1 = chunk.add_constant(3.into()) as u16;
1147        *vm.stack_mut(0) = Value::True;
1148        *vm.stack_mut(1) = Value::False;
1149        *vm.stack_mut(2) = Value::Nil;
1150        *vm.stack_mut(3) = 0.into();
1151        let line = 1;
1152        chunk.encode2(CONST, 4, const0, Some(line))?;
1153        let jmp = chunk.add_jump(chunk.code.len() as u32 + 5);
1154        chunk.encode1(JMP, jmp as u16, Some(line))?;
1155        chunk.encode2(CONST, 4, const1, Some(line))?;
1156        chunk.encode2(CONST, 5, const1, Some(line))?;
1157
1158        chunk.encode2(CONST, 6, const0, Some(line))?;
1159        let jmp = chunk.add_jump(chunk.code.len() as u32 + 5);
1160        chunk.encode1(JMP, jmp as u16, Some(line))?;
1161        chunk.encode2(CONST, 6, const1, Some(line))?;
1162        chunk.encode2(CONST, 7, const1, Some(line))?;
1163
1164        let jmp = chunk.add_jump(chunk.code.len() as u32 + 7);
1165        chunk.encode1(JMP, jmp as u16, Some(line))?;
1166        let jmp_back = chunk.add_jump(chunk.code.len() as u32);
1167        chunk.encode2(CONST, 8, const0, Some(line))?;
1168        let jmp = chunk.add_jump(chunk.code.len() as u32 + 4);
1169        chunk.encode1(JMP, jmp as u16, Some(line))?;
1170        chunk.encode1(JMP, jmp_back as u16, Some(line))?;
1171        chunk.encode2(CONST, 9, const1, Some(line))?;
1172
1173        chunk.encode2(CONST, 10, const0, Some(line))?;
1174        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1175        chunk.encode2(JMPT, 0, jmp as u16, Some(line))?;
1176        chunk.encode2(CONST, 10, const1, Some(line))?;
1177        chunk.encode2(CONST, 11, const1, Some(line))?;
1178
1179        chunk.encode2(CONST, 12, const0, Some(line))?;
1180        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1181        chunk.encode2(JMPT, 3, jmp as u16, Some(line))?;
1182        chunk.encode2(CONST, 12, const1, Some(line))?;
1183        chunk.encode2(CONST, 13, const1, Some(line))?;
1184
1185        chunk.encode2(CONST, 14, const0, Some(line))?;
1186        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1187        chunk.encode2(JMPF, 1, jmp as u16, Some(line))?;
1188        chunk.encode2(CONST, 14, const1, Some(line))?;
1189        chunk.encode2(CONST, 15, const1, Some(line))?;
1190
1191        chunk.encode2(CONST, 16, const0, Some(line))?;
1192        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1193        chunk.encode2(JMPF, 2, jmp as u16, Some(line))?;
1194        chunk.encode2(CONST, 16, const1, Some(line))?;
1195        chunk.encode2(CONST, 17, const1, Some(line))?;
1196
1197        chunk.encode2(CONST, 18, const0, Some(line))?;
1198        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1199        chunk.encode2(JMPT, 1, jmp as u16, Some(line))?;
1200        chunk.encode2(CONST, 18, const1, Some(line))?;
1201        chunk.encode2(CONST, 19, const1, Some(line))?;
1202
1203        chunk.encode2(CONST, 20, const0, Some(line))?;
1204        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1205        chunk.encode2(JMPT, 2, jmp as u16, Some(line))?;
1206        chunk.encode2(CONST, 20, const1, Some(line))?;
1207        chunk.encode2(CONST, 21, const1, Some(line))?;
1208
1209        chunk.encode2(CONST, 22, const0, Some(line))?;
1210        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1211        chunk.encode2(JMPF, 0, jmp as u16, Some(line))?;
1212        chunk.encode2(CONST, 22, const1, Some(line))?;
1213        chunk.encode2(CONST, 23, const1, Some(line))?;
1214
1215        chunk.encode2(CONST, 24, const0, Some(line))?;
1216        let jmp = chunk.add_jump(chunk.code.len() as u32 + 6);
1217        chunk.encode2(JMPF, 3, jmp as u16, Some(line))?;
1218        chunk.encode2(CONST, 24, const1, Some(line))?;
1219        chunk.encode2(CONST, 25, const1, Some(line))?;
1220
1221        chunk.encode0(RET, Some(line))?;
1222        let chunk = Arc::new(chunk);
1223        vm.execute(chunk)?;
1224        assert!(vm.stack(4).get_int(&vm)? == 2);
1225        assert!(vm.stack(5).get_int(&vm)? == 3);
1226        assert!(vm.stack(6).get_int(&vm)? == 2);
1227        assert!(vm.stack(7).get_int(&vm)? == 3);
1228        assert!(vm.stack(8).get_int(&vm)? == 2);
1229        assert!(vm.stack(9).get_int(&vm)? == 3);
1230        assert!(vm.stack(10).get_int(&vm)? == 2);
1231        assert!(vm.stack(11).get_int(&vm)? == 3);
1232        assert!(vm.stack(12).get_int(&vm)? == 2);
1233        assert!(vm.stack(13).get_int(&vm)? == 3);
1234        assert!(vm.stack(14).get_int(&vm)? == 2);
1235        assert!(vm.stack(15).get_int(&vm)? == 3);
1236        assert!(vm.stack(16).get_int(&vm)? == 2);
1237        assert!(vm.stack(17).get_int(&vm)? == 3);
1238        assert!(vm.stack(18).get_int(&vm)? == 3);
1239        assert!(vm.stack(19).get_int(&vm)? == 3);
1240        assert!(vm.stack(20).get_int(&vm)? == 3);
1241        assert!(vm.stack(21).get_int(&vm)? == 3);
1242        assert!(vm.stack(22).get_int(&vm)? == 3);
1243        assert!(vm.stack(23).get_int(&vm)? == 3);
1244        assert!(vm.stack(24).get_int(&vm)? == 3);
1245        assert!(vm.stack(25).get_int(&vm)? == 3);
1246        Ok(())
1247    }
1248
1249    #[test]
1250    fn test_vecs() -> VMResult<()> {
1251        let mut vm = Vm::new();
1252        let mut chunk = Chunk::new("no_file", 1);
1253        let zero = chunk.add_constant(0.into()) as u16;
1254        let hundred = chunk.add_constant(100.into()) as u16;
1255        let one = chunk.add_constant(1.into()) as u16;
1256        let line = 1;
1257        chunk.encode2(CONST, 2, hundred, Some(line))?;
1258        chunk.encode2(CONST, 3, zero, Some(line))?;
1259        chunk.encode2(CONST, 4, one, Some(line))?;
1260        chunk.encode3(VECMKD, 1, 2, 3, Some(line))?;
1261        chunk.encode2(VECPSH, 1, 4, Some(line))?;
1262        chunk.encode2(VECPOP, 1, 5, Some(line))?;
1263        chunk.encode2(VECPOP, 1, 6, Some(line))?;
1264        chunk.encode2(VECPSH, 1, 4, Some(line))?;
1265        chunk.encode2(VECPSH, 1, 4, Some(line))?;
1266        chunk.encode3(GET, 7, 1, 2, Some(line))?;
1267        chunk.encode3(SETCOL, 3, 1, 2, Some(line))?;
1268        chunk.encode3(GET, 8, 1, 2, Some(line))?;
1269        chunk.encode2(VECMK, 10, 2, Some(line))?;
1270        chunk.encode2(VECPSH, 10, 4, Some(line))?;
1271        chunk.encode2(VECPSH, 10, 3, Some(line))?;
1272        chunk.encode2(VECPOP, 10, 15, Some(line))?;
1273        chunk.encode2(VECPOP, 10, 16, Some(line))?;
1274        chunk.encode2(VECPSH, 10, 4, Some(line))?;
1275        chunk.encode2(VECPSH, 10, 4, Some(line))?;
1276        chunk.encode3(GET, 17, 10, 3, Some(line))?;
1277        chunk.encode3(SETCOL, 3, 10, 3, Some(line))?;
1278        chunk.encode3(GET, 18, 10, 3, Some(line))?;
1279        chunk.encode2(VECMK, 20, 2, Some(line))?;
1280        chunk.encode2(VECELS, 20, 2, Some(line))?;
1281        chunk.encode3(SETCOL, 3, 20, 3, Some(line))?;
1282        chunk.encode0(RET, Some(line))?;
1283        let chunk = Arc::new(chunk);
1284        vm.execute(chunk)?;
1285        assert!(vm.stack(5).get_int(&vm)? == 1);
1286        assert!(vm.stack(6).get_int(&vm)? == 0);
1287        assert!(vm.stack(7).get_int(&vm)? == 1);
1288        assert!(vm.stack(8).get_int(&vm)? == 0);
1289
1290        assert!(vm.stack(15).get_int(&vm)? == 0);
1291        assert!(vm.stack(16).get_int(&vm)? == 1);
1292        assert!(vm.stack(17).get_int(&vm)? == 1);
1293        assert!(vm.stack(18).get_int(&vm)? == 0);
1294        let vc = vm.stack(1);
1295        if let Value::Vector(h) = vc {
1296            let v = vm.get_vector(h);
1297            assert!(v.len() == 101);
1298            assert!(v[0].get_int(&vm)? == 0);
1299        }
1300        let vc = vm.stack(10);
1301        if let Value::Vector(h) = vc {
1302            let v = vm.get_vector(h);
1303            assert!(v.len() == 2);
1304            assert!(v[0].get_int(&vm)? == 0);
1305            assert!(v[1].get_int(&vm)? == 1);
1306        }
1307        let vc = vm.stack(20);
1308        if let Value::Vector(h) = vc {
1309            let v = vm.get_vector(h);
1310            assert!(v.len() == 100);
1311            assert!(v[0].get_int(&vm)? == 0);
1312            assert!(v[1].is_undef());
1313            assert!(v[99].is_undef());
1314        }
1315        Ok(())
1316    }
1317
1318    #[test]
1319    fn test_add() -> VMResult<()> {
1320        let mut chunk = Chunk::new("no_file", 1);
1321        let line = 1;
1322        let const0 = chunk.add_constant(2.into()) as u16;
1323        let const1 = chunk.add_constant(3.into()) as u16;
1324        let const2 = chunk.add_constant(Value::Byte(1)) as u16;
1325        chunk.encode2(CONST, 0, const0, Some(line))?;
1326        chunk.encode2(CONST, 1, const1, Some(line))?;
1327        chunk.encode2(CONST, 2, const2, Some(line))?;
1328        chunk.encode2(ADD, 0, 1, Some(line)).unwrap();
1329        chunk.encode2(ADD, 0, 2, Some(line)).unwrap();
1330        chunk.encode0(RET, Some(line))?;
1331        let mut vm = Vm::new();
1332        let chunk = Arc::new(chunk);
1333        vm.execute(chunk)?;
1334        assert!(vm.stack(0).get_int(&vm)? == 6);
1335
1336        let mut chunk = Chunk::new("no_file", 1);
1337        let const0 = chunk.add_constant(2_f32.into()) as u16;
1338        let const1 = chunk.add_constant(3.into()) as u16;
1339        let const2 = chunk.add_constant(Value::Byte(1)) as u16;
1340        chunk.encode2(CONST, 0, const0, Some(line))?;
1341        chunk.encode2(CONST, 1, const1, Some(line))?;
1342        chunk.encode2(CONST, 2, const2, Some(line))?;
1343        chunk.encode2(ADD, 0, 1, Some(line)).unwrap();
1344        chunk.encode2(ADD, 0, 2, Some(line)).unwrap();
1345        chunk.encode0(RET, Some(line))?;
1346        let chunk = Arc::new(chunk);
1347        vm.execute(chunk)?;
1348        let item = vm.stack(0);
1349        assert!(!item.is_int());
1350        assert!(item.is_number());
1351        assert!(item.get_float(&vm)? == 6.0);
1352
1353        let mut chunk = Chunk::new("no_file", 1);
1354        for i in 0..501 {
1355            chunk.add_constant(i.into());
1356        }
1357        chunk.encode2(CONST, 1, 1, Some(line))?;
1358        chunk.encode2(CONST, 2, 2, Some(line))?;
1359        chunk.encode2(CONST, 5, 5, Some(line))?;
1360        chunk.encode2(CONST, 500, 500, Some(line))?;
1361        chunk.encode2(MOV, 0, 1, Some(line)).unwrap();
1362        chunk.encode2(ADD, 0, 2, Some(line)).unwrap();
1363        chunk.encode2(ADD, 0, 5, Some(line)).unwrap();
1364        chunk.encode2(ADD, 500, 0, Some(line)).unwrap();
1365        chunk.encode2(MOV, 1, 500, Some(line)).unwrap();
1366        chunk.encode0(RET, Some(line))?;
1367        let chunk = Arc::new(chunk);
1368        vm.execute(chunk)?;
1369        let item = vm.stack(0);
1370        let item2 = vm.stack(1);
1371        assert!(item.is_int());
1372        assert!(item.get_int(&vm)? == 8);
1373        assert!(item2.get_int(&vm)? == 508);
1374        Ok(())
1375    }
1376
1377    #[test]
1378    fn test_sub() -> VMResult<()> {
1379        let mut chunk = Chunk::new("no_file", 1);
1380        let line = 1;
1381        let const0 = chunk.add_constant(2.into()) as u16;
1382        let const1 = chunk.add_constant(3.into()) as u16;
1383        let const2 = chunk.add_constant(Value::Byte(1)) as u16;
1384        chunk.encode2(CONST, 0, const0, Some(line))?;
1385        chunk.encode2(CONST, 1, const1, Some(line))?;
1386        chunk.encode2(CONST, 2, const2, Some(line))?;
1387        chunk.encode2(SUB, 0, 1, Some(line)).unwrap();
1388        chunk.encode2(SUB, 0, 2, Some(line)).unwrap();
1389        chunk.encode0(RET, Some(line))?;
1390        let mut vm = Vm::new();
1391        let chunk = Arc::new(chunk);
1392        vm.execute(chunk)?;
1393        assert_eq!(vm.stack(0).get_int(&vm)?, -2);
1394
1395        let mut chunk = Chunk::new("no_file", 1);
1396        let const0 = chunk.add_constant(5_f32.into()) as u16;
1397        let const1 = chunk.add_constant(3.into()) as u16;
1398        let const2 = chunk.add_constant(Value::Byte(1)) as u16;
1399        chunk.encode2(CONST, 0, const0, Some(line))?;
1400        chunk.encode2(CONST, 1, const1, Some(line))?;
1401        chunk.encode2(CONST, 2, const2, Some(line))?;
1402        chunk.encode2(SUB, 0, 1, Some(line)).unwrap();
1403        chunk.encode2(SUB, 0, 2, Some(line)).unwrap();
1404        chunk.encode0(RET, Some(line))?;
1405        let chunk = Arc::new(chunk);
1406        vm.execute(chunk)?;
1407        let item = vm.stack(0);
1408        assert!(!item.is_int(), "Item an int");
1409        assert!(item.is_number(), "Item not a number");
1410        assert_eq!(item.get_float(&vm)?, 1.0);
1411
1412        let mut chunk = Chunk::new("no_file", 1);
1413        for i in 0..501 {
1414            chunk.add_constant(i.into());
1415        }
1416        chunk.encode2(CONST, 1, 1, Some(line))?;
1417        chunk.encode2(CONST, 2, 2, Some(line))?;
1418        chunk.encode2(CONST, 5, 5, Some(line))?;
1419        chunk.encode2(CONST, 500, 500, Some(line))?;
1420        chunk.encode2(SUB, 1, 2, Some(line)).unwrap();
1421        chunk.encode2(SUB, 5, 1, Some(line)).unwrap();
1422        chunk.encode2(MOV, 0, 5, Some(line)).unwrap();
1423        chunk.encode2(SUB, 500, 5, Some(line)).unwrap();
1424        chunk.encode2(MOV, 1, 500, Some(line)).unwrap();
1425        chunk.encode0(RET, Some(line))?;
1426        let chunk = Arc::new(chunk);
1427        vm.execute(chunk)?;
1428        let item = vm.stack(0);
1429        let item2 = vm.stack(1);
1430        assert!(item.is_int(), "Item not an int");
1431        assert_eq!(item.get_int(&vm)?, 6);
1432        assert_eq!(item2.get_int(&vm)?, 494);
1433        Ok(())
1434    }
1435
1436    #[test]
1437    fn test_mul() -> VMResult<()> {
1438        let mut chunk = Chunk::new("no_file", 1);
1439        let line = 1;
1440        let const0 = chunk.add_constant(2.into()) as u16;
1441        let const1 = chunk.add_constant(3.into()) as u16;
1442        let const2 = chunk.add_constant(Value::Byte(1)) as u16;
1443        chunk.encode2(CONST, 0, const0, Some(line))?;
1444        chunk.encode2(CONST, 1, const1, Some(line))?;
1445        chunk.encode2(CONST, 2, const2, Some(line))?;
1446        chunk.encode2(MUL, 0, 1, Some(line)).unwrap();
1447        chunk.encode2(MUL, 0, 2, Some(line)).unwrap();
1448        chunk.encode0(RET, Some(line))?;
1449        let mut vm = Vm::new();
1450        let chunk = Arc::new(chunk);
1451        vm.execute(chunk)?;
1452        assert!(vm.stack(0).get_int(&vm)? == 6);
1453
1454        let mut chunk = Chunk::new("no_file", 1);
1455        let const0 = chunk.add_constant(5_f32.into()) as u16;
1456        let const1 = chunk.add_constant(3.into()) as u16;
1457        let const2 = chunk.add_constant(Value::Byte(2)) as u16;
1458        chunk.encode2(CONST, 0, const0, Some(line))?;
1459        chunk.encode2(CONST, 1, const1, Some(line))?;
1460        chunk.encode2(CONST, 2, const2, Some(line))?;
1461        chunk.encode2(MUL, 0, 1, Some(line)).unwrap();
1462        chunk.encode2(MUL, 0, 2, Some(line)).unwrap();
1463        chunk.encode0(RET, Some(line))?;
1464        let chunk = Arc::new(chunk);
1465        vm.execute(chunk)?;
1466        let item = vm.stack(0);
1467        assert!(!item.is_int());
1468        assert!(item.is_number());
1469        assert!(item.get_float(&vm)? == 30.0);
1470
1471        let mut chunk = Chunk::new("no_file", 1);
1472        for i in 0..501 {
1473            chunk.add_constant(i.into());
1474        }
1475        chunk.encode2(CONST, 1, 1, Some(line))?;
1476        chunk.encode2(CONST, 2, 2, Some(line))?;
1477        chunk.encode2(CONST, 5, 5, Some(line))?;
1478        chunk.encode2(CONST, 500, 500, Some(line))?;
1479        chunk.encode2(MOV, 0, 2, Some(line)).unwrap();
1480        chunk.encode2(MUL, 0, 1, Some(line)).unwrap();
1481        chunk.encode2(MUL, 0, 5, Some(line)).unwrap();
1482        chunk.encode2(MUL, 500, 0, Some(line)).unwrap();
1483        chunk.encode2(MOV, 1, 500, Some(line)).unwrap();
1484        chunk.encode0(RET, Some(line))?;
1485        let chunk = Arc::new(chunk);
1486        vm.execute(chunk)?;
1487        let item = vm.stack(0);
1488        let item2 = vm.stack(1);
1489        assert!(item.is_int());
1490        assert!(item.get_int(&vm)? == 10);
1491        assert!(item2.get_int(&vm)? == 5000);
1492        Ok(())
1493    }
1494
1495    #[test]
1496    fn test_div() -> VMResult<()> {
1497        let mut chunk = Chunk::new("no_file", 1);
1498        let line = 1;
1499        let const0 = chunk.add_constant(18.into()) as u16;
1500        let const1 = chunk.add_constant(2.into()) as u16;
1501        let const2 = chunk.add_constant(Value::Byte(3)) as u16;
1502        chunk.encode2(CONST, 0, const0, Some(line))?;
1503        chunk.encode2(CONST, 1, const1, Some(line))?;
1504        chunk.encode2(CONST, 2, const2, Some(line))?;
1505        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1506        chunk.encode2(DIV, 0, 2, Some(line)).unwrap();
1507        chunk.encode0(RET, Some(line))?;
1508        let mut vm = Vm::new();
1509        let val10 = 10_f32.into();
1510        let val0 = 0_f32.into();
1511        let chunk = Arc::new(chunk);
1512        vm.execute(chunk)?;
1513        assert!(vm.stack(0).get_int(&vm)? == 3);
1514
1515        let mut chunk = Chunk::new("no_file", 1);
1516        let const0 = chunk.add_constant(val10) as u16;
1517        let const1 = chunk.add_constant(2.into()) as u16;
1518        let const2 = chunk.add_constant(Value::Byte(2)) as u16;
1519        chunk.encode2(CONST, 0, const0, Some(line))?;
1520        chunk.encode2(CONST, 1, const1, Some(line))?;
1521        chunk.encode2(CONST, 2, const2, Some(line))?;
1522        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1523        chunk.encode2(DIV, 0, 2, Some(line)).unwrap();
1524        chunk.encode0(RET, Some(line))?;
1525        let chunk = Arc::new(chunk);
1526        vm.execute(chunk)?;
1527        let item = vm.stack(0);
1528        assert!(!item.is_int());
1529        assert!(item.is_number());
1530        assert!(item.get_float(&vm)? == 2.5);
1531
1532        let mut chunk = Chunk::new("no_file", 1);
1533        for i in 0..501 {
1534            chunk.add_constant(i.into());
1535        }
1536        chunk.encode2(CONST, 1, 1, Some(line))?;
1537        chunk.encode2(CONST, 2, 2, Some(line))?;
1538        chunk.encode2(CONST, 10, 10, Some(line))?;
1539        chunk.encode2(CONST, 500, 500, Some(line))?;
1540        chunk.encode2(MOV, 0, 2, Some(line)).unwrap();
1541        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1542        chunk.encode2(DIV, 10, 0, Some(line)).unwrap();
1543        chunk.encode2(MOV, 0, 10, Some(line)).unwrap();
1544        chunk.encode2(DIV, 500, 0, Some(line)).unwrap();
1545        chunk.encode2(MOV, 1, 500, Some(line)).unwrap();
1546        chunk.encode0(RET, Some(line))?;
1547        let chunk = Arc::new(chunk);
1548        vm.execute(chunk)?;
1549        let item = vm.stack(0);
1550        let item2 = vm.stack(1);
1551        assert!(item.is_int());
1552        assert!(item.get_int(&vm)? == 5);
1553        assert!(item2.get_int(&vm)? == 100);
1554
1555        let mut chunk = Chunk::new("no_file", 1);
1556        let const0 = chunk.add_constant(10.into()) as u16;
1557        let const1 = chunk.add_constant(0.into()) as u16;
1558        chunk.encode2(CONST, 0, const0, Some(line))?;
1559        chunk.encode2(CONST, 1, const1, Some(line))?;
1560        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1561        chunk.encode0(RET, Some(line))?;
1562        let chunk = Arc::new(chunk);
1563        let res = vm.execute(chunk);
1564        assert!(res.is_err());
1565        assert!(res.unwrap_err().to_string() == "[rt]: Divide by zero error.");
1566
1567        let mut chunk = Chunk::new("no_file", 1);
1568        let const0 = chunk.add_constant(val10) as u16;
1569        let const1 = chunk.add_constant(val0) as u16;
1570        chunk.encode2(CONST, 0, const0, Some(line))?;
1571        chunk.encode2(CONST, 1, const1, Some(line))?;
1572        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1573        chunk.encode0(RET, Some(line))?;
1574        let chunk = Arc::new(chunk);
1575        let res = vm.execute(chunk);
1576        assert!(res.is_err());
1577        assert!(res.unwrap_err().to_string() == "[rt]: Divide by zero error.");
1578
1579        let mut chunk = Chunk::new("no_file", 1);
1580        let const1 = chunk.add_constant(Value::Byte(0)) as u16;
1581        chunk.encode2(CONST, 0, const0, Some(line))?;
1582        chunk.encode2(CONST, 1, const1, Some(line))?;
1583        chunk.encode2(DIV, 0, 1, Some(line)).unwrap();
1584        chunk.encode0(RET, Some(line))?;
1585        let chunk = Arc::new(chunk);
1586        let res = vm.execute(chunk);
1587        assert!(res.is_err());
1588        assert!(res.unwrap_err().to_string() == "[rt]: Divide by zero error.");
1589        Ok(())
1590    }
1591
1592    #[test]
1593    fn test_equality() {
1594        let vm = Vm::new();
1595
1596        let byte = Value::Byte(2);
1597        let another_byte = Value::Byte(2);
1598        let int = Value::Int([0, 0, 0, 0, 0, 0, 2]);
1599        let another_int = Value::Int([0, 0, 0, 0, 0, 0, 2]);
1600        let float = Value::Float(2.0.into());
1601        let another_float = Value::Float(2.0000000000000000000000000000000000000000001.into());
1602
1603        // testing `=`
1604        assert!(vm.is_equal_pair(byte, int).unwrap().is_true());
1605        assert!(vm.is_equal_pair(byte, float).unwrap().is_false());
1606        assert!(vm.is_equal_pair(int, float).unwrap().is_false());
1607
1608        // testing `identical?`
1609        assert!(byte == another_byte);
1610        assert!(int == another_int);
1611        assert!(float == another_float);
1612        assert!(byte != int);
1613        assert!(byte != float);
1614        assert!(int != float);
1615    }
1616}