From bdcdbf7d65b7a05216c33f802f1f1646e1f68718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 31 Jan 2021 20:25:06 +0100 Subject: basic arithmatic for tuples --- src/lib.rs | 110 ++++++++++++++++++++++++++++++++++++++++++ src/vm.rs | 158 ++++++++++++++++--------------------------------------------- 2 files changed, 151 insertions(+), 117 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9a9aaa7..c7841f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -384,6 +384,109 @@ impl Debug for Value { } } +mod op { + use super::Value; + use std::rc::Rc; + + fn tuple_op(a: &Rc>, b: &Rc>, f: fn (&Value, &Value) -> Value) -> Value { + Value::Tuple(Rc::new(a.iter().zip(b.iter()).map(|(a, b)| f(a, b)).collect())) + } + + pub fn neg(value: &Value) -> Value { + match value { + Value::Float(a) => Value::Float(-a), + Value::Int(a) => Value::Int(-a), + Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(neg).collect())), + _ => Value::Nil, + } + } + + pub fn not(value: &Value) -> Value { + match value { + Value::Bool(a) => Value::Bool(!a), + Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(not).collect())), + _ => Value::Nil, + } + } + + + pub fn add(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Float(a), Value::Float(b)) => Value::Float(a + b), + (Value::Int(a), Value::Int(b)) => Value::Int(a + b), + (Value::String(a), Value::String(b)) => Value::String(Rc::from(format!("{}{}", a, b))), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, add), + _ => Value::Nil, + } + } + + pub fn sub(a: &Value, b: &Value) -> Value { + add(a, &neg(b)) + } + + pub fn mul(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Float(a), Value::Float(b)) => Value::Float(a * b), + (Value::Int(a), Value::Int(b)) => Value::Int(a * b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, mul), + _ => Value::Nil, + } + } + + pub fn div(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Float(a), Value::Float(b)) => Value::Float(a / b), + (Value::Int(a), Value::Int(b)) => Value::Int(a / b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, div), + _ => Value::Nil, + } + } + + pub fn eq(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Float(a), Value::Float(b)) => Value::Bool(a == b), + (Value::Int(a), Value::Int(b)) => Value::Bool(a == b), + (Value::String(a), Value::String(b)) => Value::Bool(a == b), + (Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, eq), + _ => Value::Nil, + } + } + + pub fn less(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Float(a), Value::Float(b)) => Value::Bool(a < b), + (Value::Int(a), Value::Int(b)) => Value::Bool(a < b), + (Value::String(a), Value::String(b)) => Value::Bool(a < b), + (Value::Bool(a), Value::Bool(b)) => Value::Bool(a < b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, less), + _ => Value::Nil, + } + } + + pub fn greater(a: &Value, b: &Value) -> Value { + less(b, a) + } + + pub fn and(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, and), + _ => Value::Nil, + } + } + + pub fn or(a: &Value, b: &Value) -> Value { + match (a, b) { + (Value::Bool(a), Value::Bool(b)) => Value::Bool(*a || *b), + (Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_op(a, b, or), + _ => Value::Nil, + } + } + +} + + impl Value { fn identity(self) -> Self { match self { @@ -394,6 +497,13 @@ impl Value { } } + fn is_nil(&self) -> bool { + match self { + Value::Nil => true, + _ => false, + } + } + fn as_type(&self) -> Type { Type::from(self) } diff --git a/src/vm.rs b/src/vm.rs index 59ad0bf..dd233dc 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use owo_colors::OwoColorize; -use crate::{Blob, Block, Op, Prog, UpValue, Value}; +use crate::{Blob, Block, Op, Prog, UpValue, Value, op}; use crate::error::{Error, ErrorKind}; use crate::RustFunction; pub use crate::Type; @@ -20,6 +20,31 @@ macro_rules! error { }; } +macro_rules! one_op { + ( $self:expr, $op:expr, $fun:expr ) => { + let a = $self.pop(); + let b = $fun(&a); + if b.is_nil() { + $self.push(b); + error!($self, ErrorKind::RuntimeTypeError($op, vec![a])); + } + $self.push(b); + }; +} + +macro_rules! two_op { + ( $self:expr, $op:expr, $fun:expr ) => { + let b = $self.pop(); + let a = $self.pop(); + let c = $fun(&a, &b); + if c.is_nil() { + $self.push(c); + error!($self, ErrorKind::RuntimeTypeError($op, vec![a, b])); + } + $self.push(c); + }; +} + #[derive(Debug)] struct Frame { stack_offset: usize, @@ -90,6 +115,10 @@ impl VM { self.stack.pop().unwrap() } + fn push(&mut self, value: Value) { + self.stack.push(value) + } + fn pop_twice(&mut self) -> (Value, Value) { let (a, b) = (self.stack.remove(self.stack.len() - 1), self.stack.remove(self.stack.len() - 1)); @@ -216,132 +245,27 @@ impl VM { } } - Op::Neg => { - match self.stack.pop().unwrap() { - Value::Float(a) => self.stack.push(Value::Float(-a)), - Value::Int(a) => self.stack.push(Value::Int(-a)), - a => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a])); - } - } - } + Op::Neg => { one_op!(self, Op::Neg, op::neg); } - Op::Add => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a + b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a + b)), - (Value::String(a), Value::String(b)) => { - self.stack.push(Value::String(Rc::from(format!("{}{}", a, b)))) - } - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Add => { two_op!(self, Op::Add, op::add); } - Op::Sub => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a - b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a - b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Sub => { two_op!(self, Op::Sub, op::sub); } - Op::Mul => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a * b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a * b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Mul => { two_op!(self, Op::Mul, op::mul); } - Op::Div => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a / b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a / b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Div => { two_op!(self, Op::Div, op::div); } - Op::Equal => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a == b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a == b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a == b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a == b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Equal => { two_op!(self, Op::Equal, op::eq); } - Op::Less => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a < b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a < b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a < b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a < b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Less => { two_op!(self, Op::Less, op::less); } - Op::Greater => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a > b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a > b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a > b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a > b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Greater => { two_op!(self, Op::Greater, op::greater); } - Op::And => { - match self.pop_twice() { - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::And => { two_op!(self, Op::And, op::and); } - Op::Or => { - match self.pop_twice() { - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)), - (a, b) => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])); - } - } - } + Op::Or => { two_op!(self, Op::Or, op::or); } - Op::Not => { - match self.stack.pop().unwrap() { - Value::Bool(a) => self.stack.push(Value::Bool(!a)), - a => { - self.stack.push(Value::Nil); - error!(self, ErrorKind::RuntimeTypeError(op, vec![a])); - } - } - } + Op::Not => { one_op!(self, Op::Not, op::not); } Op::Jmp(line) => { self.frame_mut().ip = line; -- cgit v1.2.1