Compare commits
No commits in common. "37d59517d0c3eddd7d02c6328f9d7b202c131a68" and "b0ad9a303599e773cc660ab4dae7077fb04a2f41" have entirely different histories.
37d59517d0
...
b0ad9a3035
@ -2,7 +2,7 @@ use std::ops::Not;
|
||||
|
||||
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.
|
||||
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);
|
||||
|
||||
/// 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> {
|
||||
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.
|
||||
/// 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() {
|
||||
return;
|
||||
}
|
||||
@ -132,162 +132,12 @@ pub fn code_do_then_pop(state: &mut PushState) {
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
instructions::numeric::int_add,
|
||||
push::{interpreter::interpret_program, state::EMPTY_STATE},
|
||||
};
|
||||
use crate::{instructions::numeric::int_add, push::state::EMPTY_STATE};
|
||||
use rust_decimal::dec;
|
||||
|
||||
const STEP_LIMIT: usize = 1000;
|
||||
const MAX_STACK_SIZE: usize = 1000;
|
||||
|
||||
#[test]
|
||||
fn is_block_test() {
|
||||
let mut test_state = EMPTY_STATE;
|
||||
@ -515,7 +365,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_do_then_pop_test() {
|
||||
fn _code_do_then_pop_test() {
|
||||
let mut test_state = EMPTY_STATE;
|
||||
|
||||
test_state.code.push(Gene::StateFunc(int_add));
|
||||
@ -526,95 +376,4 @@ mod tests {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ make_instruction_clone!(code, code, _noop, Gene, 0);
|
||||
make_instruction_clone!(exec, exec, _noop, Gene, 0);
|
||||
|
||||
/// Pops the top value from the stack
|
||||
fn _pop<T>(vals: Vec<T>) -> Option<T>
|
||||
where
|
||||
T: Clone,
|
||||
fn _pop<T>(vals: Vec<T>) -> Option<T>
|
||||
where
|
||||
T: Clone
|
||||
{
|
||||
// This is suboptimal, how to re-write?
|
||||
// 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!(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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -94,20 +65,4 @@ mod tests {
|
||||
let empty_vec: Vec<Gene> = vec![];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
use crate::push::state::PushState;
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
|
||||
use std::cmp::{max, min};
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub fn gene_to_stack(state: &mut PushState, gene: Gene) {
|
||||
Gene::GeneVectorString(x) => state.vector_string.push(x),
|
||||
Gene::GeneVectorChar(x) => state.vector_char.push(x),
|
||||
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::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!"),
|
||||
@ -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.
|
||||
/// 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;
|
||||
while state.exec.len() > 0 && steps < step_limit {
|
||||
if let Some(gene) = state.exec.pop() {
|
||||
@ -62,7 +62,10 @@ mod tests {
|
||||
assert_eq!(vec![true], test_state.boolean);
|
||||
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);
|
||||
test_state.string.clear();
|
||||
|
||||
@ -134,36 +137,14 @@ mod tests {
|
||||
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)
|
||||
//],
|
||||
vec![
|
||||
Gene::GeneInt(2),
|
||||
Gene::StateFunc(int_add),
|
||||
Gene::GeneFloat(dec!(2.3)),
|
||||
Gene::GeneInt(1),
|
||||
Gene::GeneFloat(dec!(2.3)),
|
||||
Gene::StateFunc(int_add)
|
||||
],
|
||||
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);
|
||||
// println!("{:?}", test_state.exec);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user