sylt_machine/
vm.rs

1use owo_colors::OwoColorize;
2use std::borrow::Cow;
3use std::cell::RefCell;
4use std::collections::{hash_map::Entry, HashMap, HashSet};
5use std::rc::Rc;
6use sylt_common::error::{Error, RuntimeError, RuntimePhase};
7use sylt_common::{
8    Blob, Block, BlockLinkState, Frame, Machine, Op, OpResult, Prog, RuntimeContext, RustFunction,
9    Type, UpValue, Value,
10};
11
12macro_rules! error {
13    ( $thing:expr, $kind:expr) => {
14        return Err($thing.error($kind, None));
15    };
16    ( $thing:expr, $kind:expr, $( $msg:expr ),*) => {
17        {
18            let msg = Some(format!($( $msg ),*).into());
19            return Err($thing.error($kind, msg));
20        }
21    };
22}
23
24macro_rules! one_op {
25    ( $self:expr, $op:expr, $fun:expr ) => {
26        let a = $self.pop();
27        let b = $fun(&a);
28        if b.is_nil() {
29            $self.push(b);
30            error!($self, RuntimeError::TypeError($op, vec![a.into()]));
31        }
32        $self.push(b);
33    };
34}
35
36macro_rules! two_op {
37    ( $self:expr, $op:expr, $fun:expr ) => {
38        let (a, b) = $self.poppop();
39        let c = $fun(&a, &b);
40        if c.is_nil() {
41            $self.push(c);
42            error!(
43                $self,
44                RuntimeError::TypeError($op, vec![a.into(), b.into()])
45            );
46        }
47        $self.push(c);
48    };
49}
50
51pub struct VM {
52    upvalues: HashMap<usize, Rc<RefCell<UpValue>>>,
53
54    stack: Vec<Value>,
55    frames: Vec<Frame>,
56    blocks: Vec<Rc<RefCell<Block>>>,
57    blobs: Vec<Blob>,
58    args: Vec<String>,
59
60    constants: Vec<Value>,
61    strings: Vec<String>,
62
63    pub print_bytecode: bool,
64    pub print_exec: bool,
65
66    extern_functions: Vec<RustFunction>,
67}
68
69impl VM {
70    pub fn new() -> Self {
71        Self {
72            upvalues: HashMap::new(),
73
74            stack: Vec::new(),
75            frames: Vec::new(),
76            blocks: Vec::new(),
77            blobs: Vec::new(),
78            args: Vec::new(),
79
80            constants: Vec::new(),
81            strings: Vec::new(),
82
83            print_bytecode: false,
84            print_exec: false,
85
86            extern_functions: Vec::new(),
87        }
88    }
89
90    fn drop_upvalue(&mut self, slot: usize, value: Value) {
91        if let Entry::Occupied(entry) = self.upvalues.entry(slot) {
92            entry.get().borrow_mut().close(value);
93            entry.remove();
94        }
95    }
96
97    fn find_upvalue(&mut self, slot: usize) -> &mut Rc<RefCell<UpValue>> {
98        self.upvalues
99            .entry(slot)
100            .or_insert_with(|| Rc::new(RefCell::new(UpValue::new(slot))))
101    }
102
103    fn push(&mut self, value: Value) {
104        self.stack.push(value);
105    }
106
107    fn pop(&mut self) -> Value {
108        match self.stack.pop() {
109            Some(x) => x,
110            None => self.crash_and_burn(),
111        }
112    }
113
114    fn poppop(&mut self) -> (Value, Value) {
115        let (a, b) = (
116            self.stack.remove(self.stack.len() - 1),
117            self.stack.remove(self.stack.len() - 1),
118        );
119        (b, a) // this matches the order they were on the stack
120    }
121
122    fn frame(&self) -> &Frame {
123        self.frames.last().unwrap()
124    }
125
126    fn frame_mut(&mut self) -> &mut Frame {
127        self.frames.last_mut().unwrap()
128    }
129
130    fn constant(&self, slot: usize) -> &Value {
131        &self.constants[slot]
132    }
133
134    fn string(&self, slot: usize) -> &String {
135        &self.strings[slot]
136    }
137
138    fn op(&self) -> Op {
139        let ip = self.frame().ip;
140        self.frame().block.borrow().ops[ip]
141    }
142
143    fn print_stacktrace(&self) {
144        println!("\n<{}>", "STACK".red());
145        for (i, frame) in self.frames.iter().enumerate() {
146            println!(
147                "  {:>3}. {}:{:<4} in {:10}",
148                i,
149                frame.block.borrow().file.display(),
150                frame.block.borrow().line(self.frame().ip),
151                frame.block.borrow().name.blue()
152            );
153        }
154        println!()
155    }
156
157    /// Stop the program, violently
158    fn crash_and_burn(&self) -> ! {
159        self.print_stack();
160        println!("\n");
161        self.print_stacktrace();
162        self.frame()
163            .block
164            .borrow()
165            .debug_print(Some(&self.constants));
166        println!(
167            "    ip: {}, line: {}\n",
168            self.frame().ip.blue(),
169            self.frame().block.borrow().line(self.frame().ip).blue()
170        );
171        unreachable!();
172    }
173
174    fn error(&self, kind: RuntimeError, message: Option<String>) -> Error {
175        let frame = self.frames.last().unwrap();
176        self.print_stacktrace();
177        Error::RuntimeError {
178            kind,
179            phase: RuntimePhase::Runtime,
180            file: frame.block.borrow().file.clone(),
181            line: frame.block.borrow().line(frame.ip),
182            message,
183        }
184    }
185
186    fn print_stack(&self) {
187        let start = self.frame().stack_offset;
188        print!("    {:3} [", start);
189        for (i, s) in self.stack.iter().skip(start).enumerate() {
190            if i != 0 {
191                print!(" ");
192            }
193            print!("{:?}", s.green());
194        }
195        println!("]");
196
197        println!(
198            "{:5} {:05} {:?}",
199            self.frame().block.borrow().line(self.frame().ip).blue(),
200            self.frame().ip.red(),
201            self.frame().block.borrow().ops[self.frame().ip]
202        );
203    }
204
205    #[doc(hidden)]
206    pub fn init(&mut self, prog: &Prog, args: &[String]) {
207        let block = Rc::clone(&prog.blocks[0]);
208        self.constants = prog.constants.clone();
209        self.strings = prog.strings.clone();
210        self.blocks = prog.blocks.clone();
211        self.blobs = prog.blobs.clone();
212        self.args = Vec::from(args);
213
214        self.extern_functions = prog.functions.clone();
215        self.stack.clear();
216        self.frames.clear();
217
218        self.push(Value::Function(
219            Rc::new(Vec::new()),
220            Type::Function(Vec::new(), Box::new(Type::Void)),
221            0,
222        ));
223
224        self.frames.push(Frame {
225            stack_offset: 0,
226            block,
227            ip: 0,
228            contains_upvalues: false,
229        });
230    }
231
232    /// Simulates the program.
233    pub fn run(&mut self) -> Result<OpResult, Error> {
234        if self.print_bytecode {
235            println!("\n    [[{}]]\n", "RUNNING".red());
236            self.frame()
237                .block
238                .borrow()
239                .debug_print(Some(&self.constants));
240        }
241
242        loop {
243            #[cfg(debug_assertions)]
244            if self.print_exec {
245                self.print_stack()
246            }
247
248            let op = self.eval_op(self.op())?;
249            if matches!(op, OpResult::Done | OpResult::Yield) {
250                return Ok(op);
251            }
252        }
253    }
254}
255
256impl Machine for VM {
257    fn stack_from_base(&self, base: usize) -> Cow<[Value]> {
258        Cow::Borrowed(&self.stack[base..])
259    }
260
261    fn blobs(&self) -> &[Blob] {
262        &self.blobs
263    }
264
265    fn args(&self) -> &[String] {
266        &self.args
267    }
268
269    /// Calls `callable` with `args`. Continues to run until the call returns and then returns the
270    /// returned value.
271    fn eval_call(&mut self, callable: Value, args: &[&Value]) -> Result<Value, Error> {
272        self.push(callable);
273        let num_args = args.len();
274        args.iter().for_each(|value| self.push(Value::clone(value)));
275        // Since the Op::Call below isn't a compiled instruction, we need to store the current
276        // instruction pointer and restore it when we return to this frame.
277        let ip = self.frame().ip;
278        self.eval_op(Op::Call(num_args))?;
279
280        let cur_frame = self.frames.len();
281        while self.frames.len() >= cur_frame {
282            #[cfg(debug_assertions)]
283            if self.print_exec {
284                self.print_stack()
285            }
286
287            self.eval_op(self.op())?;
288        }
289        // Restore the instruction pointer.
290        self.frame_mut().ip = ip;
291        // Take the return value from the stack.
292        Ok(self.pop())
293    }
294
295    /// Runs a single operation on the VM
296    fn eval_op(&mut self, op: Op) -> Result<OpResult, Error> {
297        match op {
298            Op::Illegal => {
299                error!(self, RuntimeError::InvalidProgram);
300            }
301
302            Op::Unreachable => {
303                error!(self, RuntimeError::Unreachable);
304            }
305
306            Op::Pop => {
307                self.pop();
308            }
309
310            Op::Tuple(size) => {
311                let values = self.stack.split_off(self.stack.len() - size);
312                self.stack.push(Value::Tuple(Rc::new(values)));
313            }
314
315            Op::List(size) => {
316                let values = self.stack.split_off(self.stack.len() - size);
317                self.stack.push(Value::List(Rc::new(RefCell::new(values))));
318            }
319
320            Op::Set(size) => {
321                let values: HashSet<_> = self
322                    .stack
323                    .split_off(self.stack.len() - size)
324                    .into_iter()
325                    .collect();
326                self.stack.push(Value::Set(Rc::new(RefCell::new(values))));
327            }
328
329            Op::Dict(size) => {
330                assert!(size % 2 == 0);
331                let values = self.stack.split_off(self.stack.len() - size);
332                let values: HashMap<_, _> = values
333                    .chunks_exact(2)
334                    .map(|a| (a[0].clone(), a[1].clone()))
335                    .collect();
336                self.stack.push(Value::Dict(Rc::new(RefCell::new(values))));
337            }
338
339            Op::PopUpvalue => {
340                let value = self.pop();
341                let slot = self.stack.len();
342                self.drop_upvalue(slot, value);
343            }
344
345            Op::Copy(n) => {
346                let end = Vec::from(&self.stack[self.stack.len() - n..]);
347                self.stack.extend(end);
348            }
349
350            Op::Swap => {
351                let (a, b) = self.poppop();
352                self.push(b);
353                self.push(a);
354            }
355
356            Op::Yield => {
357                self.frame_mut().ip += 1;
358                return Ok(OpResult::Yield);
359            }
360
361            Op::Constant(value) => {
362                let offset = self.frame().stack_offset;
363                let constant = self.constant(value).clone();
364                let value = match constant {
365                    Value::Function(ups, ty, block) => {
366                        let inner = Rc::clone(&self.blocks[block]);
367                        if matches!(inner.borrow().linking, BlockLinkState::Linked) {
368                            Value::Function(ups, ty, block)
369                        } else {
370                            let mut ups = Vec::new();
371                            for (slot, is_up, _) in inner.borrow().upvalues.iter() {
372                                self.frame_mut().contains_upvalues = true;
373                                let up = if *is_up {
374                                    if let Value::Function(local_ups, _, _) = &self.stack[offset] {
375                                        Rc::clone(&local_ups[*slot])
376                                    } else {
377                                        unreachable!()
378                                    }
379                                } else {
380                                    let slot = self.frame().stack_offset + slot;
381                                    Rc::clone(self.find_upvalue(slot))
382                                };
383                                ups.push(up);
384                            }
385                            Value::Function(Rc::new(ups), ty, block)
386                        }
387                    }
388                    value => value,
389                };
390                self.push(value);
391            }
392
393            Op::Link(slot) => {
394                let offset = self.frame().stack_offset;
395                let constant = self.constant(slot).clone();
396                let constant = match constant {
397                    Value::Function(_, ty, block) => {
398                        let inner = Rc::clone(&self.blocks[block]);
399                        let mut ups = Vec::new();
400                        for (slot, is_up, _) in inner.borrow().upvalues.iter() {
401                            let up = if *is_up {
402                                if let Value::Function(local_ups, _, _) = &self.stack[offset] {
403                                    Rc::clone(&local_ups[*slot])
404                                } else {
405                                    unreachable!()
406                                }
407                            } else {
408                                let slot = self.frame().stack_offset + slot;
409                                Rc::clone(self.find_upvalue(slot))
410                            };
411                            ups.push(up);
412                        }
413                        Value::Function(Rc::new(ups), ty, block)
414                    }
415                    value => error!(
416                        self,
417                        RuntimeError::ValueError(op, vec![value]),
418                        "Not a function {:?}",
419                        value
420                    ),
421                };
422                self.constants[slot] = constant;
423            }
424
425            Op::GetIndex => {
426                let slot = self.pop();
427                let val = self.pop();
428                match (val, slot) {
429                    (Value::Tuple(v), Value::Int(slot)) => {
430                        let slot = slot as usize;
431                        if v.len() <= slot {
432                            self.stack.push(Value::Nil);
433                            let len = v.len();
434                            error!(
435                                self,
436                                RuntimeError::IndexOutOfBounds(Value::Tuple(v), len, slot)
437                            );
438                        }
439                        self.stack.push(v[slot].clone());
440                    }
441                    (Value::List(rc_v), Value::Int(slot)) => {
442                        let slot = slot as usize;
443                        let v = rc_v.borrow();
444                        if v.len() <= slot {
445                            self.stack.push(Value::Nil);
446                            let len = v.len();
447                            drop(v);
448                            error!(
449                                self,
450                                RuntimeError::IndexOutOfBounds(Value::List(rc_v), len, slot)
451                            );
452                        }
453                        self.stack.push(v[slot].clone());
454                    }
455                    (Value::Dict(dict), i) => {
456                        self.push(
457                            dict.as_ref()
458                                .borrow()
459                                .get(&i)
460                                .cloned()
461                                .unwrap_or(Value::Nil),
462                        );
463                    }
464                    (val, slot) => {
465                        self.stack.push(Value::Nil);
466                        error!(self, RuntimeError::IndexError(val, slot.into()));
467                    }
468                }
469            }
470
471            Op::GetConstIndex(slot) => {
472                let val = self.pop();
473                match val {
474                    Value::Tuple(v) => {
475                        let slot = slot as usize;
476                        if v.len() <= slot {
477                            self.stack.push(Value::Nil);
478                            let len = v.len();
479                            error!(
480                                self,
481                                RuntimeError::IndexOutOfBounds(Value::Tuple(v), len, slot)
482                            );
483                        }
484                        self.stack.push(v[slot].clone());
485                    }
486                    Value::List(rc_v) => {
487                        let slot = slot as usize;
488                        let v = rc_v.borrow();
489                        if v.len() <= slot {
490                            self.stack.push(Value::Nil);
491                            let len = v.len();
492                            drop(v);
493                            error!(
494                                self,
495                                RuntimeError::IndexOutOfBounds(Value::List(rc_v), len, slot)
496                            );
497                        }
498                        self.stack.push(v[slot].clone());
499                    }
500                    Value::Dict(dict) => {
501                        self.push(
502                            dict.as_ref()
503                                .borrow()
504                                .get(&Value::Int(slot))
505                                .cloned()
506                                .unwrap_or(Value::Nil),
507                        );
508                    }
509                    val => {
510                        self.stack.push(Value::Nil);
511                        error!(self, RuntimeError::IndexError(val, Type::Int));
512                    }
513                }
514            }
515
516            Op::AssignIndex => {
517                let value = self.pop();
518                let slot = self.pop();
519                let indexable = self.pop();
520                match (indexable, slot, value) {
521                    (Value::List(rc_v), Value::Int(slot), n) => {
522                        let slot = slot as usize;
523                        let v = rc_v.borrow();
524                        if v.len() <= slot {
525                            self.stack.push(Value::Nil);
526                            let len = v.len();
527                            drop(v);
528                            error!(
529                                self,
530                                RuntimeError::IndexOutOfBounds(Value::List(rc_v), len, slot)
531                            );
532                        }
533                        drop(v);
534                        rc_v.borrow_mut()[slot] = n;
535                    }
536                    (Value::Dict(rc_v), slot, n) => {
537                        rc_v.as_ref().borrow_mut().insert(slot, n);
538                    }
539                    (indexable, slot, _) => {
540                        self.push(Value::Nil);
541                        error!(self, RuntimeError::IndexError(indexable, slot.into()));
542                    }
543                }
544            }
545
546            Op::ReadGlobal(slot) => {
547                if self.stack.len() > slot {
548                    let global = self.stack[slot].clone();
549                    self.push(global);
550                } else {
551                    error!(self, RuntimeError::InvalidProgram);
552                }
553            }
554
555            Op::AssignGlobal(slot) => {
556                self.stack[slot] = self.pop();
557            }
558
559            Op::Contains => {
560                let (element, container) = self.poppop();
561                match (container, element) {
562                    (Value::List(rc_v), e) => {
563                        self.push(Value::Bool(rc_v.as_ref().borrow_mut().contains(&e)));
564                    }
565                    (Value::Dict(rc_v), e) => {
566                        self.push(Value::Bool(rc_v.as_ref().borrow_mut().contains_key(&e)));
567                    }
568                    (Value::Set(rc_v), e) => {
569                        self.push(Value::Bool(rc_v.as_ref().borrow_mut().contains(&e)));
570                    }
571                    (indexable, e) => {
572                        self.push(Value::Nil);
573                        error!(self, RuntimeError::IndexError(indexable, e.into()));
574                    }
575                }
576            }
577
578            Op::GetField(field) => {
579                let inst = self.pop();
580                match inst {
581                    Value::Instance(ty, values) => {
582                        let ty = &self.blobs[ty];
583                        let field = self.string(field);
584                        match values.borrow().get(field) {
585                            Some(value) => {
586                                self.push(value.clone());
587                            }
588                            _ => {
589                                let err = Err(self.error(
590                                    RuntimeError::UnknownField(ty.name.clone(), field.clone()),
591                                    None,
592                                ));
593                                self.push(Value::Nil);
594                                return err;
595                            }
596                        };
597                    }
598                    inst => {
599                        error!(
600                            self,
601                            RuntimeError::TypeError(Op::GetField(field), vec![Type::from(inst)])
602                        );
603                    }
604                }
605            }
606
607            Op::AssignField(field) => {
608                let (inst, value) = self.poppop();
609                match inst {
610                    Value::Instance(ty, values) => {
611                        let ty = &self.blobs[ty];
612                        let field = self.string(field).clone();
613                        if !ty.fields.contains_key(&field) {
614                            error!(self, RuntimeError::UnknownField(ty.name.to_string(), field));
615                        }
616                        (*values).borrow_mut().insert(field, value);
617                    }
618                    inst => {
619                        error!(
620                            self,
621                            RuntimeError::TypeError(Op::AssignField(field), vec![Type::from(inst)])
622                        );
623                    }
624                }
625            }
626
627            Op::Is => {
628                let (a, b) = self.poppop();
629                let a = match a {
630                    Value::Ty(ty) => ty,
631                    val => Type::from(val),
632                };
633                let b = match b {
634                    Value::Ty(ty) => ty,
635                    val => Type::from(val),
636                };
637                let result = a.fits(&b, &self.blobs).is_ok();
638                self.push(Value::Bool(result));
639            }
640
641            // TODO(ed): These look the same as in typechecker.rs, since the macros and functions hide the
642            // rest, maybe merge them?
643            Op::Neg => {
644                one_op!(self, Op::Neg, op::neg);
645            }
646
647            Op::Add => {
648                two_op!(self, Op::Add, op::add);
649            }
650
651            Op::Sub => {
652                two_op!(self, Op::Sub, op::sub);
653            }
654
655            Op::Mul => {
656                two_op!(self, Op::Mul, op::mul);
657            }
658
659            Op::Div => {
660                two_op!(self, Op::Div, op::div);
661            }
662
663            Op::Equal => {
664                two_op!(self, Op::Equal, op::eq);
665            }
666
667            Op::Less => {
668                two_op!(self, Op::Less, op::less);
669            }
670
671            Op::Greater => {
672                two_op!(self, Op::Greater, op::greater);
673            }
674
675            Op::And => {
676                two_op!(self, Op::And, op::and);
677            }
678
679            Op::Or => {
680                two_op!(self, Op::Or, op::or);
681            }
682
683            Op::Not => {
684                one_op!(self, Op::Not, op::not);
685            }
686
687            Op::Jmp(line) => {
688                self.frame_mut().ip = line;
689                return Ok(OpResult::Continue);
690            }
691
692            Op::JmpFalse(line) => {
693                if matches!(self.pop(), Value::Bool(false)) {
694                    self.frame_mut().ip = line;
695                    return Ok(OpResult::Continue);
696                }
697            }
698
699            Op::JmpNPop(line, to_pop) => {
700                let hi = self.stack.len();
701                let lo = hi - to_pop;
702                for slot in lo..hi {
703                    if self.upvalues.contains_key(&slot) {
704                        let value = self.stack[slot].clone();
705                        self.drop_upvalue(slot, value);
706                    }
707                }
708                self.stack.truncate(lo);
709                self.frame_mut().ip = line;
710                return Ok(OpResult::Continue);
711            }
712
713            Op::Assert => {
714                if matches!(self.pop(), Value::Bool(false)) {
715                    error!(self, RuntimeError::AssertFailed);
716                }
717                self.push(Value::Bool(true));
718            }
719
720            Op::ReadUpvalue(slot) => {
721                let offset = self.frame().stack_offset;
722                let value = match &self.stack[offset] {
723                    Value::Function(ups, _, _) => ups[slot].borrow().get(&self.stack),
724                    _ => unreachable!(),
725                };
726                self.push(value);
727            }
728
729            Op::AssignUpvalue(slot) => {
730                let offset = self.frame().stack_offset;
731                let value = self.pop();
732                let slot = match &self.stack[offset] {
733                    Value::Function(ups, _, _) => Rc::clone(&ups[slot]),
734                    _ => unreachable!(),
735                };
736                slot.borrow_mut().set(&mut self.stack, value);
737            }
738
739            Op::ReadLocal(slot) => {
740                let slot = self.frame().stack_offset + slot;
741                self.push(self.stack[slot].clone());
742            }
743
744            Op::AssignLocal(slot) => {
745                let slot = self.frame().stack_offset + slot;
746                self.stack[slot] = self.pop();
747            }
748
749            Op::Define(_) => {}
750
751            Op::Force(_) => {}
752
753            Op::Union => {}
754
755            Op::Call(num_args) => {
756                let new_base = self.stack.len() - 1 - num_args;
757                match self.stack[new_base].clone() {
758                    Value::Blob(blob_slot) => {
759                        let blob = &self.blobs[blob_slot];
760                        let mut values = self.stack[new_base + 1..]
761                            .chunks_exact(2)
762                            .map(|b| {
763                                if let Value::Field(name) = &b[0] {
764                                    (name.clone(), b[1].clone())
765                                } else {
766                                    panic!("Expected Field but got {:?} for field names", b[0]);
767                                }
768                            })
769                            .collect::<HashMap<_, _>>();
770                        self.stack.truncate(new_base);
771                        for name in blob.fields.keys() {
772                            values.entry(name.clone()).or_insert(Value::Nil);
773                        }
774                        values.insert("_id".to_string(), Value::Int(blob.id as i64));
775                        values.insert(
776                            "_name".to_string(),
777                            Value::String(Rc::new(blob.name.clone())),
778                        );
779                        self.push(Value::Instance(blob_slot, Rc::new(RefCell::new(values))));
780                    }
781                    Value::Function(_, _, block) => {
782                        let inner = self.blocks[block].borrow();
783                        let args = inner.args();
784                        if args.len() != num_args {
785                            error!(self, RuntimeError::ArgumentCount(args.len(), num_args));
786                        }
787
788                        #[cfg(debug_assertions)]
789                        if self.print_bytecode {
790                            inner.debug_print(Some(&self.constants));
791                        }
792                        self.frames.push(Frame {
793                            stack_offset: new_base,
794                            block: Rc::clone(&self.blocks[block]),
795                            ip: 0,
796                            contains_upvalues: true,
797                        });
798                        return Ok(OpResult::Continue);
799                    }
800                    Value::ExternFunction(slot) => {
801                        let extern_func = self.extern_functions[slot];
802                        let ctx = RuntimeContext {
803                            typecheck: false,
804                            stack_base: new_base + 1,
805                            machine: self,
806                        };
807                        let res = match extern_func(ctx) {
808                            Ok(value) => value,
809                            Err(ek) => error!(self, ek, "Failed in external function"),
810                        };
811                        self.stack.truncate(new_base);
812                        self.push(res);
813                    }
814                    _ => {
815                        unreachable!()
816                    }
817                }
818            }
819
820            Op::Print => {
821                println!("PRINT: {:?}", self.pop());
822            }
823
824            Op::Return => {
825                let last = self.frames.pop().unwrap();
826                if self.frames.is_empty() {
827                    return Ok(OpResult::Done);
828                } else {
829                    self.stack[last.stack_offset] = self.pop();
830                    if last.contains_upvalues {
831                        for slot in last.stack_offset + 1..self.stack.len() {
832                            if self.upvalues.contains_key(&slot) {
833                                let value = self.stack[slot].clone();
834                                self.drop_upvalue(slot, value);
835                            }
836                        }
837                    }
838                    self.stack.truncate(last.stack_offset + 1);
839                }
840            }
841        }
842        self.frame_mut().ip += 1;
843        Ok(OpResult::Continue)
844    }
845}
846
847///
848/// Module with all the operators that can be applied
849/// to values.
850///
851/// Broken out because they need to be recursive.
852mod op {
853    use super::Rc;
854    use super::Value;
855    use std::collections::HashSet;
856
857    fn tuple_bin_op(
858        a: &Rc<Vec<Value>>,
859        b: &Rc<Vec<Value>>,
860        f: fn(&Value, &Value) -> Value,
861    ) -> Value {
862        Value::Tuple(Rc::new(
863            a.iter().zip(b.iter()).map(|(a, b)| f(a, b)).collect(),
864        ))
865    }
866
867    fn tuple_un_op(a: &Rc<Vec<Value>>, f: fn(&Value) -> Value) -> Value {
868        Value::Tuple(Rc::new(a.iter().map(f).collect()))
869    }
870
871    fn union_un_op(a: &HashSet<Value>, f: fn(&Value) -> Value) -> Value {
872        a.iter()
873            .find_map(|x| {
874                let x = f(x);
875                if x.is_nil() {
876                    None
877                } else {
878                    Some(x)
879                }
880            })
881            .unwrap_or(Value::Nil)
882    }
883
884    fn union_bin_op(a: &HashSet<Value>, b: &Value, f: fn(&Value, &Value) -> Value) -> Value {
885        a.iter()
886            .find_map(|x| {
887                let x = f(x, b);
888                if x.is_nil() {
889                    None
890                } else {
891                    Some(x)
892                }
893            })
894            .unwrap_or(Value::Nil)
895    }
896
897    pub fn neg(value: &Value) -> Value {
898        match value {
899            Value::Float(a) => Value::Float(-*a),
900            Value::Int(a) => Value::Int(-*a),
901            Value::Tuple(a) => tuple_un_op(a, neg),
902            Value::Union(v) => union_un_op(&v, neg),
903            Value::Unknown => Value::Unknown,
904            _ => Value::Nil,
905        }
906    }
907
908    pub fn not(value: &Value) -> Value {
909        match value {
910            Value::Bool(a) => Value::Bool(!*a),
911            Value::Tuple(a) => tuple_un_op(a, not),
912            Value::Union(v) => union_un_op(&v, not),
913            Value::Unknown => Value::Bool(true),
914            _ => Value::Nil,
915        }
916    }
917
918    pub fn add(a: &Value, b: &Value) -> Value {
919        match (a, b) {
920            (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
921            (Value::Int(a), Value::Int(b)) => Value::Int(a + b),
922            (Value::String(a), Value::String(b)) => Value::String(Rc::from(format!("{}{}", a, b))),
923            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, add),
924            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => add(a, a),
925            (Value::Unknown, Value::Unknown) => Value::Unknown,
926            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, add),
927            _ => Value::Nil,
928        }
929    }
930
931    pub fn sub(a: &Value, b: &Value) -> Value {
932        add(a, &neg(b))
933    }
934
935    pub fn mul(a: &Value, b: &Value) -> Value {
936        match (a, b) {
937            (Value::Float(a), Value::Float(b)) => Value::Float(a * b),
938            (Value::Int(a), Value::Int(b)) => Value::Int(a * b),
939            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, mul),
940            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => mul(a, a),
941            (Value::Unknown, Value::Unknown) => Value::Unknown,
942            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, mul),
943            (Value::Tuple(t), Value::Float(f)) | (Value::Float(f), Value::Tuple(t))
944                if t.iter().all(|t| matches!(t, Value::Float(_))) =>
945            {
946                Value::Tuple(Rc::new(t.iter().map(|v| Value::Float(f64::from(v) * f)).collect()))
947            }
948            (Value::Tuple(t), Value::Int(i)) | (Value::Int(i), Value::Tuple(t))
949                if t.iter().all(|t| matches!(t, Value::Int(_))) =>
950            {
951                Value::Tuple(Rc::new(t.iter().map(|v| Value::Int(i64::from(v) * i)).collect()))
952            }
953            _ => Value::Nil,
954        }
955    }
956
957    pub fn div(a: &Value, b: &Value) -> Value {
958        match (a, b) {
959            (Value::Float(a), Value::Float(b)) => Value::Float(a / b),
960            (Value::Int(a), Value::Int(b)) => Value::Int(a / b),
961            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, div),
962            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => div(a, a),
963            (Value::Unknown, Value::Unknown) => Value::Unknown,
964            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, div),
965            (Value::Tuple(a), Value::Float(b)) if a.iter().all(|t| matches!(t, Value::Float(_))) => {
966                Value::Tuple(Rc::new(a.iter().map(|v| Value::Float(f64::from(v) / b)).collect()))
967            }
968            (Value::Tuple(a), Value::Int(b)) if a.iter().all(|t| matches!(t, Value::Int(_))) => {
969                Value::Tuple(Rc::new(a.iter().map(|v| Value::Int(i64::from(v) / b)).collect()))
970            }
971            _ => Value::Nil,
972        }
973    }
974
975    pub fn eq(a: &Value, b: &Value) -> Value {
976        match (a, b) {
977            (Value::Float(a), Value::Float(b)) => Value::Bool(a == b),
978            (Value::Int(a), Value::Int(b)) => Value::Bool(a == b),
979            (Value::String(a), Value::String(b)) => Value::Bool(a == b),
980            (Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
981            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => {
982                for (a, b) in a.iter().zip(b.iter()) {
983                    match eq(a, b) {
984                        Value::Bool(true) => {}
985                        Value::Bool(false) => {
986                            return Value::Bool(false);
987                        }
988                        Value::Nil => {
989                            return Value::Nil;
990                        }
991                        _ => unreachable!("Equality should only return bool or nil."),
992                    }
993                }
994                Value::Bool(true)
995            }
996            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => eq(a, a),
997            (Value::Unknown, Value::Unknown) => Value::Unknown,
998            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, eq),
999            (Value::Nil, Value::Nil) => Value::Bool(true),
1000            (Value::List(a), Value::List(b)) => {
1001                let a = a.borrow();
1002                let b = b.borrow();
1003                if a.len() != b.len() {
1004                    return Value::Bool(false);
1005                }
1006                for (a, b) in a.iter().zip(b.iter()) {
1007                    match eq(a, b) {
1008                        Value::Bool(true) => {}
1009                        Value::Bool(false) => {
1010                            return Value::Bool(false);
1011                        }
1012                        Value::Nil => {
1013                            return Value::Nil;
1014                        }
1015                        _ => unreachable!("Equality should only return bool or nil."),
1016                    }
1017                }
1018                Value::Bool(true)
1019            }
1020            _ => Value::Nil,
1021        }
1022    }
1023
1024    pub fn less(a: &Value, b: &Value) -> Value {
1025        match (a, b) {
1026            (Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
1027            (Value::Float(a), Value::Int(b)) => Value::Bool(*a < (*b as f64)),
1028            (Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) < *b),
1029            (Value::Int(a), Value::Int(b)) => Value::Bool(a < b),
1030            (Value::String(a), Value::String(b)) => Value::Bool(a < b),
1031            (Value::Bool(a), Value::Bool(b)) => Value::Bool(a < b),
1032            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => a
1033                .iter()
1034                .zip(b.iter())
1035                .find_map(|(a, b)| match less(a, b) {
1036                    Value::Bool(true) => None,
1037                    a => Some(a),
1038                })
1039                .unwrap_or(Value::Bool(true)),
1040            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => less(a, a),
1041            (Value::Unknown, Value::Unknown) => Value::Unknown,
1042            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, less),
1043            _ => Value::Nil,
1044        }
1045    }
1046
1047    pub fn greater(a: &Value, b: &Value) -> Value {
1048        less(b, a)
1049    }
1050
1051    pub fn and(a: &Value, b: &Value) -> Value {
1052        match (a, b) {
1053            (Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b),
1054            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, and),
1055            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => and(a, a),
1056            (Value::Unknown, Value::Unknown) => Value::Unknown,
1057            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, and),
1058            _ => Value::Nil,
1059        }
1060    }
1061
1062    pub fn or(a: &Value, b: &Value) -> Value {
1063        match (a, b) {
1064            (Value::Bool(a), Value::Bool(b)) => Value::Bool(*a || *b),
1065            (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, or),
1066            (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => or(a, a),
1067            (Value::Unknown, Value::Unknown) => Value::Unknown,
1068            (Value::Union(a), b) | (b, Value::Union(a)) => union_bin_op(&a, b, or),
1069            _ => Value::Nil,
1070        }
1071    }
1072}