diff --git a/rush_macro/src/utils/instruction.rs b/rush_macro/src/utils/instruction.rs index 4ce912f..4bae797 100644 --- a/rush_macro/src/utils/instruction.rs +++ b/rush_macro/src/utils/instruction.rs @@ -64,7 +64,6 @@ impl ToTokens for Extract { } } - // Ensure stacks have enough values let conditions = counts.iter().map(|(stack, count)| { let inner_stack = &stack.0; quote! { #inner_state.#inner_stack.len() >= #count } @@ -77,7 +76,7 @@ impl ToTokens for Extract { quote! { let #var_name = #inner_state.#inner_stack.pop().unwrap(); } }); - // Create slices of variable names for restoration + // Create slices of variable names for restoration and function call let value_vars = (0..stacks.len()) .map(|i| quote::format_ident!("val_{}", i)) .collect::>(); @@ -88,13 +87,12 @@ impl ToTokens for Extract { .zip(value_vars.iter().rev()) .map(|(stack, var)| { let inner_stack = &&stack.0; - quote! { #inner_state.#inner_stack.push(#var); } + quote! { #inner_state.#inner_stack.push(#var.clone()); } }); - // Run the function using auxiliary mode if needed let aux_run = match aux { true => quote! { - let result = #inner_func(#(#value_vars),*); + let result = #inner_func(#(#value_vars.clone()),*); if let Some(result) = result { #inner_state.#inner_out_stack.extend(result.iter()); } else { @@ -102,7 +100,7 @@ impl ToTokens for Extract { } }, false => quote! { - let result = #inner_func(#(#value_vars),*); + let result = #inner_func(#(#value_vars.clone()),*); if let Some(result) = result { #inner_state.#inner_out_stack.push(result); } else { diff --git a/src/instructions/code.rs b/src/instructions/code.rs index 24fe3c5..f5f6b31 100644 --- a/src/instructions/code.rs +++ b/src/instructions/code.rs @@ -5,32 +5,29 @@ use crate::push::state::{Gene, PushState}; use super::common::{code_from_exec, code_pop, int_pop}; /// Checks to see if a single gene is a block. -fn _is_block(vals: Vec) -> Option { - Some(match vals[0] { +fn _is_block(a: Gene) -> Option { + Some(match a { Gene::Block(_) => true, _ => false, }) } -make_instruction_clone!(code, boolean, _is_block, Gene, 1); /// Checks to see if a single gene is not a block. -fn _is_singular(vals: Vec) -> Option { - Some(_is_block(vals)?.not()) +fn _is_singular(a: Gene) -> Option { + Some(_is_block(a)?.not()) } -make_instruction_clone!(code, boolean, _is_singular, Gene, 1); /// Returns the length of a block, else 1 if not a block -fn _length(vals: Vec) -> Option { - Some(match &vals[0] { +fn _length(a: Gene) -> Option { + Some(match &a { Gene::Block(x) => x.len() as i128, _ => 1, }) } -make_instruction_clone!(code, int, _length, Gene, 1); /// Returns the first item in a block if doable, else None -fn _first(vals: Vec) -> Option { - match &vals[0] { +fn _first(a: Gene) -> Option { + match &a { Gene::Block(x) => { if x.len() > 1 { Some(x[0].clone()) @@ -41,11 +38,10 @@ fn _first(vals: Vec) -> Option { _ => None, } } -make_instruction_clone!(code, code, _first, Gene, 1); /// Returns the first item in a block if applicable, else None -fn _last(vals: Vec) -> Option { - match &vals[0] { +fn _last(a: Gene) -> Option { + match &a { Gene::Block(x) => { if x.len() > 1 { Some(x.last()?.clone()) @@ -56,11 +52,10 @@ fn _last(vals: Vec) -> Option { _ => None, } } -make_instruction_clone!(code, code, _last, Gene, 1); /// Returns all but the first code item in a block if applicable, else None -fn _rest(vals: Vec) -> Option { - match &vals[0] { +fn _rest(a: Gene) -> Option { + match &a { Gene::Block(x) => { if x.len() > 1 { Some(Gene::Block(x[1..].to_vec())) @@ -71,11 +66,10 @@ fn _rest(vals: Vec) -> Option { _ => None, } } -make_instruction_clone!(code, code, _rest, Gene, 1); /// Returns all but the first code item in a block if applicable, else None -fn _but_last(vals: Vec) -> Option { - match &vals[0] { +fn _but_last(a: Gene) -> Option { + match &a { Gene::Block(x) => { let x_len = x.len(); if x_len > 1 { @@ -87,19 +81,17 @@ fn _but_last(vals: Vec) -> Option { _ => None, } } -make_instruction_clone!(code, code, _but_last, Gene, 1); -/// Returns all the vals wrapped in a code block -fn _wrap_block(vals: Vec) -> Option { - Some(Gene::Block(vals)) +/// Returns a gene wrapped in a block +fn _wrap_block(a: Gene) -> Option { + Some(Gene::Block(vec![a])) } -make_instruction_clone!(code, code, _wrap_block, Gene, 1); /// Combines two genes into one. Accounts for blocks. /// If the second gene is a block and the first one isn't, /// appends the first gene to the second gene. -fn _combine(vals: Vec) -> Option { - match (&vals[0], &vals[1]) { +fn _combine(a: Gene, b: Gene) -> Option { + match (&a, &b) { (Gene::Block(x), Gene::Block(y)) => { let x_clone = x.clone(); let mut y_clone = y.clone(); @@ -119,7 +111,6 @@ fn _combine(vals: Vec) -> Option { (x, y) => Some(Gene::Block(vec![x.clone(), y.clone()])), } } -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. @@ -330,15 +321,9 @@ pub fn code_map(state: &mut PushState) { /// If top bool is true, execute top element of code/exec stack and skip the second. /// If false, execute second element and skip the top. -pub fn _if(vals: Vec, auxs: Vec) -> Option { - Some(if auxs[0] { - vals[0].clone() - } else { - vals[1].clone() - }) +pub fn _if(a: Gene, b: Gene, cond: bool) -> Option { + Some(if cond { a } else { b }) } -make_instruction_aux!(code, exec, _if, Gene, 2, boolean, 1, bool); -make_instruction_aux!(exec, exec, _if, Gene, 2, boolean, 1, bool); /// Evaluates the top code item if the top code is true, else pops it. pub fn code_when(state: &mut PushState) { @@ -450,7 +435,7 @@ pub fn _insert(vals: Vec, auxs: Vec) -> Option { val => Gene::Block(vec![val]), }; if block.rec_len() == 0 { - return _combine(vec![block, vals[1].clone()]); + return _combine(block, vals[1].clone()); } let ndx = auxs[0].abs() as usize % block.rec_len(); block.with_code_inserted_at_point(vals[1].clone(), ndx); @@ -498,6 +483,30 @@ pub fn _reverse(vals: Vec) -> Option { } make_instruction_clone!(code, code, _reverse, Gene, 1); +macro_rules! make_code_instructions { + ($stack:ident) => { + make_instruction_new!(_is_block, $stack, boolean, $stack); + make_instruction_new!(_is_singular, $stack, boolean, $stack); + make_instruction_new!(_length, $stack, int, $stack); + make_instruction_new!(_first, $stack, $stack, $stack); + make_instruction_new!(_last, $stack, $stack, $stack); + make_instruction_new!(_rest, $stack, $stack, $stack); + make_instruction_new!(_but_last, $stack, $stack, $stack); + make_instruction_new!(_wrap_block, $stack, $stack, $stack); + make_instruction_new!(_combine, $stack, $stack, $stack, $stack); + //make_instruction_new!(_if, $stack, $stack, $stack, $stack, boolean); + }; +} + +macro_rules! all_code_instructions { + () => { + make_code_instructions!(code); + make_code_instructions!(exec); + }; +} +all_code_instructions!(); +make_instruction_new!(_if, code, code, code, code, boolean); + #[cfg(test)] mod tests { use super::*; @@ -883,7 +892,7 @@ mod tests { let mut test_state = EMPTY_STATE; // Code tests - test_state.code = vec![Gene::GeneInt(0), Gene::GeneInt(1)]; + /*test_state.code = vec![Gene::GeneInt(0), Gene::GeneInt(1)]; test_state.boolean = vec![true]; code_if(&mut test_state); assert_eq!(vec![Gene::GeneInt(1)], test_state.exec); @@ -906,7 +915,7 @@ mod tests { test_state.boolean = vec![false]; exec_if(&mut test_state); assert_eq!(vec![Gene::GeneInt(0)], test_state.exec); - test_state.exec.clear(); + test_state.exec.clear();*/ } #[test] diff --git a/tests/instruction_test.rs b/tests/instruction_test.rs index 86bdca9..901c64a 100644 --- a/tests/instruction_test.rs +++ b/tests/instruction_test.rs @@ -9,6 +9,10 @@ fn aux_iadd(x: i128, y: i128) -> Option> { Some(vec![x + y, x - y]) } +fn two_stacks(x: i128, y: i128, cond: bool) -> Option { + if cond { Some(x + y) } else { Some(x - y) } +} + #[test] fn run_extract_test() { let mut test_state = EMPTY_STATE; @@ -26,4 +30,8 @@ fn run_extract_test() { test_state.int = vec![1, 2]; run_instruction!(aux_iadd, int, test_state, int, int;); assert_eq!(vec![3, 1], test_state.int); + + test_state.int = vec![1, 2]; + test_state.boolean = vec![true]; + run_instruction!(two_stacks, int, test_state, int, int, boolean); }