Improve the errors system 😆🦀

This commit is contained in:
Anas Elgarhy 2022-10-08 12:01:28 +02:00
parent 6be7873702
commit 353bdec211
6 changed files with 114 additions and 63 deletions

View file

@ -20,7 +20,7 @@ pub struct Args {
pub enum Feature { pub enum Feature {
/// If the value is you want decrement the value and the value is 0, set the value to 255, otherwise decrement the value. /// If the value is you want decrement the value and the value is 0, set the value to 255, otherwise decrement the value.
/// If the value is you want increment the value and the value is 255, set the value to 0, otherwise increment the value. /// If the value is you want increment the value and the value is 255, set the value to 0, otherwise increment the value.
ReverseCounter, ReverseValue,
/// If the pointer at the end of the array, set the pointer to 0, otherwise increment the pointer. /// If the pointer at the end of the array, set the pointer to 0, otherwise increment the pointer.
/// If the pointer at the beginning of the array, set the pointer to the end of the array, otherwise decrement the pointer. /// If the pointer at the beginning of the array, set the pointer to the end of the array, otherwise decrement the pointer.
ReversePointer, ReversePointer,

View file

@ -0,0 +1,71 @@
use std::fmt::{Debug, Formatter, Display};
pub struct InterpreterError {
message: String,
pub code: i32,
}
impl InterpreterError {
pub fn new(message: String, code: i32) -> Self {
Self {
message: message.to_string(),
code,
}
}
}
impl Display for InterpreterError {
fn fmt(&self, f: &mut 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
}
}
pub enum InterpreterErrorKind {
PointerOutOfBounds(usize),
// takes pointer value
ValueOutOfBounds,
ByteReadError(std::io::Error),
ReadError,
UnmatchedClosingBracket(usize), // takes position
}
impl InterpreterErrorKind {
pub fn to_error(&self) -> InterpreterError {
InterpreterError::new(self.to_string(), self.code())
}
fn code(&self) -> i32 {
match self {
InterpreterErrorKind::PointerOutOfBounds(_) => 11,
InterpreterErrorKind::ValueOutOfBounds => 12,
InterpreterErrorKind::ByteReadError(_) => 13,
InterpreterErrorKind::ReadError => 14,
InterpreterErrorKind::UnmatchedClosingBracket(_) => 15,
}
}
}
impl Display for InterpreterErrorKind {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
InterpreterErrorKind::PointerOutOfBounds(pointer) => write!(f, "Pointer out of bounds {}", pointer),
InterpreterErrorKind::ValueOutOfBounds => write!(f, "Value out of bounds"),
InterpreterErrorKind::ByteReadError(error) =>
write!(f, "Failed to read byte from stdin: no bytes available: {}", error),
InterpreterErrorKind::ReadError => write!(f, "Failed to read byte from stdin: no bytes available"),
InterpreterErrorKind::UnmatchedClosingBracket(pos) => write!(f, "Unmatched closing bracket at position {}", pos),
}
}
}

View file

@ -1,5 +1,5 @@
use crate::arguments; use crate::arguments;
use crate::interpreter::error::InterpreterError; use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::usize; use std::usize;
@ -74,10 +74,7 @@ impl Interpreter {
if self.features.contains(&arguments::Feature::ReversePointer) { if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = 0; self.pointer = 0;
} else { } else {
return Err(InterpreterError::new( return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error())
format!("Pointer out of bounds {}", self.pointer),
11,
));
} }
} }
} }
@ -86,20 +83,33 @@ impl Interpreter {
if self.features.contains(&arguments::Feature::ReversePointer) { if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = self.array_size - 1; self.pointer = self.array_size - 1;
} else { } else {
return Err(InterpreterError::new( return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error());
format!("Pointer out of bounds {}", self.pointer),
11,
));
} }
} else { } else {
self.pointer -= 1; self.pointer -= 1;
} }
} }
BfCommand::IncVal => { BfCommand::IncVal => {
self.cells[self.pointer] = self.cells[self.pointer].wrapping_add(1); if self.cells[self.pointer] == 255 {
if self.features.contains(&arguments::Feature::ReverseValue) {
self.cells[self.pointer] = 0;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
}
} else {
self.cells[self.pointer] += 1;
}
} }
BfCommand::DecVal => { BfCommand::DecVal => {
self.cells[self.pointer] = self.cells[self.pointer].wrapping_sub(1); if self.cells[self.pointer] == 0 {
if self.features.contains(&arguments::Feature::ReverseValue) {
self.cells[self.pointer] = 255;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
}
} else {
self.cells[self.pointer] -= 1;
}
} }
BfCommand::Print => { BfCommand::Print => {
print!("{}", self.cells[self.pointer] as char); print!("{}", self.cells[self.pointer] as char);
@ -109,16 +119,10 @@ impl Interpreter {
self.cells[self.pointer] = match std::io::stdin().bytes().next() { self.cells[self.pointer] = match std::io::stdin().bytes().next() {
Some(Ok(byte)) => byte, Some(Ok(byte)) => byte,
Some(Err(e)) => { Some(Err(e)) => {
return Err(InterpreterError::new( return Err(InterpreterErrorKind::ByteReadError(e).to_error());
format!("Failed to read byte from stdin: {}", e),
12,
));
} }
None => { None => {
return Err(InterpreterError::new( return Err(InterpreterErrorKind::ReadError.to_error());
"Failed to read byte from stdin: no bytes available".to_string(),
13,
));
} }
}; };
} }
@ -137,7 +141,7 @@ impl Interpreter {
_ => { _ => {
return Err(InterpreterError::new( return Err(InterpreterError::new(
format!("Unmatched closing bracket at position {}", i), format!("Unmatched closing bracket at position {}", i),
14, 15,
)); ));
} }
} }
@ -181,38 +185,3 @@ impl BfCommand {
} }
} }
pub mod error {
use std::fmt::{Debug, Formatter};
pub struct InterpreterError {
message: String,
pub(crate) code: i32,
}
impl InterpreterError {
pub fn new(message: String, code: i32) -> Self {
Self {
message: message.to_string(),
code,
}
}
}
impl std::fmt::Display for InterpreterError {
fn fmt(&self, f: &mut 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

@ -0,0 +1,2 @@
pub mod interpreter;
pub mod error;

View file

@ -1,7 +1,7 @@
mod arguments; mod arguments;
mod interpreter;
mod repl; mod repl;
mod utils; mod utils;
mod bf_interpreter;
use clap::Parser; use clap::Parser;
@ -10,6 +10,7 @@ extern crate pretty_env_logger;
extern crate log; extern crate log;
use arguments::Args; use arguments::Args;
use bf_interpreter::interpreter::Interpreter;
fn main() { fn main() {
pretty_env_logger::init(); pretty_env_logger::init();
@ -18,8 +19,8 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
info!("Parsed command line arguments: {:?}", args); info!("Parsed command line arguments: {:?}", args);
info!("Initializing interpreter"); info!("Initializing bf_interpreter");
let mut interpreter = interpreter::Interpreter::new( let mut interpreter = Interpreter::new(
args.array_size, args.array_size,
utils::read_brainfuck_code_if_any(&args.source), utils::read_brainfuck_code_if_any(&args.source),
args.features.unwrap_or_else(|| vec![]), args.features.unwrap_or_else(|| vec![]),

View file

@ -1,4 +1,4 @@
use crate::interpreter::Interpreter; use crate::bf_interpreter::interpreter::Interpreter;
use std::io::Write; use std::io::Write;
struct Repl { struct Repl {
@ -50,7 +50,7 @@ impl Repl {
let mut cmd = input.split_whitespace(); let mut cmd = input.split_whitespace();
match cmd.next() { match cmd.next() {
Some(repl_cmd) => { Some(repl_cmd) => {
match repl_cmd { match repl_cmd.get(1..).unwrap_or("") {
"fuck" => { "fuck" => {
println!("Bye bye :D"); println!("Bye bye :D");
std::process::exit(0); std::process::exit(0);
@ -64,6 +64,13 @@ impl Repl {
"pointer" | "p" => { "pointer" | "p" => {
println!("Current pointer: {}", self.interpreter.pointer); println!("Current pointer: {}", self.interpreter.pointer);
} }
"pointer_value" | "pv" => {
println!(
"Current pointer value: {} = \'{}\' (char)",
self.interpreter.cells[self.interpreter.pointer],
self.interpreter.cells[self.interpreter.pointer] as char
);
}
"history" | "h" => { "history" | "h" => {
println!("History:"); println!("History:");
for (i, cmd) in self.history.iter().enumerate() { for (i, cmd) in self.history.iter().enumerate() {
@ -122,10 +129,11 @@ impl Repl {
println!("!array, !a: print the current array"); println!("!array, !a: print the current array");
println!("!array_size, !as: print the current array size"); println!("!array_size, !as: print the current array size");
println!("!pointer, !p: print the current pointer value"); println!("!pointer, !p: print the current pointer value");
println!("!pointer_value, !pv: print the current pointer value");
println!("!history, !h: print the history of the commands"); println!("!history, !h: print the history of the commands");
println!("!save, !s: save the history to a file"); println!("!save, !s: save the history to a file");
println!("!load, !l: load the history from a file"); println!("!load, !l: load the history from a file");
println!("!reset, !r: reset the interpreter"); println!("!reset, !r: reset the bf_interpreter");
println!("!help: show this fu*king help message"); println!("!help: show this fu*king help message");
println!("!fuck: exit the REPL mode"); println!("!fuck: exit the REPL mode");
} }
@ -141,7 +149,7 @@ pub fn start(interpreter: Interpreter) {
info!("Entering REPL mode"); info!("Entering REPL mode");
println!("Welcome to the brainfuck REPL mode! :)"); println!("Welcome to the brainfuck REPL mode! :)");
println!( println!(
"Brainfuck interpreter v {}\nBy {}", "Brainfuck bf_interpreter v {}\nBy {}",
clap::crate_version!(), clap::crate_version!(),
clap::crate_authors!() clap::crate_authors!()
); );