about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs51
1 files changed, 50 insertions, 1 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index e35cd99b1e3d..077acfcc1b8d 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -1,7 +1,12 @@
 //! This module implements the virtual (or abstract) machine that runs
 //! Tvix bytecode.
 
-use crate::{chunk::Chunk, errors::EvalResult, opcode::OpCode, value::Value};
+use crate::{
+    chunk::Chunk,
+    errors::{Error, EvalResult},
+    opcode::OpCode,
+    value::{NumberPair, Value},
+};
 
 pub struct VM {
     ip: usize,
@@ -18,6 +23,30 @@ impl VM {
         self.stack.pop().expect("TODO")
     }
 
+    fn pop_number_pair(&mut self) -> EvalResult<NumberPair> {
+        let v2 = self.pop();
+        let v1 = self.pop();
+
+        match (v1, v2) {
+            (Value::Integer(i1), Value::Integer(i2)) => Ok(NumberPair::Integer(i1, i2)),
+
+            (Value::Float(f1), Value::Float(f2)) => Ok(NumberPair::Floats(f1, f2)),
+
+            (Value::Integer(i1), Value::Float(f2)) => Ok(NumberPair::Floats(i1 as f64, f2)),
+
+            (Value::Float(f1), Value::Integer(i2)) => Ok(NumberPair::Floats(f1, i2 as f64)),
+
+            _ => Err(Error::TypeError {
+                expected: "number (either int or float)",
+                actual: if v1.is_number() {
+                    v2.type_of()
+                } else {
+                    v1.type_of()
+                },
+            }),
+        }
+    }
+
     fn inc_ip(&mut self) -> OpCode {
         let op = self.chunk.code[self.ip];
         self.ip += 1;
@@ -32,6 +61,26 @@ impl VM {
                     self.push(c);
                 }
 
+                OpCode::OpAdd => match self.pop_number_pair()? {
+                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 + f2)),
+                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 + i2)),
+                },
+
+                OpCode::OpSub => match self.pop_number_pair()? {
+                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 - f2)),
+                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 - i2)),
+                },
+
+                OpCode::OpMul => match self.pop_number_pair()? {
+                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 * f2)),
+                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 * i2)),
+                },
+
+                OpCode::OpDiv => match self.pop_number_pair()? {
+                    NumberPair::Floats(f1, f2) => self.push(Value::Float(f1 / f2)),
+                    NumberPair::Integer(i1, i2) => self.push(Value::Integer(i1 / i2)),
+                },
+
                 OpCode::OpNull => todo!(),
                 OpCode::OpTrue => todo!(),
                 OpCode::OpFalse => todo!(),