brainfuck interpreter
brainfuck cli rust
5

Configure Feed

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

evaluator: refactor repeat leftover byte consumption code into a single function

digi.rip (Jun 17, 2026, 3:40 PM EDT) a482c62b 26537653

+27 -26
+27 -26
src/evaluator.rs
··· 311 311 Ok(()) 312 312 } 313 313 314 - fn read_ascii<R: std::io::BufRead>(&mut self, input: &mut R) -> Result<(), RuntimeError> { 315 - let mut buffer = [0u8; 1]; 316 - 317 - input 318 - .read_exact(&mut buffer) 319 - .map_err(|e| RuntimeError::IoReadError { err: e })?; 320 - self.tape[self.data_pointer] = buffer[0]; 321 - 314 + fn consume_while<R: std::io::BufRead>( 315 + &self, 316 + input: &mut R, 317 + pred: fn(u8) -> bool, 318 + ) -> Result<(), RuntimeError> { 322 319 loop { 323 320 match input.fill_buf() { 324 - Err(e) => { 325 - return Err(RuntimeError::IoReadError { err: e }); 326 - } 321 + Err(e) => return Err(RuntimeError::IoReadError { err: e }), 327 322 Ok([]) => break, 328 - Ok(r) if r[0].is_ascii_alphanumeric() => input.consume(1), 323 + Ok(r) if pred(r[0]) => input.consume(1), 329 324 Ok(_) => { 330 325 input.consume(1); 331 326 break; ··· 336 331 Ok(()) 337 332 } 338 333 334 + fn read_ascii<R: std::io::BufRead>(&mut self, input: &mut R) -> Result<(), RuntimeError> { 335 + let mut buffer = [0u8; 1]; 336 + 337 + input 338 + .read_exact(&mut buffer) 339 + .map_err(|e| RuntimeError::IoReadError { err: e })?; 340 + self.tape[self.data_pointer] = buffer[0]; 341 + 342 + self.consume_while(input, |b| b.is_ascii_alphanumeric())?; 343 + 344 + Ok(()) 345 + } 346 + 339 347 fn write_ascii<W: std::io::Write>(&mut self, output: &mut W) -> Result<(), RuntimeError> { 340 348 output 341 349 .write_all(&[self.tape[self.data_pointer]]) ··· 364 372 365 373 // consume any leftover bytes in input to avoid leaking into next read_raw call 366 374 if buffer.len() == 3 { 367 - loop { 368 - match input.fill_buf() { 369 - Err(e) => { 370 - return Err(RuntimeError::IoReadError { err: e }); 371 - } 372 - Ok([]) => break, 373 - Ok(r) if r[0].is_ascii_digit() => input.consume(1), 374 - Ok(_) => { 375 - input.consume(1); 376 - break; 377 - } 378 - } 379 - } 375 + self.consume_while(input, |b| b.is_ascii_digit())?; 380 376 } 381 377 382 378 match buffer.parse::<u16>() { ··· 422 418 ); 423 419 eprint!("\nInst: '{}' @ {}", current.byte as char, self.inst_pointer); 424 420 } 421 + 422 + // if self.debug: pretty print 425 423 426 424 match current.byte { 427 425 b'>' => { ··· 475 473 } 476 474 477 475 _ => { 478 - debug_assert!(false, "tokenizer should have filtered this non-BF chars"); 476 + debug_assert!( 477 + false, 478 + "tokenizer should have filtered this non-BF character" 479 + ); 479 480 Err(RuntimeError::InvalidToken { 480 481 src: NamedSource::new(Arc::clone(&self.filename), Arc::clone(&self.source)), 481 482 span: (current.offset, 1).into(),