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); +}