Create the REPL yooooo 😆💙
This commit is contained in:
parent
ed155f285b
commit
636bbd0bed
3 changed files with 133 additions and 54 deletions
|
@ -1,4 +1,4 @@
|
|||
use std::io::{Write};
|
||||
use std::io::{Read, Write};
|
||||
use std::usize;
|
||||
use crate::arguments;
|
||||
|
||||
|
@ -25,7 +25,7 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, bf_code: Option<String>) -> Result<u32, (String, u32)> {
|
||||
pub fn run(&mut self, bf_code: Option<String>) -> Result<i32, (String, i32)> {
|
||||
let bf_code = match bf_code {
|
||||
Some(bf_code) => {
|
||||
self.bf_code.push_str(&*bf_code);
|
||||
|
@ -98,10 +98,15 @@ impl Interpreter {
|
|||
std::io::stdout().flush().unwrap();
|
||||
},
|
||||
BfCommand::Read => {
|
||||
let mut input = String::new();
|
||||
// TODO: Handle errors, and read only one byte
|
||||
std::io::stdin().read_line(&mut input).unwrap();
|
||||
self.cells[self.pointer] = input.chars().next().unwrap() as u8;
|
||||
self.cells[self.pointer] = match std::io::stdin().bytes().next() {
|
||||
Some(Ok(byte)) => byte,
|
||||
Some(Err(e)) => {
|
||||
return Err(format!("Failed to read byte from stdin: {}", e));
|
||||
}
|
||||
None => {
|
||||
return Err("Failed to read byte from stdin: EOF".to_string());
|
||||
}
|
||||
};
|
||||
},
|
||||
BfCommand::LoopStart(i) => {
|
||||
self.brackets.push(BfCommand::LoopStart(i));
|
||||
|
|
63
src/main.rs
63
src/main.rs
|
@ -1,15 +1,13 @@
|
|||
mod arguments;
|
||||
mod interpreter;
|
||||
mod utils;
|
||||
mod repl;
|
||||
|
||||
use std::io::Write;
|
||||
use clap::Parser;
|
||||
extern crate pretty_env_logger;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use arguments::Args;
|
||||
use crate::utils::read_brainfuck_code_if_any;
|
||||
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
|
@ -25,58 +23,27 @@ fn main() {
|
|||
info!("Initializing interpreter");
|
||||
let mut interpreter = interpreter::Interpreter::new(
|
||||
args.array_size,
|
||||
read_brainfuck_code_if_any(&args.source),
|
||||
utils::read_brainfuck_code_if_any(&args.source),
|
||||
args.features.unwrap_or_else(|| vec![]));
|
||||
|
||||
match args.source {
|
||||
Some(source) => {
|
||||
info!("Running brainfuck source code from file: {}", source);
|
||||
interpreter.run(None).unwrap();
|
||||
match interpreter.run(None) {
|
||||
Ok(exit_code) => {
|
||||
println!("Successfully ran brainfuck source code from file: {}", source);
|
||||
println!("Exiting with code: {exit_code}");
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err((e, code)) => {
|
||||
error!("Failed to run brainfuck source code from file: {}", e);
|
||||
std::process::exit(code);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
info!("Entering REPL mode");
|
||||
println!("Welcome to the brainfuck REPL mode! :)");
|
||||
println!("Brainfuck interpreter v {}\nBy {}",
|
||||
clap::crate_version!(), clap::crate_authors!());
|
||||
println!("Enter your brainfuck code and press enter to run it.");
|
||||
println!("Enter !fuck to exit :D");
|
||||
println!("Enter !help fuck to get more help");
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
std::io::stdout().flush().unwrap();
|
||||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input).unwrap();
|
||||
if input.starts_with("!") {
|
||||
match input.trim().get(1..).unwrap() {
|
||||
"fuck" => {
|
||||
println!("Bye bye :D");
|
||||
break;
|
||||
},
|
||||
"array" | "a" => {
|
||||
println!("Current array: {:#?}", interpreter.cells);
|
||||
},
|
||||
"array_size" | "as" => {
|
||||
println!("Current array size: {}", interpreter.array_size);
|
||||
},
|
||||
"pointer" | "p" => {
|
||||
println!("Current pointer: {}", interpreter.pointer);
|
||||
},
|
||||
|
||||
"help" => {
|
||||
println!("!fuck: exit the REPL mode");
|
||||
println!("!array, !a: print the current array");
|
||||
println!("!array_size, !as: print the current array size");
|
||||
println!("!pointer, !p: print the current pointer value");
|
||||
println!("!history: print the history of the commands");
|
||||
println!("!help: show this fu*king help message");
|
||||
},
|
||||
_ => println!("Unknown command: {}, type !help to show the help", input.trim())
|
||||
}
|
||||
} else {
|
||||
interpreter.run(Some(input));
|
||||
}
|
||||
}
|
||||
repl::start(interpreter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
107
src/repl.rs
Normal file
107
src/repl.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
use std::io::Write;
|
||||
use crate::interpreter::Interpreter;
|
||||
|
||||
struct Repl {
|
||||
interpreter: Interpreter,
|
||||
history: Vec<String>,
|
||||
}
|
||||
|
||||
impl Repl {
|
||||
pub fn new(interpreter: Interpreter) -> Self {
|
||||
Self {
|
||||
interpreter,
|
||||
history: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(mut self) {
|
||||
loop {
|
||||
print!("\n> ");
|
||||
std::io::stdout().flush().unwrap();
|
||||
let mut input = String::new();
|
||||
|
||||
match std::io::stdin().read_line(&mut input) {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
error!("Failed to read input: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
input = input.trim().to_string(); // Remove trailing newline
|
||||
|
||||
self.history.push(input.clone()); // Save input to history
|
||||
|
||||
if input.starts_with("!") {
|
||||
self.run_repl_cmd(input);
|
||||
} else {
|
||||
match self.interpreter.run(Some(input)) {
|
||||
Ok(_) => {
|
||||
info!("Successfully ran brainfuck source code from REPL");
|
||||
}
|
||||
Err((e, _)) => {
|
||||
error!("Failed to run brainfuck source code from REPL: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_repl_cmd(&self, input: String) {
|
||||
match input.trim().get(1..).unwrap() {
|
||||
"fuck" => {
|
||||
println!("Bye bye :D");
|
||||
std::process::exit(0);
|
||||
}
|
||||
"array" | "a" => {
|
||||
println!("Current array: {:?}", self.interpreter.cells);
|
||||
}
|
||||
"array_size" | "as" => {
|
||||
println!("Current array size: {}", self.interpreter.array_size);
|
||||
}
|
||||
"pointer" | "p" => {
|
||||
println!("Current pointer: {}", self.interpreter.pointer);
|
||||
}
|
||||
"history" | "h" => {
|
||||
println!("History:");
|
||||
for (i, cmd) in self.history.iter().enumerate() {
|
||||
println!("{}: {}", i, cmd);
|
||||
}
|
||||
}
|
||||
"save" | "s" => {
|
||||
/// TODO: Use custom name for file
|
||||
println!("Saving history to file: history.bfr");
|
||||
match std::fs::write("history.bfr", self.history.join("\n")) {
|
||||
Ok(_) => {
|
||||
info!("Successfully saved history to file: history.bfr");
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to save history to file: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
"help" => {
|
||||
println!("!array, !a: print the current array");
|
||||
println!("!array_size, !as: print the current array size");
|
||||
println!("!pointer, !p: print the current pointer value");
|
||||
println!("!history, !h: print the history of the commands");
|
||||
println!("!save, !s: save the history to a file");
|
||||
println!("!help: show this fu*king help message");
|
||||
println!("!fuck: exit the REPL mode");
|
||||
}
|
||||
_ => println!("Unknown command: {}, type !help to show the help", input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(interpreter: Interpreter) {
|
||||
info!("Entering REPL mode");
|
||||
println!("Welcome to the brainfuck REPL mode! :)");
|
||||
println!("Brainfuck interpreter v {}\nBy {}",
|
||||
clap::crate_version!(), clap::crate_authors!());
|
||||
println!("Enter your brainfuck code and press enter to run it.");
|
||||
println!("Enter !fuck to exit :D");
|
||||
println!("Enter !help fuck to get more help");
|
||||
|
||||
Repl::new(interpreter)
|
||||
.run();
|
||||
}
|
Loading…
Reference in a new issue