brainfrick/lib.rs
1/*!
2 An optimizing Brainfuck interpreter.
3
4 - For the full documentation, see [`Brainfuck`].
5 - If you don't like swearing, `Brainfuck` is also re-exported as `Brainfrick`.
6
7 # Example
8 ```
9 use brainfrick::Brainfuck;
10
11 let purpzie_sucks = Brainfuck::execute("
12 ++++++++[>++++++++++<-]>.<++[>++++++++++<-]+++[>+++++<-]>+
13 +.---.--.++++++++++.<++[>----------<-]>+++.----.<+++++++[>
14 ----------<-]>+.<++++++++[>++++++++++<-]>+++.++.<+++[>----
15 --<-]>.++++++++.++++++++.<++++++++[>----------<-]>--.
16 ")?;
17
18 assert_eq!(purpzie_sucks, "Purpzie sucks!");
19 # Ok::<(), brainfrick::Error>(())
20 ```
21*/
22
23#![allow(clippy::match_bool)]
24#![doc(html_root_url = "https://docs.rs/brainfrick/1.1.2")]
25
26mod error;
27mod execute;
28mod mem;
29mod parse;
30mod step;
31
32use execute::execute;
33use parse::parse;
34use std::sync::Arc;
35
36pub use error::{Error, ErrorKind};
37
38/**
39 A struct that parses and runs brainfuck.
40
41 # Example
42 ```
43 use brainfrick::Brainfuck;
44
45 let purpzie_sucks = Brainfuck::execute("
46 ++++++++[>++++++++++<-]>.<++[>++++++++++<-]+++[>+++++<-]>+
47 +.---.--.++++++++++.<++[>----------<-]>+++.----.<+++++++[>
48 ----------<-]>+.<++++++++[>++++++++++<-]>+++.++.<+++[>----
49 --<-]>.++++++++.++++++++.<++++++++[>----------<-]>--.
50 ")?;
51
52 assert_eq!(purpzie_sucks, "Purpzie sucks!");
53 # Ok::<(), brainfrick::Error>(())
54 ```
55
56 ## The debug character
57 To aid whoever is crazy enough to write in brainfuck, the question mark `?` will output the
58 current cell number and value.
59
60 ```
61 # use brainfrick::Brainfuck;
62 let where_am_i = Brainfuck::execute(">>+++++?")?;
63 assert_eq!(where_am_i, "[2,5]");
64 # Ok::<(), brainfrick::Error>(())
65 ```
66
67 ## Memory details
68 Memory is infinite in both directions. In order to prevent malicious brainfuck from running
69 forever, there is a configurable, maximum number of 'steps' you can allow to be executed before
70 stopping.
71
72 ```
73 # use brainfrick::Brainfuck;
74 let mut infinite = Brainfuck::parse("+[>+]")?;
75 infinite.max_steps = 100;
76 let result = infinite.run();
77
78 assert!(result.is_err());
79 # Ok::<(), brainfrick::Error>(())
80 ```
81
82 ## Testing multiple inputs
83 If you'd like to quickly test the same brainfuck with many different inputs, you can
84 parse it beforehand to speed up the process. See [`Brainfuck::input`] for information.
85*/
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub struct Brainfuck {
88 steps: Vec<step::Step>,
89 indexes: Vec<error::Index>,
90 code: Arc<String>,
91 /// The maximum number of 'steps' that will be run before stopping. Defaults to
92 /// [`Brainfuck::MAX_STEPS`].
93 pub max_steps: usize,
94}
95
96impl Brainfuck {
97 /// The default maximum number of 'steps' that will be run before stopping.
98 pub const MAX_STEPS: usize = 100_000;
99
100 /**
101 Run some brainfuck.
102
103 # Errors
104 May return an [`Error`] of kind [`UnmatchedBracket`](ErrorKind::UnmatchedBracket) or
105 [`MaxSteps`](ErrorKind::MaxSteps).
106
107 # Example
108 ```
109 # use brainfrick::Brainfuck;
110 let purpzie_sucks = Brainfuck::execute("
111 ++++++++[>++++++++++<-]>.<++[>++++++++++<-]+++[>+++++<-]>+
112 +.---.--.++++++++++.<++[>----------<-]>+++.----.<+++++++[>
113 ----------<-]>+.<++++++++[>++++++++++<-]>+++.++.<+++[>----
114 --<-]>.++++++++.++++++++.<++++++++[>----------<-]>--.
115 ")?;
116
117 assert_eq!(purpzie_sucks, "Purpzie sucks!");
118 # Ok::<(), brainfrick::Error>(())
119 ```
120 */
121 pub fn execute<S: Into<String>>(code: S) -> Result<String, Error> {
122 Self::parse(code)?.run()
123 }
124
125 /**
126 Run some brainfuck with input.
127
128 # Errors
129 May return an [`Error`] of kind [`UnmatchedBracket`](ErrorKind::UnmatchedBracket) or
130 [`MaxSteps`](ErrorKind::MaxSteps).
131
132 # Example
133 ```
134 # use brainfrick::Brainfuck;
135 let loud = Brainfuck::execute_with_input(
136 ",[>++++[<-------->-]<.,]",
137 "foobar",
138 )?;
139
140 assert_eq!(loud, "FOOBAR");
141 # Ok::<(), brainfrick::Error>(())
142 ```
143 */
144 pub fn execute_with_input<O: Into<String>, R: AsRef<str>>(
145 code: O,
146 input: R,
147 ) -> Result<String, Error> {
148 Self::parse(code)?.input(input)
149 }
150
151 /**
152 Parse some brainfuck for later use.
153
154 This essentially just creates a [`Brainfuck`] struct.
155
156 # Errors
157 May return an [`UnmatchedBracket`](ErrorKind::UnmatchedBracket) error.
158
159 # Example
160 ```
161 # use brainfrick::Brainfuck;
162 let purpzie = Brainfuck::parse("
163 ++++++++[>++++++++++<-]>.<++[>++++++++++<-]+++[>+++++<-]>+
164 +.---.--.++++++++++.<++[>----------<-]>+++.----.<+++++++[>
165 ----------<-]>+.<++++++++[>++++++++++<-]>+++.++.<+++[>----
166 --<-]>.++++++++.++++++++.<++++++++[>----------<-]>--.
167 ")?;
168
169 // ...later
170
171 let sucks = purpzie.run()?;
172
173 assert_eq!(sucks, "Purpzie sucks!");
174 # Ok::<(), brainfrick::Error>(())
175 ```
176 */
177 pub fn parse<S: Into<String>>(code: S) -> Result<Brainfuck, Error> {
178 parse(code.into(), Self::MAX_STEPS)
179 }
180
181 /**
182 Run the parsed brainfuck.
183
184 Note that, for a single [`Brainfuck`], this will always output the same result.
185
186 # Errors
187 May return a [`MaxSteps`](ErrorKind::MaxSteps) error.
188
189 # Example
190 ```
191 # use brainfrick::Brainfuck;
192 let purpzie = Brainfuck::parse("
193 ++++++++[>++++++++++<-]>.<++[>++++++++++<-]+++[>+++++<-]>+
194 +.---.--.++++++++++.<++[>----------<-]>+++.----.<+++++++[>
195 ----------<-]>+.<++++++++[>++++++++++<-]>+++.++.<+++[>----
196 --<-]>.++++++++.++++++++.<++++++++[>----------<-]>--.
197 ")?;
198
199 // ...later
200
201 let sucks = purpzie.run()?;
202
203 assert_eq!(sucks, "Purpzie sucks!");
204 # Ok::<(), brainfrick::Error>(())
205 ```
206 */
207 pub fn run(&self) -> Result<String, Error> {
208 execute(self, None)
209 }
210
211 /**
212 Run the parsed brainfuck with input.
213
214 # Errors
215 May return a [`MaxSteps`](ErrorKind::MaxSteps) error.
216
217 # Example
218 ```
219 # use brainfrick::Brainfuck;
220 let loud = Brainfuck::parse(",[>++++[<-------->-]<.,]")?;
221
222 assert_eq!(loud.input("foobar")?, "FOOBAR");
223 assert_eq!(loud.input("heck")?, "HECK");
224 assert_eq!(loud.input("aaaaa")?, "AAAAA");
225 # Ok::<(), brainfrick::Error>(())
226 ```
227 */
228 pub fn input<S: AsRef<str>>(&self, input: S) -> Result<String, Error> {
229 execute(self, Some(input.as_ref()))
230 }
231
232 /**
233 The original brainfuck 'source'.
234
235 # Example
236 ```
237 # use brainfrick::Brainfuck;
238 let code = ",[>++++[<-------->-]<.,]";
239 let example = Brainfuck::parse(code)?;
240 assert_eq!(code, example.code());
241 # Ok::<(), brainfrick::Error>(())
242 ```
243 */
244 pub fn code(&self) -> &str {
245 &self.code
246 }
247}
248
249// for people who don't like swearing
250pub use Brainfuck as Brainfrick;