various progress around the block

This commit is contained in:
Rowan Torbitzky-Lane 2025-04-06 17:06:33 -05:00
parent 93a4749425
commit 5fe9ca40c6
7 changed files with 309 additions and 58 deletions

150
src/instructions/logical.rs Normal file
View File

@ -0,0 +1,150 @@
//! # Logical Instructions
//!
//! This file holds instructions for the boolean stack.
use super::utils::{LogicalTrait, NumericTrait};
use crate::push::state::PushState;
/// Runs logical and on two values
fn _and<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_and(vals[1]))
}
make_instruction!(boolean, boolean, _and, bool, 2);
/// Runs logical or on two values
fn _or<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_or(vals[1]))
}
make_instruction!(boolean, boolean, _or, bool, 2);
/// Runs logical not on two values
fn _not<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_not())
}
make_instruction!(boolean, boolean, _not, bool, 1);
/// Runs logical xor on two values
fn _xor<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_xor(vals[1]))
}
make_instruction!(boolean, boolean, _xor, bool, 2);
/// Inverts the first value and runs logical and on two values
fn _invert_first_then_and<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_not().logical_and(vals[1]))
}
make_instruction!(boolean, boolean, _invert_first_then_and, bool, 2);
/// Inverts the second value and runs logical and on two values
fn _invert_second_then_and<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + LogicalTrait,
{
Some(vals[0].logical_and(vals[1].logical_not()))
}
make_instruction!(boolean, boolean, _invert_second_then_and, bool, 2);
// fn _to_int<T>(vals: Vec<T>) -> Option<T>
// where
// T: Copy + NumericTrait,
// {
// Some(T::from_bool(vals))
// }
#[cfg(test)]
mod tests {
use super::*;
use crate::push::state::EMPTY_STATE;
#[test]
fn and_test() {
let mut test_state = EMPTY_STATE;
test_state.boolean = vec![true, false, true];
boolean_and(&mut test_state);
assert_eq!(vec![true, false], test_state.boolean);
test_state.boolean = vec![true, true];
boolean_and(&mut test_state);
assert_eq!(vec![true], test_state.boolean);
}
#[test]
fn or_test() {
let mut test_state = EMPTY_STATE;
test_state.boolean = vec![true, false, true];
boolean_or(&mut test_state);
assert_eq!(vec![true, true], test_state.boolean);
test_state.boolean = vec![false, false];
boolean_or(&mut test_state);
assert_eq!(vec![false], test_state.boolean);
}
#[test]
fn not_test() {
let mut test_state = EMPTY_STATE;
test_state.boolean = vec![true, false, true];
boolean_not(&mut test_state);
assert_eq!(vec![true, false, false], test_state.boolean);
test_state.boolean = vec![false, false];
boolean_not(&mut test_state);
assert_eq!(vec![false, true], test_state.boolean);
}
#[test]
fn xor_test() {
let mut test_state = EMPTY_STATE;
test_state.boolean = vec![true, false, true];
boolean_xor(&mut test_state);
assert_eq!(vec![true, true], test_state.boolean);
test_state.boolean = vec![false, false];
boolean_xor(&mut test_state);
assert_eq!(vec![false], test_state.boolean);
test_state.boolean = vec![true, true];
boolean_xor(&mut test_state);
assert_eq!(vec![false], test_state.boolean);
}
#[test]
fn invert_test() {
let mut test_state = EMPTY_STATE;
test_state.boolean = vec![true, false];
boolean_invert_first_then_and(&mut test_state);
assert_eq!(vec![true], test_state.boolean);
test_state.boolean = vec![false, false];
boolean_invert_first_then_and(&mut test_state);
assert_eq!(vec![false], test_state.boolean);
test_state.boolean = vec![true, false];
boolean_invert_second_then_and(&mut test_state);
assert_eq!(vec![false], test_state.boolean);
test_state.boolean = vec![false, true];
boolean_invert_second_then_and(&mut test_state);
assert_eq!(vec![true], test_state.boolean);
}
}

View File

@ -45,30 +45,6 @@ pub mod macros {
}
}
pub mod logical;
pub mod numeric;
pub mod utils;
// /// A macro that makes a push instruction given: the name of the stack to use,
// /// an internal function to call, and the type of a function.
// #[macro_export]
// macro_rules! make_instruction {
// ($stack_name:ident, $fn_name:ident, $fn_type:ty) => {
// paste::item! {
// fn [< $stack_name $fn_name >] (state: &mut PushState, num_inputs: usize) {
// if state.$stack_name.len() < num_inputs {
// return;
// }
// let mut inputs: Vec<$fn_type> = Vec::with_capacity(num_inputs);
// for n in 0..num_inputs {
// inputs.push(state.$stack_name[n]);
// }
// if let Some(result) = $fn_name(inputs) {
// for _ in 0..num_inputs {
// state.$stack_name.pop();
// }
// state.$stack_name.push(result);
// }
// }
// }
// };
// }

View File

@ -11,7 +11,7 @@ use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
use std::cmp::{max, min};
use std::ops::{Add, Div, Mul, Sub};
use super::utils::InstructionTrait;
use super::utils::NumericTrait;
/// Adds two addable values together.
fn _add<T>(vals: Vec<T>) -> Option<T>
@ -46,7 +46,7 @@ make_instruction!(float, float, _mult, Decimal, 2);
/// Divides two values from each other.
fn _div<T>(vals: Vec<T>) -> Option<T>
where
T: Div<Output = T> + Copy + InstructionTrait,
T: Div<Output = T> + Copy + NumericTrait,
{
vals[1].checked_div(vals[0])
}
@ -56,7 +56,7 @@ make_instruction!(float, float, _div, Decimal, 2);
/// Takes the remainder of two values
fn _rem<T>(vals: Vec<T>) -> Option<T>
where
T: Div<Output = T> + Copy + InstructionTrait,
T: Div<Output = T> + Copy + NumericTrait,
{
vals[1].checked_mod(vals[0])
}
@ -86,7 +86,7 @@ make_instruction!(float, float, _min, Decimal, 2);
/// Increments a single value by 1
fn _inc<T>(vals: Vec<T>) -> Option<T>
where
T: InstructionTrait + Copy,
T: NumericTrait + Copy,
{
Some(vals[0].increment())
}
@ -96,7 +96,7 @@ make_instruction!(float, float, _inc, Decimal, 1);
/// Decrements a single value by 1
fn _dec<T>(vals: Vec<T>) -> Option<T>
where
T: InstructionTrait + Copy,
T: NumericTrait + Copy,
{
Some(vals[0].decrement())
}
@ -146,7 +146,7 @@ make_instruction!(float, boolean, _gte, Decimal, 2);
/// Runs sin on a single item.
fn _sin<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_sin()
}
@ -156,7 +156,7 @@ make_instruction!(float, float, _sin, Decimal, 1);
/// Runs arcsin on a single item.
fn _arcsin<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_sin()?.inverse()
}
@ -166,7 +166,7 @@ make_instruction!(float, float, _arcsin, Decimal, 1);
/// Runs cos on a single item.
fn _cos<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_cos()
}
@ -176,7 +176,7 @@ make_instruction!(float, float, _cos, Decimal, 1);
/// Runs arcsin on a single item.
fn _arccos<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_cos()?.inverse()
}
@ -186,7 +186,7 @@ make_instruction!(float, float, _arccos, Decimal, 1);
/// Runs tan on a single item.
fn _tan<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_tan()
}
@ -196,7 +196,7 @@ make_instruction!(float, float, _tan, Decimal, 1);
/// Runs arctan on a single item.
fn _arctan<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_tan()?.inverse()
}
@ -216,21 +216,21 @@ fn _to_float(vals: Vec<i128>) -> Option<Decimal> {
make_instruction!(int, float, _to_float, i128, 1);
/// Converts a single number to a bool.
fn _to_bool<T>(vals: Vec<T>) -> Option<bool>
fn _from_bool<T>(vals: Vec<bool>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
Some(vals[0].to_bool())
Some(T::from_bool(vals[0]))
}
make_instruction!(int, boolean, _to_bool, i128, 1);
make_instruction!(float, boolean, _to_bool, Decimal, 1);
make_instruction!(int, boolean, _from_bool, bool, 1);
make_instruction!(float, boolean, _from_bool, bool, 1);
/// Takes the log base 10 of a single Decimal. Acts as a
/// NoOp if the value is 0. If the value is negative, takes
/// the absolute value of the number.
fn _log<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].absolute().safe_log10()
}
@ -240,7 +240,7 @@ make_instruction!(float, float, _log, Decimal, 1);
/// Takes the exp of a single value. Ints get truncated.
fn _exp<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_exp()
}
@ -250,7 +250,7 @@ make_instruction!(float, float, _exp, Decimal, 1);
/// Takes the square root of the absolute value of a single value.
fn _sqrt<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].safe_sqrt()
}
@ -261,7 +261,7 @@ make_instruction!(float, float, _sqrt, Decimal, 1);
/// does nothing (returns None). Truncates an int to 0.
fn _inv<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
vals[0].inverse()
}
@ -271,7 +271,7 @@ make_instruction!(float, float, _inv, Decimal, 1);
/// Takes the absolute value of the top number
fn _abs<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
Some(vals[0].absolute())
}
@ -281,7 +281,7 @@ make_instruction!(float, float, _abs, Decimal, 1);
/// Reverses the sign of the top number
fn _sign_reverse<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
Some(vals[0].sign_reverse())
}
@ -291,7 +291,7 @@ make_instruction!(float, float, _sign_reverse, Decimal, 1);
/// Squares the top number
fn _square<T>(vals: Vec<T>) -> Option<T>
where
T: Copy + InstructionTrait,
T: Copy + NumericTrait,
{
Some(vals[0].square())
}

View File

@ -8,7 +8,7 @@ use std::ops::Div;
///
/// Trig functions named safe rather than checked to not overlap
/// with Decimal library's checked function names.
pub trait InstructionTrait: Sized + Div<Output = Self> {
pub trait NumericTrait: Sized + Div<Output = Self> {
fn checked_div(self, v: Self) -> Option<Self>;
fn checked_mod(self, v: Self) -> Option<Self>;
fn increment(self) -> Self;
@ -24,9 +24,10 @@ pub trait InstructionTrait: Sized + Div<Output = Self> {
fn to_bool(self) -> bool;
fn sign_reverse(self) -> Self;
fn square(self) -> Self;
fn from_bool(v: bool) -> Self;
}
impl InstructionTrait for Decimal {
impl NumericTrait for Decimal {
fn checked_div(self, v: Self) -> Option<Self> {
if v == dec!(0.0) { None } else { Some(self / v) }
}
@ -72,9 +73,12 @@ impl InstructionTrait for Decimal {
fn square(self) -> Self {
self * self
}
fn from_bool(v: bool) -> Self {
if v { dec!(1.0) } else { dec!(0.0) }
}
}
impl InstructionTrait for i128 {
impl NumericTrait for i128 {
fn checked_div(self, v: Self) -> Option<Self> {
if v == 0 { None } else { Some(self / v) }
}
@ -125,4 +129,32 @@ impl InstructionTrait for i128 {
fn square(self) -> Self {
self * self
}
fn from_bool(v: bool) -> Self {
if v { 1 } else { 0 }
}
}
pub trait LogicalTrait {
fn logical_and(self, v: Self) -> Self;
fn logical_or(self, v: Self) -> Self;
fn logical_not(self) -> Self;
fn logical_xor(self, v: Self) -> Self;
}
impl LogicalTrait for bool {
fn logical_and(self, v: Self) -> Self {
self && v
}
fn logical_or(self, v: Self) -> Self {
self || v
}
fn logical_not(self) -> Self {
!self
}
fn logical_xor(self, v: Self) -> Self {
match (self, v) {
(true, true) | (false, false) => false,
_ => true,
}
}
}

View File

@ -1,4 +1,4 @@
use instructions::utils::InstructionTrait;
use instructions::utils::NumericTrait;
use rust_decimal::MathematicalOps;
use rust_decimal::prelude::*;

View File

@ -1,5 +1,8 @@
use crate::push::state::*;
/// The main function that disperses the exec stack Genes into
/// the respective stacks. Also is where the individual instructions
/// (such as int_add) is ran.
pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
match gene {
Gene::GeneInt(x) => state.int.push(x),
@ -23,15 +26,22 @@ pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
}
}
/// Where a push program's exec stack is interpreted to completion.
/// TODO: Decide where to place loading in a push program.
pub fn interpret_program(state: &mut PushState, step_limit: usize, max_stack_size: isize) {
let mut steps: usize = 0;
while state.exec.len() > 0 && steps < step_limit {
if let Some(val) = state.exec.pop() {}
if let Some(gene) = state.exec.pop() {
gene_to_stack(state, gene);
steps += 1;
}
}
}
#[cfg(test)]
mod tests {
use crate::instructions::numeric::int_add;
use super::*;
use rust_decimal::dec;
@ -52,6 +62,89 @@ mod tests {
assert_eq!(vec![true], test_state.boolean);
test_state.boolean.clear();
// Need to finish these tests later.
gene_to_stack(
&mut test_state,
Gene::GeneString("test".as_bytes().to_vec()),
);
assert_eq!(vec!["test".as_bytes().to_vec()], test_state.string);
test_state.string.clear();
gene_to_stack(&mut test_state, Gene::GeneChar('a'));
gene_to_stack(&mut test_state, Gene::GeneChar('b'));
gene_to_stack(&mut test_state, Gene::GeneChar('c'));
assert_eq!(vec!['a', 'b', 'c'], test_state.char);
test_state.char.clear();
gene_to_stack(&mut test_state, Gene::GeneVectorInt(vec![1, 2, 3]));
gene_to_stack(&mut test_state, Gene::GeneVectorInt(vec![4, 5, 6]));
assert_eq!(vec![vec![1, 2, 3], vec![4, 5, 6]], test_state.vector_int);
test_state.vector_int.clear();
gene_to_stack(
&mut test_state,
Gene::GeneVectorFloat(vec![dec!(1.7), dec!(2.4), dec!(3.9)]),
);
gene_to_stack(
&mut test_state,
Gene::GeneVectorFloat(vec![dec!(4.7), dec!(5.4), dec!(6.9)]),
);
assert_eq!(
vec![
vec![dec!(1.7), dec!(2.4), dec!(3.9)],
vec![dec!(4.7), dec!(5.4), dec!(6.9)]
],
test_state.vector_float
);
test_state.vector_float.clear();
gene_to_stack(&mut test_state, Gene::GeneVectorBoolean(vec![true, false]));
assert_eq!(vec![vec![true, false]], test_state.vector_boolean);
test_state.vector_boolean.clear();
gene_to_stack(
&mut test_state,
Gene::GeneVectorString(vec!["test0".as_bytes().to_vec()]),
);
gene_to_stack(
&mut test_state,
Gene::GeneVectorString(vec![
"test1".as_bytes().to_vec(),
"test2".as_bytes().to_vec(),
]),
);
assert_eq!(
vec![
vec!["test0".as_bytes().to_vec()],
vec!["test1".as_bytes().to_vec(), "test2".as_bytes().to_vec()]
],
test_state.vector_string
);
test_state.vector_string.clear();
gene_to_stack(&mut test_state, Gene::GeneVectorChar(vec!['a', 'b']));
gene_to_stack(&mut test_state, Gene::GeneVectorChar(vec!['b', 'c', 'd']));
assert_eq!(
vec![vec!['a', 'b'], vec!['b', 'c', 'd']],
test_state.vector_char
);
test_state.vector_char.clear();
let test_block: Gene = Gene::Block(Box::new(vec![
Gene::GeneInt(1),
Gene::GeneFloat(dec!(2.3)),
Gene::StateFunc(int_add),
]));
test_state.exec.push(Gene::GeneInt(2));
gene_to_stack(&mut test_state, test_block);
assert_eq!(
vec![
Gene::GeneInt(2),
Gene::GeneInt(1),
Gene::GeneFloat(dec!(2.3)),
Gene::StateFunc(int_add)
],
test_state.exec
);
// println!("{:?}", test_state.exec);
}
}

View File

@ -10,12 +10,12 @@ pub struct PushState {
pub float: Vec<Decimal>,
pub string: Vec<Vec<u8>>,
pub boolean: Vec<bool>,
pub char: Vec<u8>,
pub char: Vec<char>,
pub vector_int: Vec<Vec<i128>>,
pub vector_float: Vec<Vec<Decimal>>,
pub vector_string: Vec<Vec<Vec<u8>>>,
pub vector_boolean: Vec<Vec<bool>>,
pub vector_char: Vec<Vec<u8>>,
pub vector_char: Vec<Vec<char>>,
pub exec: Vec<Gene>,
pub code: Vec<Gene>,
}
@ -41,12 +41,12 @@ pub enum Gene {
GeneFloat(Decimal),
GeneBoolean(bool),
GeneString(Vec<u8>),
GeneChar(u8),
GeneChar(char),
GeneVectorInt(Vec<i128>),
GeneVectorFloat(Vec<Decimal>),
GeneVectorBoolean(Vec<bool>),
GeneVectorString(Vec<Vec<u8>>),
GeneVectorChar(Vec<u8>),
GeneVectorChar(Vec<char>),
StateFunc(fn(&mut PushState)),
Close,
Open(u8),