From 69fb0bef4e1eb6b249a7c199ee32989cf5e6f802 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Wed, 16 Apr 2025 21:32:34 -0500 Subject: [PATCH 01/21] progress on using basic macro_rules! --- src/instructions/common.rs | 2 +- src/instructions/mod.rs | 83 +++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/instructions/common.rs b/src/instructions/common.rs index 9fbbee6..577ee4d 100644 --- a/src/instructions/common.rs +++ b/src/instructions/common.rs @@ -423,6 +423,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 1edf472..37a34af 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -224,7 +224,7 @@ pub mod macros { aux_inputs.push(state.$aux_stack[aux_stack_len - n].clone()); } for n in 1..=$fn_arity { - if std::any::type_name::<$fn_type>() == std::any::type_name::<$aux_type>() { + 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()); @@ -265,9 +265,7 @@ pub mod macros { if in_stack_len < $fn_arity || aux0_stack_len < $aux0_arity || aux1_stack_len < $aux1_arity { return; } - // This is crazy jank, not meant for use in actual code :) - // https://doc.rust-lang.org/std/any/fn.type_name.html - if std::any::type_name::<$aux0_type>() == std::any::type_name::<$aux1_type>() { + if stringify!($aux0_type) == stringify!($aux1_type) { if aux0_stack_len + aux1_stack_len < $aux0_arity + $aux1_arity { return; } @@ -279,7 +277,7 @@ pub mod macros { aux1_inputs.push(state.$aux1_stack[aux1_stack_len - n].clone()); } for n in 1..=$aux0_arity { - if std::any::type_name::<$aux0_type>() == std::any::type_name::<$aux1_type>() { + 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()); @@ -305,6 +303,38 @@ pub mod macros { } }; } + + /// Runs a function and ensures needed variables are extracted from a state without error + macro_rules! make_instruction_new { + ($prefix:ident, $func:ident, $($stacks:ident), *) => { + paste::item! { + pub fn [< $prefix $func >] (state: &mut PushState) { + run_func!($func, extract_state_vals!(state, $($stacks), *)) + } + } + }; + } + + /// Extracts values from passed state based on an amount of stacks passed. + macro_rules! extract_state_vals { + ($state:ident) => {}; + ($state:ident, $stack:ident) => { + $state.$stack.pop().unwrap() + }; + ($state:ident, $stack:ident, $($rest:ident), *) => { + ($state.$stack.pop().unwrap(), $(extract_state_vals!($state, $rest)), *) + }; + } + + /// Runs a given function passed in the first argument with all the sequential arguments + /// in order. + macro_rules! run_func { + () => {}; + ($func:ident, $($args:expr), *) => { + $func($($args), *) + }; + ($($args:expr), *) => { $args, run_func!(*) }; + } } pub mod code; @@ -751,3 +781,46 @@ pub fn code_instructions() -> Vec { code_from_exec, ] } + +#[cfg(test)] +mod tests { + use super::*; + use crate::push::state::EMPTY_STATE; + + #[test] + fn run_func_test() { + pub fn uadd(x: usize, y: usize, z: usize) -> usize { + x + y + z + } + + pub fn make_instruction_expr_test() -> usize { + run_func!(uadd, 1, 2, 3) + } + + let res = make_instruction_expr_test(); + assert_eq!(res, 6); + } + + #[test] + fn extract_state_vals_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![0, 1]; + test_state.boolean = vec![true]; + + let res = extract_state_vals!(test_state, int, int, boolean); + assert_eq!((1, 0, true), res); + } + + #[test] + fn make_instruction_new_test() { + fn _test_func(x: i128, y: i128) -> i128 { + x + y + } + + let mut test_state = EMPTY_STATE; + + test_state.int = vec![0, 1]; + let test_instr = make_instruction_new!(int, _test_func, int, int); + } +} From c8fe24dd45c27ebe60fa597cab72b2046c0be36c Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Wed, 16 Apr 2025 21:44:05 -0500 Subject: [PATCH 02/21] so it truly runs --- src/instructions/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 37a34af..8424843 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -821,6 +821,6 @@ mod tests { let mut test_state = EMPTY_STATE; test_state.int = vec![0, 1]; - let test_instr = make_instruction_new!(int, _test_func, int, int); + //let test_instr = make_instruction_new!(int, _test_func, int, int); } } From c66d35b9806607feaa694aaae5f6c8a236d9af94 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Wed, 16 Apr 2025 21:57:33 -0500 Subject: [PATCH 03/21] I truly want proc macros this time --- rush_macro/Cargo.toml | 9 +++++++++ rush_macro/src/lib.rs | 14 ++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 rush_macro/Cargo.toml create mode 100644 rush_macro/src/lib.rs diff --git a/rush_macro/Cargo.toml b/rush_macro/Cargo.toml new file mode 100644 index 0000000..a3fc13a --- /dev/null +++ b/rush_macro/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rush_macro" +version = "0.1.0" +edition = "2024" + +[dependencies] +syn = { version = "2.0.100" } +quote = { version = "1.0.40" } +proc_macro2 = { version = "1.0.95" } diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/rush_macro/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From d697e14173737b6d61dabd0f7ac6d2f236acba0e Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Thu, 17 Apr 2025 01:26:05 -0500 Subject: [PATCH 04/21] Incomplete, will change all this code later --- Cargo.toml | 1 + rush_macro/Cargo.toml | 7 ++- rush_macro/src/lib.rs | 15 ++++-- rush_macro/src/utils/extractstate.rs | 68 ++++++++++++++++++++++++++++ rush_macro/src/utils/mod.rs | 12 +++++ rush_macro/src/utils/varfunc.rs | 62 +++++++++++++++++++++++++ rush_macro/tests/var_func_test.rs | 11 +++++ src/instructions/mod.rs | 4 +- 8 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 rush_macro/src/utils/extractstate.rs create mode 100644 rush_macro/src/utils/mod.rs create mode 100644 rush_macro/src/utils/varfunc.rs create mode 100644 rush_macro/tests/var_func_test.rs diff --git a/Cargo.toml b/Cargo.toml index f6daca5..1793912 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" rand = "0.9.0" paste = "1.0.15" rust_decimal = { version = "1.37", features = ["macros", "maths"] } +rush_macro = { path = "rush_macro" } \ No newline at end of file diff --git a/rush_macro/Cargo.toml b/rush_macro/Cargo.toml index a3fc13a..e262311 100644 --- a/rush_macro/Cargo.toml +++ b/rush_macro/Cargo.toml @@ -3,7 +3,10 @@ name = "rush_macro" version = "0.1.0" edition = "2024" +[lib] +proc-macro = true + [dependencies] -syn = { version = "2.0.100" } +syn = { version = "2.0.100", features = ["full"] } quote = { version = "1.0.40" } -proc_macro2 = { version = "1.0.95" } +proc-macro2 = { version = "1.0.95" } diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index b93cf3f..97d8977 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,5 +1,13 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +use crate::utils::varfunc::VarFunc; +use quote::quote; +use syn::parse_macro_input; + +mod utils; + +#[proc_macro] +pub fn run_func(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let f = parse_macro_input!(input as VarFunc); + quote! { #f }.into() } #[cfg(test)] @@ -8,7 +16,6 @@ mod tests { #[test] fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + assert!(true); } } diff --git a/rush_macro/src/utils/extractstate.rs b/rush_macro/src/utils/extractstate.rs new file mode 100644 index 0000000..73f4c20 --- /dev/null +++ b/rush_macro/src/utils/extractstate.rs @@ -0,0 +1,68 @@ +// Extract: State (`,` Stack `:` Amount)* +// +// State: identifier +// +// Stack: identifier +// +// Amount: expression + +use crate::utils::parse_zero_or_more; +use proc_macro2::TokenStream as TokenStream2; +use quote::{ToTokens, quote}; +use std::cmp::PartialEq; +use syn::parse::{Parse, ParseStream}; + +struct Extract { + state: State, + stacks: Vec, +} + +impl Parse for Extract { + fn parse(input: ParseStream) -> syn::Result { + let state = input.parse()?; + let stacks = parse_zero_or_more(input); + Ok(Extract { state, stacks }) + } +} + +impl ToTokens for Extract { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let state = &self.state; + let stacks = &self.stacks; + } +} + +struct State(syn::Ident); + +impl Parse for State { + fn parse(input: ParseStream) -> syn::Result { + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for State { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} + +struct Stack(syn::Ident); + +impl Parse for Stack { + fn parse(input: ParseStream) -> syn::Result { + _ = input.parse::(); + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for Stack { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} + +impl PartialEq for &Stack { + fn eq(&self, other: &Stack) -> bool { + self.0 == other.0 + } +} diff --git a/rush_macro/src/utils/mod.rs b/rush_macro/src/utils/mod.rs new file mode 100644 index 0000000..0d38e16 --- /dev/null +++ b/rush_macro/src/utils/mod.rs @@ -0,0 +1,12 @@ +use syn::parse::{Parse, ParseStream}; + +pub mod extractstate; +pub mod varfunc; + +fn parse_zero_or_more(input: ParseStream) -> Vec { + let mut result = Vec::new(); + while let Ok(item) = input.parse() { + result.push(item); + } + result +} diff --git a/rush_macro/src/utils/varfunc.rs b/rush_macro/src/utils/varfunc.rs new file mode 100644 index 0000000..3812b70 --- /dev/null +++ b/rush_macro/src/utils/varfunc.rs @@ -0,0 +1,62 @@ +// Run: Function Argument* +// +// Function: identifier +// +// Argument: (, expression) + +use crate::utils::parse_zero_or_more; +use proc_macro2::TokenStream as TokenStream2; +use quote::{ToTokens, quote}; +use syn::parse::{Parse, ParseStream}; + +pub struct VarFunc { + func: Function, + args: Vec, +} + +impl Parse for VarFunc { + fn parse(input: ParseStream) -> syn::Result { + let func = input.parse()?; + let args = parse_zero_or_more(input); + Ok(Self { func, args }) + } +} + +impl ToTokens for VarFunc { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let function = &self.func; + let args = &self.args; + tokens.extend(quote! { + #function(#(#args),*) + }) + } +} + +struct Function(syn::Ident); + +impl Parse for Function { + fn parse(input: ParseStream) -> syn::Result { + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for Function { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} + +struct Argument(syn::Expr); + +impl Parse for Argument { + fn parse(input: ParseStream) -> syn::Result { + _ = input.parse::()?; + syn::Expr::parse(input).map(Self) + } +} + +impl ToTokens for Argument { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} diff --git a/rush_macro/tests/var_func_test.rs b/rush_macro/tests/var_func_test.rs new file mode 100644 index 0000000..daaf598 --- /dev/null +++ b/rush_macro/tests/var_func_test.rs @@ -0,0 +1,11 @@ +use rush_macro::run_func; + +fn uadd(x: usize, y: usize, z: usize) -> usize { + x + y + z +} + +#[test] +fn run_func_test() { + let res = run_func!(uadd, 1, 4, 2); + assert_eq!(res, 7); +} diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 8424843..73fbba2 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -328,7 +328,7 @@ pub mod macros { /// Runs a given function passed in the first argument with all the sequential arguments /// in order. - macro_rules! run_func { + macro_rules! run_func_old { () => {}; ($func:ident, $($args:expr), *) => { $func($($args), *) @@ -794,7 +794,7 @@ mod tests { } pub fn make_instruction_expr_test() -> usize { - run_func!(uadd, 1, 2, 3) + run_func_old!(uadd, 1, 2, 3) } let res = make_instruction_expr_test(); From 38f94e4e8e993eacafe51b27f9963394a6169dfe Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Thu, 17 Apr 2025 15:52:10 -0500 Subject: [PATCH 05/21] need to test extractstate --- rush_macro/src/lib.rs | 7 +++++++ rush_macro/src/utils/extractstate.rs | 19 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 97d8977..54bb978 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,4 +1,5 @@ use crate::utils::varfunc::VarFunc; +use crate::utils::extractstate::Extract; use quote::quote; use syn::parse_macro_input; @@ -10,6 +11,12 @@ pub fn run_func(input: proc_macro::TokenStream) -> proc_macro::TokenStream { quote! { #f }.into() } +#[proc_macro] +pub fn run_extract(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let f = parse_macro_input!(input as Extract); + quote! { #f }.into() +} + #[cfg(test)] mod tests { use super::*; diff --git a/rush_macro/src/utils/extractstate.rs b/rush_macro/src/utils/extractstate.rs index 73f4c20..4648a27 100644 --- a/rush_macro/src/utils/extractstate.rs +++ b/rush_macro/src/utils/extractstate.rs @@ -12,7 +12,7 @@ use quote::{ToTokens, quote}; use std::cmp::PartialEq; use syn::parse::{Parse, ParseStream}; -struct Extract { +pub struct Extract { state: State, stacks: Vec, } @@ -27,8 +27,23 @@ impl Parse for Extract { impl ToTokens for Extract { fn to_tokens(&self, tokens: &mut TokenStream2) { - let state = &self.state; + let inner_state = &self.state.0; let stacks = &self.stacks; + + let mut counts = Vec::new(); + for stack in stacks { + match counts.iter_mut().find(|(x, _)| x == stack) { + Some((_, count)) => *count += 1, + None => counts.push((stack, 1)), + } + } + + for (stack, count) in counts { + let inner_stack = &stack.0; + tokens.extend(quote! { + #inner_state.#inner_stack < #count + }) + } } } From 41e2d94e1cc55c20c6fd3032300cc8afa65a59c1 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Thu, 17 Apr 2025 15:52:26 -0500 Subject: [PATCH 06/21] need to test extractstate --- rush_macro/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 54bb978..ab413a9 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,5 +1,5 @@ -use crate::utils::varfunc::VarFunc; use crate::utils::extractstate::Extract; +use crate::utils::varfunc::VarFunc; use quote::quote; use syn::parse_macro_input; @@ -19,8 +19,6 @@ pub fn run_extract(input: proc_macro::TokenStream) -> proc_macro::TokenStream { #[cfg(test)] mod tests { - use super::*; - #[test] fn it_works() { assert!(true); From cb2e61e8d36318744a7a13a7bc416591888808f7 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Thu, 17 Apr 2025 22:18:23 -0500 Subject: [PATCH 07/21] status update --- rush_macro/src/lib.rs | 16 ++++- rush_macro/src/utils/canextractstate.rs | 85 +++++++++++++++++++++++++ rush_macro/src/utils/extractidents.rs | 65 +++++++++++++++++++ rush_macro/src/utils/extractstate.rs | 79 +---------------------- rush_macro/src/utils/mod.rs | 4 +- rush_macro/tests/extractidents_test.rs | 8 +++ src/instructions/mod.rs | 31 ++------- src/lib.rs | 3 +- src/main.rs | 6 ++ tests/extractstate_test.rs | 15 +++++ 10 files changed, 205 insertions(+), 107 deletions(-) create mode 100644 rush_macro/src/utils/canextractstate.rs create mode 100644 rush_macro/src/utils/extractidents.rs create mode 100644 rush_macro/tests/extractidents_test.rs create mode 100644 tests/extractstate_test.rs diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index ab413a9..8ae668b 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,22 +1,34 @@ -use crate::utils::extractstate::Extract; +use crate::utils::canextractstate::Extract; +use crate::utils::extractidents::ExtractIdents; use crate::utils::varfunc::VarFunc; use quote::quote; use syn::parse_macro_input; mod utils; +/// Runs a function passed as the first argument with a variable amount of functions +/// passed to it afterward. #[proc_macro] pub fn run_func(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as VarFunc); quote! { #f }.into() } +/// Checks to see if extracting values from a state is possible. #[proc_macro] -pub fn run_extract(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn run_canextract(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as Extract); quote! { #f }.into() } +/// Returns the arguments to this proc macro in a usable way to other +/// functions. Check the utils file for a more in depth explanation. +#[proc_macro] +pub fn run_extractidents(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let f = parse_macro_input!(input as ExtractIdents); + quote! { #f }.into() +} + #[cfg(test)] mod tests { #[test] diff --git a/rush_macro/src/utils/canextractstate.rs b/rush_macro/src/utils/canextractstate.rs new file mode 100644 index 0000000..c0b4e80 --- /dev/null +++ b/rush_macro/src/utils/canextractstate.rs @@ -0,0 +1,85 @@ +// Extract: State (`,` Stack `:` Amount)* +// +// State: identifier +// +// Stack: identifier +// +// Amount: expression + +use crate::utils::parse_zero_or_more; +use proc_macro2::TokenStream as TokenStream2; +use quote::{ToTokens, quote}; +use std::cmp::PartialEq; +use syn::parse::{Parse, ParseStream}; + +pub struct Extract { + state: State, + stacks: Vec, +} + +impl Parse for Extract { + fn parse(input: ParseStream) -> syn::Result { + let state = input.parse()?; + let stacks = parse_zero_or_more(input); + Ok(Extract { state, stacks }) + } +} + +impl ToTokens for Extract { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let inner_state = &self.state.0; + let stacks = &self.stacks; + + let mut counts = Vec::new(); + for stack in stacks { + match counts.iter_mut().find(|(x, _)| x == stack) { + Some((_, count)) => *count += 1, + None => counts.push((stack, 1usize)), + } + } + + let conditions = counts.iter().map(|(stack, count)| { + let inner_stack = &stack.0; + quote! { #inner_state.#inner_stack.len() >= #count } + }); + + tokens.extend(quote! { + true #(&& (#conditions))* + }); + } +} + +struct State(syn::Ident); + +impl Parse for State { + fn parse(input: ParseStream) -> syn::Result { + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for State { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} + +struct Stack(syn::Ident); + +impl Parse for Stack { + fn parse(input: ParseStream) -> syn::Result { + _ = input.parse::(); + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for Stack { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} + +impl PartialEq for &Stack { + fn eq(&self, other: &Stack) -> bool { + self.0 == other.0 + } +} diff --git a/rush_macro/src/utils/extractidents.rs b/rush_macro/src/utils/extractidents.rs new file mode 100644 index 0000000..0027e95 --- /dev/null +++ b/rush_macro/src/utils/extractidents.rs @@ -0,0 +1,65 @@ +//! Extracts identifiers from a passed list of them. +//! +//! IdentExtract: identifier CommaIdentifier* +//! +//! CommaIdentifier: (, identifier) +//! +//! For Example: +//! run_extract_idents!(int, int, int) would return (literally): +//! `int, int, int` to rust + +use crate::utils::parse_zero_or_more; +use proc_macro2::TokenStream as TokenStream2; +use quote::{ToTokens, quote}; +use std::io::stdout; +use syn::parse::{Parse, ParseStream}; + +pub struct ExtractIdents { + ident: syn::Ident, + comma_idents: Vec, +} + +impl Parse for ExtractIdents { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse()?; + let comma_idents = parse_zero_or_more(input); + Ok(Self { + ident, + comma_idents, + }) + } +} + +impl ToTokens for ExtractIdents { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let first_ident = &self.ident; + let comma_idents = &self.comma_idents; + + /*tokens.extend(quote! { #first_ident }); + for id in comma_idents { + let syn_id = &id.0; + tokens.(syn_id); + }*/ + + let output = quote! { + #first_ident #(, #comma_idents)* + }; + + tokens.extend(output); + } +} + +pub struct CommaIdentifiers(syn::Ident); + +impl Parse for CommaIdentifiers { + fn parse(input: ParseStream) -> syn::Result { + _ = input.parse::()?; + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for CommaIdentifiers { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} diff --git a/rush_macro/src/utils/extractstate.rs b/rush_macro/src/utils/extractstate.rs index 4648a27..3b25241 100644 --- a/rush_macro/src/utils/extractstate.rs +++ b/rush_macro/src/utils/extractstate.rs @@ -1,83 +1,8 @@ -// Extract: State (`,` Stack `:` Amount)* -// -// State: identifier -// -// Stack: identifier -// -// Amount: expression +// The parsing will be same for canextractstate.rs but +// instead of chaining trues at the end, will just chain the values. use crate::utils::parse_zero_or_more; use proc_macro2::TokenStream as TokenStream2; use quote::{ToTokens, quote}; use std::cmp::PartialEq; use syn::parse::{Parse, ParseStream}; - -pub struct Extract { - state: State, - stacks: Vec, -} - -impl Parse for Extract { - fn parse(input: ParseStream) -> syn::Result { - let state = input.parse()?; - let stacks = parse_zero_or_more(input); - Ok(Extract { state, stacks }) - } -} - -impl ToTokens for Extract { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let inner_state = &self.state.0; - let stacks = &self.stacks; - - let mut counts = Vec::new(); - for stack in stacks { - match counts.iter_mut().find(|(x, _)| x == stack) { - Some((_, count)) => *count += 1, - None => counts.push((stack, 1)), - } - } - - for (stack, count) in counts { - let inner_stack = &stack.0; - tokens.extend(quote! { - #inner_state.#inner_stack < #count - }) - } - } -} - -struct State(syn::Ident); - -impl Parse for State { - fn parse(input: ParseStream) -> syn::Result { - syn::Ident::parse(input).map(Self) - } -} - -impl ToTokens for State { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.0.to_tokens(tokens) - } -} - -struct Stack(syn::Ident); - -impl Parse for Stack { - fn parse(input: ParseStream) -> syn::Result { - _ = input.parse::(); - syn::Ident::parse(input).map(Self) - } -} - -impl ToTokens for Stack { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.0.to_tokens(tokens) - } -} - -impl PartialEq for &Stack { - fn eq(&self, other: &Stack) -> bool { - self.0 == other.0 - } -} diff --git a/rush_macro/src/utils/mod.rs b/rush_macro/src/utils/mod.rs index 0d38e16..0725128 100644 --- a/rush_macro/src/utils/mod.rs +++ b/rush_macro/src/utils/mod.rs @@ -1,6 +1,8 @@ use syn::parse::{Parse, ParseStream}; -pub mod extractstate; +pub mod canextractstate; +pub mod extractidents; +mod extractstate; pub mod varfunc; fn parse_zero_or_more(input: ParseStream) -> Vec { diff --git a/rush_macro/tests/extractidents_test.rs b/rush_macro/tests/extractidents_test.rs new file mode 100644 index 0000000..94a4b15 --- /dev/null +++ b/rush_macro/tests/extractidents_test.rs @@ -0,0 +1,8 @@ +use rush_macro::run_extractidents; + +#[test] +fn extractidents_test() { + assert!(true); + + // I'm not sure how to test this tbh. +} diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 73fbba2..ec6d49e 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -4,6 +4,7 @@ use crate::instructions::logical::*; use crate::instructions::numeric::*; use crate::instructions::vector::*; use crate::push::state::PushState; +use rush_macro::{run_canextract, run_extractidents, run_func}; #[macro_use] pub mod macros { @@ -309,7 +310,9 @@ pub mod macros { ($prefix:ident, $func:ident, $($stacks:ident), *) => { paste::item! { pub fn [< $prefix $func >] (state: &mut PushState) { - run_func!($func, extract_state_vals!(state, $($stacks), *)) + if run_canextract!(state, run_extractidents!($($stacks), *)) { + $func extract_state_vals!(state, $($stacks), *) + } } } }; @@ -325,16 +328,6 @@ pub mod macros { ($state.$stack.pop().unwrap(), $(extract_state_vals!($state, $rest)), *) }; } - - /// Runs a given function passed in the first argument with all the sequential arguments - /// in order. - macro_rules! run_func_old { - () => {}; - ($func:ident, $($args:expr), *) => { - $func($($args), *) - }; - ($($args:expr), *) => { $args, run_func!(*) }; - } } pub mod code; @@ -787,20 +780,6 @@ mod tests { use super::*; use crate::push::state::EMPTY_STATE; - #[test] - fn run_func_test() { - pub fn uadd(x: usize, y: usize, z: usize) -> usize { - x + y + z - } - - pub fn make_instruction_expr_test() -> usize { - run_func_old!(uadd, 1, 2, 3) - } - - let res = make_instruction_expr_test(); - assert_eq!(res, 6); - } - #[test] fn extract_state_vals_test() { let mut test_state = EMPTY_STATE; @@ -821,6 +800,6 @@ mod tests { let mut test_state = EMPTY_STATE; test_state.int = vec![0, 1]; - //let test_instr = make_instruction_new!(int, _test_func, int, int); + let test_instr = make_instruction_new!(int, _test_func, int, int); } } diff --git a/src/lib.rs b/src/lib.rs index 8b13789..15e8271 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ - +pub mod instructions; +pub mod push; diff --git a/src/main.rs b/src/main.rs index c9c20e8..07d5c9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,4 +21,10 @@ fn main() { code_instructions(); let mut empty_state = EMPTY_STATE; interpret_program(&mut empty_state, 1000, 1000); + + let mut counts: Vec<(&str, usize)> = vec![]; + counts.push(("int", 2)); + counts.push(("float", 1)); + + // counts.iter().map() } diff --git a/tests/extractstate_test.rs b/tests/extractstate_test.rs new file mode 100644 index 0000000..838f284 --- /dev/null +++ b/tests/extractstate_test.rs @@ -0,0 +1,15 @@ +use rush::push::state::EMPTY_STATE; +use rush_macro::run_canextract; + +#[test] +fn run_extract_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![1, 2]; + let res = run_canextract!(test_state, int, int, float); + assert_eq!(false, res); + + test_state.int = vec![1, 2]; + let res = run_canextract!(test_state, int, int); + assert_eq!(true, res); +} From 6744896494d281a65efcef4a07db8164b45e1f0c Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 00:10:17 -0500 Subject: [PATCH 08/21] run instruction works, time to refactor rush now --- rush_macro/src/lib.rs | 20 +------- rush_macro/src/utils/canextractstate.rs | 45 +++++++++++++++-- rush_macro/src/utils/extractidents.rs | 65 ------------------------- rush_macro/src/utils/extractstate.rs | 8 --- rush_macro/src/utils/mod.rs | 3 -- rush_macro/src/utils/varfunc.rs | 62 ----------------------- rush_macro/tests/extractidents_test.rs | 8 --- rush_macro/tests/var_func_test.rs | 11 ----- src/instructions/mod.rs | 14 +++--- tests/extractstate_test.rs | 16 +++--- 10 files changed, 58 insertions(+), 194 deletions(-) delete mode 100644 rush_macro/src/utils/extractidents.rs delete mode 100644 rush_macro/src/utils/extractstate.rs delete mode 100644 rush_macro/src/utils/varfunc.rs delete mode 100644 rush_macro/tests/extractidents_test.rs delete mode 100644 rush_macro/tests/var_func_test.rs diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 8ae668b..84e49a3 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,34 +1,16 @@ use crate::utils::canextractstate::Extract; -use crate::utils::extractidents::ExtractIdents; -use crate::utils::varfunc::VarFunc; use quote::quote; use syn::parse_macro_input; mod utils; -/// Runs a function passed as the first argument with a variable amount of functions -/// passed to it afterward. -#[proc_macro] -pub fn run_func(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let f = parse_macro_input!(input as VarFunc); - quote! { #f }.into() -} - /// Checks to see if extracting values from a state is possible. #[proc_macro] -pub fn run_canextract(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn run_instruction(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as Extract); quote! { #f }.into() } -/// Returns the arguments to this proc macro in a usable way to other -/// functions. Check the utils file for a more in depth explanation. -#[proc_macro] -pub fn run_extractidents(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let f = parse_macro_input!(input as ExtractIdents); - quote! { #f }.into() -} - #[cfg(test)] mod tests { #[test] diff --git a/rush_macro/src/utils/canextractstate.rs b/rush_macro/src/utils/canextractstate.rs index c0b4e80..8a4ac62 100644 --- a/rush_macro/src/utils/canextractstate.rs +++ b/rush_macro/src/utils/canextractstate.rs @@ -1,10 +1,11 @@ -// Extract: State (`,` Stack `:` Amount)* +// This Stack that isn't repeated is the desired output stack. +// Extract: Function, Stack, State, (`,` Stack)* +// +// Function: identifier // // State: identifier // // Stack: identifier -// -// Amount: expression use crate::utils::parse_zero_or_more; use proc_macro2::TokenStream as TokenStream2; @@ -13,20 +14,31 @@ use std::cmp::PartialEq; use syn::parse::{Parse, ParseStream}; pub struct Extract { + func: Function, + out_stack: Stack, state: State, stacks: Vec, } impl Parse for Extract { fn parse(input: ParseStream) -> syn::Result { + let func = input.parse()?; + let out_stack = input.parse()?; let state = input.parse()?; let stacks = parse_zero_or_more(input); - Ok(Extract { state, stacks }) + Ok(Extract { + func, + out_stack, + state, + stacks, + }) } } impl ToTokens for Extract { fn to_tokens(&self, tokens: &mut TokenStream2) { + let inner_func = &self.func; + let inner_out_stack = &self.out_stack.0; let inner_state = &self.state.0; let stacks = &self.stacks; @@ -43,8 +55,16 @@ impl ToTokens for Extract { quote! { #inner_state.#inner_stack.len() >= #count } }); + let values = stacks.iter().map(|stack| { + let inner_stack = &&stack.0; + quote! { #inner_state.#inner_stack.pop().unwrap() } + }); + tokens.extend(quote! { - true #(&& (#conditions))* + if true #(&& (#conditions))* { + let result = vec![#inner_func(#(#values, )*)]; + #inner_state.#inner_out_stack.extend(result.iter()); + } }); } } @@ -53,6 +73,7 @@ struct State(syn::Ident); impl Parse for State { fn parse(input: ParseStream) -> syn::Result { + _ = input.parse::(); syn::Ident::parse(input).map(Self) } } @@ -83,3 +104,17 @@ impl PartialEq for &Stack { self.0 == other.0 } } + +struct Function(syn::Ident); + +impl Parse for Function { + fn parse(input: ParseStream) -> syn::Result { + syn::Ident::parse(input).map(Self) + } +} + +impl ToTokens for Function { + fn to_tokens(&self, tokens: &mut TokenStream2) { + self.0.to_tokens(tokens) + } +} diff --git a/rush_macro/src/utils/extractidents.rs b/rush_macro/src/utils/extractidents.rs deleted file mode 100644 index 0027e95..0000000 --- a/rush_macro/src/utils/extractidents.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Extracts identifiers from a passed list of them. -//! -//! IdentExtract: identifier CommaIdentifier* -//! -//! CommaIdentifier: (, identifier) -//! -//! For Example: -//! run_extract_idents!(int, int, int) would return (literally): -//! `int, int, int` to rust - -use crate::utils::parse_zero_or_more; -use proc_macro2::TokenStream as TokenStream2; -use quote::{ToTokens, quote}; -use std::io::stdout; -use syn::parse::{Parse, ParseStream}; - -pub struct ExtractIdents { - ident: syn::Ident, - comma_idents: Vec, -} - -impl Parse for ExtractIdents { - fn parse(input: ParseStream) -> syn::Result { - let ident = input.parse()?; - let comma_idents = parse_zero_or_more(input); - Ok(Self { - ident, - comma_idents, - }) - } -} - -impl ToTokens for ExtractIdents { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let first_ident = &self.ident; - let comma_idents = &self.comma_idents; - - /*tokens.extend(quote! { #first_ident }); - for id in comma_idents { - let syn_id = &id.0; - tokens.(syn_id); - }*/ - - let output = quote! { - #first_ident #(, #comma_idents)* - }; - - tokens.extend(output); - } -} - -pub struct CommaIdentifiers(syn::Ident); - -impl Parse for CommaIdentifiers { - fn parse(input: ParseStream) -> syn::Result { - _ = input.parse::()?; - syn::Ident::parse(input).map(Self) - } -} - -impl ToTokens for CommaIdentifiers { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.0.to_tokens(tokens) - } -} diff --git a/rush_macro/src/utils/extractstate.rs b/rush_macro/src/utils/extractstate.rs deleted file mode 100644 index 3b25241..0000000 --- a/rush_macro/src/utils/extractstate.rs +++ /dev/null @@ -1,8 +0,0 @@ -// The parsing will be same for canextractstate.rs but -// instead of chaining trues at the end, will just chain the values. - -use crate::utils::parse_zero_or_more; -use proc_macro2::TokenStream as TokenStream2; -use quote::{ToTokens, quote}; -use std::cmp::PartialEq; -use syn::parse::{Parse, ParseStream}; diff --git a/rush_macro/src/utils/mod.rs b/rush_macro/src/utils/mod.rs index 0725128..c963bb0 100644 --- a/rush_macro/src/utils/mod.rs +++ b/rush_macro/src/utils/mod.rs @@ -1,9 +1,6 @@ use syn::parse::{Parse, ParseStream}; pub mod canextractstate; -pub mod extractidents; -mod extractstate; -pub mod varfunc; fn parse_zero_or_more(input: ParseStream) -> Vec { let mut result = Vec::new(); diff --git a/rush_macro/src/utils/varfunc.rs b/rush_macro/src/utils/varfunc.rs deleted file mode 100644 index 3812b70..0000000 --- a/rush_macro/src/utils/varfunc.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Run: Function Argument* -// -// Function: identifier -// -// Argument: (, expression) - -use crate::utils::parse_zero_or_more; -use proc_macro2::TokenStream as TokenStream2; -use quote::{ToTokens, quote}; -use syn::parse::{Parse, ParseStream}; - -pub struct VarFunc { - func: Function, - args: Vec, -} - -impl Parse for VarFunc { - fn parse(input: ParseStream) -> syn::Result { - let func = input.parse()?; - let args = parse_zero_or_more(input); - Ok(Self { func, args }) - } -} - -impl ToTokens for VarFunc { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let function = &self.func; - let args = &self.args; - tokens.extend(quote! { - #function(#(#args),*) - }) - } -} - -struct Function(syn::Ident); - -impl Parse for Function { - fn parse(input: ParseStream) -> syn::Result { - syn::Ident::parse(input).map(Self) - } -} - -impl ToTokens for Function { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.0.to_tokens(tokens) - } -} - -struct Argument(syn::Expr); - -impl Parse for Argument { - fn parse(input: ParseStream) -> syn::Result { - _ = input.parse::()?; - syn::Expr::parse(input).map(Self) - } -} - -impl ToTokens for Argument { - fn to_tokens(&self, tokens: &mut TokenStream2) { - self.0.to_tokens(tokens) - } -} diff --git a/rush_macro/tests/extractidents_test.rs b/rush_macro/tests/extractidents_test.rs deleted file mode 100644 index 94a4b15..0000000 --- a/rush_macro/tests/extractidents_test.rs +++ /dev/null @@ -1,8 +0,0 @@ -use rush_macro::run_extractidents; - -#[test] -fn extractidents_test() { - assert!(true); - - // I'm not sure how to test this tbh. -} diff --git a/rush_macro/tests/var_func_test.rs b/rush_macro/tests/var_func_test.rs deleted file mode 100644 index daaf598..0000000 --- a/rush_macro/tests/var_func_test.rs +++ /dev/null @@ -1,11 +0,0 @@ -use rush_macro::run_func; - -fn uadd(x: usize, y: usize, z: usize) -> usize { - x + y + z -} - -#[test] -fn run_func_test() { - let res = run_func!(uadd, 1, 4, 2); - assert_eq!(res, 7); -} diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index ec6d49e..93f6e10 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -4,7 +4,7 @@ use crate::instructions::logical::*; use crate::instructions::numeric::*; use crate::instructions::vector::*; use crate::push::state::PushState; -use rush_macro::{run_canextract, run_extractidents, run_func}; +use rush_macro::run_instruction; #[macro_use] pub mod macros { @@ -307,12 +307,10 @@ pub mod macros { /// Runs a function and ensures needed variables are extracted from a state without error macro_rules! make_instruction_new { - ($prefix:ident, $func:ident, $($stacks:ident), *) => { + ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { paste::item! { pub fn [< $prefix $func >] (state: &mut PushState) { - if run_canextract!(state, run_extractidents!($($stacks), *)) { - $func extract_state_vals!(state, $($stacks), *) - } + run_instruction!($func, $out_stack, state, $($stacks), *); } } }; @@ -799,7 +797,9 @@ mod tests { let mut test_state = EMPTY_STATE; - test_state.int = vec![0, 1]; - let test_instr = make_instruction_new!(int, _test_func, int, int); + test_state.int = vec![1, 2]; + make_instruction_new!(_test_func, int, int, int, int); + int_test_func(&mut test_state); + assert_eq!(vec![3], test_state.int); } } diff --git a/tests/extractstate_test.rs b/tests/extractstate_test.rs index 838f284..35226c5 100644 --- a/tests/extractstate_test.rs +++ b/tests/extractstate_test.rs @@ -1,15 +1,19 @@ use rush::push::state::EMPTY_STATE; -use rush_macro::run_canextract; +use rush_macro::run_instruction; + +fn iadd(x: i128, y: i128) -> i128 { + x + y +} #[test] fn run_extract_test() { let mut test_state = EMPTY_STATE; test_state.int = vec![1, 2]; - let res = run_canextract!(test_state, int, int, float); - assert_eq!(false, res); + run_instruction!(iadd, int, test_state, int, int); + assert_eq!(vec![3], test_state.int); - test_state.int = vec![1, 2]; - let res = run_canextract!(test_state, int, int); - assert_eq!(true, res); + /*test_state.int = vec![1]; + run_instruction!(iadd, int, test_state, int, int); + assert_eq!(vec![1], test_state.int);*/ } From f13cd7ad20dfb17440d5da9eeef580c2674fcbd9 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 01:13:09 -0500 Subject: [PATCH 09/21] make_instruction_new works, time to refactor --- rush_macro/src/lib.rs | 33 +++++++++++++- .../{canextractstate.rs => instruction.rs} | 44 ++++++++++++++----- rush_macro/src/utils/mod.rs | 2 +- src/instructions/mod.rs | 37 ++++++++-------- ...tractstate_test.rs => instruction_test.rs} | 14 +++++- 5 files changed, 96 insertions(+), 34 deletions(-) rename rush_macro/src/utils/{canextractstate.rs => instruction.rs} (75%) rename tests/{extractstate_test.rs => instruction_test.rs} (51%) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 84e49a3..45b963f 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -1,10 +1,39 @@ -use crate::utils::canextractstate::Extract; +use crate::utils::instruction::Extract; use quote::quote; use syn::parse_macro_input; mod utils; -/// Checks to see if extracting values from a state is possible. +/// This macro kinda goes super crazy mode +/// Here's how to use the macro: +/// +/// `run_instruction!(function_name, output_stack, push state, any amount of +/// comma separated stacks by name ; (the semicolon instructs use whether the instruction +/// has multiple outputs. If ; passed, assumes multiple, without assumes just one output))` +/// +/// An instruction for int add would be: +/// `run_instruction!(_add, int, state, int, int)` +/// assuming the _add function takes two integers and returns a single value (Hint: It does). +/// +/// Important notice: the order in which the last amount +/// of stacks are passed in matters. The first `int` identifier will tell +/// the macro to pop the top int first, the second `int` will pop the next int +/// and so on. This even works with multiple different types of stacks. +/// +/// Another important notice: This macro generates boundary checking as well. +/// If there are not enough items in the stack to run the function, it +/// will not be called. +/// +/// An function with multiple outputs, for example this one: +/// ``` +/// fn aux_iadd(x: i128, y: i128) -> Vec { +/// vec![x + y, x - y] +/// } +/// +/// run_instruction!(aux_iadd, int, state, int, int;); +/// ``` +/// would have the ; placed at the end of the instruction. Check rush's `tests/instruction_test.rs` +/// file for an example using this code. #[proc_macro] pub fn run_instruction(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as Extract); diff --git a/rush_macro/src/utils/canextractstate.rs b/rush_macro/src/utils/instruction.rs similarity index 75% rename from rush_macro/src/utils/canextractstate.rs rename to rush_macro/src/utils/instruction.rs index 8a4ac62..1ffe818 100644 --- a/rush_macro/src/utils/canextractstate.rs +++ b/rush_macro/src/utils/instruction.rs @@ -1,11 +1,13 @@ -// This Stack that isn't repeated is the desired output stack. -// Extract: Function, Stack, State, (`,` Stack)* -// -// Function: identifier -// -// State: identifier -// -// Stack: identifier +//! This Stack that isn't repeated is the desired output stack. +//! Extract: Function, Stack, State, (`,` Stack)* ;? +//! +//! Function: identifier +//! +//! State: identifier +//! +//! Stack: identifier +//! +//! Aux: expression use crate::utils::parse_zero_or_more; use proc_macro2::TokenStream as TokenStream2; @@ -13,11 +15,20 @@ use quote::{ToTokens, quote}; use std::cmp::PartialEq; use syn::parse::{Parse, ParseStream}; +/// Checks if there is a semicolon at the end +fn parse_aux(input: ParseStream) -> bool { + if let Ok(_) = input.parse::() { + return true; + } + false +} + pub struct Extract { func: Function, out_stack: Stack, state: State, stacks: Vec, + aux: bool, } impl Parse for Extract { @@ -26,11 +37,13 @@ impl Parse for Extract { let out_stack = input.parse()?; let state = input.parse()?; let stacks = parse_zero_or_more(input); + let aux = parse_aux::(input); Ok(Extract { func, out_stack, state, stacks, + aux, }) } } @@ -41,6 +54,7 @@ impl ToTokens for Extract { let inner_out_stack = &self.out_stack.0; let inner_state = &self.state.0; let stacks = &self.stacks; + let aux = &self.aux; let mut counts = Vec::new(); for stack in stacks { @@ -60,10 +74,20 @@ impl ToTokens for Extract { quote! { #inner_state.#inner_stack.pop().unwrap() } }); + let aux_run = match aux { + true => quote! { + let result = #inner_func(#(#values),*); + #inner_state.#inner_out_stack.extend(result.iter()); + }, + false => quote! { + let result = #inner_func(#(#values),*); + #inner_state.#inner_out_stack.push(result); + }, + }; + tokens.extend(quote! { if true #(&& (#conditions))* { - let result = vec![#inner_func(#(#values, )*)]; - #inner_state.#inner_out_stack.extend(result.iter()); + #aux_run } }); } diff --git a/rush_macro/src/utils/mod.rs b/rush_macro/src/utils/mod.rs index c963bb0..28504b1 100644 --- a/rush_macro/src/utils/mod.rs +++ b/rush_macro/src/utils/mod.rs @@ -1,6 +1,6 @@ use syn::parse::{Parse, ParseStream}; -pub mod canextractstate; +pub mod instruction; fn parse_zero_or_more(input: ParseStream) -> Vec { let mut result = Vec::new(); diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 93f6e10..67604bc 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -316,14 +316,15 @@ pub mod macros { }; } - /// Extracts values from passed state based on an amount of stacks passed. - macro_rules! extract_state_vals { - ($state:ident) => {}; - ($state:ident, $stack:ident) => { - $state.$stack.pop().unwrap() - }; - ($state:ident, $stack:ident, $($rest:ident), *) => { - ($state.$stack.pop().unwrap(), $(extract_state_vals!($state, $rest)), *) + /// Runs a function and ensures needed variables are extracted from a state without error while + /// returning multiple variables from the function + macro_rules! make_instruction_new_aux { + ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { + paste::item! { + pub fn [< $prefix $func >] (state: &mut PushState) { + run_instruction!($func, $out_stack, state, $($stacks), *, ;); + } + } }; } } @@ -778,28 +779,26 @@ mod tests { use super::*; use crate::push::state::EMPTY_STATE; - #[test] - fn extract_state_vals_test() { - let mut test_state = EMPTY_STATE; - - test_state.int = vec![0, 1]; - test_state.boolean = vec![true]; - - let res = extract_state_vals!(test_state, int, int, boolean); - assert_eq!((1, 0, true), res); - } - #[test] fn make_instruction_new_test() { fn _test_func(x: i128, y: i128) -> i128 { x + y } + fn _aux_test_func(x: i128, y: i128) -> Vec { + vec![x + y, x - y] + } + let mut test_state = EMPTY_STATE; test_state.int = vec![1, 2]; make_instruction_new!(_test_func, int, int, int, int); int_test_func(&mut test_state); assert_eq!(vec![3], test_state.int); + + test_state.int = vec![1, 2]; + make_instruction_new_aux!(_aux_test_func, int, int, int, int); + int_aux_test_func(&mut test_state); + assert_eq!(vec![3, 1], test_state.int); } } diff --git a/tests/extractstate_test.rs b/tests/instruction_test.rs similarity index 51% rename from tests/extractstate_test.rs rename to tests/instruction_test.rs index 35226c5..1eefdb4 100644 --- a/tests/extractstate_test.rs +++ b/tests/instruction_test.rs @@ -5,6 +5,10 @@ fn iadd(x: i128, y: i128) -> i128 { x + y } +fn aux_iadd(x: i128, y: i128) -> Vec { + vec![x + y, x - y] +} + #[test] fn run_extract_test() { let mut test_state = EMPTY_STATE; @@ -13,7 +17,13 @@ fn run_extract_test() { run_instruction!(iadd, int, test_state, int, int); assert_eq!(vec![3], test_state.int); - /*test_state.int = vec![1]; + test_state.int = vec![1]; run_instruction!(iadd, int, test_state, int, int); - assert_eq!(vec![1], test_state.int);*/ + assert_eq!(vec![1], test_state.int); + + // If you're coming from the run_instruction docs, this is + // the one. + test_state.int = vec![1, 2]; + run_instruction!(aux_iadd, int, test_state, int, int;); + assert_eq!(vec![3, 1], test_state.int); } From 2f0500c2d2730205dc60a4bdaceaa7e6e1ba0618 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 01:21:43 -0500 Subject: [PATCH 10/21] optionify the code --- rush_macro/src/lib.rs | 6 +- rush_macro/src/utils/instruction.rs | 10 +- src/instructions/mod.rs | 450 +--------------------------- src/instructions/numeric.rs | 7 +- tests/instruction_test.rs | 8 +- 5 files changed, 22 insertions(+), 459 deletions(-) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 45b963f..8bf6864 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -24,10 +24,10 @@ mod utils; /// If there are not enough items in the stack to run the function, it /// will not be called. /// -/// An function with multiple outputs, for example this one: +/// A function with multiple outputs, for example this one: /// ``` -/// fn aux_iadd(x: i128, y: i128) -> Vec { -/// vec![x + y, x - y] +/// fn aux_iadd(x: i128, y: i128) -> Option> { +/// Some(vec![x + y, x - y]) /// } /// /// run_instruction!(aux_iadd, int, state, int, int;); diff --git a/rush_macro/src/utils/instruction.rs b/rush_macro/src/utils/instruction.rs index 1ffe818..e7ea2e0 100644 --- a/rush_macro/src/utils/instruction.rs +++ b/rush_macro/src/utils/instruction.rs @@ -76,12 +76,14 @@ impl ToTokens for Extract { let aux_run = match aux { true => quote! { - let result = #inner_func(#(#values),*); - #inner_state.#inner_out_stack.extend(result.iter()); + if let Some(result) = #inner_func(#(#values),*) { + #inner_state.#inner_out_stack.extend(result.iter()); + } }, false => quote! { - let result = #inner_func(#(#values),*); - #inner_state.#inner_out_stack.push(result); + if let Some(result) = #inner_func(#(#values),*) { + #inner_state.#inner_out_stack.push(result); + } }, }; diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 67604bc..e8c6851 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -310,7 +310,7 @@ pub mod macros { ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { paste::item! { pub fn [< $prefix $func >] (state: &mut PushState) { - run_instruction!($func, $out_stack, state, $($stacks), *); + rush_macro::run_instruction!($func, $out_stack, state, $($stacks), *); } } }; @@ -322,7 +322,7 @@ pub mod macros { ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { paste::item! { pub fn [< $prefix $func >] (state: &mut PushState) { - run_instruction!($func, $out_stack, state, $($stacks), *, ;); + rush_macro::run_instruction!($func, $out_stack, state, $($stacks), *, ;); } } }; @@ -336,444 +336,6 @@ pub mod numeric; pub mod utils; pub mod vector; -// unsure how to procedurally read a file and put all functions -// into a vector. Probably need to use procedural macros, but I'm not there yet. -pub fn int_instructions() -> Vec { - vec![ - // numeric.rs - int_add, - int_sub, - int_mult, - int_div, - int_rem, - int_max, - int_min, - int_inc, - int_dec, - int_lt, - int_gt, - int_lte, - int_gte, - int_sin, - int_arcsin, - int_cos, - int_arccos, - int_tan, - int_arctan, - int_from_float, - int_from_boolean, - int_log, - int_exp, - int_sqrt, - int_inv, - int_abs, - int_sign_reverse, - int_square, - // common.rs - int_pop, - ] -} -pub fn float_instructions() -> Vec { - vec![ - // numeric - float_add, - float_sub, - float_mult, - float_div, - float_rem, - float_max, - float_min, - float_inc, - float_dec, - float_lt, - float_gt, - float_lte, - float_gte, - float_sin, - float_arcsin, - float_cos, - float_arccos, - float_tan, - float_arctan, - float_from_int, - float_from_boolean, - float_log, - float_exp, - float_sqrt, - float_inv, - float_abs, - float_sign_reverse, - float_square, - // common.rs - float_pop, - ] -} -pub fn string_instructions() -> Vec { - vec![ - // numeric.rs - string_concat, - string_conj, - string_conj_end, - string_take_n, - string_take_last_n, - string_sub, - string_first, - string_from_first_prim, - string_from_prim, - string_last, - string_from_last_prim, - string_nth, - string_from_nth_prim, - string_rest, - string_but_last, - string_drop, - string_drop_last, - string_length, - string_reverse, - string_push_all, - string_make_empty, - string_is_empty, - string_contains, - string_contains_vector_non_contiguous, - string_contains_vector_contiguous, - string_index_of, - string_index_of_vector, - string_occurrences_of, - string_occurrences_of_vector, - string_parse_to_prim, - string_set_nth, - string_split_on, - string_replace, - string_remove, - string_insert, - string_insert_vector, - // common.rs - string_pop, - ] -} -pub fn boolean_instructions() -> Vec { - vec![ - // logical.rs - boolean_and, - boolean_or, - boolean_not, - boolean_xor, - boolean_invert_first_then_and, - boolean_invert_second_then_and, - boolean_from_int, - boolean_from_float, - // common.rs - boolean_pop, - ] -} -pub fn char_instructions() -> Vec { - vec![ - // common.rs - char_pop, - ] -} -pub fn vector_int_instructions() -> Vec { - vec![ - // vector.rs - vector_int_concat, - vector_int_conj, - vector_int_conj_end, - vector_int_take_n, - vector_int_take_last_n, - vector_int_sub, - vector_int_first, - vector_int_from_first_prim, - vector_int_from_prim, - vector_int_last, - vector_int_from_last_prim, - vector_int_nth, - vector_int_from_nth_prim, - vector_int_rest, - vector_int_but_last, - vector_int_drop, - vector_int_drop_last, - vector_int_length, - vector_int_reverse, - vector_int_push_all, - vector_int_make_empty, - vector_int_is_empty, - vector_int_contains, - vector_int_contains_vector_non_contiguous, - vector_int_contains_vector_contiguous, - vector_int_index_of, - vector_int_index_of_vector, - vector_int_occurrences_of, - vector_int_occurrences_of_vector, - vector_int_parse_to_prim, - vector_int_set_nth, - vector_int_split_on, - vector_int_replace, - vector_int_remove, - vector_int_iterate, - vector_int_sort, - vector_int_sort_reverse, - vector_int_insert, - vector_int_insert_vector, - vector_int_mean, - vector_int_maximum, - vector_int_minimum, - vector_int_sum, - vector_int_mode, - vector_int_two_norm, - vector_int_cumulative_sum, - // common.rs - vector_int_pop, - ] -} -pub fn vector_float_instructions() -> Vec { - vec![ - // vector.rs - vector_float_concat, - vector_float_conj, - vector_float_conj_end, - vector_float_take_n, - vector_float_take_last_n, - vector_float_sub, - vector_float_first, - vector_float_from_first_prim, - vector_float_from_prim, - vector_float_last, - vector_float_from_last_prim, - vector_float_nth, - vector_float_from_nth_prim, - vector_float_rest, - vector_float_but_last, - vector_float_drop, - vector_float_drop_last, - vector_float_length, - vector_float_reverse, - vector_float_push_all, - vector_float_make_empty, - vector_float_is_empty, - vector_float_contains, - vector_float_contains_vector_non_contiguous, - vector_float_contains_vector_contiguous, - vector_float_index_of, - vector_float_index_of_vector, - vector_float_occurrences_of, - vector_float_occurrences_of_vector, - vector_float_parse_to_prim, - vector_float_set_nth, - vector_float_split_on, - vector_float_replace, - vector_float_remove, - vector_float_iterate, - vector_float_sort, - vector_float_sort_reverse, - vector_float_insert, - vector_float_insert_vector, - vector_float_mean, - vector_float_maximum, - vector_float_minimum, - vector_float_sum, - vector_float_mode, - vector_float_two_norm, - vector_float_cumulative_sum, - // common.rs - vector_float_pop, - ] -} -pub fn vector_string_instructions() -> Vec { - vec![ - // vector.rs - vector_string_concat, - vector_string_conj, - vector_string_conj_end, - vector_string_take_n, - vector_string_take_last_n, - vector_string_sub, - vector_string_first, - vector_string_from_first_prim, - vector_string_from_prim, - vector_string_last, - vector_string_from_last_prim, - vector_string_nth, - vector_string_from_nth_prim, - vector_string_rest, - vector_string_but_last, - vector_string_drop, - vector_string_drop_last, - vector_string_length, - vector_string_reverse, - vector_string_make_empty, - vector_string_is_empty, - vector_string_contains, - vector_string_contains_vector_non_contiguous, - vector_string_contains_vector_contiguous, - vector_string_index_of, - vector_string_index_of_vector, - vector_string_occurrences_of, - vector_string_occurrences_of_vector, - vector_string_parse_to_prim, - vector_string_set_nth, - vector_string_split_on, - vector_string_replace, - vector_string_remove, - vector_string_insert, - vector_string_insert_vector, - // common.rs - vector_string_pop, - ] -} -pub fn vector_boolean_instructions() -> Vec { - vec![ - // vector.rs - vector_boolean_concat, - vector_boolean_conj, - vector_boolean_conj_end, - vector_boolean_take_n, - vector_boolean_take_last_n, - vector_boolean_sub, - vector_boolean_first, - vector_boolean_from_first_prim, - vector_boolean_from_prim, - vector_boolean_last, - vector_boolean_from_last_prim, - vector_boolean_nth, - vector_boolean_from_nth_prim, - vector_boolean_rest, - vector_boolean_but_last, - vector_boolean_drop, - vector_boolean_drop_last, - vector_boolean_length, - vector_boolean_reverse, - vector_boolean_push_all, - vector_boolean_make_empty, - vector_boolean_is_empty, - vector_boolean_contains, - vector_boolean_contains_vector_non_contiguous, - vector_boolean_contains_vector_contiguous, - vector_boolean_index_of, - vector_boolean_index_of_vector, - vector_boolean_occurrences_of, - vector_boolean_occurrences_of_vector, - vector_boolean_parse_to_prim, - vector_boolean_set_nth, - vector_boolean_split_on, - vector_boolean_replace, - vector_boolean_remove, - vector_boolean_iterate, - vector_boolean_insert, - vector_boolean_insert_vector, - // common.rs - vector_boolean_pop, - ] -} -pub fn vector_char_instructions() -> Vec { - vec![ - // vector.rs - vector_char_concat, - vector_char_conj, - vector_char_conj_end, - vector_char_take_n, - vector_char_take_last_n, - vector_char_sub, - vector_char_first, - vector_char_from_first_prim, - vector_char_from_prim, - vector_char_last, - vector_char_from_last_prim, - vector_char_nth, - vector_char_from_nth_prim, - vector_char_rest, - vector_char_but_last, - vector_char_drop, - vector_char_drop_last, - vector_char_length, - vector_char_reverse, - vector_char_push_all, - vector_char_make_empty, - vector_char_is_empty, - vector_char_contains, - vector_char_contains_vector_non_contiguous, - vector_char_contains_vector_contiguous, - vector_char_index_of, - vector_char_index_of_vector, - vector_char_occurrences_of, - vector_char_occurrences_of_vector, - vector_char_parse_to_prim, - vector_char_set_nth, - vector_char_split_on, - vector_char_replace, - vector_char_remove, - vector_char_iterate, - vector_char_insert, - vector_char_insert_vector, - // common.rs - vector_char_pop, - ] -} -pub fn exec_instructions() -> Vec { - vec![ - // code.rs - exec_do_range, - exec_do_count, - exec_do_times, - exec_while, - exec_do_while, - exec_if, - exec_when, - exec_make_empty_block, - exec_is_empty_block, - exec_size, - // common.rs - exec_noop, - exec_noop_block, - exec_pop, - ] -} -pub fn code_instructions() -> Vec { - vec![ - // code.rs - code_is_block, - code_is_singular, - code_length, - code_first, - code_last, - code_rest, - code_but_last, - code_wrap_block, - code_combine, - code_do_then_pop, - code_do_range, - code_do_count, - code_do_times, - code_map, - code_if, - code_when, - code_member, - code_nth, - code_make_empty_block, - code_is_empty_block, - code_size, - code_extract, - code_insert, - code_insert, - code_first_position, - code_reverse, - // common.rs - code_noop, - code_noop_block, - code_pop, - code_from_int, - code_from_float, - code_from_string, - code_from_boolean, - code_from_char, - code_from_vector_int, - code_from_vector_float, - code_from_vector_string, - code_from_vector_boolean, - code_from_vector_char, - code_from_exec, - ] -} - #[cfg(test)] mod tests { use super::*; @@ -781,12 +343,12 @@ mod tests { #[test] fn make_instruction_new_test() { - fn _test_func(x: i128, y: i128) -> i128 { - x + y + fn _test_func(x: i128, y: i128) -> Option { + Some(x + y) } - fn _aux_test_func(x: i128, y: i128) -> Vec { - vec![x + y, x - y] + fn _aux_test_func(x: i128, y: i128) -> Option> { + Some(vec![x + y, x - y]) } let mut test_state = EMPTY_STATE; diff --git a/src/instructions/numeric.rs b/src/instructions/numeric.rs index 535ddfb..10a787c 100644 --- a/src/instructions/numeric.rs +++ b/src/instructions/numeric.rs @@ -13,14 +13,13 @@ use std::ops::{Add, Div, Mul, Sub}; use super::utils::{CastingTrait, NumericTrait}; /// Adds two addable values together. -fn _add(vals: Vec) -> Option +fn _add(b: T, a: T) -> Option where T: Add + Copy, { - Some(vals[1] + vals[0]) + Some(b + a) } -make_instruction!(int, int, _add, i128, 2); -make_instruction!(float, float, _add, Decimal, 2); +make_instruction_new!(_add, int, int, int, int); /// Subtracts two subtractable values from each other. fn _sub(vals: Vec) -> Option diff --git a/tests/instruction_test.rs b/tests/instruction_test.rs index 1eefdb4..86bdca9 100644 --- a/tests/instruction_test.rs +++ b/tests/instruction_test.rs @@ -1,12 +1,12 @@ use rush::push::state::EMPTY_STATE; use rush_macro::run_instruction; -fn iadd(x: i128, y: i128) -> i128 { - x + y +fn iadd(x: i128, y: i128) -> Option { + Some(x + y) } -fn aux_iadd(x: i128, y: i128) -> Vec { - vec![x + y, x - y] +fn aux_iadd(x: i128, y: i128) -> Option> { + Some(vec![x + y, x - y]) } #[test] From 9af22c13c612c60ff82e59c5cd30b84de12840f9 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 01:24:05 -0500 Subject: [PATCH 11/21] _add works --- src/instructions/numeric.rs | 10 ++++------ src/main.rs | 12 ------------ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/instructions/numeric.rs b/src/instructions/numeric.rs index 10a787c..100431b 100644 --- a/src/instructions/numeric.rs +++ b/src/instructions/numeric.rs @@ -13,13 +13,14 @@ use std::ops::{Add, Div, Mul, Sub}; use super::utils::{CastingTrait, NumericTrait}; /// Adds two addable values together. -fn _add(b: T, a: T) -> Option +fn _add(a: T, b: T) -> Option where T: Add + Copy, { Some(b + a) } make_instruction_new!(_add, int, int, int, int); +make_instruction_new!(_add, float, float, float, float); /// Subtracts two subtractable values from each other. fn _sub(vals: Vec) -> Option @@ -311,11 +312,8 @@ mod tests { /// Tests the _add function. #[test] fn add_test() { - let vals: Vec = vec![1, 2]; - assert_eq!(Some(3), _add(vals)); - - let vals: Vec = vec![dec!(1.1), dec!(2.2)]; - assert_eq!(Some(dec!(3.3)), _add(vals)); + assert_eq!(Some(3), _add(1, 2)); + assert_eq!(Some(dec!(3.3)), _add(dec!(1.1), dec!(2.2))); } /// Tests the _sub function. diff --git a/src/main.rs b/src/main.rs index 07d5c9b..9214a79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,18 +7,6 @@ mod push; fn main() { // These need to stay so linter doesn't go crazy. - int_instructions(); - float_instructions(); - string_instructions(); - boolean_instructions(); - char_instructions(); - vector_int_instructions(); - vector_float_instructions(); - vector_string_instructions(); - vector_boolean_instructions(); - vector_char_instructions(); - exec_instructions(); - code_instructions(); let mut empty_state = EMPTY_STATE; interpret_program(&mut empty_state, 1000, 1000); From df4c6cfcfaf102a2808d2018f9427585cb9e0921 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 01:40:53 -0500 Subject: [PATCH 12/21] Still figuring things out --- src/instructions/numeric.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/instructions/numeric.rs b/src/instructions/numeric.rs index 100431b..913f864 100644 --- a/src/instructions/numeric.rs +++ b/src/instructions/numeric.rs @@ -12,17 +12,15 @@ use std::ops::{Add, Div, Mul, Sub}; use super::utils::{CastingTrait, NumericTrait}; -/// Adds two addable values together. +/// Adds two values together. fn _add(a: T, b: T) -> Option where T: Add + Copy, { Some(b + a) } -make_instruction_new!(_add, int, int, int, int); -make_instruction_new!(_add, float, float, float, float); -/// Subtracts two subtractable values from each other. +/// Subtracts two values from each other. fn _sub(vals: Vec) -> Option where T: Sub + Copy, @@ -32,7 +30,7 @@ where make_instruction!(int, int, _sub, i128, 2); make_instruction!(float, float, _sub, Decimal, 2); -/// Multiplies two multipliable values together. +/// Multiplies two values with each other. fn _mult(vals: Vec) -> Option where T: Mul + Copy, @@ -303,6 +301,17 @@ where make_instruction!(int, int, _square, i128, 1); make_instruction!(float, float, _square, Decimal, 1); +macro_rules! make_instructions { + ($stack:ident) => { + paste::item! { + make_instruction_new!(_add, $stack, $stack, $stack, $stack); + } + }; +} + +make_instructions!(int); +make_instructions!(float); + #[cfg(test)] mod tests { use super::*; From cd2071f965ab8cedd47b027776a3fb73c6648db7 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 12:21:38 -0500 Subject: [PATCH 13/21] pre AI --- src/instructions/numeric.rs | 57 +++++++++++++------------------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/src/instructions/numeric.rs b/src/instructions/numeric.rs index 913f864..66c4ed3 100644 --- a/src/instructions/numeric.rs +++ b/src/instructions/numeric.rs @@ -15,40 +15,34 @@ use super::utils::{CastingTrait, NumericTrait}; /// Adds two values together. fn _add(a: T, b: T) -> Option where - T: Add + Copy, + T: Add, { Some(b + a) } /// Subtracts two values from each other. -fn _sub(vals: Vec) -> Option +fn _sub(a: T, b: T) -> Option where - T: Sub + Copy, + T: Sub, { - Some(vals[1] - vals[0]) + Some(b - a) } -make_instruction!(int, int, _sub, i128, 2); -make_instruction!(float, float, _sub, Decimal, 2); /// Multiplies two values with each other. -fn _mult(vals: Vec) -> Option +fn _mult(a: T, b: T) -> Option where T: Mul + Copy, { - Some(vals[1] * vals[0]) + Some(b * a) } -make_instruction!(int, int, _mult, i128, 2); -make_instruction!(float, float, _mult, Decimal, 2); /// Divides two values from each other. -fn _div(vals: Vec) -> Option +fn _div(a: T, b: T) -> Option where - T: Div + Copy + NumericTrait, + T: Div + NumericTrait, { - vals[1].checked_div(vals[0]) + b.checked_div(a) } -make_instruction!(int, int, _div, i128, 2); -make_instruction!(float, float, _div, Decimal, 2); /// Takes the remainder of two values fn _rem(vals: Vec) -> Option @@ -305,6 +299,9 @@ macro_rules! make_instructions { ($stack:ident) => { paste::item! { make_instruction_new!(_add, $stack, $stack, $stack, $stack); + make_instruction_new!(_sub, $stack, $stack, $stack, $stack); + make_instruction_new!(_mult, $stack, $stack, $stack, $stack); + make_instruction_new!(_div, $stack, $stack, $stack, $stack); } }; } @@ -328,37 +325,24 @@ mod tests { /// Tests the _sub function. #[test] fn sub_test() { - let vals: Vec = vec![1, 2]; - assert_eq!(Some(1), _sub(vals)); - - let vals: Vec = vec![dec!(1.1), dec!(2.2)]; - assert_eq!(Some(dec!(1.1)), _sub(vals)); + assert_eq!(Some(1), _sub(1, 2)); + assert_eq!(Some(dec!(1.1)), _sub(dec!(1.1), dec!(2.2))); } /// Tests the _mult function. #[test] fn mult_test() { - let vals: Vec = vec![4, 5]; - assert_eq!(Some(20), _mult(vals)); - - let vals: Vec = vec![dec!(1.1), dec!(2.2)]; - assert_eq!(Some(dec!(2.42)), _mult(vals)); + assert_eq!(Some(20), _mult(5, 4)); + assert_eq!(Some(dec!(2.42)), _mult(dec!(2.2), dec!(1.1))); } /// Tests the _div function #[test] fn div_test() { - let vals: Vec = vec![4, 20]; - assert_eq!(Some(5), _div(vals)); - - let vals: Vec = vec![3, 20]; - assert_eq!(Some(6), _div(vals)); - - let vals: Vec = vec![dec!(1.6), dec!(2.2)]; - assert_eq!(Some(dec!(1.375)), _div(vals)); - - let vals: Vec = vec![0, 1]; - assert_eq!(None, _div(vals)); + assert_eq!(Some(5), _div(4, 20)); + assert_eq!(Some(6), _div(3, 20)); + assert_eq!(Some(dec!(1.375)), _div(dec!(1.6), dec!(2.2))); + assert_eq!(None, _div(0, 1)); } /// Tests the _rem function @@ -545,7 +529,6 @@ mod tests { assert_eq!(vec![2, 0], test_state.int); test_state.int = vec![6, 3]; - int_div(&mut test_state); assert_eq!(vec![2], test_state.int); From bcb9d130c757e474f7050472f2be3d3287b5c498 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 14:06:21 -0500 Subject: [PATCH 14/21] conversion to new instructions started --- rush_macro/src/lib.rs | 3 + rush_macro/src/utils/instruction.rs | 33 ++- src/instructions/logical.rs | 76 +++--- src/instructions/mod.rs | 14 +- src/instructions/numeric.rs | 391 ++++++++++++---------------- 5 files changed, 241 insertions(+), 276 deletions(-) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index 8bf6864..dffb7c6 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -34,6 +34,9 @@ mod utils; /// ``` /// would have the ; placed at the end of the instruction. Check rush's `tests/instruction_test.rs` /// file for an example using this code. +/// +/// Suggestion: If you need to pull an index from the int stack, make it the first argument +/// to your function. #[proc_macro] pub fn run_instruction(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as Extract); diff --git a/rush_macro/src/utils/instruction.rs b/rush_macro/src/utils/instruction.rs index e7ea2e0..4ce912f 100644 --- a/rush_macro/src/utils/instruction.rs +++ b/rush_macro/src/utils/instruction.rs @@ -64,31 +64,56 @@ 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 } }); - let values = stacks.iter().map(|stack| { + // Create variables to store popped values + let store_values = stacks.iter().enumerate().map(|(i, stack)| { let inner_stack = &&stack.0; - quote! { #inner_state.#inner_stack.pop().unwrap() } + let var_name = quote::format_ident!("val_{}", i); + quote! { let #var_name = #inner_state.#inner_stack.pop().unwrap(); } }); + // Create slices of variable names for restoration + let value_vars = (0..stacks.len()) + .map(|i| quote::format_ident!("val_{}", i)) + .collect::>(); + + // Create restore operations for each stack + let restore_values = stacks + .iter() + .zip(value_vars.iter().rev()) + .map(|(stack, var)| { + let inner_stack = &&stack.0; + quote! { #inner_state.#inner_stack.push(#var); } + }); + + // Run the function using auxiliary mode if needed let aux_run = match aux { true => quote! { - if let Some(result) = #inner_func(#(#values),*) { + let result = #inner_func(#(#value_vars),*); + if let Some(result) = result { #inner_state.#inner_out_stack.extend(result.iter()); + } else { + #(#restore_values)* } }, false => quote! { - if let Some(result) = #inner_func(#(#values),*) { + let result = #inner_func(#(#value_vars),*); + if let Some(result) = result { #inner_state.#inner_out_stack.push(result); + } else { + #(#restore_values)* } }, }; tokens.extend(quote! { if true #(&& (#conditions))* { + #(#store_values)* #aux_run } }); diff --git a/src/instructions/logical.rs b/src/instructions/logical.rs index 05c33e4..639b08d 100644 --- a/src/instructions/logical.rs +++ b/src/instructions/logical.rs @@ -7,74 +7,86 @@ use crate::push::state::PushState; use rust_decimal::Decimal; /// Runs logical and on two values -fn _and(vals: Vec) -> Option +fn _and(a: T, b: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_and(vals[1])) + Some(b.logical_and(a)) } -make_instruction!(boolean, boolean, _and, bool, 2); /// Runs logical or on two values -fn _or(vals: Vec) -> Option +fn _or(a: T, b: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_or(vals[1])) + Some(b.logical_or(a)) } -make_instruction!(boolean, boolean, _or, bool, 2); /// Runs logical not on two values -fn _not(vals: Vec) -> Option +fn _not(a: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_not()) + Some(a.logical_not()) } -make_instruction!(boolean, boolean, _not, bool, 1); /// Runs logical xor on two values -fn _xor(vals: Vec) -> Option +fn _xor(a: T, b: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_xor(vals[1])) + Some(b.logical_xor(a)) } -make_instruction!(boolean, boolean, _xor, bool, 2); /// Inverts the first value and runs logical and on two values -fn _invert_first_then_and(vals: Vec) -> Option +fn _invert_first_then_and(a: T, b: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_not().logical_and(vals[1])) + Some(a.logical_not().logical_and(b)) } -make_instruction!(boolean, boolean, _invert_first_then_and, bool, 2); /// Inverts the second value and runs logical and on two values -fn _invert_second_then_and(vals: Vec) -> Option +fn _invert_second_then_and(a: T, b: T) -> Option where - T: Copy + LogicalTrait, + T: LogicalTrait, { - Some(vals[0].logical_and(vals[1].logical_not())) + Some(a.logical_and(b.logical_not())) } -make_instruction!(boolean, boolean, _invert_second_then_and, bool, 2); -fn _from_int(vals: Vec) -> Option +fn _from_int(a: i128) -> Option where - T: Copy + CastingTrait, + T: CastingTrait, { - T::from_int(vals[0]) + T::from_int(a) } -make_instruction_out!(int, boolean, _from_int, i128, 1); -fn _from_float(vals: Vec) -> Option +fn _from_float(a: Decimal) -> Option where - T: Copy + CastingTrait, + T: CastingTrait, { - T::from_float(vals[0]) + T::from_float(a) } -make_instruction_out!(float, boolean, _from_float, Decimal, 1); + +macro_rules! make_logical_instructions { + ($stack:ident) => { + make_instruction_new!(_and, $stack, $stack, $stack, $stack); + make_instruction_new!(_or, $stack, $stack, $stack, $stack); + make_instruction_new!(_not, $stack, $stack, $stack); + make_instruction_new!(_xor, $stack, $stack, $stack, $stack); + make_instruction_new!(_invert_first_then_and, $stack, $stack, $stack, $stack); + make_instruction_new!(_invert_second_then_and, $stack, $stack, $stack, $stack); + make_instruction_new!(_from_int, $stack, $stack, int); + make_instruction_new!(_from_float, $stack, $stack, float); + }; +} + +macro_rules! all_logical_instructions { + () => { + make_logical_instructions!(boolean); + }; +} +all_logical_instructions!(); #[cfg(test)] mod tests { diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index e8c6851..327b4c3 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -1,11 +1,3 @@ -use crate::instructions::code::*; -use crate::instructions::common::*; -use crate::instructions::logical::*; -use crate::instructions::numeric::*; -use crate::instructions::vector::*; -use crate::push::state::PushState; -use rush_macro::run_instruction; - #[macro_use] pub mod macros { /// A macro that makes a push instruction given: the name of the input stack to use, @@ -305,7 +297,7 @@ pub mod macros { }; } - /// Runs a function and ensures needed 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 { ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { paste::item! { @@ -338,8 +330,8 @@ pub mod vector; #[cfg(test)] mod tests { - use super::*; - use crate::push::state::EMPTY_STATE; + //use super::*; + use crate::push::state::{EMPTY_STATE, PushState}; #[test] fn make_instruction_new_test() { diff --git a/src/instructions/numeric.rs b/src/instructions/numeric.rs index 66c4ed3..a9823e0 100644 --- a/src/instructions/numeric.rs +++ b/src/instructions/numeric.rs @@ -45,269 +45,249 @@ where } /// Takes the remainder of two values -fn _rem(vals: Vec) -> Option +fn _rem(a: T, b: T) -> Option where T: Div + Copy + NumericTrait, { - vals[1].checked_mod(vals[0]) + b.checked_mod(a) } -make_instruction!(int, int, _rem, i128, 2); -make_instruction!(float, float, _rem, Decimal, 2); /// Takes the max of two values -fn _max(vals: Vec) -> Option +fn _max(a: T, b: T) -> Option where - T: Ord + Copy, + T: Ord, { - Some(max(vals[1], vals[0])) + Some(max(a, b)) } -make_instruction!(int, int, _max, i128, 2); -make_instruction!(float, float, _max, Decimal, 2); /// Takes the min of two values -fn _min(vals: Vec) -> Option +fn _min(a: T, b: T) -> Option where - T: Ord + Copy, + T: Ord, { - Some(min(vals[1], vals[0])) + Some(min(a, b)) } -make_instruction!(int, int, _min, i128, 2); -make_instruction!(float, float, _min, Decimal, 2); /// Increments a single value by 1 -fn _inc(vals: Vec) -> Option +fn _inc(a: T) -> Option where T: NumericTrait + Copy, { - Some(vals[0].increment()) + Some(a.increment()) } -make_instruction!(int, int, _inc, i128, 1); -make_instruction!(float, float, _inc, Decimal, 1); /// Decrements a single value by 1 -fn _dec(vals: Vec) -> Option +fn _dec(a: T) -> Option where - T: NumericTrait + Copy, + T: NumericTrait, { - Some(vals[0].decrement()) + Some(a.decrement()) } -make_instruction!(int, int, _dec, i128, 1); -make_instruction!(float, float, _dec, Decimal, 1); /// Checks if the 2nd to top value is less than the top value -fn _lt(vals: Vec) -> Option +fn _lt(a: T, b: T) -> Option where - T: Ord + Copy, + T: Ord, { - Some(vals[1] < vals[0]) + Some(b < a) } -make_instruction!(int, boolean, _lt, i128, 2); -make_instruction!(float, boolean, _lt, Decimal, 2); /// Checks if the 2nd to top value is greater than the top value -fn _gt(vals: Vec) -> Option +fn _gt(a: T, b: T) -> Option where - T: Ord + Copy, + T: Ord, { - Some(vals[1] > vals[0]) + Some(b > a) } -make_instruction!(int, boolean, _gt, i128, 2); -make_instruction!(float, boolean, _gt, Decimal, 2); /// Checks if the 2nd to top value is less than or equal to the top value -fn _lte(vals: Vec) -> Option +fn _lte(a: T, b: T) -> Option where T: Ord + Copy, { - Some(vals[1] <= vals[0]) + Some(b <= a) } -make_instruction!(int, boolean, _lte, i128, 2); -make_instruction!(float, boolean, _lte, Decimal, 2); /// Checks if the 2nd to top value is greater than or equal to the top value -fn _gte(vals: Vec) -> Option +fn _gte(a: T, b: T) -> Option where - T: Ord + Copy, + T: Ord, { - Some(vals[1] >= vals[0]) + Some(b >= a) } -make_instruction!(int, boolean, _gte, i128, 2); -make_instruction!(float, boolean, _gte, Decimal, 2); /// Runs sin on a single item. -fn _sin(vals: Vec) -> Option +fn _sin(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_sin() + a.safe_sin() } -make_instruction!(int, int, _sin, i128, 1); -make_instruction!(float, float, _sin, Decimal, 1); /// Runs arcsin on a single item. -fn _arcsin(vals: Vec) -> Option +fn _arcsin(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_sin()?.inverse() + a.safe_sin()?.inverse() } -make_instruction!(int, int, _arcsin, i128, 1); -make_instruction!(float, float, _arcsin, Decimal, 1); /// Runs cos on a single item. -fn _cos(vals: Vec) -> Option +fn _cos(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_cos() + a.safe_cos() } -make_instruction!(int, int, _cos, i128, 1); -make_instruction!(float, float, _cos, Decimal, 1); /// Runs arcsin on a single item. -fn _arccos(vals: Vec) -> Option +fn _arccos(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_cos()?.inverse() + a.safe_cos()?.inverse() } -make_instruction!(int, int, _arccos, i128, 1); -make_instruction!(float, float, _arccos, Decimal, 1); /// Runs tan on a single item. -fn _tan(vals: Vec) -> Option +fn _tan(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_tan() + a.safe_tan() } -make_instruction!(int, int, _tan, i128, 1); -make_instruction!(float, float, _tan, Decimal, 1); /// Runs arctan on a single item. -fn _arctan(vals: Vec) -> Option +fn _arctan(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_tan()?.inverse() + a.safe_tan()?.inverse() +} + +/// Converts a single value from an int to an arbitrary type. +fn _from_int(a: i128) -> Option +where + T: CastingTrait, +{ + T::from_int(a) } -make_instruction!(int, int, _arctan, i128, 1); -make_instruction!(float, float, _arctan, Decimal, 1); /// Converts a single value from a float to an arbitrary type. -fn _from_int(vals: Vec) -> Option +fn _from_float(a: Decimal) -> Option where - T: Copy + CastingTrait, + T: CastingTrait, { - T::from_int(vals[0]) + T::from_float(a) } -make_instruction_out!(int, float, _from_int, i128, 1); -/// Converts a single value from a float to an arbitrary type. -fn _from_float(vals: Vec) -> Option +/// Converts a bool to a new type. +fn _from_boolean(a: bool) -> Option where - T: Copy + CastingTrait, + T: CastingTrait, { - T::from_float(vals[0]) + T::from_bool(a) } -make_instruction_out!(float, int, _from_float, Decimal, 1); -/// Converts a bool to a to a new type. -fn _from_boolean(vals: Vec) -> Option -where - T: Copy + CastingTrait, -{ - T::from_bool(vals[0]) -} -make_instruction_out!(boolean, int, _from_boolean, bool, 1); -make_instruction_out!(boolean, float, _from_boolean, bool, 1); - -/// Takes the log base 10 of a single Decimal. Acts as a +/// Takes log base 10 of a single Decimal. Acts as a /// NoOp if the value is 0. If the value is negative, takes /// the absolute value of the number. -fn _log(vals: Vec) -> Option +fn _log(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].absolute().safe_log10() + a.absolute().safe_log10() } -make_instruction!(int, int, _log, i128, 1); -make_instruction!(float, float, _log, Decimal, 1); /// Takes the exp of a single value. Ints get truncated. -fn _exp(vals: Vec) -> Option +fn _exp(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_exp() + a.safe_exp() } -make_instruction!(int, int, _exp, i128, 1); -make_instruction!(float, float, _exp, Decimal, 1); /// Takes the square root of the absolute value of a single value. -fn _sqrt(vals: Vec) -> Option +fn _sqrt(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].safe_sqrt() + a.safe_sqrt() } -make_instruction!(int, int, _sqrt, i128, 1); -make_instruction!(float, float, _sqrt, Decimal, 1); /// Takes the inverse of a single value. If the number is 0, /// does nothing (returns None). Truncates an int to 0. -fn _inv(vals: Vec) -> Option +fn _inv(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - vals[0].inverse() + a.inverse() } -make_instruction!(int, int, _inv, i128, 1); -make_instruction!(float, float, _inv, Decimal, 1); /// Takes the absolute value of the top number -fn _abs(vals: Vec) -> Option +fn _abs(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - Some(vals[0].absolute()) + Some(a.absolute()) } -make_instruction!(int, int, _abs, i128, 1); -make_instruction!(float, float, _abs, Decimal, 1); /// Reverses the sign of the top number -fn _sign_reverse(vals: Vec) -> Option +fn _sign_reverse(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - Some(vals[0].sign_reverse()) + Some(a.sign_reverse()) } -make_instruction!(int, int, _sign_reverse, i128, 1); -make_instruction!(float, float, _sign_reverse, Decimal, 1); /// Squares the top number -fn _square(vals: Vec) -> Option +fn _square(a: T) -> Option where - T: Copy + NumericTrait, + T: NumericTrait, { - Some(vals[0].square()) + Some(a.square()) } -make_instruction!(int, int, _square, i128, 1); -make_instruction!(float, float, _square, Decimal, 1); -macro_rules! make_instructions { +macro_rules! make_numeric_instructions { ($stack:ident) => { - paste::item! { - make_instruction_new!(_add, $stack, $stack, $stack, $stack); - make_instruction_new!(_sub, $stack, $stack, $stack, $stack); - make_instruction_new!(_mult, $stack, $stack, $stack, $stack); - make_instruction_new!(_div, $stack, $stack, $stack, $stack); - } + make_instruction_new!(_add, $stack, $stack, $stack, $stack); + make_instruction_new!(_sub, $stack, $stack, $stack, $stack); + make_instruction_new!(_mult, $stack, $stack, $stack, $stack); + make_instruction_new!(_div, $stack, $stack, $stack, $stack); + make_instruction_new!(_rem, $stack, $stack, $stack, $stack); + make_instruction_new!(_max, $stack, $stack, $stack, $stack); + make_instruction_new!(_min, $stack, $stack, $stack, $stack); + make_instruction_new!(_inc, $stack, $stack, $stack); + make_instruction_new!(_dec, $stack, $stack, $stack); + make_instruction_new!(_lt, $stack, boolean, $stack, $stack); + make_instruction_new!(_gt, $stack, boolean, $stack, $stack); + make_instruction_new!(_lte, $stack, boolean, $stack, $stack); + make_instruction_new!(_gte, $stack, boolean, $stack, $stack); + make_instruction_new!(_sin, $stack, $stack, $stack); + make_instruction_new!(_arcsin, $stack, $stack, $stack); + make_instruction_new!(_cos, $stack, $stack, $stack); + make_instruction_new!(_arccos, $stack, $stack, $stack); + make_instruction_new!(_tan, $stack, $stack, $stack); + make_instruction_new!(_arctan, $stack, $stack, $stack); + make_instruction_new!(_from_boolean, $stack, $stack, boolean); + make_instruction_new!(_log, $stack, $stack, $stack); + make_instruction_new!(_exp, $stack, $stack, $stack); + make_instruction_new!(_sqrt, $stack, $stack, $stack); + make_instruction_new!(_inv, $stack, $stack, $stack); + make_instruction_new!(_abs, $stack, $stack, $stack); + make_instruction_new!(_sign_reverse, $stack, $stack, $stack); + make_instruction_new!(_square, $stack, $stack, $stack); }; } -make_instructions!(int); -make_instructions!(float); +macro_rules! all_numeric_instructions { + () => { + make_numeric_instructions!(int); + make_numeric_instructions!(float); + make_instruction_new!(_from_int, float, float, int); + make_instruction_new!(_from_float, int, int, float); + }; +} +all_numeric_instructions!(); #[cfg(test)] mod tests { @@ -348,124 +328,70 @@ mod tests { /// Tests the _rem function #[test] fn rem_test() { - let vals: Vec = vec![3, 20]; - assert_eq!(Some(2), _rem(vals)); - - let vals: Vec = vec![20, 20]; - assert_eq!(Some(0), _rem(vals)); - - let vals: Vec = vec![0, 9]; - assert_eq!(None, _rem(vals)); + assert_eq!(Some(2), _rem(3, 20)); + assert_eq!(Some(0), _rem(20, 20)); + assert_eq!(None, _rem(0, 9)); } /// Tests the _max function #[test] fn max_test() { - let vals: Vec = vec![1, 2]; - assert_eq!(Some(2), _max(vals)); - - let vals: Vec = vec![3, 0]; - assert_eq!(Some(3), _max(vals)); - - let vals: Vec = vec![dec!(2.2), dec!(1.1)]; - assert_eq!(Some(dec!(2.2)), _max(vals)); - - let vals: Vec = vec![dec!(3.3), dec!(-1.1)]; - assert_eq!(Some(dec!(3.3)), _max(vals)); + assert_eq!(Some(2), _max(1, 2)); + assert_eq!(Some(3), _max(3, 0)); + assert_eq!(Some(dec!(2.2)), _max(dec!(2.2), dec!(1.1))); + assert_eq!(Some(dec!(3.3)), _max(dec!(3.3), dec!(-1.1))); } /// Tests the _min function #[test] fn min_test() { - let vals: Vec = vec![1, 2]; - assert_eq!(Some(1), _min(vals)); - - let vals: Vec = vec![3, 0]; - assert_eq!(Some(0), _min(vals)); - - let vals: Vec = vec![dec!(2.2), dec!(1.1)]; - assert_eq!(Some(dec!(1.1)), _min(vals)); - - let vals: Vec = vec![dec!(3.3), dec!(-1.1)]; - assert_eq!(Some(dec!(-1.1)), _min(vals)); + assert_eq!(Some(1), _min(1, 2)); + assert_eq!(Some(0), _min(3, 0)); + assert_eq!(Some(dec!(1.1)), _min(dec!(2.2), dec!(1.1))); + assert_eq!(Some(dec!(-1.1)), _min(dec!(3.3), dec!(-1.1))); } /// Tests the _inc and _dec functions #[test] fn inc_dec_test() { - let vals: Vec = vec![2]; - assert_eq!(Some(3), _inc(vals)); - - let vals: Vec = vec![10]; - assert_eq!(Some(9), _dec(vals)); - - let vals: Vec = vec![dec!(2.2)]; - assert_eq!(Some(dec!(3.2)), _inc(vals)); - - let vals: Vec = vec![dec!(5.6)]; - assert_eq!(Some(dec!(4.6)), _dec(vals)); + assert_eq!(Some(3), _inc(2)); + assert_eq!(Some(9), _dec(10)); + assert_eq!(Some(dec!(3.2)), _inc(dec!(2.2))); + assert_eq!(Some(dec!(4.6)), _dec(dec!(5.6))); } /// Tests the _lt, _gt, _lte, and _gte functions #[test] fn lt_gt_lte_gte_test() { - let vals: Vec = vec![3, 2]; - assert_eq!(Some(true), _lt(vals)); - - let vals: Vec = vec![1, 4]; - assert_eq!(Some(false), _lt(vals)); - - let vals: Vec = vec![3, 3]; - assert_eq!(Some(false), _lt(vals)); - - let vals: Vec = vec![2, 3]; - assert_eq!(Some(true), _gt(vals)); - - let vals: Vec = vec![4, 1]; - assert_eq!(Some(false), _gt(vals)); - - let vals: Vec = vec![3, 3]; - assert_eq!(Some(false), _gt(vals)); - - let vals: Vec = vec![3, 2]; - assert_eq!(Some(true), _lte(vals)); - - let vals: Vec = vec![1, 4]; - assert_eq!(Some(false), _lte(vals)); - - let vals: Vec = vec![3, 3]; - assert_eq!(Some(true), _lte(vals)); - - let vals: Vec = vec![2, 3]; - assert_eq!(Some(true), _gte(vals)); - - let vals: Vec = vec![4, 1]; - assert_eq!(Some(false), _gte(vals)); - - let vals: Vec = vec![3, 3]; - assert_eq!(Some(true), _gte(vals)); + assert_eq!(Some(true), _lt(3, 2)); + assert_eq!(Some(false), _lt(1, 4)); + assert_eq!(Some(false), _lt(3, 3)); + assert_eq!(Some(true), _gt(2, 3)); + assert_eq!(Some(false), _gt(4, 1)); + assert_eq!(Some(false), _gt(3, 3)); + assert_eq!(Some(true), _lte(3, 2)); + assert_eq!(Some(false), _lte(1, 4)); + assert_eq!(Some(true), _lte(3, 3)); + assert_eq!(Some(true), _gte(2, 3)); + assert_eq!(Some(false), _gte(4, 1)); + assert_eq!(Some(true), _gte(3, 3)); } /// Tests the various trig functions. #[test] fn trig_tests() { - let vals = vec![Decimal::PI]; - assert_eq!(Some(dec!(0.0)), _sin(vals)); - - let vals = vec![Decimal::QUARTER_PI]; - assert_eq!(Some(dec!(1.4142135623869512272301701717)), _arcsin(vals)); - - let vals = vec![Decimal::PI]; - assert_eq!(Some(dec!(-1.0)), _cos(vals)); - - let vals = vec![Decimal::QUARTER_PI]; - assert_eq!(Some(dec!(1.4142135626023406165042434783)), _arccos(vals)); - - let vals = vec![Decimal::PI]; - assert_eq!(Some(dec!(0.0)), _tan(vals)); - - let vals = vec![Decimal::QUARTER_PI]; - assert_eq!(Some(dec!(1.0000000043184676055890307049)), _arctan(vals)); + assert_eq!(Some(dec!(0.0)), _sin(Decimal::PI)); + assert_eq!( + Some(dec!(1.4142135623869512272301701717)), + _arcsin(Decimal::QUARTER_PI) + ); + assert_eq!(Some(dec!(-1.0)), _cos(Decimal::PI)); + assert_eq!(Some(dec!(-1.0)), _arccos(Decimal::PI)); + assert_eq!(Some(dec!(0.0)), _tan(Decimal::PI)); + assert_eq!( + Some(dec!(1.0000000043184676055890307049)), + _arctan(Decimal::QUARTER_PI) + ); } /// Tests that the various addition functions. @@ -714,6 +640,13 @@ mod tests { test_state.float = vec![dec!(2.1)]; int_from_float(&mut test_state); assert_eq!(vec![2], test_state.int); + test_state.float.clear(); + test_state.int.clear(); + + test_state.boolean = vec![true]; + int_from_boolean(&mut test_state); + assert_eq!(vec![1], test_state.int); + test_state.boolean.clear(); } /// Tests the log function From 9abb9d1febff9c670133a3ff75782fb5482a3fdc Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 16:27:00 -0500 Subject: [PATCH 15/21] multi stack problem --- rush_macro/src/utils/instruction.rs | 10 ++-- src/instructions/code.rs | 87 ++++++++++++++++------------- tests/instruction_test.rs | 8 +++ 3 files changed, 60 insertions(+), 45 deletions(-) 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); } From 0a1f0fa601b664011d11cd15ab608c7b8dc87164 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Fri, 18 Apr 2025 23:23:29 -0500 Subject: [PATCH 16/21] code done --- rush_macro/src/lib.rs | 2 + rush_macro/src/utils/instruction.rs | 41 ++++++++++---- src/instructions/code.rs | 88 ++++++++++++++--------------- src/instructions/mod.rs | 16 +++++- 4 files changed, 89 insertions(+), 58 deletions(-) diff --git a/rush_macro/src/lib.rs b/rush_macro/src/lib.rs index dffb7c6..fbe64cd 100644 --- a/rush_macro/src/lib.rs +++ b/rush_macro/src/lib.rs @@ -37,6 +37,8 @@ mod utils; /// /// Suggestion: If you need to pull an index from the int stack, make it the first argument /// to your function. +/// +/// If there is an instruction with no stacks as input, must put a comma at the end. #[proc_macro] pub fn run_instruction(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let f = parse_macro_input!(input as Extract); diff --git a/rush_macro/src/utils/instruction.rs b/rush_macro/src/utils/instruction.rs index 4bae797..fbf5b3a 100644 --- a/rush_macro/src/utils/instruction.rs +++ b/rush_macro/src/utils/instruction.rs @@ -1,5 +1,8 @@ +//! Where the hard work for automatically generating instructions is done. +//! Check `run_instruction!` for more details. +//! //! This Stack that isn't repeated is the desired output stack. -//! Extract: Function, Stack, State, (`,` Stack)* ;? +//! Extract: Function, Stack, State (`,` Stack)* ;? //! //! Function: identifier //! @@ -56,6 +59,12 @@ impl ToTokens for Extract { let stacks = &self.stacks; let aux = &self.aux; + // Gets the counts of each stack passed to the macro held + // similarly to a map as: (stack, count). + // + // Chosen over a HashMap bc these types don't implement Hash + // HashMaps are O(nlogn) at worst this is O(n^2). Largest instruction + // passes 4 stacks so this shouldn't matter in the long run. let mut counts = Vec::new(); for stack in stacks { match counts.iter_mut().find(|(x, _)| x == stack) { @@ -64,32 +73,40 @@ impl ToTokens for Extract { } } + // Writes the piece of the code that ensures the stacks have enough values + // to function without error. let conditions = counts.iter().map(|(stack, count)| { let inner_stack = &stack.0; quote! { #inner_state.#inner_stack.len() >= #count } }); - // Create variables to store popped values + // In case the instruction returns None (meaning revert the state), + // need to store the values to return them let store_values = stacks.iter().enumerate().map(|(i, stack)| { let inner_stack = &&stack.0; let var_name = quote::format_ident!("val_{}", i); quote! { let #var_name = #inner_state.#inner_stack.pop().unwrap(); } }); - // Create slices of variable names for restoration and function call + // Create the variable names themselves to store the + // popped values. let value_vars = (0..stacks.len()) .map(|i| quote::format_ident!("val_{}", i)) .collect::>(); - // Create restore operations for each stack - let restore_values = stacks - .iter() - .zip(value_vars.iter().rev()) - .map(|(stack, var)| { - let inner_stack = &&stack.0; - quote! { #inner_state.#inner_stack.push(#var.clone()); } - }); + // Create restore code in case None is returned from the function. + let restore_values = + stacks + .iter() + .rev() + .zip(value_vars.iter().rev()) + .map(|(stack, var)| { + let inner_stack = &&stack.0; + quote! { #inner_state.#inner_stack.push(#var.clone()); } + }); + // The logic for running the function and returning values + // if bad. let aux_run = match aux { true => quote! { let result = #inner_func(#(#value_vars.clone()),*); @@ -109,6 +126,8 @@ impl ToTokens for Extract { }, }; + // Where the pieces of the puzzle are put together. + // tokens then used to create the function. tokens.extend(quote! { if true #(&& (#conditions))* { #(#store_values)* diff --git a/src/instructions/code.rs b/src/instructions/code.rs index f5f6b31..c0a9f9c 100644 --- a/src/instructions/code.rs +++ b/src/instructions/code.rs @@ -349,20 +349,19 @@ pub fn exec_when(state: &mut PushState) { /// Pushes true if the second code item is found within the first item. /// If the first item isn't a block, coerced into one. -pub fn _member(vals: Vec) -> Option { - let block = match vals[0].clone() { +pub fn _member(a: Gene, b: Gene) -> Option { + let block = match b { Gene::Block(val) => val, val => vec![val], }; - Some(block.contains(&vals[1])) + Some(block.contains(&a)) } -make_instruction_clone!(code, boolean, _member, Gene, 2); /// Pushes the nth item of the top element of the code stack. /// If top code item isn't a block, wrap one around it. -pub fn _nth(vals: Vec, auxs: Vec) -> Option { - let gene_vec = match vals[0].clone() { +pub fn _nth(a: Gene, idx: i128) -> Option { + let gene_vec = match a { Gene::Block(val) => val, val => vec![val], }; @@ -370,22 +369,19 @@ pub fn _nth(vals: Vec, auxs: Vec) -> Option { if gene_vec_len == 0 { return None; } - let ndx = auxs[0].abs() as usize % gene_vec_len; + let ndx = idx.abs() as usize % gene_vec_len; Some(gene_vec[ndx].clone()) } -make_instruction_aux!(code, code, _nth, Gene, 1, int, 1, i128); /// Pushes an empty block to the top of a stack. -pub fn _make_empty_block(_: Vec) -> Option { +pub fn _make_empty_block() -> Option { Some(Gene::Block(vec![])) } -make_instruction_clone!(code, code, _make_empty_block, Gene, 0); -make_instruction_clone!(exec, exec, _make_empty_block, Gene, 0); /// Checks to see if the top item on the code/exec stack is an empty block. /// True if is, False if not. -pub fn _is_empty_block(vals: Vec) -> Option { - Some(match vals[0].clone() { +pub fn _is_empty_block(a: Gene) -> Option { + Some(match a { Gene::Block(val) => { if val.is_empty() { true @@ -396,70 +392,64 @@ pub fn _is_empty_block(vals: Vec) -> Option { _ => false, }) } -make_instruction_clone!(code, boolean, _is_empty_block, Gene, 1); -make_instruction_clone!(exec, boolean, _is_empty_block, Gene, 1); /// Returns the size of the top item on the code/exec stack. -pub fn _size(vals: Vec) -> Option { - Some(match vals[0].clone() { +pub fn _size(a: Gene) -> Option { + Some(match a.clone() { Gene::Block(val) => val.len() as i128, _ => 1, }) } -make_instruction_clone!(code, int, _size, Gene, 1); -make_instruction_clone!(exec, int, _size, Gene, 1); /// Returns a nested element inside a block based on an int. -pub fn _extract(vals: Vec, auxs: Vec) -> Option { - match vals[0].clone() { +pub fn _extract(a: Gene, idx: i128) -> Option { + match &a { block @ Gene::Block(_) => { let block_len = block.rec_len(); if block_len == 0 { None } else { - let ndx = (auxs[0] % block_len as i128).abs() as usize; - Some(vals[0].clone().code_at_point(ndx)?) + let ndx = (idx % block_len as i128).abs() as usize; + Some(a.code_at_point(ndx)?) } } - val => Some(val), + _ => Some(a), } } -make_instruction_aux!(code, code, _extract, Gene, 1, int, 1, i128); /// Inserts a gene at a given position in into the top block based off an /// int from the top of the int stack. The top code item is coerced into a block /// if needed. -pub fn _insert(vals: Vec, auxs: Vec) -> Option { - let mut block = match vals[0].clone() { +pub fn _insert(a: Gene, b: Gene, idx: i128) -> Option { + let mut block = match a.clone() { iblock @ Gene::Block(_) => iblock, val => Gene::Block(vec![val]), }; if block.rec_len() == 0 { - return _combine(block, vals[1].clone()); + return _combine(block, b); } - let ndx = auxs[0].abs() as usize % block.rec_len(); - block.with_code_inserted_at_point(vals[1].clone(), ndx); + let ndx = idx.abs() as usize % block.rec_len(); + block.with_code_inserted_at_point(b, ndx); Some(block) } -make_instruction_aux!(code, code, _insert, Gene, 2, int, 1, i128); /// Pushes the first position of the 2nd code item within the top code item. /// If not found, pushes -1. If top code item isn't a block, returns 0 if top /// two code items equal, -1 otherwise. -pub fn _first_position(vals: Vec) -> Option { - let bad_cond: bool = match &vals[0] { +pub fn _first_position(a: Gene, b: Gene) -> Option { + let bad_cond: bool = match &a { Gene::Block(val) => val.len() == 0, _ => true, }; if bad_cond { - if vals[0] == vals[1] { + if a == b { return Some(0); } } else { - match &vals[0] { + match &a { Gene::Block(val) => { for (idx, el) in val.iter().enumerate() { - if el == &vals[1] { + if el == &b { return Some(idx as i128); } } @@ -469,11 +459,10 @@ pub fn _first_position(vals: Vec) -> Option { } Some(-1) } -make_instruction_clone!(code, int, _first_position, Gene, 2); /// Reverses the top block. Does nothing if not a block. -pub fn _reverse(vals: Vec) -> Option { - Some(match vals[0].clone() { +pub fn _reverse(a: Gene) -> Option { + Some(match a { Gene::Block(mut val) => { val.reverse(); Gene::Block(val) @@ -481,7 +470,6 @@ pub fn _reverse(vals: Vec) -> Option { val => val, }) } -make_instruction_clone!(code, code, _reverse, Gene, 1); macro_rules! make_code_instructions { ($stack:ident) => { @@ -494,7 +482,16 @@ macro_rules! make_code_instructions { 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); + make_instruction_new!(_if, $stack, exec, $stack, $stack, boolean); + make_instruction_new!(_member, $stack, boolean, $stack, $stack); + make_instruction_new!(_nth, $stack, $stack, $stack, int); + make_instruction_empty!(_make_empty_block, $stack, $stack, Gene); + make_instruction_new!(_is_empty_block, $stack, boolean, $stack); + make_instruction_new!(_size, $stack, int, $stack); + make_instruction_new!(_extract, $stack, $stack, $stack, int); + make_instruction_new!(_insert, $stack, $stack, $stack, $stack, int); + make_instruction_new!(_first_position, $stack, int, $stack, $stack); + make_instruction_new!(_reverse, $stack, $stack, $stack); }; } @@ -505,7 +502,6 @@ macro_rules! all_code_instructions { }; } all_code_instructions!(); -make_instruction_new!(_if, code, code, code, code, boolean); #[cfg(test)] mod tests { @@ -892,7 +888,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); @@ -915,7 +911,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] @@ -959,24 +955,24 @@ mod tests { let mut test_state = EMPTY_STATE; test_state.code = vec![ - Gene::GeneInt(0), Gene::Block(vec![ Gene::GeneInt(0), Gene::GeneInt(4), Gene::StateFunc(exec_do_range), ]), + Gene::GeneInt(0), ]; code_member(&mut test_state); assert_eq!(vec![true], test_state.boolean); test_state.boolean.clear(); test_state.code = vec![ - Gene::GeneInt(0), Gene::Block(vec![ Gene::GeneInt(5), Gene::GeneInt(4), Gene::StateFunc(exec_do_range), ]), + Gene::GeneInt(0), ]; code_member(&mut test_state); assert_eq!(vec![false], test_state.boolean); diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 327b4c3..fd2ce21 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -308,7 +308,7 @@ pub mod macros { }; } - /// Runs a function and ensures needed variables are extracted from a state without error while + /// Runs a function and ensures the necessary variables are extracted from a state without error while /// returning multiple variables from the function macro_rules! make_instruction_new_aux { ($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => { @@ -319,6 +319,20 @@ pub mod macros { } }; } + + /// Makes an instruction that takes no input stacks. Must specify a type for this + /// one so because the result needs a type, and the compiler can't infer it here :( + macro_rules! make_instruction_empty { + ($func:ident, $prefix:ident, $out_stack:ident, $out_type:ty) => { + paste::item! { + pub fn [< $prefix $func >] (state: &mut PushState) { + if let Some(result) = $func::<$out_type>() { + state.$out_stack.push(result); + } + } + } + }; + } } pub mod code; From e1a79fbffb6586c9162ddc94136165589790b207 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 02:41:35 -0500 Subject: [PATCH 17/21] Some more instructions done --- src/instructions/vector.rs | 727 ++++++++----------------------------- tests/instruction_test.rs | 8 + 2 files changed, 156 insertions(+), 579 deletions(-) diff --git a/src/instructions/vector.rs b/src/instructions/vector.rs index 655e3b2..78e952d 100644 --- a/src/instructions/vector.rs +++ b/src/instructions/vector.rs @@ -10,695 +10,210 @@ fn bounded_idx(num: i128, length: usize) -> usize { } /// Concats two vectors together. -pub fn _concat(vals: Vec>) -> Option> +fn _concat(a: Vec, b: Vec) -> Option> where T: Clone, { - let mut concat_vec = vals[0].clone(); - concat_vec.extend(vals[1].clone().into_iter()); + let mut concat_vec = a; + concat_vec.extend(b.into_iter()); Some(concat_vec) } -make_instruction_clone!(vector_int, vector_int, _concat, Vec, 2); -make_instruction_clone!(vector_float, vector_float, _concat, Vec, 2); -make_instruction_clone!(vector_string, vector_string, _concat, Vec>, 2); -make_instruction_clone!(vector_boolean, vector_boolean, _concat, Vec, 2); -make_instruction_clone!(vector_char, vector_char, _concat, Vec, 2); -make_instruction_clone!(string, string, _concat, Vec, 2); /// Prepends a primitive value to a vector. -pub fn _conj(vec_vals: Vec>, prim_vals: Vec) -> Option> -where - T: Clone, -{ - let mut t_vec = vec_vals[0].clone(); - t_vec.insert(0, prim_vals[0].clone()); +fn _conj(vect: Vec, prim: T) -> Option> { + let mut t_vec = vect; + t_vec.insert(0, prim); Some(t_vec) } -make_instruction_aux!(vector_int, vector_int, _conj, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - vector_float, - _conj, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - vector_string, - _conj, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _conj, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!(vector_char, vector_char, _conj, Vec, 1, char, 1, char); -make_instruction_aux!(string, string, _conj, Vec, 1, char, 1, char); /// Appends a primitive value to a vector. -pub fn _conj_end(vec_vals: Vec>, prim_vals: Vec) -> Option> -where - T: Clone, -{ - let mut t_vec = vec_vals[0].clone(); - t_vec.push(prim_vals[0].clone()); - Some(t_vec) +fn _conj_end(mut vals: Vec, prim: T) -> Option> { + vals.push(prim); + Some(vals) } -make_instruction_aux!( - vector_int, - vector_int, - _conj_end, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_float, - vector_float, - _conj_end, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - vector_string, - _conj_end, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _conj_end, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!( - vector_char, - vector_char, - _conj_end, - Vec, - 1, - char, - 1, - char -); -make_instruction_aux!(string, string, _conj_end, Vec, 1, char, 1, char); /// Takes the first N items from a vector. N based on an int. -pub fn _take_n(vals: Vec>, auxs: Vec) -> Option> +fn _take_n(vals: Vec, amt: i128) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(ret_vec[0..bounded_idx(auxs[0], ret_vec.len())].to_vec()) + Some(vals[0..bounded_idx(amt, vals.len())].to_vec()) } -make_instruction_aux!(vector_int, vector_int, _take_n, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - vector_float, - _take_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _take_n, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _take_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_char, - vector_char, - _take_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!(string, string, _take_n, Vec, 1, int, 1, i128); /// Takes the first N items from a vector. N based on an int. -pub fn _take_last_n(vals: Vec>, auxs: Vec) -> Option> +fn _take_last_n(vals: Vec, amt: i128) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - let ret_vec_len = ret_vec.len(); - Some(ret_vec[ret_vec_len - bounded_idx(auxs[0], ret_vec_len)..ret_vec_len].to_vec()) + let vals_len = vals.len(); + Some(vals[vals_len - bounded_idx(amt, vals_len)..vals_len].to_vec()) } -make_instruction_aux!( - vector_int, - vector_int, - _take_last_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_float, - vector_float, - _take_last_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _take_last_n, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _take_last_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_char, - vector_char, - _take_last_n, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!(string, string, _take_last_n, Vec, 1, int, 1, i128); /// Takes a sublist of a vector based on two ints. -pub fn _sub(vals: Vec>, auxs: Vec) -> Option> +fn _sub(vals: Vec, idx0: i128, idx1: i128) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - let (mut start, mut end): (usize, usize) = ( - auxs[0].unsigned_abs() as usize, - auxs[1].unsigned_abs() as usize, - ); + let (mut start, mut end): (usize, usize) = + (idx0.unsigned_abs() as usize, idx1.unsigned_abs() as usize); if start > end { (start, end) = (end, start) } - let fin_start = start.min(ret_vec.len()); - let fin_end = end.min(ret_vec.len()); - Some(ret_vec[fin_start..fin_end].to_vec()) + let fin_start = start.min(vals.len()); + let fin_end = end.min(vals.len()); + Some(vals[fin_start..fin_end].to_vec()) } -make_instruction_aux!(vector_int, vector_int, _sub, Vec, 1, int, 2, i128); -make_instruction_aux!( - vector_float, - vector_float, - _sub, - Vec, - 1, - int, - 2, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _sub, - Vec>, - 1, - int, - 2, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _sub, - Vec, - 1, - int, - 2, - i128 -); -make_instruction_aux!(vector_char, vector_char, _sub, Vec, 1, int, 2, i128); -make_instruction_aux!(string, string, _sub, Vec, 1, int, 2, i128); /// Takes the first item from a vector. -pub fn _first(vals: Vec>) -> Option +fn _first(vals: Vec) -> Option where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vals[0][0].clone()) + Some(vals[0].clone()) } -make_instruction_clone!(vector_int, int, _first, Vec, 1); -make_instruction_clone!(vector_float, float, _first, Vec, 1); -make_instruction_clone!(vector_string, string, _first, Vec>, 1); -make_instruction_clone!(vector_boolean, boolean, _first, Vec, 1); -make_instruction_clone!(vector_char, char, _first, Vec, 1); -make_instruction_clone!(string, char, _first, Vec, 1); /// Takes the first item from a vector, wraps it into a vector, and pushes it back /// to the same stack. -pub fn _from_first_prim(vals: Vec>) -> Option> +fn _from_first_prim(vals: Vec) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vec![vals[0][0].clone()]) -} -make_instruction_clone!(vector_int, vector_int, _from_first_prim, Vec, 1); -make_instruction_clone!( - vector_float, - vector_float, - _from_first_prim, - Vec, - 1 -); -make_instruction_clone!( - vector_string, - vector_string, - _from_first_prim, - Vec>, - 1 -); -make_instruction_clone!( - vector_boolean, - vector_boolean, - _from_first_prim, - Vec, - 1 -); -make_instruction_clone!(vector_char, vector_char, _from_first_prim, Vec, 1); -make_instruction_clone!(string, string, _from_first_prim, Vec, 1); - -/// Places the top of a primitive type into a vector -pub fn _from_prim(vals: Vec) -> Option> -where - T: Clone, -{ Some(vec![vals[0].clone()]) } -make_instruction_out!(int, vector_int, _from_prim, i128, 1); -make_instruction_out!(float, vector_float, _from_prim, Decimal, 1); -make_instruction_out!(string, vector_string, _from_prim, Vec, 1); -make_instruction_out!(boolean, vector_boolean, _from_prim, bool, 1); -make_instruction_out!(char, vector_char, _from_prim, char, 1); -make_instruction_out!(char, string, _from_prim, char, 1); + +/// Places the top of a primitive type into a vector +fn _from_prim(prim: T) -> Option> { + Some(vec![prim]) +} /// Takes the last item from a vector. -pub fn _last(vals: Vec>) -> Option +fn _last(vals: Vec) -> Option where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vals[0][ret_vec.len() - 1].clone()) + Some(vals[vals.len() - 1].clone()) } -make_instruction_clone!(vector_int, int, _last, Vec, 1); -make_instruction_clone!(vector_float, float, _last, Vec, 1); -make_instruction_clone!(vector_string, string, _last, Vec>, 1); -make_instruction_clone!(vector_boolean, boolean, _last, Vec, 1); -make_instruction_clone!(vector_char, char, _last, Vec, 1); -make_instruction_clone!(string, char, _last, Vec, 1); /// Takes the last item from a vector, wraps it into a vector, and pushes it back /// to the same stack. -pub fn _from_last_prim(vals: Vec>) -> Option> +fn _from_last_prim(vals: Vec) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vec![vals[0][ret_vec.len() - 1].clone()]) + Some(vec![vals[vals.len() - 1].clone()]) } -make_instruction_clone!(vector_int, vector_int, _from_last_prim, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _from_last_prim, Vec, 1); -make_instruction_clone!( - vector_string, - vector_string, - _from_last_prim, - Vec>, - 1 -); -make_instruction_clone!( - vector_boolean, - vector_boolean, - _from_last_prim, - Vec, - 1 -); -make_instruction_clone!(vector_char, vector_char, _from_last_prim, Vec, 1); -make_instruction_clone!(string, string, _from_last_prim, Vec, 1); /// Takes the nth item from a vector. N from int stack. -pub fn _nth(vals: Vec>, auxs: Vec) -> Option +fn _nth(vals: Vec, idx: i128) -> Option where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vals[0][bounded_idx(auxs[0], ret_vec.len())].clone()) + Some(vals[bounded_idx(idx, vals.len())].clone()) } -make_instruction_aux!(vector_int, int, _nth, Vec, 1, int, 1, i128); -make_instruction_aux!(vector_float, float, _nth, Vec, 1, int, 1, i128); -make_instruction_aux!(vector_string, string, _nth, Vec>, 1, int, 1, i128); -make_instruction_aux!(vector_boolean, boolean, _nth, Vec, 1, int, 1, i128); -make_instruction_aux!(vector_char, char, _nth, Vec, 1, int, 1, i128); -make_instruction_aux!(string, char, _nth, Vec, 1, int, 1, i128); /// Takes the nth item from a vector, wraps it into a vector, and pushes it back /// to the same stack. N from int stack -pub fn _from_nth_prim(vals: Vec>, auxs: Vec) -> Option> +fn _from_nth_prim(vals: Vec, idx: i128) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(vec![vals[0][bounded_idx(auxs[0], ret_vec.len())].clone()]) + Some(vec![vals[bounded_idx(idx, vals.len())].clone()]) } -make_instruction_aux!( - vector_int, - vector_int, - _from_nth_prim, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_float, - vector_float, - _from_nth_prim, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _from_nth_prim, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _from_nth_prim, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_char, - vector_char, - _from_nth_prim, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - string, - vector_char, - _from_nth_prim, - Vec, - 1, - int, - 1, - i128 -); /// Takes a vector and removes the first element. -pub fn _rest(vals: Vec>) -> Option> +fn _rest(vals: Vec) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(ret_vec[1..].to_vec()) + Some(vals[1..].to_vec()) } -make_instruction_clone!(vector_int, vector_int, _rest, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _rest, Vec, 1); -make_instruction_clone!(vector_string, vector_string, _rest, Vec>, 1); -make_instruction_clone!(vector_boolean, vector_boolean, _rest, Vec, 1); -make_instruction_clone!(vector_char, vector_char, _rest, Vec, 1); -make_instruction_clone!(string, string, _rest, Vec, 1); /// Takes a vector and removes the last element. -pub fn _but_last(vals: Vec>) -> Option> +fn _but_last(vals: Vec) -> Option> where T: Clone, { - let ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - Some(ret_vec[0..ret_vec.len() - 1].to_vec()) + Some(vals[0..vals.len() - 1].to_vec()) } -make_instruction_clone!(vector_int, vector_int, _but_last, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _but_last, Vec, 1); -make_instruction_clone!(vector_string, vector_string, _but_last, Vec>, 1); -make_instruction_clone!(vector_boolean, vector_boolean, _but_last, Vec, 1); -make_instruction_clone!(vector_char, vector_char, _but_last, Vec, 1); -make_instruction_clone!(string, string, _but_last, Vec, 1); /// Removes the first n items from a vector. n from the int stack. -pub fn _drop(vals: Vec>, auxs: Vec) -> Option> +fn _drop(mut vals: Vec, idx: i128) -> Option> where T: Clone, { - let mut ret_vec = vals[0].clone(); - if ret_vec.is_empty() { + if vals.is_empty() { return None; } - ret_vec.drain(0..auxs[0].abs().min(ret_vec.len() as i128) as usize); - Some(ret_vec) + vals.drain(0..idx.abs().min(vals.len() as i128) as usize); + Some(vals) } -make_instruction_aux!(vector_int, vector_int, _drop, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - vector_float, - _drop, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _drop, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _drop, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!(vector_char, vector_char, _drop, Vec, 1, int, 1, i128); -make_instruction_aux!(string, string, _drop, Vec, 1, int, 1, i128); -pub fn _drop_last(vals: Vec>, auxs: Vec) -> Option> +fn _drop_last(mut vals: Vec, idx: i128) -> Option> where T: Clone, { - let mut ret_vec = vals[0].clone(); - let rvlen = ret_vec.len(); //Ret_Vec Len - if ret_vec.is_empty() { + let valslen = vals.len(); //Ret_Vec Len + if vals.is_empty() { return None; } - ret_vec.drain((rvlen - (auxs[0].abs().min(rvlen as i128) as usize))..rvlen); - Some(ret_vec) + vals.drain((valslen - (idx.abs().min(valslen as i128) as usize))..valslen); + Some(vals) } -make_instruction_aux!( - vector_int, - vector_int, - _drop_last, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_float, - vector_float, - _drop_last, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _drop_last, - Vec>, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _drop_last, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!( - vector_char, - vector_char, - _drop_last, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_aux!(string, string, _drop_last, Vec, 1, int, 1, i128); /// Takes the length of a vector. -pub fn _length(vals: Vec>) -> Option { - Some(vals[0].len() as i128) +fn _length(vals: Vec) -> Option { + Some(vals.len() as i128) } -make_instruction_clone!(vector_int, int, _length, Vec, 1); -make_instruction_clone!(vector_float, int, _length, Vec, 1); -make_instruction_clone!(vector_string, int, _length, Vec>, 1); -make_instruction_clone!(vector_boolean, int, _length, Vec, 1); -make_instruction_clone!(vector_char, int, _length, Vec, 1); -make_instruction_clone!(string, int, _length, Vec, 1); /// Reverses a vector -pub fn _reverse(vals: Vec>) -> Option> +fn _reverse(mut vals: Vec) -> Option> where T: Clone, { - let mut rev_vec = vals[0].clone(); - rev_vec.reverse(); - Some(rev_vec) + vals.reverse(); + Some(vals) } -make_instruction_clone!(vector_int, vector_int, _reverse, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _reverse, Vec, 1); -make_instruction_clone!(vector_string, vector_string, _reverse, Vec>, 1); -make_instruction_clone!(vector_boolean, vector_boolean, _reverse, Vec, 1); -make_instruction_clone!(vector_char, vector_char, _reverse, Vec, 1); -make_instruction_clone!(string, string, _reverse, Vec, 1); /// Pushes all values of a vector into a primitive stack -pub fn _push_all(vals: Vec>) -> Option> -where - T: Clone, -{ - Some(vals[0].clone()) +fn _push_all(vals: Vec) -> Option> { + Some(vals) } -make_instruction_mult!(vector_int, int, _push_all, Vec, 1); -make_instruction_mult!(vector_float, float, _push_all, Vec, 1); -// make_instruction_mult!(vector_string, string, _push_all, Vec>, 1); // Optional -make_instruction_mult!(vector_boolean, boolean, _push_all, Vec, 1); -make_instruction_mult!(vector_char, char, _push_all, Vec, 1); -make_instruction_mult!(string, char, _push_all, Vec, 1); /// Creates an empty vector -pub fn _make_empty(_: Vec>) -> Option> { +fn _make_empty(_: Vec>) -> Option> { let empty_vec: Vec = Vec::new(); Some(empty_vec) } @@ -710,7 +225,7 @@ make_instruction_clone!(vector_char, vector_char, _make_empty, Vec, 0); make_instruction_clone!(string, string, _make_empty, Vec, 0); /// Checks if a vector is empty. Pushes true if is, false otherwise -pub fn _is_empty(vals: Vec>) -> Option { +fn _is_empty(vals: Vec>) -> Option { Some(vals[0].is_empty()) } make_instruction_clone!(vector_int, boolean, _is_empty, Vec, 1); @@ -721,7 +236,7 @@ make_instruction_clone!(vector_char, boolean, _is_empty, Vec, 1); make_instruction_clone!(string, boolean, _is_empty, Vec, 1); /// Checks if a vector contains a primitive. True if does, false otherwise -pub fn _contains(vals: Vec>, auxs: Vec) -> Option +fn _contains(vals: Vec>, auxs: Vec) -> Option where T: Eq, { @@ -762,7 +277,7 @@ make_instruction_aux!(vector_char, boolean, _contains, Vec, 1, char, 1, ch make_instruction_aux!(string, boolean, _contains, Vec, 1, char, 1, char); /// Checks if a vector contains another vector in no order. True if does, false otherwise -pub fn _contains_vector_non_contiguous(vals: Vec>) -> Option +fn _contains_vector_non_contiguous(vals: Vec>) -> Option where T: Eq + Hash, { @@ -813,7 +328,7 @@ make_instruction_clone!( ); /// Checks if a vector contains another contiguous vector. True if does, false otherwise -pub fn _contains_vector_contiguous(vals: Vec>) -> Option +fn _contains_vector_contiguous(vals: Vec>) -> Option where T: Eq, { @@ -860,7 +375,7 @@ make_instruction_clone!( make_instruction_clone!(string, boolean, _contains_vector_contiguous, Vec, 2); /// Returns the index of a primitive in a vector, pushes result to int stack -pub fn _index_of(vals: Vec>, auxs: Vec) -> Option +fn _index_of(vals: Vec>, auxs: Vec) -> Option where T: Clone + Eq, { @@ -906,7 +421,7 @@ make_instruction_aux!(vector_char, int, _index_of, Vec, 1, char, 1, char); make_instruction_aux!(string, int, _index_of, Vec, 1, char, 1, char); /// Finds the index of the start of one vector in another. Searches in contiguous space. -pub fn _index_of_vector(vals: Vec>) -> Option +fn _index_of_vector(vals: Vec>) -> Option where T: Eq, { @@ -926,7 +441,7 @@ make_instruction_clone!(vector_char, int, _index_of_vector, Vec, 2); make_instruction_clone!(string, int, _index_of_vector, Vec, 2); /// Counts the amount of a primitive in a vector -pub fn _occurrences_of(vals: Vec>, auxs: Vec) -> Option +fn _occurrences_of(vals: Vec>, auxs: Vec) -> Option where T: Clone + Eq, { @@ -982,7 +497,7 @@ make_instruction_aux!( make_instruction_aux!(string, int, _occurrences_of, Vec, 1, char, 1, char); /// Counts the amount of continuous occurrences one vector appears in another. -pub fn _occurrences_of_vector(vals: Vec>) -> Option +fn _occurrences_of_vector(vals: Vec>) -> Option where T: Eq, { @@ -1011,7 +526,7 @@ make_instruction_clone!(string, int, _occurrences_of_vector, Vec, 2); /// Pushes the values inside a vector separated into individual vectors back to /// the stack. -pub fn _parse_to_prim(vals: Vec>) -> Option>> +fn _parse_to_prim(vals: Vec>) -> Option>> where T: Clone, Vec: FromIterator, @@ -1032,7 +547,7 @@ make_instruction_mult!(vector_char, vector_char, _parse_to_prim, Vec, 1); make_instruction_mult!(string, string, _parse_to_prim, Vec, 1); /// Sets the nth index in a vector. N from the int stack. -pub fn _set_nth(vals: Vec>, aux0: Vec, aux1: Vec) -> Option> +fn _set_nth(vals: Vec>, aux0: Vec, aux1: Vec) -> Option> where T: Clone, { @@ -1121,7 +636,7 @@ make_instruction_aux2!( ); /// Splits a vector based the first occurence of a primitive -pub fn _split_on(vals: Vec>, auxs: Vec) -> Option>> +fn _split_on(vals: Vec>, auxs: Vec) -> Option>> where T: Clone + Eq, Vec: FromIterator, @@ -1194,7 +709,7 @@ make_instruction_mult_aux!( make_instruction_mult_aux!(string, string, _split_on, Vec, 1, char, 1, char); /*/// Splits a vector based the first occurence of a primitive -pub fn _split_on_vector(vals: Vec>) -> Option>> +fn _split_on_vector(vals: Vec>) -> Option>> where T: Clone + Eq, { @@ -1243,7 +758,7 @@ make_instruction_mult!(string, string, _split_on_vector, Vec, 1);*/ /// Replaces all values in a vector with respect to two primitives. The first primitive is /// the search value and the second value is the one to replace. -pub fn _replace(mut vals: Vec>, auxs: Vec) -> Option> +fn _replace(mut vals: Vec>, auxs: Vec) -> Option> where T: Clone, for<'a> &'a T: Eq, @@ -1306,7 +821,7 @@ make_instruction_aux!( make_instruction_aux!(string, string, _replace, Vec, 1, char, 2, char); /// Removes all values in a vector with respect to a primitives. If is equal, remove it. -pub fn _remove(vals: Vec>, auxs: Vec) -> Option> +fn _remove(vals: Vec>, auxs: Vec) -> Option> where T: Clone, for<'a> &'a T: Eq, @@ -1398,7 +913,7 @@ make_iterate!(vector_char, char, GeneVectorChar); //make_iterate!(string, string, GeneString); /// Sorts a vector -pub fn _sort(mut vals: Vec>) -> Option> +fn _sort(mut vals: Vec>) -> Option> where T: NumericTrait + Clone, { @@ -1409,7 +924,7 @@ make_instruction_clone!(vector_int, vector_int, _sort, Vec, 1); make_instruction_clone!(vector_float, vector_float, _sort, Vec, 1); /// Sorts a vector and reverses it -pub fn _sort_reverse(mut vals: Vec>) -> Option> +fn _sort_reverse(mut vals: Vec>) -> Option> where T: NumericTrait + Clone, { @@ -1421,7 +936,7 @@ make_instruction_clone!(vector_int, vector_int, _sort_reverse, Vec, 1); make_instruction_clone!(vector_float, vector_float, _sort_reverse, Vec, 1); /// Inserts a primitive into a vector at a given point from the int stack -pub fn _insert(mut vals: Vec>, auxs: Vec, auxs2: Vec) -> Option> +fn _insert(mut vals: Vec>, auxs: Vec, auxs2: Vec) -> Option> where T: Clone, { @@ -1509,7 +1024,7 @@ make_instruction_aux2!( ); /// Inserts one vector into another based on an index. -pub fn _insert_vector(mut vals: Vec>, auxs: Vec) -> Option> +fn _insert_vector(mut vals: Vec>, auxs: Vec) -> Option> where T: Clone, { @@ -1572,7 +1087,7 @@ make_instruction_aux!( make_instruction_aux!(string, string, _insert_vector, Vec, 2, int, 1, i128); /// Takes the mean of a vector -pub fn _mean(vals: Vec>) -> Option { +fn _mean(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1586,7 +1101,7 @@ make_instruction_clone!(vector_int, int, _mean, Vec, 1); make_instruction_clone!(vector_float, float, _mean, Vec, 1); /// Takes the max of a vector -pub fn _maximum(vals: Vec>) -> Option { +fn _maximum(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1596,7 +1111,7 @@ make_instruction_clone!(vector_int, int, _maximum, Vec, 1); make_instruction_clone!(vector_float, float, _maximum, Vec, 1); /// Takes the min of a vector -pub fn _minimum(vals: Vec>) -> Option { +fn _minimum(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1606,7 +1121,7 @@ make_instruction_clone!(vector_int, int, _minimum, Vec, 1); make_instruction_clone!(vector_float, float, _minimum, Vec, 1); /// Takes the sum of a vector -pub fn _sum(vals: Vec>) -> Option { +fn _sum(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1620,7 +1135,7 @@ make_instruction_clone!(vector_int, int, _sum, Vec, 1); make_instruction_clone!(vector_float, float, _sum, Vec, 1); /// Takes the mode of a vector -pub fn _mode(vals: Vec>) -> Option { +fn _mode(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1638,7 +1153,7 @@ make_instruction_clone!(vector_int, int, _mode, Vec, 1); make_instruction_clone!(vector_float, float, _mode, Vec, 1); /// Adds the squares of all values in a vector and then takes the square root -pub fn _two_norm(vals: Vec>) -> Option { +fn _two_norm(vals: Vec>) -> Option { if vals[0].is_empty() { return Some(T::zero()); } @@ -1652,7 +1167,7 @@ make_instruction_clone!(vector_int, int, _two_norm, Vec, 1); make_instruction_clone!(vector_float, float, _two_norm, Vec, 1); /// Takes the cumulative sum of a vector -pub fn _cumulative_sum(vals: Vec>) -> Option> { +fn _cumulative_sum(vals: Vec>) -> Option> { if vals[0].is_empty() { return Some(vec![]); } @@ -1668,7 +1183,7 @@ make_instruction_clone!(vector_int, vector_int, _cumulative_sum, Vec, 1); make_instruction_clone!(vector_float, vector_float, _cumulative_sum, Vec, 1); /* /// Takes the cumulative mean of a vector -pub fn _cumulative_mean(vals: Vec>) -> Option> { +fn _cumulative_mean(vals: Vec>) -> Option> { if vals[0].is_empty() { return Some(vec![]); } @@ -1694,6 +1209,51 @@ make_instruction_clone!( 1 );*/ +macro_rules! make_vector_instructions { + ($stack:ident, $prim_stack:ident) => { + make_instruction_new!(_concat, $stack, $stack, $stack, $stack); + make_instruction_new!(_conj, $stack, $stack, $stack, $prim_stack); + make_instruction_new!(_conj_end, $stack, $stack, $stack, $prim_stack); + make_instruction_new!(_take_n, $stack, $stack, $stack, int); + make_instruction_new!(_take_last_n, $stack, $stack, $stack, int); + make_instruction_new!(_sub, $stack, $stack, $stack, int, int); + make_instruction_new!(_first, $stack, $prim_stack, $stack); + make_instruction_new!(_from_first_prim, $stack, $stack, $stack); + make_instruction_new!(_from_prim, $stack, $stack, $prim_stack); + make_instruction_new!(_last, $stack, $prim_stack, $stack); + make_instruction_new!(_from_last_prim, $stack, $stack, $stack); + make_instruction_new!(_nth, $stack, $prim_stack, $stack, int); + make_instruction_new!(_from_nth_prim, $stack, $stack, $stack, int); + make_instruction_new!(_rest, $stack, $stack, $stack); + make_instruction_new!(_but_last, $stack, $stack, $stack); + make_instruction_new!(_drop, $stack, $stack, $stack, int); + make_instruction_new!(_drop_last, $stack, $stack, $stack, int); + make_instruction_new!(_length, $stack, int, $stack); + make_instruction_new!(_reverse, $stack, $stack, $stack); + //make_instruction_new_aux!(_push_all, $stack, $prim_stack, $stack); + //make_instruction_empty!(_make_empty, $stack, $stack, $stack); + }; +} + +macro_rules! all_vector_instructions { + () => { + make_vector_instructions!(vector_int, int); + make_vector_instructions!(vector_float, float); + make_vector_instructions!(vector_string, string); + make_vector_instructions!(vector_boolean, boolean); + make_vector_instructions!(vector_char, char); + make_vector_instructions!(string, char); + + // Instructions that don't work on every stack + make_instruction_new_aux!(_push_all, vector_int, int, vector_int); + make_instruction_new_aux!(_push_all, vector_float, float, vector_float); + make_instruction_new_aux!(_push_all, vector_boolean, boolean, vector_boolean); + make_instruction_new_aux!(_push_all, vector_char, char, vector_char); + make_instruction_new_aux!(_push_all, string, char, string); + }; +} +all_vector_instructions!(); + #[cfg(test)] mod tests { use super::*; @@ -2069,6 +1629,15 @@ mod tests { assert_eq!(vec![vec![5, 4, 3, 2, 1, 0]], test_state.vector_int); } + #[test] + fn push_all_test() { + let mut test_state = EMPTY_STATE; + + test_state.vector_int = vec![vec![1, 2, 3]]; + vector_int_push_all(&mut test_state); + assert_eq!(vec![1, 2, 3], test_state.int); + } + #[test] fn make_empty_vec_test() { let mut test_state = EMPTY_STATE; diff --git a/tests/instruction_test.rs b/tests/instruction_test.rs index 901c64a..f1d5b61 100644 --- a/tests/instruction_test.rs +++ b/tests/instruction_test.rs @@ -13,6 +13,10 @@ fn two_stacks(x: i128, y: i128, cond: bool) -> Option { if cond { Some(x + y) } else { Some(x - y) } } +fn aux_char(ch: Vec) -> Option> { + Some(ch) +} + #[test] fn run_extract_test() { let mut test_state = EMPTY_STATE; @@ -34,4 +38,8 @@ fn run_extract_test() { test_state.int = vec![1, 2]; test_state.boolean = vec![true]; run_instruction!(two_stacks, int, test_state, int, int, boolean); + + test_state.vector_char = vec![vec!['a', 'b']]; + run_instruction!(aux_char, char, test_state, vector_char;); + assert_eq!(vec!['a', 'b'], test_state.char); } From eb2c033a98831270209f2be5ff8b0efd7fd208d8 Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 18:50:32 -0500 Subject: [PATCH 18/21] vector on new system --- rush_macro/src/utils/instruction.rs | 9 +- src/instructions/vector.rs | 885 +++++----------------------- 2 files changed, 151 insertions(+), 743 deletions(-) diff --git a/rush_macro/src/utils/instruction.rs b/rush_macro/src/utils/instruction.rs index fbf5b3a..6d1c2d0 100644 --- a/rush_macro/src/utils/instruction.rs +++ b/rush_macro/src/utils/instruction.rs @@ -111,12 +111,17 @@ impl ToTokens for Extract { true => quote! { let result = #inner_func(#(#value_vars.clone()),*); if let Some(result) = result { - #inner_state.#inner_out_stack.extend(result.iter()); + // Transforming the result vector into an iterator with .iter() was + // causing problems with the vector_string stack. Iterating this way + // fixes the problem. + for n in 0..result.len() { + #inner_state.#inner_out_stack.push(result[n].clone()) + } } else { #(#restore_values)* } }, - false => quote! { + false => quote! { // This arm is used most of the time let result = #inner_func(#(#value_vars.clone()),*); if let Some(result) = result { #inner_state.#inner_out_stack.push(result); diff --git a/src/instructions/vector.rs b/src/instructions/vector.rs index 78e952d..bbfa7bd 100644 --- a/src/instructions/vector.rs +++ b/src/instructions/vector.rs @@ -213,438 +213,121 @@ fn _push_all(vals: Vec) -> Option> { } /// Creates an empty vector -fn _make_empty(_: Vec>) -> Option> { +fn _make_empty() -> Option> { let empty_vec: Vec = Vec::new(); Some(empty_vec) } -make_instruction_clone!(vector_int, vector_int, _make_empty, Vec, 0); -make_instruction_clone!(vector_float, vector_float, _make_empty, Vec, 0); -make_instruction_clone!(vector_string, vector_string, _make_empty, Vec>, 0); -make_instruction_clone!(vector_boolean, vector_boolean, _make_empty, Vec, 0); -make_instruction_clone!(vector_char, vector_char, _make_empty, Vec, 0); -make_instruction_clone!(string, string, _make_empty, Vec, 0); /// Checks if a vector is empty. Pushes true if is, false otherwise -fn _is_empty(vals: Vec>) -> Option { - Some(vals[0].is_empty()) +fn _is_empty(vals: Vec) -> Option { + Some(vals.is_empty()) } -make_instruction_clone!(vector_int, boolean, _is_empty, Vec, 1); -make_instruction_clone!(vector_float, boolean, _is_empty, Vec, 1); -make_instruction_clone!(vector_string, boolean, _is_empty, Vec>, 1); -make_instruction_clone!(vector_boolean, boolean, _is_empty, Vec, 1); -make_instruction_clone!(vector_char, boolean, _is_empty, Vec, 1); -make_instruction_clone!(string, boolean, _is_empty, Vec, 1); /// Checks if a vector contains a primitive. True if does, false otherwise -fn _contains(vals: Vec>, auxs: Vec) -> Option +fn _contains(vals: Vec, prim: T) -> Option where T: Eq, { - Some(vals[0].contains(&auxs[0])) + Some(vals.contains(&prim)) } -make_instruction_aux!(vector_int, boolean, _contains, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - boolean, - _contains, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - boolean, - _contains, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - boolean, - _contains, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!(vector_char, boolean, _contains, Vec, 1, char, 1, char); -make_instruction_aux!(string, boolean, _contains, Vec, 1, char, 1, char); /// Checks if a vector contains another vector in no order. True if does, false otherwise -fn _contains_vector_non_contiguous(vals: Vec>) -> Option +fn _contains_vector_non_contiguous(vec0: Vec, vec1: Vec) -> Option where T: Eq + Hash, { - let hashset: HashSet<&T> = vals[1].iter().collect(); - Some(vals[0].iter().all(|x| hashset.contains(x))) + let hashset: HashSet<&T> = vec1.iter().collect(); + Some(vec0.iter().all(|x| hashset.contains(x))) } -make_instruction_clone!( - vector_int, - boolean, - _contains_vector_non_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_float, - boolean, - _contains_vector_non_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_string, - boolean, - _contains_vector_non_contiguous, - Vec>, - 2 -); -make_instruction_clone!( - vector_boolean, - boolean, - _contains_vector_non_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_char, - boolean, - _contains_vector_non_contiguous, - Vec, - 2 -); -make_instruction_clone!( - string, - boolean, - _contains_vector_non_contiguous, - Vec, - 2 -); /// Checks if a vector contains another contiguous vector. True if does, false otherwise -fn _contains_vector_contiguous(vals: Vec>) -> Option +fn _contains_vector_contiguous(vec0: Vec, vec1: Vec) -> Option where T: Eq, { - if vals[0].is_empty() { + if vec0.is_empty() { return Some(true); // would argue the empty set is in everything } - Some(vals[1].windows(vals[0].len()).any(|x| x == vals[0])) + Some(vec1.windows(vec0.len()).any(|x| x == vec0)) } -make_instruction_clone!( - vector_int, - boolean, - _contains_vector_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_float, - boolean, - _contains_vector_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_string, - boolean, - _contains_vector_contiguous, - Vec>, - 2 -); -make_instruction_clone!( - vector_boolean, - boolean, - _contains_vector_contiguous, - Vec, - 2 -); -make_instruction_clone!( - vector_char, - boolean, - _contains_vector_contiguous, - Vec, - 2 -); -make_instruction_clone!(string, boolean, _contains_vector_contiguous, Vec, 2); /// Returns the index of a primitive in a vector, pushes result to int stack -fn _index_of(vals: Vec>, auxs: Vec) -> Option +fn _index_of(vals: Vec, prim: T) -> Option where T: Clone + Eq, { - let temp_vec = &vals[0]; - let temp_aux = &auxs[0]; + let temp_vec = &vals; + let temp_aux = &prim; if let Some(idx) = temp_vec.iter().position(|r| r == temp_aux) { return Some(idx as i128); } Some(-1) } -make_instruction_aux!(vector_int, int, _index_of, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - int, - _index_of, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - int, - _index_of, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - int, - _index_of, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!(vector_char, int, _index_of, Vec, 1, char, 1, char); -make_instruction_aux!(string, int, _index_of, Vec, 1, char, 1, char); /// Finds the index of the start of one vector in another. Searches in contiguous space. -fn _index_of_vector(vals: Vec>) -> Option +fn _index_of_vector(vec0: Vec, vec1: Vec) -> Option where T: Eq, { - if vals[0].is_empty() { + if vec0.is_empty() { return Some(0); } - if let Some(val) = vals[1].windows(vals[0].len()).position(|x| x == vals[0]) { + if let Some(val) = vec1.windows(vec0.len()).position(|x| x == vec0) { return Some(val as i128); } Some(-1) } -make_instruction_clone!(vector_int, int, _index_of_vector, Vec, 2); -make_instruction_clone!(vector_float, int, _index_of_vector, Vec, 2); -make_instruction_clone!(vector_string, int, _index_of_vector, Vec>, 2); -make_instruction_clone!(vector_boolean, int, _index_of_vector, Vec, 2); -make_instruction_clone!(vector_char, int, _index_of_vector, Vec, 2); -make_instruction_clone!(string, int, _index_of_vector, Vec, 2); /// Counts the amount of a primitive in a vector -fn _occurrences_of(vals: Vec>, auxs: Vec) -> Option +fn _occurrences_of(vals: Vec, prim: T) -> Option where T: Clone + Eq, { - Some( - vals[0] - .clone() - .into_iter() - .filter(|r| r == &auxs[0]) - .count() as i128, - ) + Some(vals.into_iter().filter(|r| r == &prim).count() as i128) } -make_instruction_aux!(vector_int, int, _occurrences_of, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - int, - _occurrences_of, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - int, - _occurrences_of, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - int, - _occurrences_of, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!( - vector_char, - int, - _occurrences_of, - Vec, - 1, - char, - 1, - char -); -make_instruction_aux!(string, int, _occurrences_of, Vec, 1, char, 1, char); /// Counts the amount of continuous occurrences one vector appears in another. -fn _occurrences_of_vector(vals: Vec>) -> Option +fn _occurrences_of_vector(vec0: Vec, vec1: Vec) -> Option where T: Eq, { - if vals[0].is_empty() { + if vec0.is_empty() { return Some(0); } - Some( - vals[1] - .windows(vals[0].len()) - .filter(|x| x == &vals[0]) - .count() as i128, - ) + Some(vec1.windows(vec0.len()).filter(|x| x == &vec0).count() as i128) } -make_instruction_clone!(vector_int, int, _occurrences_of_vector, Vec, 2); -make_instruction_clone!(vector_float, int, _occurrences_of_vector, Vec, 2); -make_instruction_clone!( - vector_string, - int, - _occurrences_of_vector, - Vec>, - 2 -); -make_instruction_clone!(vector_boolean, int, _occurrences_of_vector, Vec, 2); -make_instruction_clone!(vector_char, int, _occurrences_of_vector, Vec, 2); -make_instruction_clone!(string, int, _occurrences_of_vector, Vec, 2); /// Pushes the values inside a vector separated into individual vectors back to /// the stack. -fn _parse_to_prim(vals: Vec>) -> Option>> +fn _parse_to_prim(vals: Vec) -> Option>> where T: Clone, Vec: FromIterator, { - Some(vals[0].clone().into_iter().map(|x| vec![x]).collect()) + Some(vals.clone().into_iter().map(|x| vec![x]).collect()) } -make_instruction_mult!(vector_int, vector_int, _parse_to_prim, Vec, 1); -make_instruction_mult!(vector_float, vector_float, _parse_to_prim, Vec, 1); -make_instruction_mult!( - vector_string, - vector_string, - _parse_to_prim, - Vec>, - 1 -); -make_instruction_mult!(vector_boolean, vector_boolean, _parse_to_prim, Vec, 1); -make_instruction_mult!(vector_char, vector_char, _parse_to_prim, Vec, 1); -make_instruction_mult!(string, string, _parse_to_prim, Vec, 1); /// Sets the nth index in a vector. N from the int stack. -fn _set_nth(vals: Vec>, aux0: Vec, aux1: Vec) -> Option> +fn _set_nth(vals: Vec, idx: i128, prim: T) -> Option> where T: Clone, { - let mut temp_vec = vals[0].clone(); - let idx = bounded_idx(aux1[0], temp_vec.len()); - temp_vec.insert(idx, aux0[0].clone()); + let mut temp_vec = vals.clone(); + let idx = bounded_idx(idx, temp_vec.len()); + temp_vec.insert(idx, prim); Some(temp_vec) } -make_instruction_aux2!( - vector_int, - vector_int, - _set_nth, - Vec, - 1, - int, - 1, - i128, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_float, - vector_float, - _set_nth, - Vec, - 1, - float, - 1, - Decimal, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_string, - vector_string, - _set_nth, - Vec>, - 1, - string, - 1, - Vec, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_boolean, - vector_boolean, - _set_nth, - Vec, - 1, - boolean, - 1, - bool, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_char, - vector_char, - _set_nth, - Vec, - 1, - char, - 1, - char, - int, - 1, - i128 -); -make_instruction_aux2!( - string, - string, - _set_nth, - Vec, - 1, - char, - 1, - char, - int, - 1, - i128 -); -/// Splits a vector based the first occurence of a primitive -fn _split_on(vals: Vec>, auxs: Vec) -> Option>> +/// Splits a vector based on the first occurence of a primitive +fn _split_on(vals: Vec, prim: T) -> Option>> where T: Clone + Eq, Vec: FromIterator, { let mut final_vec = vec![]; let mut temp_vec = vec![]; - for val in vals[0].iter() { - if &auxs[0] == val { + for val in vals.iter() { + if &prim == val { final_vec.push(temp_vec.clone()); temp_vec.clear(); continue; @@ -656,59 +339,8 @@ where } Some(final_vec) } -make_instruction_mult_aux!( - vector_int, - vector_int, - _split_on, - Vec, - 1, - int, - 1, - i128 -); -make_instruction_mult_aux!( - vector_float, - vector_float, - _split_on, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_mult_aux!( - vector_string, - vector_string, - _split_on, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_mult_aux!( - vector_boolean, - vector_boolean, - _split_on, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_mult_aux!( - vector_char, - vector_char, - _split_on, - Vec, - 1, - char, - 1, - char -); -make_instruction_mult_aux!(string, string, _split_on, Vec, 1, char, 1, char); -/*/// Splits a vector based the first occurence of a primitive +/*/// Splits a vector based the first occurrence of a primitive fn _split_on_vector(vals: Vec>) -> Option>> where T: Clone + Eq, @@ -730,153 +362,35 @@ where final_vec.push(temp_vec); } Some(final_vec) -} -make_instruction_mult!(vector_int, vector_int, _split_on_vector, Vec, 1); -make_instruction_mult!( - vector_float, - vector_float, - _split_on_vector, - Vec, - 1 -); -make_instruction_mult!( - vector_string, - vector_string, - _split_on_vector, - Vec>, - 1 -); -make_instruction_mult!( - vector_boolean, - vector_boolean, - _split_on_vector, - Vec, - 1 -); -make_instruction_mult!(vector_char, vector_char, _split_on_vector, Vec, 1); -make_instruction_mult!(string, string, _split_on_vector, Vec, 1);*/ +}*/ /// Replaces all values in a vector with respect to two primitives. The first primitive is /// the search value and the second value is the one to replace. -fn _replace(mut vals: Vec>, auxs: Vec) -> Option> +fn _replace(mut vals: Vec, from: T, to: T) -> Option> where T: Clone, for<'a> &'a T: Eq, Vec: FromIterator, { - let temp_vec = &mut vals[0]; + let temp_vec = &mut vals; let ret_vec: Vec = temp_vec .iter() - .map(|x| { - if x == &auxs[0] { - auxs[1].clone() - } else { - x.clone() - } - }) + .map(|x| if x == &from { to.clone() } else { x.clone() }) .collect(); Some(ret_vec) } -make_instruction_aux!(vector_int, vector_int, _replace, Vec, 1, int, 2, i128); -make_instruction_aux!( - vector_float, - vector_float, - _replace, - Vec, - 1, - float, - 2, - Decimal -); -make_instruction_aux!( - vector_string, - vector_string, - _replace, - Vec>, - 1, - string, - 2, - Vec -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _replace, - Vec, - 1, - boolean, - 2, - bool -); -make_instruction_aux!( - vector_char, - vector_char, - _replace, - Vec, - 1, - char, - 2, - char -); -make_instruction_aux!(string, string, _replace, Vec, 1, char, 2, char); -/// Removes all values in a vector with respect to a primitives. If is equal, remove it. -fn _remove(vals: Vec>, auxs: Vec) -> Option> +/// Removes all values in a vector with respect to a primitive. If is equal, remove it. +fn _remove(vals: Vec, prim: T) -> Option> where T: Clone, for<'a> &'a T: Eq, Vec: FromIterator, { - let temp_vec = &vals[0]; - let ret_vec = temp_vec - .iter() - .filter(|&x| x != &auxs[0]) - .cloned() - .collect(); + let temp_vec = &vals; + let ret_vec = temp_vec.iter().filter(|&x| x != &prim).cloned().collect(); Some(ret_vec) } -make_instruction_aux!(vector_int, vector_int, _remove, Vec, 1, int, 1, i128); -make_instruction_aux!( - vector_float, - vector_float, - _remove, - Vec, - 1, - float, - 1, - Decimal -); -make_instruction_aux!( - vector_string, - vector_string, - _remove, - Vec>, - 1, - string, - 1, - Vec -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _remove, - Vec, - 1, - boolean, - 1, - bool -); -make_instruction_aux!( - vector_char, - vector_char, - _remove, - Vec, - 1, - char, - 1, - char -); -make_instruction_aux!(string, string, _remove, Vec, 1, char, 1, char); /// Iterates over a vector using an instruction from the exec stack. macro_rules! make_iterate { @@ -891,11 +405,11 @@ macro_rules! make_iterate { state.exec.pop(); return; } else if first_vec.len() == 1 { - state.$prim_stack.push(first_vec[0]); + state.$prim_stack.push(first_vec[0].clone()); return; } else { let top_exec = state.exec[state.exec.len() - 1].clone(); - let first_prim = first_vec[0]; + let first_prim = first_vec[0].clone(); state.exec.push(Gene::StateFunc([< $vec_stack _iterate >])); state.exec.push(Gene::$vec_gene(first_vec[1..].to_vec())); state.exec.push(top_exec); @@ -907,241 +421,94 @@ macro_rules! make_iterate { } make_iterate!(vector_int, int, GeneVectorInt); make_iterate!(vector_float, float, GeneVectorFloat); -//make_iterate!(vector_string, string, GeneVectorString); +make_iterate!(vector_string, string, GeneVectorString); make_iterate!(vector_boolean, boolean, GeneVectorBoolean); make_iterate!(vector_char, char, GeneVectorChar); -//make_iterate!(string, string, GeneString); +make_iterate!(string, char, GeneString); /// Sorts a vector -fn _sort(mut vals: Vec>) -> Option> +fn _sort(mut vals: Vec) -> Option> where - T: NumericTrait + Clone, + T: NumericTrait, { - vals[0].sort(); - Some(vals[0].clone()) + vals.sort(); + Some(vals) } -make_instruction_clone!(vector_int, vector_int, _sort, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _sort, Vec, 1); /// Sorts a vector and reverses it -fn _sort_reverse(mut vals: Vec>) -> Option> +fn _sort_reverse(mut vals: Vec) -> Option> where - T: NumericTrait + Clone, + T: NumericTrait, { - vals[0].sort(); - vals[0].reverse(); - Some(vals[0].clone()) + vals.sort(); + vals.reverse(); + Some(vals) } -make_instruction_clone!(vector_int, vector_int, _sort_reverse, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _sort_reverse, Vec, 1); /// Inserts a primitive into a vector at a given point from the int stack -fn _insert(mut vals: Vec>, auxs: Vec, auxs2: Vec) -> Option> -where - T: Clone, -{ - let vec_len = vals[0].len(); - vals[0].insert(bounded_idx(auxs2[0], vec_len), auxs[0].clone()); - Some(vals[0].clone()) +fn _insert(mut vals: Vec, idx: i128, prim: T) -> Option> { + let vec_len = vals.len(); + vals.insert(bounded_idx(idx, vec_len), prim); + Some(vals) } -make_instruction_aux2!( - vector_int, - vector_int, - _insert, - Vec, - 1, - int, - 1, - i128, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_float, - vector_float, - _insert, - Vec, - 1, - float, - 1, - Decimal, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_string, - vector_string, - _insert, - Vec>, - 1, - string, - 1, - Vec, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_boolean, - vector_boolean, - _insert, - Vec, - 1, - boolean, - 1, - bool, - int, - 1, - i128 -); -make_instruction_aux2!( - vector_char, - vector_char, - _insert, - Vec, - 1, - char, - 1, - char, - int, - 1, - i128 -); -make_instruction_aux2!( - string, - string, - _insert, - Vec, - 1, - char, - 1, - char, - int, - 1, - i128 -); /// Inserts one vector into another based on an index. -fn _insert_vector(mut vals: Vec>, auxs: Vec) -> Option> +fn _insert_vector(vec0: Vec, mut vec1: Vec, idx: i128) -> Option> where T: Clone, { - let vec_len = vals[0].len(); - let idx = bounded_idx(auxs[0], vec_len); - let insert_list = vals[0].clone(); - vals[1].splice(idx..idx, insert_list); - Some(vals[1].clone()) + let bound_idx = bounded_idx(idx, vec0.len()); + vec1.splice(bound_idx..bound_idx, vec0); + Some(vec1) } -make_instruction_aux!( - vector_int, - vector_int, - _insert_vector, - Vec, - 2, - int, - 1, - i128 -); -make_instruction_aux!( - vector_float, - vector_float, - _insert_vector, - Vec, - 2, - int, - 1, - i128 -); -make_instruction_aux!( - vector_string, - vector_string, - _insert_vector, - Vec>, - 2, - int, - 1, - i128 -); -make_instruction_aux!( - vector_boolean, - vector_boolean, - _insert_vector, - Vec, - 2, - int, - 1, - i128 -); -make_instruction_aux!( - vector_char, - vector_char, - _insert_vector, - Vec, - 2, - int, - 1, - i128 -); -make_instruction_aux!(string, string, _insert_vector, Vec, 2, int, 1, i128); /// Takes the mean of a vector -fn _mean(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _mean(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } let mut fin_num = T::zero(); - for num in vals[0].clone().into_iter() { + for num in vals.clone().into_iter() { fin_num = fin_num + num; } - Some(fin_num.div(T::from_usize(vals[0].len()))) + Some(fin_num.div(T::from_usize(vals.len()))) } -make_instruction_clone!(vector_int, int, _mean, Vec, 1); -make_instruction_clone!(vector_float, float, _mean, Vec, 1); /// Takes the max of a vector -fn _maximum(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _maximum(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } - Some(vals[0].iter().max()?.clone()) + vals.into_iter().max() } -make_instruction_clone!(vector_int, int, _maximum, Vec, 1); -make_instruction_clone!(vector_float, float, _maximum, Vec, 1); /// Takes the min of a vector -fn _minimum(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _minimum(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } - Some(vals[0].iter().min()?.clone()) + vals.into_iter().min() } -make_instruction_clone!(vector_int, int, _minimum, Vec, 1); -make_instruction_clone!(vector_float, float, _minimum, Vec, 1); /// Takes the sum of a vector -fn _sum(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _sum(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } let mut fin_num = T::zero(); - for num in vals[0].clone().into_iter() { + for num in vals.clone().into_iter() { fin_num = fin_num + num; } Some(fin_num) } -make_instruction_clone!(vector_int, int, _sum, Vec, 1); -make_instruction_clone!(vector_float, float, _sum, Vec, 1); /// Takes the mode of a vector -fn _mode(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _mode(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } let mut counts = HashMap::new(); - vals[0] - .iter() + vals.iter() .max_by_key(|&x| { let count = counts.entry(x).or_insert(0); *count += 1; @@ -1149,38 +516,32 @@ fn _mode(vals: Vec>) -> Option }) .copied() } -make_instruction_clone!(vector_int, int, _mode, Vec, 1); -make_instruction_clone!(vector_float, float, _mode, Vec, 1); /// Adds the squares of all values in a vector and then takes the square root -fn _two_norm(vals: Vec>) -> Option { - if vals[0].is_empty() { +fn _two_norm(vals: Vec) -> Option { + if vals.is_empty() { return Some(T::zero()); } let mut fin_num = T::zero(); - for num in vals[0].clone().into_iter() { + for num in vals.clone().into_iter() { fin_num = fin_num + (num.clone() * num); } fin_num.safe_sqrt() } -make_instruction_clone!(vector_int, int, _two_norm, Vec, 1); -make_instruction_clone!(vector_float, float, _two_norm, Vec, 1); /// Takes the cumulative sum of a vector -fn _cumulative_sum(vals: Vec>) -> Option> { - if vals[0].is_empty() { +fn _cumulative_sum(vals: Vec) -> Option> { + if vals.is_empty() { return Some(vec![]); } let mut fin_num = T::zero(); let mut ret_vec = vec![]; - for num in vals[0].clone().into_iter() { + for num in vals.clone().into_iter() { fin_num = fin_num + num; ret_vec.push(fin_num.clone()); } Some(ret_vec) } -make_instruction_clone!(vector_int, vector_int, _cumulative_sum, Vec, 1); -make_instruction_clone!(vector_float, vector_float, _cumulative_sum, Vec, 1); /* /// Takes the cumulative mean of a vector fn _cumulative_mean(vals: Vec>) -> Option> { @@ -1230,8 +591,43 @@ macro_rules! make_vector_instructions { make_instruction_new!(_drop_last, $stack, $stack, $stack, int); make_instruction_new!(_length, $stack, int, $stack); make_instruction_new!(_reverse, $stack, $stack, $stack); - //make_instruction_new_aux!(_push_all, $stack, $prim_stack, $stack); - //make_instruction_empty!(_make_empty, $stack, $stack, $stack); + make_instruction_new_aux!(_push_all, $stack, $prim_stack, $stack); + // _make_empty would go here + make_instruction_new!(_is_empty, $stack, boolean, $stack); + make_instruction_new!(_contains, $stack, boolean, $stack, $prim_stack); + make_instruction_new!( + _contains_vector_non_contiguous, + $stack, + boolean, + $stack, + $stack + ); + make_instruction_new!(_contains_vector_contiguous, $stack, boolean, $stack, $stack); + make_instruction_new!(_index_of, $stack, int, $stack, $prim_stack); + make_instruction_new!(_index_of_vector, $stack, int, $stack, $stack); + make_instruction_new!(_occurrences_of, $stack, int, $stack, $prim_stack); + make_instruction_new!(_occurrences_of_vector, $stack, int, $stack, $stack); + make_instruction_new_aux!(_parse_to_prim, $stack, $stack, $stack); + make_instruction_new!(_set_nth, $stack, $stack, $stack, int, $prim_stack); + make_instruction_new_aux!(_split_on, $stack, $stack, $stack, $prim_stack); + make_instruction_new!(_replace, $stack, $stack, $stack, $prim_stack, $prim_stack); + make_instruction_new!(_remove, $stack, $stack, $stack, $prim_stack); + make_instruction_new!(_insert, $stack, $stack, $stack, int, $prim_stack); + make_instruction_new!(_insert_vector, $stack, $stack, $stack, $stack, int); + }; +} + +macro_rules! make_numeric_vector_instructions { + ($stack:ident, $prim_stack:ident) => { + make_instruction_new!(_sort, $stack, $stack, $stack); + make_instruction_new!(_sort_reverse, $stack, $stack, $stack); + make_instruction_new!(_mean, $stack, $prim_stack, $stack); + make_instruction_new!(_maximum, $stack, $prim_stack, $stack); + make_instruction_new!(_minimum, $stack, $prim_stack, $stack); + make_instruction_new!(_sum, $stack, $prim_stack, $stack); + make_instruction_new!(_mode, $stack, $prim_stack, $stack); + make_instruction_new!(_two_norm, $stack, $prim_stack, $stack); + make_instruction_new!(_cumulative_sum, $stack, $stack, $stack); }; } @@ -1244,12 +640,19 @@ macro_rules! all_vector_instructions { make_vector_instructions!(vector_char, char); make_vector_instructions!(string, char); - // Instructions that don't work on every stack - make_instruction_new_aux!(_push_all, vector_int, int, vector_int); - make_instruction_new_aux!(_push_all, vector_float, float, vector_float); - make_instruction_new_aux!(_push_all, vector_boolean, boolean, vector_boolean); - make_instruction_new_aux!(_push_all, vector_char, char, vector_char); - make_instruction_new_aux!(_push_all, string, char, string); + // Need to pass a stack type to the empty! macro, + // wont work in the make_vector_instructions macro without + // bloating it a bit more + make_instruction_empty!(_make_empty, vector_int, vector_int, i128); + make_instruction_empty!(_make_empty, vector_float, vector_float, Decimal); + make_instruction_empty!(_make_empty, vector_string, vector_string, Vec); + make_instruction_empty!(_make_empty, vector_boolean, vector_boolean, bool); + make_instruction_empty!(_make_empty, vector_char, vector_char, char); + make_instruction_empty!(_make_empty, string, string, char); + + // Numeric only vector instructions + make_numeric_vector_instructions!(vector_int, int); + make_numeric_vector_instructions!(vector_float, float); }; } all_vector_instructions!(); @@ -1808,6 +1211,15 @@ mod tests { assert_eq!(vec![0], test_state.int); } + #[test] + fn parse_to_prim_test() { + let mut test_state = EMPTY_STATE; + + test_state.vector_int = vec![vec![0, 1, 2]]; + vector_int_parse_to_prim(&mut test_state); + assert_eq!(vec![vec![0], vec![1], vec![2]], test_state.vector_int); + } + #[test] fn set_nth_test() { let mut test_state = EMPTY_STATE; @@ -1830,15 +1242,6 @@ mod tests { assert_eq!(vec![vec![true, false, true]], test_state.vector_boolean); } - #[test] - fn parse_to_prim_test() { - let mut test_state = EMPTY_STATE; - - test_state.vector_int = vec![vec![0, 1, 2]]; - vector_int_parse_to_prim(&mut test_state); - assert_eq!(vec![vec![0], vec![1], vec![2]], test_state.vector_int); - } - #[test] fn split_on_test() { let mut test_state = EMPTY_STATE; @@ -2051,7 +1454,7 @@ mod tests { } #[test] - fn sqrt_test() { + fn two_norm_test() { let mut test_state = EMPTY_STATE; test_state.vector_int = vec![vec![5, 5, 5, 5]]; From 082de0899855e2f560199cb1323e7a8f7bdbc50d Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 20:47:37 -0500 Subject: [PATCH 19/21] 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), } From 7f43b62808158ab5501456202e6b70a4e3544dcd Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 22:12:50 -0500 Subject: [PATCH 20/21] instructions are done, time to put them into a list --- src/instructions/common.rs | 168 ++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 4 deletions(-) diff --git a/src/instructions/common.rs b/src/instructions/common.rs index 9ef4e3b..e80e81c 100644 --- a/src/instructions/common.rs +++ b/src/instructions/common.rs @@ -128,20 +128,91 @@ macro_rules! yank { if state.int.is_empty() || state.$in_stack.is_empty() { return; } - let in_stack_len = state.$in_stack.len(); let in_stack_name = stringify!($in_stack); - if in_stack_name == "int" && in_stack_len < 2 { + if in_stack_name == "int" && state.$in_stack.len() < 2 { return; } // 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); + let pre_idx = state.int.pop().unwrap(); + let idx = min_max_bounds(pre_idx, state.$in_stack.len()); + let item = state.$in_stack.remove(state.$in_stack.len() - 1 - idx); state.$in_stack.push(item); } } }; } +macro_rules! yank_dup { + ($in_stack:ident) => { + paste::item! { + pub fn [< $in_stack _yank_dup >] (state: &mut PushState) { + if state.int.is_empty() || state.$in_stack.is_empty() { + return; + } + let in_stack_name = stringify!($in_stack); + if in_stack_name == "int" && state.$in_stack.len() < 2 { + return; + } + // no -1 from in_stack_len, 1 subtracted within the min_max_bounds function + let pre_idx = state.int.pop().unwrap(); + let idx = min_max_bounds(pre_idx, state.$in_stack.len()); + let item = state.$in_stack[state.$in_stack.len() - 1 - idx].clone(); + state.$in_stack.push(item); + } + } + }; +} + +macro_rules! shove { + ($in_stack:ident) => { + paste::item! { + pub fn [< $in_stack _shove >] (state: &mut PushState) { + if state.int.is_empty() || state.$in_stack.is_empty() { + return; + } + let in_stack_name = stringify!($in_stack); + if in_stack_name == "int" && state.$in_stack.len() < 2 { + return; + } + let pre_idx = state.int.pop().unwrap(); + let idx = min_max_bounds(pre_idx, state.$in_stack.len()); + let item = state.$in_stack.pop().unwrap(); + state.$in_stack.insert(state.$in_stack.len() - idx, item); + } + } + }; +} + +macro_rules! shove_dup { + ($in_stack:ident) => { + paste::item! { + pub fn [< $in_stack _shove_dup >] (state: &mut PushState) { + if state.int.is_empty() || state.$in_stack.is_empty() { + return; + } + let in_stack_name = stringify!($in_stack); + if in_stack_name == "int" && state.$in_stack.len() < 2 { + return; + } + let pre_idx = state.int.pop().unwrap(); + let idx = min_max_bounds(pre_idx, state.$in_stack.len()); + let item = state.$in_stack[state.$in_stack.len() - 1].clone(); + state.$in_stack.insert(state.$in_stack.len() - idx, item); + } + } + }; +} + +macro_rules! is_state_empty { + ($in_stack:ident) => { + paste::item! { + pub fn [< $in_stack _is_empty >] (state: &mut PushState) { + state.boolean.push(state.$in_stack.is_empty()); + } + } + }; +} + macro_rules! make_common_instructions { ($stack:ident) => { pop!($stack); @@ -154,6 +225,10 @@ macro_rules! make_common_instructions { flush_state!($stack); stack_depth!($stack); yank!($stack); + yank_dup!($stack); + shove!($stack); + shove_dup!($stack); + is_state_empty!($stack); }; } @@ -291,5 +366,90 @@ 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); + + test_state.int = vec![1, 2]; + int_yank(&mut test_state); + assert_eq!(vec![1], test_state.int); + + test_state.int = vec![0]; + test_state.boolean = vec![true, true, true, false]; + boolean_yank(&mut test_state); + assert_eq!(vec![true, true, true, false], test_state.boolean); + } + + #[test] + fn yank_dup_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![1, 2, 3, 4, 5, 6, 7, 8, 2]; + int_yank_dup(&mut test_state); + assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8, 6], test_state.int); + + test_state.int = vec![1, 2]; + int_yank_dup(&mut test_state); + assert_eq!(vec![1, 1], test_state.int); + + test_state.int = vec![0]; + test_state.boolean = vec![true, true, true, false]; + boolean_yank_dup(&mut test_state); + assert_eq!(vec![true, true, true, false, false], test_state.boolean); + + test_state.int = vec![0]; + int_yank_dup(&mut test_state); + assert_eq!(vec![0], test_state.int); + } + + #[test] + fn shove_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![1, 2, 3, 4, 5, 1]; + int_shove(&mut test_state); + assert_eq!(vec![1, 2, 3, 5, 4], test_state.int); + + test_state.int = vec![1, 2, 3, 4, 5, 0]; + int_shove(&mut test_state); + assert_eq!(vec![1, 2, 3, 4, 5], test_state.int); + + test_state.int = vec![-1]; + test_state.boolean = vec![true, true, true, false]; + boolean_shove(&mut test_state); + assert_eq!(vec![true, true, false, true], test_state.boolean); + } + + #[test] + fn shove_dup_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![1, 1, 2, 3, 2]; + int_shove_dup(&mut test_state); + assert_eq!(vec![1, 1, 3, 2, 3], test_state.int); + + test_state.int = vec![1, 2, 3, 4, 5, 1]; + int_shove_dup(&mut test_state); + assert_eq!(vec![1, 2, 3, 4, 5, 5], test_state.int); + + test_state.int = vec![1, 2, 3, 4, 5, 0]; + int_shove_dup(&mut test_state); + assert_eq!(vec![1, 2, 3, 4, 5, 5], test_state.int); + + test_state.int = vec![-1]; + test_state.boolean = vec![true, true, true, false]; + boolean_shove_dup(&mut test_state); + assert_eq!(vec![true, true, true, false, false], test_state.boolean); + } + + #[test] + fn is_state_empty_test() { + let mut test_state = EMPTY_STATE; + + test_state.int = vec![1, 2]; + int_is_empty(&mut test_state); + assert_eq!(vec![false], test_state.boolean); + test_state.boolean.clear(); + + test_state.int = vec![]; + int_is_empty(&mut test_state); + assert_eq!(vec![true], test_state.boolean); } } From 4fb19410c0e761bc58a96640f361068b601e39ea Mon Sep 17 00:00:00 2001 From: Rowan Torbitzky-Lane Date: Sat, 19 Apr 2025 23:05:41 -0500 Subject: [PATCH 21/21] no more all common instructions --- src/instructions/common.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/instructions/common.rs b/src/instructions/common.rs index e80e81c..0b1da25 100644 --- a/src/instructions/common.rs +++ b/src/instructions/common.rs @@ -232,23 +232,18 @@ macro_rules! make_common_instructions { }; } -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!(); +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); #[cfg(test)] mod tests {