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 {
|
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,
|
||||||
|
|
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::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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
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 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![]),
|
||||||
|
|
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;
|
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!()
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue