From 7de2e1c34938b0a213cd9dbd83c0479cafc3bf33 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Sun, 30 Jun 2019 22:51:47 -0500 Subject: [PATCH] DEV: Equality Ops --- src/build/opcode/mod.rs | 87 ++++++++++++++++++++++++++++++++---- src/build/opcode/test.rs | 96 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 171 insertions(+), 12 deletions(-) diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index 36005dc..6b19890 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -26,6 +26,8 @@ pub enum Primitive { Empty, } +use Primitive::{Bool, Empty, Float, Int, Str}; + #[derive(Debug, PartialEq, Clone)] pub enum Composite { List(Vec), @@ -45,6 +47,7 @@ pub enum Value { // Program Pointer T(usize), } +use Value::{C, P, S, T}; #[derive(Debug, PartialEq, Clone)] pub enum Op { @@ -56,6 +59,12 @@ pub enum Op { Sub, Div, Mul, + // Comparison Ops + Equal, + Gt, + Lt, + GtEq, + LtEq, // Primitive Types ops Val(Primitive), // A bareword for use in bindings or lookups @@ -68,7 +77,6 @@ pub enum Op { // Operations Cp, // Control Flow - Select, Bang, Jump(usize), Noop, @@ -116,6 +124,11 @@ impl VM { Op::Mul => self.op_mul()?, Op::Div => self.op_div()?, Op::Bind => self.op_bind()?, + Op::Equal => self.op_equal()?, + Op::Gt => self.op_gt()?, + Op::Lt => self.op_lt()?, + Op::GtEq => self.op_gteq()?, + Op::LtEq => self.op_lteq()?, // Add a Composite list value to the stack Op::InitList => self.composite_push(List(Vec::new()))?, // Add a composite tuple value to the stack @@ -123,7 +136,6 @@ impl VM { Op::Field => self.op_field()?, Op::Element => self.op_element()?, Op::Cp => self.op_copy()?, - Op::Select => self.op_select()?, Op::Bang => return Err(Error {}), Op::InitThunk(jp) => self.op_thunk(idx, *jp)?, Op::Noop => { @@ -148,13 +160,70 @@ impl VM { Ok(()) } - fn op_select(&mut self) -> Result<(), Error> { - // first get our compare value from the stack - let search_field = self.pop()?; - // next get our default value from the stack - let default_field = self.pop()?; - // finally get our fields from the stack - let fields = self.pop()?; + fn op_equal(&mut self) -> Result<(), Error> { + let left = self.pop()?; + let right = self.pop()?; + self.push(Value::P(Bool(left == right)))?; + Ok(()) + } + + fn op_gt(&mut self) -> Result<(), Error> { + let left = self.pop()?; + let right = self.pop()?; + match (left, right) { + (P(Int(i)), P(Int(ii))) => { + self.push(Value::P(Bool(i > ii)))?; + } + (P(Float(f)), P(Float(ff))) => { + self.push(Value::P(Bool(f > ff)))?; + } + _ => return Err(Error {}), + } + Ok(()) + } + + fn op_lt(&mut self) -> Result<(), Error> { + let left = self.pop()?; + let right = self.pop()?; + match (left, right) { + (P(Int(i)), P(Int(ii))) => { + self.push(Value::P(Bool(i < ii)))?; + } + (P(Float(f)), P(Float(ff))) => { + self.push(Value::P(Bool(f < ff)))?; + } + _ => return Err(Error {}), + } + Ok(()) + } + + fn op_lteq(&mut self) -> Result<(), Error> { + let left = self.pop()?; + let right = self.pop()?; + match (left, right) { + (P(Int(i)), P(Int(ii))) => { + self.push(Value::P(Bool(i <= ii)))?; + } + (P(Float(f)), P(Float(ff))) => { + self.push(Value::P(Bool(f <= ff)))?; + } + _ => return Err(Error {}), + } + Ok(()) + } + + fn op_gteq(&mut self) -> Result<(), Error> { + let left = self.pop()?; + let right = self.pop()?; + match (left, right) { + (P(Int(i)), P(Int(ii))) => { + self.push(Value::P(Bool(i >= ii)))?; + } + (P(Float(f)), P(Float(ff))) => { + self.push(Value::P(Bool(f >= ff)))?; + } + _ => return Err(Error {}), + } Ok(()) } diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index 309a8c9..8dea34f 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -14,10 +14,10 @@ use super::Composite::{List, Tuple}; use super::Op::{ - Add, Bind, Cp, Div, Element, Field, InitList, InitThunk, InitTuple, Jump, Mul, Noop, Sub, Sym, - Val, + Add, Bind, Cp, Div, Element, Equal, Field, InitList, InitThunk, InitTuple, Jump, JumpIfTrue, + Mul, Noop, Sub, Sym, Val, }; -use super::Primitive::{Float, Int, Str}; +use super::Primitive::{Bool, Float, Int, Str}; use super::Value::{C, P, T}; use super::VM; @@ -199,3 +199,93 @@ fn test_jump_ops() { assert_eq!(vm.pop().unwrap(), case.1); } } + +#[test] +fn test_equality_ops() { + let mut cases = vec![ + ( + vec![ + Val(Str("foo".to_owned())), + Val(Str("foo".to_owned())), + Equal, + ], + P(Bool(true)), + ), + ( + vec![ + Val(Str("bar".to_owned())), + Val(Str("foo".to_owned())), + Equal, + ], + P(Bool(false)), + ), + (vec![Val(Int(1)), Val(Int(1)), Equal], P(Bool(true))), + (vec![Val(Int(1)), Val(Int(2)), Equal], P(Bool(false))), + (vec![Val(Bool(true)), Val(Bool(true)), Equal], P(Bool(true))), + ( + vec![Val(Bool(false)), Val(Bool(false)), Equal], + P(Bool(true)), + ), + ( + vec![Val(Bool(true)), Val(Bool(false)), Equal], + P(Bool(false)), + ), + ( + vec![ + InitTuple, + Val(Str("foo".to_owned())), + Val(Int(1)), + Field, + InitTuple, + Val(Str("foo".to_owned())), + Val(Int(1)), + Field, + Equal, + ], + P(Bool(true)), + ), + ( + vec![ + InitTuple, + Val(Str("foo".to_owned())), + Val(Int(1)), + Field, + InitTuple, + Val(Str("bar".to_owned())), + Val(Int(1)), + Field, + Equal, + ], + P(Bool(false)), + ), + ( + vec![ + InitList, + Val(Str("foo".to_owned())), + Element, + InitList, + Val(Str("foo".to_owned())), + Element, + Equal, + ], + P(Bool(true)), + ), + ( + vec![ + InitList, + Val(Str("foo".to_owned())), + Element, + InitList, + Val(Str("bar".to_owned())), + Element, + Equal, + ], + P(Bool(false)), + ), + ]; + for case in cases.drain(0..) { + let mut vm = VM::new(case.0); + vm.run().unwrap(); + assert_eq!(vm.pop().unwrap(), case.1); + } +}