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) }
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 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 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 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 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 self.frame_mut().ip = ip;
291 Ok(self.pop())
293 }
294
295 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 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
847mod 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}