brainfuck interpreter
brainfuck cli rust
5

Configure Feed

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

feat: added speed setting

pairs well with tracing, allows you to watch your brainfuck scripts step
through in real-time

digi.rip (Jun 3, 2026, 10:23 AM EDT) 49a10cae acf7eb25

+25 -1
+1 -1
ROADMAP.md
··· 21 21 22 22 ## better diagnostics 23 23 - [ ] **errors**: switch to `anyhow` or `miette` for nicer errors and better context 24 - - [ ] **tracing**: cli flag to print state of vm/tape after every instruction 24 + - [x] **tracing**: cli flag to print state of vm/tape after every instruction 25 25 26 26 ## visualization 27 27 - [ ] **real-time cell visualization**: tui showing tape being adjusted and data pointer moving in real time at adjustable speed
+15
src/evaluator.rs
··· 1 1 use clap::ValueEnum; 2 2 use std::fmt; 3 3 use std::io::Write; 4 + use std::thread; 5 + use std::time; 4 6 5 7 #[derive(Debug)] 6 8 pub enum RuntimeError { ··· 52 54 input_type: IOFormat, 53 55 output_type: IOFormat, 54 56 tracing: bool, 57 + speed: u64, 55 58 } 56 59 57 60 pub struct VMBuilder { ··· 61 64 input_type: IOFormat, 62 65 output_type: IOFormat, 63 66 tracing: bool, 67 + speed: u64, 64 68 } 65 69 66 70 impl VMBuilder { ··· 72 76 input_type: IOFormat::Ascii, 73 77 output_type: IOFormat::Ascii, 74 78 tracing: false, 79 + speed: 0, 75 80 } 76 81 } 77 82 ··· 105 110 self 106 111 } 107 112 113 + pub fn speed(mut self, speed: u64) -> Self { 114 + self.speed = speed; 115 + self 116 + } 117 + 108 118 pub fn build(self) -> VM { 109 119 VM { 110 120 tape: self.tape, ··· 115 125 input_type: self.input_type, 116 126 output_type: self.output_type, 117 127 tracing: self.tracing, 128 + speed: self.speed, 118 129 } 119 130 } 120 131 } ··· 271 282 mut writer: W, 272 283 ) -> Result<(), RuntimeError> { 273 284 while self.inst_pointer < tokens.len() { 285 + thread::sleep(time::Duration::from_millis(self.speed)); 274 286 let current = tokens[self.inst_pointer]; 275 287 276 288 if self.tracing { 277 289 std::io::stdout().flush().ok(); 290 + if self.speed > 0 { 291 + print!("{}ms elapsed...", self.speed); 292 + } 278 293 print!( 279 294 "\nTape: {}[{}] ", 280 295 self.data_pointer, self.tape[self.data_pointer]
+9
src/main.rs
··· 41 41 default_value = "false" 42 42 )] 43 43 tracing: bool, 44 + 45 + #[arg( 46 + short, 47 + long, 48 + help = "set interpreter speed in milliseconds (useful with tracing!)", 49 + default_value = "0" 50 + )] 51 + speed: u64, 44 52 } 45 53 46 54 // think: switch to returning anyhow::Error? better diag ··· 57 65 .input_type(args.input_type) 58 66 .output_type(args.output_type) 59 67 .tracing(args.tracing) 68 + .speed(args.speed) 60 69 .build(); 61 70 machine.run( 62 71 &tokens,