diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-07T23·16+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-08-12T13·24+0000 |
commit | d35ecc0caf2d6ba54b5934f606796687303275b0 (patch) | |
tree | 82d6c303eb0846a053b332656205eade95d3c72a /tvix/eval/src/vm.rs | |
parent | e96a2934adadab633b6522367a4e1d768c8b5a87 (diff) |
feat(tvix/eval): implement simple arithmetic binary operations r/4410
Implements simple arithmetic operations (+, -, *, /). There is some scaffolding included to pop and coerce pairs of numbers, as the Nix language will let arithmetic operators apply to arbitrary pairs of number types (always resulting in floats if the types are mixed). Change-Id: I5f62c363bdea8baa6ef812cc64c5406759d257cf Reviewed-on: https://cl.tvl.fyi/c/depot/+/6074 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r-- | tvix/eval/src/vm.rs | 51 |
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!(), |