finish converting all the functions to new format
This commit is contained in:
parent
eb2c033a98
commit
082de08998
@ -471,6 +471,17 @@ pub fn _reverse(a: Gene) -> Option<Gene> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Acts as a noop, does nothing to the state internally.
|
||||||
|
macro_rules! noop {
|
||||||
|
($stack:ident, $name:ident) => {
|
||||||
|
paste::item! {
|
||||||
|
pub fn [< $stack $name >] (_: &mut PushState) {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! make_code_instructions {
|
macro_rules! make_code_instructions {
|
||||||
($stack:ident) => {
|
($stack:ident) => {
|
||||||
make_instruction_new!(_is_block, $stack, boolean, $stack);
|
make_instruction_new!(_is_block, $stack, boolean, $stack);
|
||||||
@ -499,6 +510,12 @@ macro_rules! all_code_instructions {
|
|||||||
() => {
|
() => {
|
||||||
make_code_instructions!(code);
|
make_code_instructions!(code);
|
||||||
make_code_instructions!(exec);
|
make_code_instructions!(exec);
|
||||||
|
|
||||||
|
// Misc instructions
|
||||||
|
noop!(code, _noop);
|
||||||
|
noop!(exec, _noop);
|
||||||
|
noop!(code, _noop_block);
|
||||||
|
noop!(exec, _noop_block);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
all_code_instructions!();
|
all_code_instructions!();
|
||||||
@ -1238,4 +1255,19 @@ mod tests {
|
|||||||
test_state.code
|
test_state.code
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn noop_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.int = vec![1, 2];
|
||||||
|
let test_state_copy = test_state.clone();
|
||||||
|
code_noop(&mut test_state);
|
||||||
|
assert_eq!(test_state, test_state_copy);
|
||||||
|
|
||||||
|
test_state.int = vec![1, 2];
|
||||||
|
let test_state_copy = test_state.clone();
|
||||||
|
exec_noop(&mut test_state);
|
||||||
|
assert_eq!(test_state, test_state_copy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use rust_decimal::Decimal;
|
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
use crate::push::state::{Gene, PushState};
|
use crate::push::state::{Gene, PushState};
|
||||||
@ -7,216 +6,100 @@ fn min_max_bounds(ndx: i128, length: usize) -> usize {
|
|||||||
max(0, min(ndx.unsigned_abs() as usize, length - 1))
|
max(0, min(ndx.unsigned_abs() as usize, length - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acts as a NoOp, does nothing with the vals list.
|
|
||||||
fn _noop<T>(_: Vec<T>) -> Option<T> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
make_instruction_clone!(code, code, _noop, Gene, 0);
|
|
||||||
make_instruction_clone!(exec, exec, _noop, Gene, 0);
|
|
||||||
|
|
||||||
fn _noop_block<T>(_: Vec<T>) -> Option<T> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
make_instruction_clone!(code, code, _noop_block, Gene, 0);
|
|
||||||
make_instruction_clone!(exec, exec, _noop_block, Gene, 0);
|
|
||||||
|
|
||||||
/// Pops the top value from the stack
|
/// Pops the top value from the stack
|
||||||
fn _pop<T>(vals: Vec<T>) -> Option<T>
|
macro_rules! pop {
|
||||||
where
|
($in_stack:ident) => {
|
||||||
T: Clone,
|
paste::item! {
|
||||||
{
|
pub fn [< $in_stack _pop >] (state: &mut PushState) {
|
||||||
// This is suboptimal, how to re-write?
|
state.$in_stack.pop();
|
||||||
// Calls for a complete overhaul later down the line.
|
}
|
||||||
Some(vals[0].clone())
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! gene_map {
|
||||||
|
(int, $val:ident) => {
|
||||||
|
Gene::GeneInt($val)
|
||||||
|
};
|
||||||
|
(float, $val:ident) => {
|
||||||
|
Gene::GeneFloat($val)
|
||||||
|
};
|
||||||
|
(string, $val:ident) => {
|
||||||
|
Gene::GeneString($val)
|
||||||
|
};
|
||||||
|
(boolean, $val:ident) => {
|
||||||
|
Gene::GeneBoolean($val)
|
||||||
|
};
|
||||||
|
(char, $val:ident) => {
|
||||||
|
Gene::GeneChar($val)
|
||||||
|
};
|
||||||
|
(vector_int, $val:ident) => {
|
||||||
|
Gene::GeneVectorInt($val)
|
||||||
|
};
|
||||||
|
(vector_float, $val:ident) => {
|
||||||
|
Gene::GeneVectorFloat($val)
|
||||||
|
};
|
||||||
|
(vector_string, $val:ident) => {
|
||||||
|
Gene::GeneVectorString($val)
|
||||||
|
};
|
||||||
|
(vector_boolean, $val:ident) => {
|
||||||
|
Gene::GeneVectorBoolean($val)
|
||||||
|
};
|
||||||
|
(vector_char, $val:ident) => {
|
||||||
|
Gene::GeneVectorChar($val)
|
||||||
|
};
|
||||||
|
(code, $val:ident) => {
|
||||||
|
$val
|
||||||
|
};
|
||||||
|
(exec, $val:ident) => {
|
||||||
|
$val
|
||||||
|
};
|
||||||
}
|
}
|
||||||
make_instruction_no_out!(int, _pop, i128, 1);
|
|
||||||
make_instruction_no_out!(float, _pop, Decimal, 1);
|
|
||||||
make_instruction_no_out!(string, _pop, Vec<char>, 1);
|
|
||||||
make_instruction_no_out!(boolean, _pop, bool, 1);
|
|
||||||
make_instruction_no_out!(char, _pop, char, 1);
|
|
||||||
make_instruction_no_out!(vector_int, _pop, Vec<i128>, 1);
|
|
||||||
make_instruction_no_out!(vector_float, _pop, Vec<Decimal>, 1);
|
|
||||||
make_instruction_no_out!(vector_string, _pop, Vec<Vec<char>>, 1);
|
|
||||||
make_instruction_no_out!(vector_boolean, _pop, Vec<bool>, 1);
|
|
||||||
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
|
/// Wraps a type in its respective Gene
|
||||||
macro_rules! make_code {
|
macro_rules! make_code {
|
||||||
($in_stack:ident, $gene:ident) => {
|
($stack:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
pub fn [< code_from_ $in_stack >] (state: &mut PushState) {
|
pub fn [< code_from_ $stack >] (state: &mut PushState) {
|
||||||
if let Some(val) = state.$in_stack.pop() {
|
if let Some(val) = state.$stack.pop() {
|
||||||
state.code.push(Gene::$gene(val));
|
let push_val = gene_map!($stack, val);
|
||||||
|
state.code.push(push_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duplicates an item
|
/// Duplicates an item
|
||||||
pub fn _dup<T: Clone>(vals: Vec<T>) -> Option<Vec<T>> {
|
pub fn _dup<T: Clone>(val: T) -> Option<Vec<T>> {
|
||||||
Some(vec![vals[0].clone(), vals[0].clone()])
|
Some(vec![val.clone(), val])
|
||||||
}
|
}
|
||||||
make_instruction_mult!(int, int, _dup, i128, 1);
|
|
||||||
make_instruction_mult!(float, float, _dup, Decimal, 1);
|
|
||||||
make_instruction_mult!(string, string, _dup, Vec<char>, 1);
|
|
||||||
make_instruction_mult!(boolean, boolean, _dup, bool, 1);
|
|
||||||
make_instruction_mult!(char, char, _dup, char, 1);
|
|
||||||
make_instruction_mult!(vector_int, vector_int, _dup, Vec<i128>, 1);
|
|
||||||
make_instruction_mult!(vector_float, vector_float, _dup, Vec<Decimal>, 1);
|
|
||||||
make_instruction_mult!(vector_string, vector_string, _dup, Vec<Vec<char>>, 1);
|
|
||||||
make_instruction_mult!(vector_boolean, vector_boolean, _dup, Vec<bool>, 1);
|
|
||||||
make_instruction_mult!(vector_char, vector_char, _dup, Vec<char>, 1);
|
|
||||||
make_instruction_mult!(code, code, _dup, Gene, 1);
|
|
||||||
make_instruction_mult!(exec, exec, _dup, Gene, 1);
|
|
||||||
|
|
||||||
pub fn _dup_times<T: Clone>(vals: Vec<T>, auxs: Vec<i128>) -> Option<Vec<T>> {
|
pub fn _dup_times<T: Clone>(amt: i128, val: T) -> Option<Vec<T>> {
|
||||||
Some(vec![vals[0].clone(); auxs[0] as usize])
|
Some(vec![val; amt as usize])
|
||||||
}
|
}
|
||||||
make_instruction_mult_aux!(int, int, _dup_times, i128, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(float, float, _dup_times, Decimal, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(string, string, _dup_times, Vec<char>, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(boolean, boolean, _dup_times, bool, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(char, char, _dup_times, char, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(
|
|
||||||
vector_int,
|
|
||||||
vector_int,
|
|
||||||
_dup_times,
|
|
||||||
Vec<i128>,
|
|
||||||
1,
|
|
||||||
int,
|
|
||||||
1,
|
|
||||||
i128
|
|
||||||
);
|
|
||||||
make_instruction_mult_aux!(
|
|
||||||
vector_float,
|
|
||||||
vector_float,
|
|
||||||
_dup_times,
|
|
||||||
Vec<Decimal>,
|
|
||||||
1,
|
|
||||||
int,
|
|
||||||
1,
|
|
||||||
i128
|
|
||||||
);
|
|
||||||
make_instruction_mult_aux!(
|
|
||||||
vector_string,
|
|
||||||
vector_string,
|
|
||||||
_dup_times,
|
|
||||||
Vec<Vec<char>>,
|
|
||||||
1,
|
|
||||||
int,
|
|
||||||
1,
|
|
||||||
i128
|
|
||||||
);
|
|
||||||
make_instruction_mult_aux!(
|
|
||||||
vector_boolean,
|
|
||||||
vector_boolean,
|
|
||||||
_dup_times,
|
|
||||||
Vec<bool>,
|
|
||||||
1,
|
|
||||||
int,
|
|
||||||
1,
|
|
||||||
i128
|
|
||||||
);
|
|
||||||
make_instruction_mult_aux!(
|
|
||||||
vector_char,
|
|
||||||
vector_char,
|
|
||||||
_dup_times,
|
|
||||||
Vec<char>,
|
|
||||||
1,
|
|
||||||
int,
|
|
||||||
1,
|
|
||||||
i128
|
|
||||||
);
|
|
||||||
make_instruction_mult_aux!(code, code, _dup_times, Gene, 1, int, 1, i128);
|
|
||||||
make_instruction_mult_aux!(exec, exec, _dup_times, Gene, 1, int, 1, i128);
|
|
||||||
|
|
||||||
/// Swaps two values
|
/// Swaps two values
|
||||||
pub fn _swap<T: Clone>(vals: Vec<T>) -> Option<Vec<T>> {
|
pub fn _swap<T: Clone>(a: T, b: T) -> Option<Vec<T>> {
|
||||||
Some(vec![vals[0].clone(), vals[1].clone()])
|
Some(vec![a, b])
|
||||||
}
|
}
|
||||||
make_instruction_mult!(int, int, _swap, i128, 2);
|
|
||||||
make_instruction_mult!(float, float, _swap, Decimal, 2);
|
|
||||||
make_instruction_mult!(string, string, _swap, Vec<char>, 2);
|
|
||||||
make_instruction_mult!(boolean, boolean, _swap, bool, 2);
|
|
||||||
make_instruction_mult!(char, char, _swap, char, 2);
|
|
||||||
make_instruction_mult!(vector_int, vector_int, _swap, Vec<i128>, 2);
|
|
||||||
make_instruction_mult!(vector_float, vector_float, _swap, Vec<Decimal>, 2);
|
|
||||||
make_instruction_mult!(vector_string, vector_string, _swap, Vec<Vec<char>>, 2);
|
|
||||||
make_instruction_mult!(vector_boolean, vector_boolean, _swap, Vec<bool>, 2);
|
|
||||||
make_instruction_mult!(vector_char, vector_char, _swap, Vec<char>, 2);
|
|
||||||
make_instruction_mult!(code, code, _swap, Gene, 2);
|
|
||||||
make_instruction_mult!(exec, exec, _swap, Gene, 2);
|
|
||||||
|
|
||||||
/// Rotates three values
|
/// Rotates three values
|
||||||
pub fn _rotate<T: Clone>(vals: Vec<T>) -> Option<Vec<T>> {
|
pub fn _rotate<T>(a: T, b: T, c: T) -> Option<Vec<T>> {
|
||||||
Some(vec![vals[2].clone(), vals[0].clone(), vals[1].clone()])
|
Some(vec![c, a, b])
|
||||||
}
|
}
|
||||||
make_instruction_mult!(int, int, _rotate, i128, 3);
|
|
||||||
make_instruction_mult!(float, float, _rotate, Decimal, 3);
|
|
||||||
make_instruction_mult!(string, string, _rotate, Vec<char>, 3);
|
|
||||||
make_instruction_mult!(boolean, boolean, _rotate, bool, 3);
|
|
||||||
make_instruction_mult!(char, char, _rotate, char, 3);
|
|
||||||
make_instruction_mult!(vector_int, vector_int, _rotate, Vec<i128>, 3);
|
|
||||||
make_instruction_mult!(vector_float, vector_float, _rotate, Vec<Decimal>, 3);
|
|
||||||
make_instruction_mult!(vector_string, vector_string, _rotate, Vec<Vec<char>>, 3);
|
|
||||||
make_instruction_mult!(vector_boolean, vector_boolean, _rotate, Vec<bool>, 3);
|
|
||||||
make_instruction_mult!(vector_char, vector_char, _rotate, Vec<char>, 3);
|
|
||||||
make_instruction_mult!(code, code, _rotate, Gene, 3);
|
|
||||||
make_instruction_mult!(exec, exec, _rotate, Gene, 3);
|
|
||||||
|
|
||||||
/// Checks if two values are equal
|
/// Checks if two values are equal
|
||||||
pub fn _equal<T: Clone + Eq>(vals: Vec<T>) -> Option<bool> {
|
pub fn _equal<T: Eq>(a: T, b: T) -> Option<bool> {
|
||||||
Some(vals[1] == vals[0])
|
Some(b == a)
|
||||||
}
|
}
|
||||||
make_instruction!(int, boolean, _equal, i128, 2);
|
|
||||||
make_instruction!(float, boolean, _equal, Decimal, 2);
|
|
||||||
make_instruction_clone!(string, boolean, _equal, Vec<char>, 2);
|
|
||||||
make_instruction!(boolean, boolean, _equal, bool, 2);
|
|
||||||
make_instruction!(char, boolean, _equal, char, 2);
|
|
||||||
make_instruction_clone!(vector_int, boolean, _equal, Vec<i128>, 2);
|
|
||||||
make_instruction_clone!(vector_float, boolean, _equal, Vec<Decimal>, 2);
|
|
||||||
make_instruction_clone!(vector_string, boolean, _equal, Vec<Vec<char>>, 2);
|
|
||||||
make_instruction_clone!(vector_boolean, boolean, _equal, Vec<bool>, 2);
|
|
||||||
make_instruction_clone!(vector_char, boolean, _equal, Vec<char>, 2);
|
|
||||||
make_instruction_clone!(code, boolean, _equal, Gene, 2);
|
|
||||||
make_instruction_clone!(exec, boolean, _equal, Gene, 2);
|
|
||||||
|
|
||||||
/// Checks if two values are not equal
|
/// Checks if two values are not equal
|
||||||
pub fn _not_equal<T: Clone + Eq>(vals: Vec<T>) -> Option<bool> {
|
pub fn _not_equal<T: Clone + Eq>(a: T, b: T) -> Option<bool> {
|
||||||
Some(vals[1] != vals[0])
|
Some(b != a)
|
||||||
}
|
}
|
||||||
make_instruction!(int, boolean, _not_equal, i128, 2);
|
|
||||||
make_instruction!(float, boolean, _not_equal, Decimal, 2);
|
|
||||||
make_instruction_clone!(string, boolean, _not_equal, Vec<char>, 2);
|
|
||||||
make_instruction!(boolean, boolean, _not_equal, bool, 2);
|
|
||||||
make_instruction!(char, boolean, _not_equal, char, 2);
|
|
||||||
make_instruction_clone!(vector_int, boolean, _not_equal, Vec<i128>, 2);
|
|
||||||
make_instruction_clone!(vector_float, boolean, _not_equal, Vec<Decimal>, 2);
|
|
||||||
make_instruction_clone!(vector_string, boolean, _not_equal, Vec<Vec<char>>, 2);
|
|
||||||
make_instruction_clone!(vector_boolean, boolean, _not_equal, Vec<bool>, 2);
|
|
||||||
make_instruction_clone!(vector_char, boolean, _not_equal, Vec<char>, 2);
|
|
||||||
make_instruction_clone!(code, boolean, _not_equal, Gene, 2);
|
|
||||||
make_instruction_clone!(exec, boolean, _not_equal, Gene, 2);
|
|
||||||
|
|
||||||
|
/// Removes all values from a stack
|
||||||
macro_rules! flush_state {
|
macro_rules! flush_state {
|
||||||
($in_stack:ident) => {
|
($in_stack:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
@ -226,19 +109,8 @@ macro_rules! flush_state {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
flush_state!(int);
|
|
||||||
flush_state!(float);
|
|
||||||
flush_state!(string);
|
|
||||||
flush_state!(boolean);
|
|
||||||
flush_state!(char);
|
|
||||||
flush_state!(vector_int);
|
|
||||||
flush_state!(vector_float);
|
|
||||||
flush_state!(vector_string);
|
|
||||||
flush_state!(vector_boolean);
|
|
||||||
flush_state!(vector_char);
|
|
||||||
flush_state!(code);
|
|
||||||
flush_state!(exec);
|
|
||||||
|
|
||||||
|
/// Returns the depth of a stack
|
||||||
macro_rules! stack_depth {
|
macro_rules! stack_depth {
|
||||||
($in_stack:ident) => {
|
($in_stack:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
@ -248,31 +120,20 @@ macro_rules! stack_depth {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
stack_depth!(int);
|
|
||||||
stack_depth!(float);
|
|
||||||
stack_depth!(string);
|
|
||||||
stack_depth!(boolean);
|
|
||||||
stack_depth!(char);
|
|
||||||
stack_depth!(vector_int);
|
|
||||||
stack_depth!(vector_float);
|
|
||||||
stack_depth!(vector_string);
|
|
||||||
stack_depth!(vector_boolean);
|
|
||||||
stack_depth!(vector_char);
|
|
||||||
stack_depth!(code);
|
|
||||||
stack_depth!(exec);
|
|
||||||
|
|
||||||
macro_rules! yank {
|
macro_rules! yank {
|
||||||
($in_stack:ident, $in_type:expr) => {
|
($in_stack:ident) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
pub fn [< $in_stack _yank >] (state: &mut PushState) {
|
pub fn [< $in_stack _yank >] (state: &mut PushState) {
|
||||||
if state.int.is_empty() || state.$in_stack.is_empty() {
|
if state.int.is_empty() || state.$in_stack.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let in_stack_len = state.$in_stack.len();
|
let in_stack_len = state.$in_stack.len();
|
||||||
if $in_type == "i128" && in_stack_len < 2 {
|
let in_stack_name = stringify!($in_stack);
|
||||||
|
if in_stack_name == "int" && in_stack_len < 2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no -1 at the end, handled in the min_max_bounds function
|
// no -1 from in_stack_len, 1 subtracted within the min_max_bounds function
|
||||||
let idx = min_max_bounds(state.int.pop().unwrap(), in_stack_len);
|
let idx = min_max_bounds(state.int.pop().unwrap(), in_stack_len);
|
||||||
let item = state.$in_stack.remove(in_stack_len - idx);
|
let item = state.$in_stack.remove(in_stack_len - idx);
|
||||||
state.$in_stack.push(item);
|
state.$in_stack.push(item);
|
||||||
@ -280,39 +141,45 @@ macro_rules! yank {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
yank!(int, "i128");
|
|
||||||
yank!(float, "");
|
macro_rules! make_common_instructions {
|
||||||
yank!(string, "");
|
($stack:ident) => {
|
||||||
yank!(boolean, "");
|
pop!($stack);
|
||||||
yank!(char, "");
|
make_code!($stack);
|
||||||
yank!(vector_int, "");
|
make_instruction_new_aux!(_dup, $stack, $stack, $stack);
|
||||||
yank!(vector_float, "");
|
make_instruction_new_aux!(_dup_times, $stack, $stack, int, $stack);
|
||||||
yank!(vector_string, "");
|
make_instruction_new_aux!(_swap, $stack, $stack, $stack, $stack);
|
||||||
yank!(vector_boolean, "");
|
make_instruction_new_aux!(_rotate, $stack, $stack, $stack, $stack, $stack);
|
||||||
yank!(vector_char, "");
|
make_instruction_new!(_equal, $stack, boolean, $stack, $stack);
|
||||||
yank!(code, "");
|
flush_state!($stack);
|
||||||
yank!(exec, "");
|
stack_depth!($stack);
|
||||||
|
yank!($stack);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! all_common_instructions {
|
||||||
|
() => {
|
||||||
|
make_common_instructions!(int);
|
||||||
|
make_common_instructions!(float);
|
||||||
|
make_common_instructions!(string);
|
||||||
|
make_common_instructions!(boolean);
|
||||||
|
make_common_instructions!(char);
|
||||||
|
make_common_instructions!(vector_int);
|
||||||
|
make_common_instructions!(vector_float);
|
||||||
|
make_common_instructions!(vector_string);
|
||||||
|
make_common_instructions!(vector_boolean);
|
||||||
|
make_common_instructions!(vector_char);
|
||||||
|
make_common_instructions!(code);
|
||||||
|
make_common_instructions!(exec);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
all_common_instructions!();
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::push::state::EMPTY_STATE;
|
use crate::push::state::EMPTY_STATE;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn noop_test() {
|
|
||||||
let mut test_state = EMPTY_STATE;
|
|
||||||
|
|
||||||
test_state.int = vec![1, 2];
|
|
||||||
let test_state_copy = test_state.clone();
|
|
||||||
code_noop(&mut test_state);
|
|
||||||
assert_eq!(test_state, test_state_copy);
|
|
||||||
|
|
||||||
test_state.int = vec![1, 2];
|
|
||||||
let test_state_copy = test_state.clone();
|
|
||||||
exec_noop(&mut test_state);
|
|
||||||
assert_eq!(test_state, test_state_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pop_test() {
|
fn pop_test() {
|
||||||
let mut test_state = EMPTY_STATE;
|
let mut test_state = EMPTY_STATE;
|
||||||
@ -423,6 +290,6 @@ mod tests {
|
|||||||
|
|
||||||
test_state.int = vec![1, 2, 3, 4, 5, 6, 7, 8, 2];
|
test_state.int = vec![1, 2, 3, 4, 5, 6, 7, 8, 2];
|
||||||
int_yank(&mut test_state);
|
int_yank(&mut test_state);
|
||||||
//assert_eq!(vec![1, 2, 3, 4, 5, 7, 8, 6], test_state.int);
|
assert_eq!(vec![1, 2, 3, 4, 5, 7, 8, 6], test_state.int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,302 +1,5 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros {
|
pub mod macros {
|
||||||
/// A macro that makes a push instruction given: the name of the input stack to use,
|
|
||||||
/// the name of the output stack, an internal function to call, the type of a function,
|
|
||||||
/// and the arity of the internal function call.
|
|
||||||
///
|
|
||||||
/// The `in_stack` argument refers to which push stack should this operate on.
|
|
||||||
/// The `out_stack` argument refers to which push stack should the result be pushed to.
|
|
||||||
/// The `fn_name` argument refers to the name of the function that is to operate
|
|
||||||
/// on the values popped from `in_stack`.
|
|
||||||
/// The `fn_type` argument refers to the type of `in_stack`. For example, the
|
|
||||||
/// int stack is type: *Vec<i128>*. `fn_type` is *i128* in this case.
|
|
||||||
/// The `fn_arity` argument refers to how many popped stack items are needed to
|
|
||||||
/// execute the instruction. If the amount of items in the stack is less than
|
|
||||||
/// this value, the instruction does nothing. How many items exactly should be passed
|
|
||||||
/// as a list to the functions used for calculations.
|
|
||||||
///
|
|
||||||
/// What causes an instruction to NoOp:
|
|
||||||
/// 1) There aren't enough values on a stack to execute an instruction.
|
|
||||||
/// 2) The internal operation the instruction executes is unable to be ran without
|
|
||||||
/// erroring such as division by 0.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
if in_stack_len < $fn_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n]);
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs) {
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The same as make_instruction above but prepends the output
|
|
||||||
/// stack to the function name rather than the input stack.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_out {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
pub fn [< $out_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
if in_stack_len < $fn_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs) {
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The same as make_instruction but uses clone() to fill the arguments
|
|
||||||
/// to each function rather than a reference. Is slower, but will be okay
|
|
||||||
/// for the time being.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_clone {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
#[allow(clippy::reversed_empty_ranges, unused_comparisons)]
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
if in_stack_len < $fn_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs) {
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_mult {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
if in_stack_len < $fn_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs) {
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.extend(result.into_iter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as the make_instruction macro except it pushes nothing to the
|
|
||||||
/// output stack.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_no_out {
|
|
||||||
($in_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
#[allow(unused_comparisons)]
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
if in_stack_len < $fn_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(_) = $fn_name(inputs) {
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as `make_instruction!` but can work on two stacks.
|
|
||||||
///
|
|
||||||
/// `aux_stack` is an auxiliary stack to be used as input to internal function.
|
|
||||||
/// `aux_arity` is the amount of the auxiliary stack to use.
|
|
||||||
/// `aux_type` is the type of the auxiliary stack
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_aux {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt, $aux_stack:ident, $aux_arity:stmt, $aux_type:ty) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
/// $aux_stack is also used and popped $aux_arity time(s).
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
let aux_stack_len = state.$aux_stack.len();
|
|
||||||
if in_stack_len < $fn_arity || aux_stack_len < $aux_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
let mut aux_inputs: Vec<$aux_type> = Vec::with_capacity($aux_arity);
|
|
||||||
for n in 1..=$aux_arity {
|
|
||||||
aux_inputs.push(state.$aux_stack[aux_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs, aux_inputs) {
|
|
||||||
for _ in 0..$aux_arity {
|
|
||||||
state.$aux_stack.pop();
|
|
||||||
}
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as make_instruction_mult but can handle one auxiliary variable.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_mult_aux {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt, $aux_stack:ident, $aux_arity:stmt, $aux_type:ty) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
/// $aux_stack is also used and popped $aux_arity time(s).
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
let aux_stack_len = state.$aux_stack.len();
|
|
||||||
if in_stack_len < $fn_arity || aux_stack_len < $aux_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
let mut aux_inputs: Vec<$aux_type> = Vec::with_capacity($aux_arity);
|
|
||||||
for n in 1..=$aux_arity {
|
|
||||||
aux_inputs.push(state.$aux_stack[aux_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
if stringify!($fn_type) == stringify!($aux_type) {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - $aux_arity - n].clone());
|
|
||||||
} else {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
//inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs, aux_inputs) {
|
|
||||||
for _ in 0..$aux_arity {
|
|
||||||
state.$aux_stack.pop();
|
|
||||||
}
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.extend(result.into_iter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as `make_instruction!` but can work on three stacks. Is there a way
|
|
||||||
/// to generalize even this?
|
|
||||||
///
|
|
||||||
/// `aux_stack` is an auxiliary stack to be used as input to internal function.
|
|
||||||
/// `aux_arity` is the amount of the auxiliary stack to use.
|
|
||||||
/// `aux_type` is the type of the auxiliary stack
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! make_instruction_aux2 {
|
|
||||||
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt, $aux0_stack:ident, $aux0_arity:stmt, $aux0_type:ty, $aux1_stack:ident, $aux1_arity:stmt, $aux1_type:ty) => {
|
|
||||||
paste::item! {
|
|
||||||
/// Runs the $fn_name function on the top $fn_arity items from
|
|
||||||
/// the $in_stack and places the calculated value on the $out_stack.
|
|
||||||
/// $aux_stack is also used and popped $aux_arity time(s).
|
|
||||||
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
|
||||||
let in_stack_len = state.$in_stack.len();
|
|
||||||
let aux0_stack_len = state.$aux0_stack.len();
|
|
||||||
let aux1_stack_len = state.$aux1_stack.len();
|
|
||||||
if in_stack_len < $fn_arity || aux0_stack_len < $aux0_arity || aux1_stack_len < $aux1_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if stringify!($aux0_type) == stringify!($aux1_type) {
|
|
||||||
if aux0_stack_len + aux1_stack_len < $aux0_arity + $aux1_arity {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
|
||||||
let mut aux0_inputs: Vec<$aux0_type> = Vec::with_capacity($aux0_arity);
|
|
||||||
let mut aux1_inputs: Vec<$aux1_type> = Vec::with_capacity($aux1_arity);
|
|
||||||
for n in 1..=$aux1_arity {
|
|
||||||
aux1_inputs.push(state.$aux1_stack[aux1_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
for n in 1..=$aux0_arity {
|
|
||||||
if stringify!($aux0_type) == stringify!($aux1_type) {
|
|
||||||
aux0_inputs.push(state.$aux0_stack[aux0_stack_len - $aux1_arity - n].clone());
|
|
||||||
} else {
|
|
||||||
aux0_inputs.push(state.$aux0_stack[aux0_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Stack shouldn't be the same for all three
|
|
||||||
for n in 1..=$fn_arity {
|
|
||||||
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
|
||||||
}
|
|
||||||
if let Some(result) = $fn_name(inputs, aux0_inputs, aux1_inputs) {
|
|
||||||
for _ in 0..$aux1_arity {
|
|
||||||
state.$aux1_stack.pop();
|
|
||||||
}
|
|
||||||
for _ in 0..$aux0_arity {
|
|
||||||
state.$aux0_stack.pop();
|
|
||||||
}
|
|
||||||
for _ in 0..$fn_arity {
|
|
||||||
state.$in_stack.pop();
|
|
||||||
}
|
|
||||||
state.$out_stack.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs a function and ensures the necessary variables are extracted from a state without error
|
/// Runs a function and ensures the necessary variables are extracted from a state without error
|
||||||
macro_rules! make_instruction_new {
|
macro_rules! make_instruction_new {
|
||||||
($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => {
|
($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => {
|
||||||
|
@ -99,7 +99,7 @@ impl Gene {
|
|||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
val => Some(val),
|
val => Some(val),
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user