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}