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
18pub const STACK_CAP: usize = 1024;
20
21const DEAD_CODE: [u8; 3] = [HALT, HALT, HALT];
22
23struct 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: *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>, 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 panic!("Unable to allocate a stack!");
79 }
80 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, 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 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 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 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 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 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 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 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 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 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 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 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 *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 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 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 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 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 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 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 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 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 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 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 Arc::make_mut(&mut chunk);
723 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 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 chunk.encode0(RET, Some(line))?;
1024
1025 let chunk = Arc::new(chunk);
1026 vm.execute(chunk)?;
1027 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 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 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}