Add !load command and some improvements😃

This commit is contained in:
Anas Elgarhy 2022-10-08 00:52:43 +02:00
parent b6eb1ddf60
commit 6e6316b2bb
4 changed files with 125 additions and 55 deletions

View file

@ -3,9 +3,6 @@ use clap::{arg, Parser, ValueEnum};
#[derive(Parser, Debug)]
#[command(author, about, long_about = None, version)]
pub struct Args {
/// To be verbose
#[arg(short, long)]
pub verbose: bool,
/// The brainfuck source code file to run (if not will be entered in REPL mode)
#[arg(default_value = None)]
pub source: Option<String>,

View file

@ -164,3 +164,39 @@ impl BfCommand {
}
}
}
mod error {
use std::fmt::{Debug, Formatter};
struct InterpreterError {
message: String,
code: i32,
}
impl InterpreterError {
fn new(message: String, code: i32) -> Self {
Self {
message,
code,
}
}
}
impl std::fmt::Display for InterpreterError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl Debug for InterpreterError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}, code: {}", self.message, self.code)
}
}
impl std::error::Error for InterpreterError {
fn description(&self) -> &str {
&self.message
}
}
}

View file

@ -4,8 +4,10 @@ mod utils;
mod repl;
use clap::Parser;
extern crate pretty_env_logger;
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
use arguments::Args;
@ -16,15 +18,12 @@ fn main() {
let args = Args::parse();
info!("Parsed command line arguments: {:?}", args);
if args.verbose {
info!("Verbose mode enabled");
}
info!("Initializing interpreter");
let mut interpreter = interpreter::Interpreter::new(
args.array_size,
utils::read_brainfuck_code_if_any(&args.source),
args.features.unwrap_or_else(|| vec![]));
args.features.unwrap_or_else(|| vec![])
);
match args.source {
Some(source) => {
@ -40,7 +39,7 @@ fn main() {
std::process::exit(code);
}
}
},
}
None => {
repl::start(interpreter)
}

View file

@ -21,7 +21,7 @@ impl Repl {
let mut input = String::new();
match std::io::stdin().read_line(&mut input) {
Ok(_) => {},
Ok(_) => {}
Err(e) => {
error!("Failed to read input: {}", e);
std::process::exit(1);
@ -47,54 +47,92 @@ impl Repl {
}
fn run_repl_cmd(&mut 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");
let mut cmd = input.split_whitespace();
match cmd.next() {
Some(repl_cmd) => {
match repl_cmd {
"fuck" => {
println!("Bye bye :D");
std::process::exit(0);
}
Err(e) => {
error!("Failed to save history to file: {}", e);
"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" => {
let file_name = cmd.next()
.unwrap_or("brainfuck_repl_history.bfr");
println!("Saving history to file: {file_name}");
match std::fs::write(file_name, self.history.join("\n")) {
Ok(_) => {
info!("Successfully saved history to file: {file_name}");
}
Err(e) => {
error!("Failed to save history to file: {}", e);
}
}
}
"load" | "l" => {
let file_name = cmd.next()
.unwrap_or("brainfuck_repl_history.bfr");
println!("Loading history from file: {file_name}");
match std::fs::read_to_string(file_name) {
Ok(history) => {
info!("Successfully loaded history from file: {file_name}");
self.history = history.split("\n")
.map(|s| s.to_string())
.collect();
// Run all commands in history
for cmd in self.history.iter() {
match self.interpreter.run(Some(cmd.clone())) {
Ok(_) => {
info!("Successfully ran brainfuck source code from REPL");
}
Err((e, _)) => {
error!("Failed to run brainfuck source code from REPL: {}", e);
}
}
}
}
Err(e) => {
error!("Failed to load history from file: {}", e);
}
}
}
"reset" | "r" => {
println!("Resetting REPL");
self.interpreter.reset();
}
"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!("!load, !l: load the history from a file");
println!("!reset, !r: reset the interpreter");
println!("!help: show this fu*king help message");
println!("!fuck: exit the REPL mode");
}
_ => println!("Unknown command: {}, type !help to show the help",
input)
}
},
"reset" | "r" => {
println!("Resetting REPL");
self.interpreter.reset();
},
"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!("!load, !l: load the history from a file");
println!("!reset, !r: reset the interpreter");
println!("!help: show this fu*king help message");
println!("!fuck: exit the REPL mode");
}
_ => println!("Unknown command: {}, type !help to show the help", input)
None => {}
}
}
}