make_instruction_new works, time to refactor
This commit is contained in:
parent
6744896494
commit
f13cd7ad20
@ -1,10 +1,39 @@
|
|||||||
use crate::utils::canextractstate::Extract;
|
use crate::utils::instruction::Extract;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::parse_macro_input;
|
use syn::parse_macro_input;
|
||||||
|
|
||||||
mod utils;
|
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<i128> {
|
||||||
|
/// 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]
|
#[proc_macro]
|
||||||
pub fn run_instruction(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);
|
let f = parse_macro_input!(input as Extract);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
// This Stack that isn't repeated is the desired output stack.
|
//! This Stack that isn't repeated is the desired output stack.
|
||||||
// Extract: Function, Stack, State, (`,` Stack)*
|
//! Extract: Function, Stack, State, (`,` Stack)* ;?
|
||||||
//
|
//!
|
||||||
// Function: identifier
|
//! Function: identifier
|
||||||
//
|
//!
|
||||||
// State: identifier
|
//! State: identifier
|
||||||
//
|
//!
|
||||||
// Stack: identifier
|
//! Stack: identifier
|
||||||
|
//!
|
||||||
|
//! Aux: expression
|
||||||
|
|
||||||
use crate::utils::parse_zero_or_more;
|
use crate::utils::parse_zero_or_more;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
@ -13,11 +15,20 @@ use quote::{ToTokens, quote};
|
|||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use syn::parse::{Parse, ParseStream};
|
use syn::parse::{Parse, ParseStream};
|
||||||
|
|
||||||
|
/// Checks if there is a semicolon at the end
|
||||||
|
fn parse_aux<T: Parse>(input: ParseStream) -> bool {
|
||||||
|
if let Ok(_) = input.parse::<syn::Token![;]>() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Extract {
|
pub struct Extract {
|
||||||
func: Function,
|
func: Function,
|
||||||
out_stack: Stack,
|
out_stack: Stack,
|
||||||
state: State,
|
state: State,
|
||||||
stacks: Vec<Stack>,
|
stacks: Vec<Stack>,
|
||||||
|
aux: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Extract {
|
impl Parse for Extract {
|
||||||
@ -26,11 +37,13 @@ impl Parse for Extract {
|
|||||||
let out_stack = input.parse()?;
|
let out_stack = input.parse()?;
|
||||||
let state = input.parse()?;
|
let state = input.parse()?;
|
||||||
let stacks = parse_zero_or_more(input);
|
let stacks = parse_zero_or_more(input);
|
||||||
|
let aux = parse_aux::<syn::Token![,]>(input);
|
||||||
Ok(Extract {
|
Ok(Extract {
|
||||||
func,
|
func,
|
||||||
out_stack,
|
out_stack,
|
||||||
state,
|
state,
|
||||||
stacks,
|
stacks,
|
||||||
|
aux,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +54,7 @@ impl ToTokens for Extract {
|
|||||||
let inner_out_stack = &self.out_stack.0;
|
let inner_out_stack = &self.out_stack.0;
|
||||||
let inner_state = &self.state.0;
|
let inner_state = &self.state.0;
|
||||||
let stacks = &self.stacks;
|
let stacks = &self.stacks;
|
||||||
|
let aux = &self.aux;
|
||||||
|
|
||||||
let mut counts = Vec::new();
|
let mut counts = Vec::new();
|
||||||
for stack in stacks {
|
for stack in stacks {
|
||||||
@ -60,10 +74,20 @@ impl ToTokens for Extract {
|
|||||||
quote! { #inner_state.#inner_stack.pop().unwrap() }
|
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! {
|
tokens.extend(quote! {
|
||||||
if true #(&& (#conditions))* {
|
if true #(&& (#conditions))* {
|
||||||
let result = vec![#inner_func(#(#values, )*)];
|
#aux_run
|
||||||
#inner_state.#inner_out_stack.extend(result.iter());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use syn::parse::{Parse, ParseStream};
|
use syn::parse::{Parse, ParseStream};
|
||||||
|
|
||||||
pub mod canextractstate;
|
pub mod instruction;
|
||||||
|
|
||||||
fn parse_zero_or_more<T: Parse>(input: ParseStream) -> Vec<T> {
|
fn parse_zero_or_more<T: Parse>(input: ParseStream) -> Vec<T> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
@ -316,14 +316,15 @@ pub mod macros {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts values from passed state based on an amount of stacks passed.
|
/// Runs a function and ensures needed variables are extracted from a state without error while
|
||||||
macro_rules! extract_state_vals {
|
/// returning multiple variables from the function
|
||||||
($state:ident) => {};
|
macro_rules! make_instruction_new_aux {
|
||||||
($state:ident, $stack:ident) => {
|
($func:ident, $prefix:ident, $out_stack:ident, $($stacks:ident), *) => {
|
||||||
$state.$stack.pop().unwrap()
|
paste::item! {
|
||||||
};
|
pub fn [< $prefix $func >] (state: &mut PushState) {
|
||||||
($state:ident, $stack:ident, $($rest:ident), *) => {
|
run_instruction!($func, $out_stack, state, $($stacks), *, ;);
|
||||||
($state.$stack.pop().unwrap(), $(extract_state_vals!($state, $rest)), *)
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,28 +779,26 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::push::state::EMPTY_STATE;
|
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]
|
#[test]
|
||||||
fn make_instruction_new_test() {
|
fn make_instruction_new_test() {
|
||||||
fn _test_func(x: i128, y: i128) -> i128 {
|
fn _test_func(x: i128, y: i128) -> i128 {
|
||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _aux_test_func(x: i128, y: i128) -> Vec<i128> {
|
||||||
|
vec![x + y, x - y]
|
||||||
|
}
|
||||||
|
|
||||||
let mut test_state = EMPTY_STATE;
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
test_state.int = vec![1, 2];
|
test_state.int = vec![1, 2];
|
||||||
make_instruction_new!(_test_func, int, int, int, int);
|
make_instruction_new!(_test_func, int, int, int, int);
|
||||||
int_test_func(&mut test_state);
|
int_test_func(&mut test_state);
|
||||||
assert_eq!(vec![3], test_state.int);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ fn iadd(x: i128, y: i128) -> i128 {
|
|||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn aux_iadd(x: i128, y: i128) -> Vec<i128> {
|
||||||
|
vec![x + y, x - y]
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_extract_test() {
|
fn run_extract_test() {
|
||||||
let mut test_state = EMPTY_STATE;
|
let mut test_state = EMPTY_STATE;
|
||||||
@ -13,7 +17,13 @@ fn run_extract_test() {
|
|||||||
run_instruction!(iadd, int, test_state, int, int);
|
run_instruction!(iadd, int, test_state, int, int);
|
||||||
assert_eq!(vec![3], test_state.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);
|
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);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user