brainfuck interpreter
brainfuck cli rust
5

Configure Feed

Select the types of activity you want to include in your feed.

fix: read_raw() now consumes excess digits to prevent accidental leakage

- switched from std::io::Read traits in read_raw & run ->
std::io::BufRead. this allows read_raw to consume any extra digits
from one input and prevent them from automatically being digested in a
subsequent input. thankfully i can just swap in the BufRead trait
without much fuss
- wrapped call to stdin in main in a new BufReader
- fixed test, i forgot about the wrapping behavior...

digi.rip (Jun 2, 2026, 6:01 PM EDT) 4e3a64c4 d915a155

+20 -13
+14 -12
src/evaluator.rs
··· 207 207 Ok(()) 208 208 } 209 209 210 - fn read_raw<R: std::io::Read>(&mut self, input: &mut R) -> Result<(), RuntimeError> { 210 + fn read_raw<R: std::io::BufRead>(&mut self, input: &mut R) -> Result<(), RuntimeError> { 211 211 let mut buffer: String = String::new(); 212 212 let mut single = [0u8; 1]; 213 213 ··· 216 216 match input.read(&mut single) { 217 217 Ok(0) => break, // eof 218 218 Ok(_) if single[0].is_ascii_digit() => buffer.push(single[0] as char), 219 - // non-digit, consumed but discarded so it doesnt overflow into next input cmd 220 219 Ok(_) => break, 221 220 Err(e) => return Err(RuntimeError::IoError(e)), 222 221 } 223 222 } 224 223 225 - // discard leftover bytes so next input doesnt pick up strays 224 + // consume any leftover bytes in input to avoid leaking into next read_raw call 226 225 if buffer.len() == 3 { 227 226 loop { 228 - match input.read(&mut single) { 229 - Ok(0) => break, // eof 230 - Ok(_) if !single[0].is_ascii_digit() => break, 231 - Ok(_) => continue, 227 + match input.fill_buf() { 232 228 Err(e) => return Err(RuntimeError::IoError(e)), 229 + Ok(r) if r.is_empty() => break, 230 + Ok(r) if r[0].is_ascii_digit() => input.consume(1), 231 + Ok(_) => { 232 + input.consume(1); 233 + break; 234 + } 233 235 } 234 236 } 235 237 } ··· 251 253 Ok(()) 252 254 } 253 255 254 - pub fn run<R: std::io::Read, W: std::io::Write>( 256 + pub fn run<R: std::io::BufRead, W: std::io::Write>( 255 257 &mut self, 256 258 tokens: &[u8], 257 259 jump_map: &[usize], ··· 592 594 let tokens = tokenizer(",>,<.>."); 593 595 let map = parse_brackets(&tokens).unwrap(); 594 596 let mut machine = VM::builder() 595 - // .input_type(InputType::Raw) 596 - // .output_type(OutputType::Raw) 597 + .input_type(InputType::Raw) 598 + .output_type(OutputType::Raw) 597 599 .build(); 598 - let fake_input = std::io::Cursor::new(b"123123\n456456"); 600 + let fake_input = std::io::Cursor::new(b"100255\n200255"); 599 601 let mut capture_buffer: Vec<u8> = Vec::new(); 600 602 601 603 machine 602 604 .run(&tokens, &map, fake_input, &mut capture_buffer) 603 605 .unwrap(); 604 - assert_eq!(capture_buffer, b"123 456"); 606 + assert_eq!(capture_buffer, b"100 200 "); 605 607 } 606 608 }
+6 -1
src/main.rs
··· 50 50 .input_type(args.input_type) 51 51 .output_type(args.output_type) 52 52 .build(); 53 - machine.run(&tokens, &map, std::io::stdin(), std::io::stdout())?; 53 + machine.run( 54 + &tokens, 55 + &map, 56 + std::io::BufReader::new(std::io::stdin()), 57 + std::io::stdout(), 58 + )?; 54 59 55 60 Ok(()) 56 61 }