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 {
/// 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.
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 beginning of the array, set the pointer to the end of the array, otherwise decrement the pointer.
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::interpreter::error::InterpreterError;
use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind};
use std::io::{Read, Write};
use std::usize;
@ -74,10 +74,7 @@ impl Interpreter {
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = 0;
} else {
return Err(InterpreterError::new(
format!("Pointer out of bounds {}", self.pointer),
11,
));
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error())
}
}
}
@ -86,20 +83,33 @@ impl Interpreter {
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = self.array_size - 1;
} else {
return Err(InterpreterError::new(
format!("Pointer out of bounds {}", self.pointer),
11,
));
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error());
}
} else {
self.pointer -= 1;
}
}
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 => {
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 => {
print!("{}", self.cells[self.pointer] as char);
@ -109,16 +119,10 @@ impl Interpreter {
self.cells[self.pointer] = match std::io::stdin().bytes().next() {
Some(Ok(byte)) => byte,
Some(Err(e)) => {
return Err(InterpreterError::new(
format!("Failed to read byte from stdin: {}", e),
12,
));
return Err(InterpreterErrorKind::ByteReadError(e).to_error());
}
None => {
return Err(InterpreterError::new(
"Failed to read byte from stdin: no bytes available".to_string(),
13,
));
return Err(InterpreterErrorKind::ReadError.to_error());
}
};
}
@ -137,7 +141,7 @@ impl Interpreter {
_ => {
return Err(InterpreterError::new(
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 interpreter;
mod repl;
mod utils;
mod bf_interpreter;
use clap::Parser;
@ -10,6 +10,7 @@ extern crate pretty_env_logger;
extern crate log;
use arguments::Args;
use bf_interpreter::interpreter::Interpreter;
fn main() {
pretty_env_logger::init();
@ -18,8 +19,8 @@ fn main() {
let args = Args::parse();
info!("Parsed command line arguments: {:?}", args);
info!("Initializing interpreter");
let mut interpreter = interpreter::Interpreter::new(
info!("Initializing bf_interpreter");
let mut interpreter = Interpreter::new(
args.array_size,
utils::read_brainfuck_code_if_any(&args.source),
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;
struct Repl {
@ -50,7 +50,7 @@ impl Repl {
let mut cmd = input.split_whitespace();
match cmd.next() {
Some(repl_cmd) => {
match repl_cmd {
match repl_cmd.get(1..).unwrap_or("") {
"fuck" => {
println!("Bye bye :D");
std::process::exit(0);
@ -64,6 +64,13 @@ impl Repl {
"pointer" | "p" => {
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" => {
println!("History:");
for (i, cmd) in self.history.iter().enumerate() {
@ -122,10 +129,11 @@ impl Repl {
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!("!pointer_value, !pv: 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!("!reset, !r: reset the bf_interpreter");
println!("!help: show this fu*king help message");
println!("!fuck: exit the REPL mode");
}
@ -141,7 +149,7 @@ pub fn start(interpreter: Interpreter) {
info!("Entering REPL mode");
println!("Welcome to the brainfuck REPL mode! :)");
println!(
"Brainfuck interpreter v {}\nBy {}",
"Brainfuck bf_interpreter v {}\nBy {}",
clap::crate_version!(),
clap::crate_authors!()
);