-
Notifications
You must be signed in to change notification settings - Fork 0
Add a fast variant of the brainfunct protect function #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
use proc_macro::{TokenStream}; | ||
use quote::{quote, ToTokens, TokenStreamExt, format_ident}; | ||
use syn::{LitStr, parse_macro_input, Token, Expr}; | ||
use proc_macro::TokenStream; | ||
use proc_macro2::{Punct, Span}; | ||
use quote::{format_ident, quote, ToTokens, TokenStreamExt}; | ||
use syn::parse::{Parse, ParseStream}; | ||
use proc_macro2::Punct; | ||
use syn::{parse_macro_input, Expr, LitStr, Token}; | ||
|
||
struct InputStruct { | ||
program: LitStr, | ||
|
@@ -37,14 +37,172 @@ impl Parse for InputStruct { | |
} | ||
} | ||
|
||
struct BrainfunctProgram { | ||
operations: Vec<u8>, | ||
functions: Vec<usize>, | ||
main_index: usize, | ||
input: Vec<u8>, | ||
output: Vec<u8>, | ||
} | ||
|
||
impl Parse for BrainfunctProgram { | ||
fn parse(input: ParseStream) -> syn::Result<Self> { | ||
let p: LitStr = input.parse()?; | ||
let p_string = p.value(); | ||
input.parse::<Token![,]>()?; | ||
let input_str: LitStr = input.parse()?; | ||
let input_string = input_str.value(); | ||
input.parse::<Token![,]>()?; | ||
let output: LitStr = input.parse()?; | ||
let output_string = output.value(); | ||
let mut temp = BrainfunctProgram { | ||
operations: Vec::with_capacity(p_string.len()), | ||
functions: vec![usize::MAX], | ||
main_index: usize::MAX, | ||
input: Vec::with_capacity(input_string.len()), | ||
output: Vec::with_capacity(output_string.len()), | ||
}; | ||
let mut func_index = 0; | ||
for (index, c) in p.value().bytes().enumerate() { | ||
temp.operations.push(match c { | ||
b'>' | b'<' | b'+' | b'-' | b'.' | b',' | b'@' => c, | ||
b'/' => { | ||
temp.functions.push(temp.main_index); | ||
temp.main_index = index; | ||
func_index += 1; | ||
c | ||
} | ||
_ => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isn't brainfuck actually permissive in characters allowed? i suppose that's different for brainfunct 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know that it's actually different. It's just the rules I'm implementing for this interpreter. i could always just have it do nothing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to decide whether to ignore illegal characters or error. |
||
return Err(syn::Error::new( | ||
Span::call_site(), | ||
"You had an invalid character in your program", | ||
)) | ||
} | ||
}); | ||
|
||
// The value is 256 because you can have 255 functions (and they start indexing at 1) | ||
// and a main function which will cause the len to be 256 in the greatest case | ||
if temp.functions.len() > 256 { | ||
return Err(syn::Error::new( | ||
Span::call_site(), | ||
"You had more functions than are able to be called", | ||
)); | ||
} | ||
} | ||
|
||
if func_index == 0 { | ||
return Err(syn::Error::new( | ||
Span::call_site(), | ||
"You didn't define any functions at all", | ||
)); | ||
} | ||
|
||
for c in input_string.bytes() { | ||
temp.input.push(c); | ||
} | ||
|
||
for c in output_string.bytes() { | ||
temp.output.push(c); | ||
} | ||
|
||
Result::Ok(temp) | ||
} | ||
} | ||
|
||
#[proc_macro] | ||
pub fn fast_brainfunct_protect(input: TokenStream) -> TokenStream { | ||
let program = parse_macro_input!(input as BrainfunctProgram); | ||
let o = program.operations.iter(); | ||
let o_size = program.operations.len(); | ||
let f = program.functions.iter(); | ||
let f_size = program.functions.len(); | ||
let m = program.main_index; | ||
let i = program.input.iter(); | ||
let i_size = program.input.len(); | ||
let out = program.output.iter(); | ||
let out_size = program.output.len(); | ||
let call_const = quote! { | ||
const fn run_fast_brainfunct_protect( | ||
operations: &[u8], | ||
op_size: usize, | ||
func_map: &[u8], | ||
func_size: u8, | ||
main_index: usize, | ||
input: &[u8], | ||
i_size: usize, | ||
output: &[u8], | ||
o_size: usize, | ||
) { | ||
const fn die() { | ||
die() | ||
} | ||
|
||
let mut tape = [0u8; u16::MAX as usize]; | ||
let mut tape_ptr = 0usize; | ||
let mut input_ptr = 0usize; | ||
let mut output_ptr = 0usize; | ||
|
||
let mut stack = [usize::MAX; u16::MAX as usize]; | ||
let mut stack_head = 0i32; | ||
let mut current_index = main_index + 1usize; | ||
loop { | ||
if current_index >= op_size { | ||
if stack_head != -1 { | ||
// panic!("Your call stack wasn't completely emptied even though you have reached the end of the main function"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get rid of vestigial comments |
||
die() | ||
} | ||
break; | ||
} | ||
match operations[current_index] { | ||
b'>' => tape_ptr += 1, | ||
b'<' => tape_ptr -= 1, | ||
b'+' => tape[tape_ptr] += 1, | ||
b'-' => tape[tape_ptr] -= 1, | ||
b',' => { | ||
if input_ptr >= i_size { | ||
die(); | ||
} | ||
tape[tape_ptr] = input[input_ptr]; | ||
input_ptr += 1 | ||
} | ||
b'.' => { | ||
if output[output_ptr] != tape[tape_ptr] || output_ptr >= o_size { | ||
die() | ||
} | ||
output_ptr += 1 | ||
} | ||
b'@' => { | ||
if tape[tape_ptr] >= func_size { | ||
// panic!("Undefined function {}", tape[tape_ptr]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get rid of vestigial comments |
||
die(); | ||
} | ||
stack[stack_head as usize] = current_index; | ||
stack_head += 1; | ||
current_index = (func_map[tape[tape_ptr] as usize] + 1) as usize; | ||
} | ||
b'/' => { | ||
current_index = stack[stack_head as usize]; | ||
stack_head -= 1; | ||
} | ||
_ => die(), | ||
} | ||
current_index += 1 | ||
} | ||
} | ||
|
||
run_fast_brainfunct_protect([#(#o),*], #o_size, [#(#f),*], #f_size, #m, [#(#i),*], #i_size, [#(#out),*], #out_size); | ||
}; | ||
call_const.into() | ||
} | ||
|
||
#[proc_macro] | ||
pub fn brainfunct_protect(input: TokenStream) -> TokenStream { | ||
let input = parse_macro_input!(input as InputStruct); | ||
let mut funcs = Vec::new(); | ||
for c in input.program.value().bytes() { | ||
match c { | ||
b'/' => funcs.push(Vec::new()), | ||
op => funcs.last_mut().unwrap().push(op) | ||
op => funcs.last_mut().unwrap().push(op), | ||
} | ||
} | ||
|
||
|
@@ -92,7 +250,7 @@ pub fn brainfunct_protect(input: TokenStream) -> TokenStream { | |
inner.insert(0, "c(".into()); | ||
inner.push(")".into()); | ||
} | ||
c => panic!("You've used an illegal character: {}", c) | ||
c => panic!("You've used an illegal character: {}", c), | ||
} | ||
} | ||
let merged = inner.join(""); | ||
|
@@ -103,7 +261,10 @@ pub fn brainfunct_protect(input: TokenStream) -> TokenStream { | |
let expected_bytes = expected.bytes(); | ||
let indices = 0..expected.len(); | ||
let input_str = input.input.value(); | ||
let input_iter = input_str.bytes().chain(std::iter::repeat(0)).take(u16::MAX as usize); | ||
let input_iter = input_str | ||
.bytes() | ||
.chain(std::iter::repeat(0)) | ||
.take(u16::MAX as usize); | ||
|
||
let main_func = format_ident!("func{}", funcs.len()); | ||
let tokens = quote! { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
heh?