Compare commits

..

No commits in common. "37d59517d0c3eddd7d02c6328f9d7b202c131a68" and "b0ad9a303599e773cc660ab4dae7077fb04a2f41" have entirely different histories.

4 changed files with 18 additions and 322 deletions

View File

@ -2,7 +2,7 @@ use std::ops::Not;
use crate::push::state::{Gene, PushState}; use crate::push::state::{Gene, PushState};
use super::common::{code_from_exec, code_pop, int_pop}; use super::common::code_pop;
/// Checks to see if a single gene is a block. /// Checks to see if a single gene is a block.
fn _is_block(vals: Vec<Gene>) -> Option<bool> { fn _is_block(vals: Vec<Gene>) -> Option<bool> {
@ -89,7 +89,7 @@ fn _but_last(vals: Vec<Gene>) -> Option<Gene> {
} }
make_instruction_clone!(code, code, _but_last, Gene, 1); make_instruction_clone!(code, code, _but_last, Gene, 1);
/// Returns all the vals wrapped in a code block /// Returns all of the vals wrapped in a code block
fn _wrap_block(vals: Vec<Gene>) -> Option<Gene> { fn _wrap_block(vals: Vec<Gene>) -> Option<Gene> {
Some(Gene::Block(Box::new(vals))) Some(Gene::Block(Box::new(vals)))
} }
@ -123,7 +123,7 @@ make_instruction_clone!(code, code, _combine, Gene, 2);
/// Pushes `code_pop` and the top item of the code stack to the exec stack. /// Pushes `code_pop` and the top item of the code stack to the exec stack.
/// Top code item gets executed before being removed from code stack. /// Top code item gets executed before being removed from code stack.
pub fn code_do_then_pop(state: &mut PushState) { fn code_do_then_pop(state: &mut PushState) {
if state.code.is_empty() { if state.code.is_empty() {
return; return;
} }
@ -132,162 +132,12 @@ pub fn code_do_then_pop(state: &mut PushState) {
state.exec.push(c); state.exec.push(c);
} }
/// Evaluates the top item on the code stack based off
/// the range of two ints from the int stack.
pub fn code_do_range(state: &mut PushState) {
if state.code.is_empty() || state.int.len() < 2 {
return;
}
let to_do = state.code.pop().unwrap();
let dest_idx = state.int.pop().unwrap();
let current_idx = state.int.pop().unwrap();
let mut increment = 0;
if current_idx < dest_idx {
increment = 1
} else if current_idx > dest_idx {
increment = -1
}
if increment != 0 {
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(current_idx + increment),
Gene::GeneInt(dest_idx),
Gene::StateFunc(code_from_exec),
to_do.clone(),
Gene::StateFunc(code_do_range),
])));
}
state.int.push(current_idx);
state.exec.push(to_do);
}
/// Evaluates the top item on the exec stack based off
/// the range of two ints from the int stack.
pub fn exec_do_range(state: &mut PushState) {
if state.exec.is_empty() || state.int.len() < 2 {
return;
}
let to_do = state.exec.pop().unwrap();
let dest_idx = state.int.pop().unwrap();
let current_idx = state.int.pop().unwrap();
let mut increment = 0;
if current_idx < dest_idx {
increment = 1
} else if current_idx > dest_idx {
increment = -1
}
if increment != 0 {
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(current_idx + increment),
Gene::GeneInt(dest_idx),
Gene::StateFunc(exec_do_range),
to_do.clone(),
])));
}
state.int.push(current_idx);
state.exec.push(to_do);
}
/// Evaluates the top item on the code stack n times. N pulled from
/// top of int stack.
pub fn code_do_count(state: &mut PushState) {
if state.code.is_empty() || state.int.is_empty() {
return;
}
if state.int[state.int.len() - 1] < 1 {
return;
}
let code = state.code.pop().unwrap();
let count = state.int.pop().unwrap();
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(0),
Gene::GeneInt(count - 1),
Gene::StateFunc(code_from_exec),
code,
Gene::StateFunc(code_do_range)
])));
}
/// Evaluates the top item on the exec stack n times. N pulled from top
/// of int stack.
pub fn exec_do_count(state: &mut PushState) {
if state.exec.is_empty() || state.int.is_empty() {
return;
}
if state.int[state.int.len() - 1] < 1 {
return;
}
let code = state.exec.pop().unwrap();
let count = state.int.pop().unwrap();
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(0),
Gene::GeneInt(count - 1),
Gene::StateFunc(exec_do_range),
code
])));
}
/// Evaluates the top item on the code stack n times but differently that
/// than `code_do_count`. Don't ask, it uses a block for some reason.
pub fn code_do_times(state: &mut PushState) {
if state.code.is_empty() || state.int.is_empty() {
return;
}
if state.int[state.int.len() - 1] < 1 {
return;
}
let code = state.code.pop().unwrap();
let times = state.int.pop().unwrap();
let nested_block = Gene::Block(Box::new(vec![
Gene::StateFunc(int_pop),
code,
]));
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(0),
Gene::GeneInt(times - 1),
Gene::StateFunc(code_from_exec),
nested_block,
Gene::StateFunc(code_do_range),
])));
}
/// Evalutes the top item on the code stack n times. Also different :shrug:
pub fn exec_do_times(state: &mut PushState) {
if state.exec.is_empty() || state.int.is_empty() {
return;
}
if state.int[state.int.len() - 1] < 1 {
return;
}
let code = state.exec.pop().unwrap();
let times = state.int.pop().unwrap();
let nested_block = Gene::Block(Box::new(vec![
Gene::StateFunc(int_pop),
code,
]));
state.exec.push(Gene::Block(Box::new(vec![
Gene::GeneInt(0),
Gene::GeneInt(times - 1),
Gene::StateFunc(exec_do_range),
nested_block,
])));
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{ use crate::{instructions::numeric::int_add, push::state::EMPTY_STATE};
instructions::numeric::int_add,
push::{interpreter::interpret_program, state::EMPTY_STATE},
};
use rust_decimal::dec; use rust_decimal::dec;
const STEP_LIMIT: usize = 1000;
const MAX_STACK_SIZE: usize = 1000;
#[test] #[test]
fn is_block_test() { fn is_block_test() {
let mut test_state = EMPTY_STATE; let mut test_state = EMPTY_STATE;
@ -515,7 +365,7 @@ mod tests {
} }
#[test] #[test]
fn code_do_then_pop_test() { fn _code_do_then_pop_test() {
let mut test_state = EMPTY_STATE; let mut test_state = EMPTY_STATE;
test_state.code.push(Gene::StateFunc(int_add)); test_state.code.push(Gene::StateFunc(int_add));
@ -526,95 +376,4 @@ mod tests {
test_state.exec test_state.exec
); );
} }
#[test]
fn code_do_range_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(code_do_range),
Gene::StateFunc(int_add),
Gene::StateFunc(code_from_exec),
Gene::GeneInt(6),
Gene::GeneInt(3),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![18], test_state.int);
}
#[test]
fn exec_do_range_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(int_add),
Gene::StateFunc(exec_do_range),
Gene::GeneInt(5),
Gene::GeneInt(3),
Gene::GeneInt(8),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![20], test_state.int);
}
#[test]
fn code_do_count_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(code_do_count),
Gene::StateFunc(int_add),
Gene::StateFunc(code_from_exec),
Gene::GeneInt(6),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![15], test_state.int);
}
#[test]
fn exec_do_count_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(int_add),
Gene::StateFunc(exec_do_count),
Gene::GeneInt(5),
Gene::GeneInt(3),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![13], test_state.int);
}
#[test]
fn code_do_times_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(code_do_times),
Gene::StateFunc(int_add),
Gene::StateFunc(code_from_exec),
Gene::GeneInt(2),
Gene::GeneInt(4),
Gene::GeneInt(3),
Gene::GeneInt(6),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![13], test_state.int);
}
#[test]
fn exec_do_times_test() {
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(int_add),
Gene::StateFunc(exec_do_times),
Gene::GeneInt(7),
Gene::GeneInt(4),
Gene::GeneInt(5),
Gene::GeneInt(3),
];
interpret_program(&mut test_state, STEP_LIMIT, MAX_STACK_SIZE);
assert_eq!(vec![12], test_state.int);
}
} }

View File

@ -10,9 +10,9 @@ make_instruction_clone!(code, code, _noop, Gene, 0);
make_instruction_clone!(exec, exec, _noop, Gene, 0); make_instruction_clone!(exec, exec, _noop, Gene, 0);
/// Pops the top value from the stack /// Pops the top value from the stack
fn _pop<T>(vals: Vec<T>) -> Option<T> fn _pop<T>(vals: Vec<T>) -> Option<T>
where where
T: Clone, T: Clone
{ {
// This is suboptimal, how to re-write? // This is suboptimal, how to re-write?
// Calls for a complete overhaul later down the line. // Calls for a complete overhaul later down the line.
@ -31,35 +31,6 @@ make_instruction_no_out!(vector_char, _pop, Vec<char>, 1);
make_instruction_no_out!(code, _pop, Gene, 1); make_instruction_no_out!(code, _pop, Gene, 1);
make_instruction_no_out!(exec, _pop, Gene, 1); make_instruction_no_out!(exec, _pop, Gene, 1);
/// Wraps a type in its respective Gene
macro_rules! make_code {
($in_stack:ident, $gene:ident) => {
paste::item! {
pub fn [< code_from_ $in_stack >] (state: &mut PushState) {
if let Some(val) = state.$in_stack.pop() {
state.code.push(Gene::$gene(val));
}
}
}
};
}
make_code!(int, GeneInt);
make_code!(float, GeneFloat);
make_code!(string, GeneString);
make_code!(boolean, GeneBoolean);
make_code!(char, GeneChar);
make_code!(vector_int, GeneVectorInt);
make_code!(vector_float, GeneVectorFloat);
make_code!(vector_string, GeneVectorString);
make_code!(vector_boolean, GeneVectorBoolean);
make_code!(vector_char, GeneVectorChar);
pub fn code_from_exec(state: &mut PushState) {
if let Some(gene) = state.exec.pop() {
state.code.push(gene);
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -94,20 +65,4 @@ mod tests {
let empty_vec: Vec<Gene> = vec![]; let empty_vec: Vec<Gene> = vec![];
assert_eq!(empty_vec, test_state.code); assert_eq!(empty_vec, test_state.code);
} }
#[test]
fn from_test() {
let mut test_state = EMPTY_STATE;
test_state.int = vec![1, 2];
code_from_int(&mut test_state);
assert_eq!(vec![Gene::GeneInt(2)], test_state.code);
assert_eq!(vec![1], test_state.int);
test_state.int.clear();
test_state.code.clear();
test_state.exec.push(Gene::GeneInt(5));
code_from_exec(&mut test_state);
assert_eq!(vec![Gene::GeneInt(5)], test_state.code);
}
} }

View File

@ -7,6 +7,7 @@
use crate::push::state::PushState; use crate::push::state::PushState;
use rust_decimal::Decimal; use rust_decimal::Decimal;
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};

View File

@ -16,7 +16,7 @@ pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
Gene::GeneVectorString(x) => state.vector_string.push(x), Gene::GeneVectorString(x) => state.vector_string.push(x),
Gene::GeneVectorChar(x) => state.vector_char.push(x), Gene::GeneVectorChar(x) => state.vector_char.push(x),
Gene::StateFunc(func) => func(state), Gene::StateFunc(func) => func(state),
Gene::Block(x) => state.exec.extend(x.into_iter().rev()), Gene::Block(x) => state.exec.extend(x.into_iter()),
Gene::Close => panic!("Close found in the exec stack, this should not happen!"), Gene::Close => panic!("Close found in the exec stack, this should not happen!"),
Gene::Open(_) => panic!("Open found in the exec stack, this should not happen!"), Gene::Open(_) => panic!("Open found in the exec stack, this should not happen!"),
Gene::Skip => panic!("Skip found in the exec stack, this should not happen!"), Gene::Skip => panic!("Skip found in the exec stack, this should not happen!"),
@ -28,7 +28,7 @@ pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
/// Where a push program's exec stack is interpreted to completion. /// Where a push program's exec stack is interpreted to completion.
/// TODO: Decide where to place loading in a push program. /// TODO: Decide where to place loading in a push program.
pub fn interpret_program(state: &mut PushState, step_limit: usize, max_stack_size: usize) { pub fn interpret_program(state: &mut PushState, step_limit: usize, max_stack_size: isize) {
let mut steps: usize = 0; let mut steps: usize = 0;
while state.exec.len() > 0 && steps < step_limit { while state.exec.len() > 0 && steps < step_limit {
if let Some(gene) = state.exec.pop() { if let Some(gene) = state.exec.pop() {
@ -62,7 +62,10 @@ mod tests {
assert_eq!(vec![true], test_state.boolean); assert_eq!(vec![true], test_state.boolean);
test_state.boolean.clear(); test_state.boolean.clear();
gene_to_stack(&mut test_state, Gene::GeneString(vec!['t', 'e', 's', 't'])); gene_to_stack(
&mut test_state,
Gene::GeneString(vec!['t', 'e', 's', 't']),
);
assert_eq!(vec![vec!['t', 'e', 's', 't']], test_state.string); assert_eq!(vec![vec!['t', 'e', 's', 't']], test_state.string);
test_state.string.clear(); test_state.string.clear();
@ -134,36 +137,14 @@ mod tests {
test_state.exec.push(Gene::GeneInt(2)); test_state.exec.push(Gene::GeneInt(2));
gene_to_stack(&mut test_state, test_block); gene_to_stack(&mut test_state, test_block);
assert_eq!( assert_eq!(
//vec![
// Gene::GeneInt(2),
// Gene::GeneInt(1),
// Gene::GeneFloat(dec!(2.3)),
// Gene::StateFunc(int_add)
//],
vec![ vec![
Gene::GeneInt(2), Gene::GeneInt(2),
Gene::StateFunc(int_add),
Gene::GeneFloat(dec!(2.3)),
Gene::GeneInt(1), Gene::GeneInt(1),
Gene::GeneFloat(dec!(2.3)),
Gene::StateFunc(int_add)
], ],
test_state.exec test_state.exec
); );
} // println!("{:?}", test_state.exec);
#[test]
fn interpret_program_test() {
use crate::instructions::numeric::int_add;
let mut test_state = EMPTY_STATE;
test_state.exec = vec![
Gene::StateFunc(int_add),
Gene::StateFunc(int_add),
Gene::GeneInt(2),
Gene::GeneInt(3),
Gene::GeneInt(4),
];
interpret_program(&mut test_state, 1000, 1000);
assert_eq!(vec![9], test_state.int);
} }
} }