Improve the errors system 😆🦀
This commit is contained in:
parent
6be7873702
commit
353bdec211
6 changed files with 114 additions and 63 deletions
|
@ -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,
|
||||
|
|
71
src/bf_interpreter/error.rs
Normal file
71
src/bf_interpreter/error.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
2
src/bf_interpreter/mod.rs
Normal file
2
src/bf_interpreter/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod interpreter;
|
||||
pub mod error;
|
|
@ -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![]),
|
||||
|
|
16
src/repl.rs
16
src/repl.rs
|
@ -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!()
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue