bflib/lib.rs
1//! # BrainFuck compiler using Rust proc macro
2//! More precisely, the BrainFuck-to-Rust transpiler using Rust proc macro
3//!
4//! ## Examples:
5//!
6//! 1. Hello World
7//! (run on dropping)
8//! ```rust
9//! brain_fuck!(
10//! ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.
11//! >---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
12//! );
13//! ```
14//! 2. using `into` method to obtain `(pc: usize, mem: Vec<u8>)` after running
15//! (run on `into` calling)
16//! ```rust
17//! let (pc, mem) = brain_fuck!(
18//! ++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[
19//! -<<<[
20//! ->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
21//! ]>.>+[>>]>+
22//! ]
23//! ).into();
24//! println!("{:?}", (pc, mem));
25//! ```
26//! 3. use `env` method to set _Program Counter_ `pc` and _Memory_ `mem` for brainfuck codeblock
27//! (run on dropping)
28//! ```rust
29//! brain_fuck!(
30//! [.>]
31//! ).env(0, vec![79, 75, 10]);
32//! ```
33//! 4. Altogether
34//! (run on `into` calling)
35//! ```rust
36//! let (pc, mem) = brain_fuck!(
37//! [.>]
38//! ).env(0, vec![72, 101, 108, 108, 79, 119, 104, 97, 116, 65, 115, 10]).into();
39//! println!("{:?}", (pc, mem));
40//! ```
41//!
42//!
43//!
44//! ## Explaination
45//! The brainfuck code
46//! ```brainfuck
47//! brainfuck!(
48//! ++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[
49//! -<<<[
50//! ->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
51//! ]>.>+[>>]>+
52//! ]
53//! )
54//! ```
55//! will be transpiled to the following rust code
56//! ```rust
57//! ::bflib::BrainfuckBlock::new(&|pc: &mut usize, mem: &mut Vec<u8>| {
58//! if mem.len() <= *pc {
59//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
60//! }
61//! mem[*pc] = mem[*pc].wrapping_add(8);
62//! while mem[*pc] != 0 {
63//! *pc += 1;
64//! if mem.len() <= *pc {
65//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
66//! }
67//! mem[*pc] = mem[*pc].wrapping_add(1);
68//! *pc += 1;
69//! if mem.len() <= *pc {
70//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
71//! }
72//! mem[*pc] = mem[*pc].wrapping_add(4);
73//! if *pc < 2 {
74//! panic!("BrainFuck Program Counter reduced to below zero !!!");
75//! } else {
76//! *pc -= 2;
77//! }
78//! mem[*pc] = mem[*pc].wrapping_sub(1);
79//! }
80//! *pc += 1;
81//! if mem.len() <= *pc {
82//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
83//! }
84//! mem[*pc] = mem[*pc].wrapping_add(2);
85//! *pc += 2;
86//! if mem.len() <= *pc {
87//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
88//! }
89//! mem[*pc] = mem[*pc].wrapping_add(1);
90//! if *pc < 1 {
91//! panic!("BrainFuck Program Counter reduced to below zero !!!");
92//! } else {
93//! *pc -= 1;
94//! }
95//! while mem[*pc] != 0 {
96//! mem[*pc] = mem[*pc].wrapping_sub(1);
97//! while mem[*pc] != 0 {
98//! *pc += 2;
99//! if mem.len() <= *pc {
100//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
101//! }
102//! mem[*pc] = mem[*pc].wrapping_add(1);
103//! if *pc < 2 {
104//! panic!("BrainFuck Program Counter reduced to below zero !!!");
105//! } else {
106//! *pc -= 2;
107//! }
108//! mem[*pc] = mem[*pc].wrapping_sub(1);
109//! }
110//! mem[*pc] = mem[*pc].wrapping_add(1);
111//! *pc += 2;
112//! if mem.len() <= *pc {
113//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
114//! }
115//! }
116//! *pc += 1;
117//! if mem.len() <= *pc {
118//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
119//! }
120//! mem[*pc] = mem[*pc].wrapping_add(1);
121//! while mem[*pc] != 0 {
122//! mem[*pc] = mem[*pc].wrapping_sub(1);
123//! if *pc < 3 {
124//! panic!("BrainFuck Program Counter reduced to below zero !!!");
125//! } else {
126//! *pc -= 3;
127//! }
128//! while mem[*pc] != 0 {
129//! mem[*pc] = mem[*pc].wrapping_sub(1);
130//! *pc += 1;
131//! if mem.len() <= *pc {
132//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
133//! }
134//! while mem[*pc] != 0 {
135//! mem[*pc] = mem[*pc].wrapping_add(1);
136//! while mem[*pc] != 0 {
137//! mem[*pc] = mem[*pc].wrapping_sub(1);
138//! }
139//! mem[*pc] = mem[*pc].wrapping_add(1);
140//! *pc += 1;
141//! if mem.len() <= *pc {
142//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
143//! }
144//! mem[*pc] = mem[*pc].wrapping_add(2);
145//! *pc += 3;
146//! if mem.len() <= *pc {
147//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
148//! }
149//! mem[*pc] = mem[*pc].wrapping_sub(1);
150//! if *pc < 2 {
151//! panic!("BrainFuck Program Counter reduced to below zero !!!");
152//! } else {
153//! *pc -= 2;
154//! }
155//! }
156//! if *pc < 1 {
157//! panic!("BrainFuck Program Counter reduced to below zero !!!");
158//! } else {
159//! *pc -= 1;
160//! }
161//! while mem[*pc] != 0 {
162//! if *pc < 1 {
163//! panic!("BrainFuck Program Counter reduced to below zero !!!");
164//! } else {
165//! *pc -= 1;
166//! }
167//! }
168//! *pc += 2;
169//! if mem.len() <= *pc {
170//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
171//! }
172//! mem[*pc] = mem[*pc].wrapping_add(6);
173//! while mem[*pc] != 0 {
174//! if *pc < 2 {
175//! panic!("BrainFuck Program Counter reduced to below zero !!!");
176//! } else {
177//! *pc -= 2;
178//! }
179//! mem[*pc] = mem[*pc].wrapping_add(5);
180//! *pc += 2;
181//! if mem.len() <= *pc {
182//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
183//! }
184//! mem[*pc] = mem[*pc].wrapping_sub(1);
185//! }
186//! mem[*pc] = mem[*pc].wrapping_add(1);
187//! if *pc < 2 {
188//! panic!("BrainFuck Program Counter reduced to below zero !!!");
189//! } else {
190//! *pc -= 2;
191//! }
192//! mem[*pc] = mem[*pc].wrapping_add(2);
193//! print!("{}", mem[*pc] as char);
194//! while mem[*pc] != 0 {
195//! mem[*pc] = mem[*pc].wrapping_sub(1);
196//! }
197//! if *pc < 2 {
198//! panic!("BrainFuck Program Counter reduced to below zero !!!");
199//! } else {
200//! *pc -= 2;
201//! }
202//! }
203//! *pc += 1;
204//! if mem.len() <= *pc {
205//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
206//! }
207//! print!("{}", mem[*pc] as char);
208//! *pc += 1;
209//! if mem.len() <= *pc {
210//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
211//! }
212//! mem[*pc] = mem[*pc].wrapping_add(1);
213//! while mem[*pc] != 0 {
214//! *pc += 2;
215//! if mem.len() <= *pc {
216//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
217//! }
218//! }
219//! *pc += 1;
220//! if mem.len() <= *pc {
221//! mem.append(&mut vec![0; *pc - mem.len() + 1]);
222//! }
223//! mem[*pc] = mem[*pc].wrapping_add(1);
224//! }
225//! })
226//! ```
227
228
229pub use bflib_proc_macro::brain_fuck;
230
231/// Represents a brainfuck codeblock
232/// ```
233/// brain_fuck!(
234/// ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.
235/// >---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
236/// )
237/// ```
238pub struct BrainfuckBlock {
239 code: &'static dyn Fn(&mut usize, &mut Vec<u8>),
240 opt_env: Option<(usize, Vec<u8>)>,
241 runned: bool
242}
243
244impl BrainfuckBlock {
245 /// Constructor of `BrainfuckBlock`
246 ///
247 /// receives output of proc marco
248 ///
249 /// **HUMAN NEVER USE**
250 pub fn new(code: &'static dyn Fn(&mut usize, &mut Vec<u8>)) -> BrainfuckBlock {
251 BrainfuckBlock { code, opt_env: None, runned: false }
252 }
253 /// Sets the Program Counter `pc` and Memory `mem` of the Brainfuck codeblock
254 /// Returns self
255 pub fn env(mut self, pc: usize, mem: Vec<u8>) -> Self {
256 self.opt_env = Some((pc, mem));
257 self
258 }
259
260 fn run(&mut self) {
261 let (mut pc, mut mem) = (0, vec![]);
262 if self.opt_env.is_some() {
263 (pc, mem) = self.opt_env.take().unwrap();
264 }
265 (self.code)(&mut pc, &mut mem);
266 self.opt_env = Some((pc, mem));
267 }
268}
269
270impl Into<(usize, Vec<u8>)> for BrainfuckBlock {
271 /// obtain `(pc: usize, mem: Vec<u8>)` after running
272 fn into(mut self) -> (usize, Vec<u8>) {
273 self.runned = true;
274 self.run();
275 self.opt_env.take().unwrap()
276 }
277}
278
279impl Drop for BrainfuckBlock {
280 /// run the code on dropping if the block never runned before via `into`
281 fn drop(&mut self) {
282 if !self.runned {
283 self.run();
284 }
285 }
286}