40 lines
1.2 KiB
Rust
40 lines
1.2 KiB
Rust
|
|
use proc_macro::TokenStream;
|
||
|
|
use quote::quote;
|
||
|
|
use syn::{parse_macro_input, LitStr};
|
||
|
|
|
||
|
|
/// Usage: brainfuck!("++>-[].,")
|
||
|
|
#[proc_macro]
|
||
|
|
pub fn brainfuck(input: TokenStream) -> TokenStream {
|
||
|
|
let lit = parse_macro_input!(input as LitStr);
|
||
|
|
let s = lit.value();
|
||
|
|
|
||
|
|
// Map characters -> OpCode tokens
|
||
|
|
let mut ops = Vec::new();
|
||
|
|
for ch in s.chars() {
|
||
|
|
let token = match ch {
|
||
|
|
'>' => Some(quote! { OpCode::IncrementPointer }),
|
||
|
|
'<' => Some(quote! { OpCode::DecrementPointer }),
|
||
|
|
'+' => Some(quote! { OpCode::Increment }),
|
||
|
|
'-' => Some(quote! { OpCode::Decrement }),
|
||
|
|
'.' => Some(quote! { OpCode::Write }),
|
||
|
|
',' => Some(quote! { OpCode::Read }),
|
||
|
|
'[' => Some(quote! { OpCode::LoopBegin }),
|
||
|
|
']' => Some(quote! { OpCode::LoopEnd }),
|
||
|
|
_ => None, // ignore comments/whitespace
|
||
|
|
};
|
||
|
|
if let Some(t) = token {
|
||
|
|
ops.push(t);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let n = ops.len();
|
||
|
|
// Expand to a const array; the caller gets a [OpCode; N]
|
||
|
|
let expanded = quote! {
|
||
|
|
{
|
||
|
|
const __BF_OPS: [OpCode; #n] = [ #(#ops),* ];
|
||
|
|
__BF_OPS
|
||
|
|
}
|
||
|
|
};
|
||
|
|
expanded.into()
|
||
|
|
}
|