From 082de0899855e2f560199cb1323e7a8f7bdbc50d Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 20:47:37 -0500 Subject: [PATCH] finish converting all the functions to new format --- src/instructions/code.rs | 32 ++++ src/instructions/common.rs | 341 +++++++++++-------------------------- src/instructions/mod.rs | 297 -------------------------------- src/push/state.rs | 2 +- 4 files changed, 137 insertions(+), 535 deletions(-) diff --git a/src/instructions/code.rs b/src/instructions/code.rs index c0a9f9c..7931c9c 100644 --- a/src/instructions/code.rs +++ b/src/instructions/code.rs @@ -471,6 +471,17 @@ pub fn _reverse(a: Gene) -> Option { }) } +/// 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 { ($stack:ident) => { make_instruction_new!(_is_block, $stack, boolean, $stack); @@ -499,6 +510,12 @@ macro_rules! all_code_instructions { () => { make_code_instructions!(code); make_code_instructions!(exec); + + // Misc instructions + noop!(code, _noop); + noop!(exec, _noop); + noop!(code, _noop_block); + noop!(exec, _noop_block); }; } all_code_instructions!(); @@ -1238,4 +1255,19 @@ mod tests { 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); + } } diff --git a/src/instructions/common.rs b/src/instructions/common.rs index 577ee4d..9ef4e3b 100644 --- a/src/instructions/common.rs +++ b/src/instructions/common.rs @@ -1,4 +1,3 @@ -use rust_decimal::Decimal; use std::cmp::{max, min}; 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)) } -/// Acts as a NoOp, does nothing with the vals list. -fn _noop(_: Vec) -> Option { - None -} -make_instruction_clone!(code, code, _noop, Gene, 0); -make_instruction_clone!(exec, exec, _noop, Gene, 0); - -fn _noop_block(_: Vec) -> Option { - 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 -fn _pop(vals: Vec) -> Option -where - T: Clone, -{ - // This is suboptimal, how to re-write? - // Calls for a complete overhaul later down the line. - Some(vals[0].clone()) +macro_rules! pop { + ($in_stack:ident) => { + paste::item! { + pub fn [< $in_stack _pop >] (state: &mut PushState) { + state.$in_stack.pop(); + } + } + }; +} + +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, 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, 1); -make_instruction_no_out!(vector_float, _pop, Vec, 1); -make_instruction_no_out!(vector_string, _pop, Vec>, 1); -make_instruction_no_out!(vector_boolean, _pop, Vec, 1); -make_instruction_no_out!(vector_char, _pop, Vec, 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) => { + ($stack: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)); + pub fn [< code_from_ $stack >] (state: &mut PushState) { + if let Some(val) = state.$stack.pop() { + 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 -pub fn _dup(vals: Vec) -> Option> { - Some(vec![vals[0].clone(), vals[0].clone()]) +pub fn _dup(val: T) -> Option> { + 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, 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, 1); -make_instruction_mult!(vector_float, vector_float, _dup, Vec, 1); -make_instruction_mult!(vector_string, vector_string, _dup, Vec>, 1); -make_instruction_mult!(vector_boolean, vector_boolean, _dup, Vec, 1); -make_instruction_mult!(vector_char, vector_char, _dup, Vec, 1); -make_instruction_mult!(code, code, _dup, Gene, 1); -make_instruction_mult!(exec, exec, _dup, Gene, 1); -pub fn _dup_times(vals: Vec, auxs: Vec) -> Option> { - Some(vec![vals[0].clone(); auxs[0] as usize]) +pub fn _dup_times(amt: i128, val: T) -> Option> { + 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, 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, - 1, - int, - 1, - i128 -); -make_instruction_mult_aux!( - vector_float, - vector_float, - _dup_times, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_mult_aux!( - vector_string, - vector_string, - _dup_times, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_mult_aux!( - vector_boolean, - vector_boolean, - _dup_times, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_mult_aux!( - vector_char, - vector_char, - _dup_times, - Vec, - 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 -pub fn _swap(vals: Vec) -> Option> { - Some(vec![vals[0].clone(), vals[1].clone()]) +pub fn _swap(a: T, b: T) -> Option> { + 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, 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, 2); -make_instruction_mult!(vector_float, vector_float, _swap, Vec, 2); -make_instruction_mult!(vector_string, vector_string, _swap, Vec>, 2); -make_instruction_mult!(vector_boolean, vector_boolean, _swap, Vec, 2); -make_instruction_mult!(vector_char, vector_char, _swap, Vec, 2); -make_instruction_mult!(code, code, _swap, Gene, 2); -make_instruction_mult!(exec, exec, _swap, Gene, 2); /// Rotates three values -pub fn _rotate(vals: Vec) -> Option> { - Some(vec![vals[2].clone(), vals[0].clone(), vals[1].clone()]) +pub fn _rotate(a: T, b: T, c: T) -> Option> { + 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, 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, 3); -make_instruction_mult!(vector_float, vector_float, _rotate, Vec, 3); -make_instruction_mult!(vector_string, vector_string, _rotate, Vec>, 3); -make_instruction_mult!(vector_boolean, vector_boolean, _rotate, Vec, 3); -make_instruction_mult!(vector_char, vector_char, _rotate, Vec, 3); -make_instruction_mult!(code, code, _rotate, Gene, 3); -make_instruction_mult!(exec, exec, _rotate, Gene, 3); /// Checks if two values are equal -pub fn _equal(vals: Vec) -> Option { - Some(vals[1] == vals[0]) +pub fn _equal(a: T, b: T) -> Option { + Some(b == a) } -make_instruction!(int, boolean, _equal, i128, 2); -make_instruction!(float, boolean, _equal, Decimal, 2); -make_instruction_clone!(string, boolean, _equal, Vec, 2); -make_instruction!(boolean, boolean, _equal, bool, 2); -make_instruction!(char, boolean, _equal, char, 2); -make_instruction_clone!(vector_int, boolean, _equal, Vec, 2); -make_instruction_clone!(vector_float, boolean, _equal, Vec, 2); -make_instruction_clone!(vector_string, boolean, _equal, Vec>, 2); -make_instruction_clone!(vector_boolean, boolean, _equal, Vec, 2); -make_instruction_clone!(vector_char, boolean, _equal, Vec, 2); -make_instruction_clone!(code, boolean, _equal, Gene, 2); -make_instruction_clone!(exec, boolean, _equal, Gene, 2); /// Checks if two values are not equal -pub fn _not_equal(vals: Vec) -> Option { - Some(vals[1] != vals[0]) +pub fn _not_equal(a: T, b: T) -> Option { + 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, 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, 2); -make_instruction_clone!(vector_float, boolean, _not_equal, Vec, 2); -make_instruction_clone!(vector_string, boolean, _not_equal, Vec>, 2); -make_instruction_clone!(vector_boolean, boolean, _not_equal, Vec, 2); -make_instruction_clone!(vector_char, boolean, _not_equal, Vec, 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 { ($in_stack:ident) => { 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 { ($in_stack:ident) => { 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 { - ($in_stack:ident, $in_type:expr) => { + ($in_stack:ident) => { paste::item! { pub fn [< $in_stack _yank >] (state: &mut PushState) { if state.int.is_empty() || state.$in_stack.is_empty() { return; } 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; } - // 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 item = state.$in_stack.remove(in_stack_len - idx); state.$in_stack.push(item); @@ -280,39 +141,45 @@ macro_rules! yank { } }; } -yank!(int, "i128"); -yank!(float, ""); -yank!(string, ""); -yank!(boolean, ""); -yank!(char, ""); -yank!(vector_int, ""); -yank!(vector_float, ""); -yank!(vector_string, ""); -yank!(vector_boolean, ""); -yank!(vector_char, ""); -yank!(code, ""); -yank!(exec, ""); + +macro_rules! make_common_instructions { + ($stack:ident) => { + pop!($stack); + make_code!($stack); + make_instruction_new_aux!(_dup, $stack, $stack, $stack); + make_instruction_new_aux!(_dup_times, $stack, $stack, int, $stack); + make_instruction_new_aux!(_swap, $stack, $stack, $stack, $stack); + make_instruction_new_aux!(_rotate, $stack, $stack, $stack, $stack, $stack); + make_instruction_new!(_equal, $stack, boolean, $stack, $stack); + flush_state!($stack); + 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)] mod tests { use super::*; 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] fn pop_test() { 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]; 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); } } diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index fd2ce21..f09221d 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -1,302 +1,5 @@ #[macro_use] 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*. `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 macro_rules! make_instruction_new { ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { diff --git a/src/push/state.rs b/src/push/state.rs index 1669d80..99117c7 100644 --- a/src/push/state.rs +++ b/src/push/state.rs @@ -99,7 +99,7 @@ impl Gene { _ => continue, } } - return None; + None } val => Some(val), }