diff --git a/src/bf_interpreter/cell.rs b/src/bf_interpreter/cell.rs index 2914315..ad4c0c7 100644 --- a/src/bf_interpreter/cell.rs +++ b/src/bf_interpreter/cell.rs @@ -55,7 +55,7 @@ impl Cell { pub fn increment(&mut self, no_reverse_value: bool) -> Result<(), InterpreterError> { if self.get_value_utf8() == self.max_value() && no_reverse_value { - return Err(InterpreterErrorKind::ValueOutOfBounds.to_error()) + return Err(InterpreterErrorKind::ValueOutOfBounds.to_error()); } match self { Self::Byte(value) => { @@ -78,7 +78,7 @@ impl Cell { pub fn decrement(&mut self, no_reverse_value: bool) -> Result<(), InterpreterError> { if self.get_value_utf8() == 0 && no_reverse_value { - return Err(InterpreterErrorKind::ValueOutOfBounds.to_error()) + return Err(InterpreterErrorKind::ValueOutOfBounds.to_error()); } match self { Self::Byte(value) => { @@ -109,7 +109,7 @@ impl Cell { pub fn to_char(&self) -> Result { let c = match self { Self::Byte(value) => Some(*value as char), - Self::Utf8(value) => char::from_u32(*value) + Self::Utf8(value) => char::from_u32(*value), }; if let Some(c) = c { @@ -145,7 +145,10 @@ mod tests { } assert_eq!(cell, Cell::Byte(255)); - assert_eq!(cell.increment(true).unwrap_err(), InterpreterErrorKind::ValueOutOfBounds.to_error()); + assert_eq!( + cell.increment(true).unwrap_err(), + InterpreterErrorKind::ValueOutOfBounds.to_error() + ); assert_eq!(cell, Cell::Byte(255)); } @@ -160,7 +163,10 @@ mod tests { } assert_eq!(cell, Cell::Utf8(1114111)); - assert_eq!(cell.increment(true).unwrap_err(), InterpreterErrorKind::ValueOutOfBounds.to_error()); + assert_eq!( + cell.increment(true).unwrap_err(), + InterpreterErrorKind::ValueOutOfBounds.to_error() + ); assert_eq!(cell, Cell::Utf8(1114111)); } @@ -205,7 +211,10 @@ mod tests { } assert_eq!(cell, Cell::Byte(0)); - assert_eq!(cell.decrement(true).unwrap_err(), InterpreterErrorKind::ValueOutOfBounds.to_error()); + assert_eq!( + cell.decrement(true).unwrap_err(), + InterpreterErrorKind::ValueOutOfBounds.to_error() + ); assert_eq!(cell, Cell::Byte(0)); } @@ -220,7 +229,10 @@ mod tests { } assert_eq!(cell, Cell::Utf8(0)); - assert_eq!(cell.decrement(true).unwrap_err(), InterpreterErrorKind::ValueOutOfBounds.to_error()); + assert_eq!( + cell.decrement(true).unwrap_err(), + InterpreterErrorKind::ValueOutOfBounds.to_error() + ); assert_eq!(cell, Cell::Utf8(0)); } @@ -276,5 +288,4 @@ mod tests { cell.set_value('🦀'); assert_eq!(cell, Cell::Utf8(129408)); } - -} \ No newline at end of file +} diff --git a/src/bf_interpreter/interpreter.rs b/src/bf_interpreter/interpreter.rs index f8e9112..e4d74ac 100644 --- a/src/bf_interpreter/interpreter.rs +++ b/src/bf_interpreter/interpreter.rs @@ -1,8 +1,8 @@ use crate::arguments; -use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind}; -use std::io::{Write}; -use std::{char, usize, vec}; use crate::bf_interpreter::cell::Cell; +use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind}; +use std::io::Write; +use std::{char, usize, vec}; pub struct Interpreter { pub cells: Vec, @@ -14,11 +14,7 @@ pub struct Interpreter { } impl Interpreter { - pub fn new( - array_size: usize, - features: Vec, - term: console::Term, - ) -> Self { + pub fn new(array_size: usize, features: Vec, term: console::Term) -> Self { Self { cells: vec![Cell::default_cell(&features); array_size], pointer: 0, @@ -92,15 +88,15 @@ impl Interpreter { fn increment_value(&mut self) -> Result<(), InterpreterError> { trace!("Increment value"); - self.cells[self.pointer].increment( - !self.features.contains(&arguments::Feature::NoReverseValue))?; + self.cells[self.pointer] + .increment(!self.features.contains(&arguments::Feature::NoReverseValue))?; Ok(()) } fn decrement_value(&mut self) -> Result<(), InterpreterError> { trace!("Decrement value"); - self.cells[self.pointer].decrement( - !self.features.contains(&arguments::Feature::NoReverseValue))?; + self.cells[self.pointer] + .decrement(!self.features.contains(&arguments::Feature::NoReverseValue))?; Ok(()) } @@ -126,7 +122,7 @@ impl Interpreter { trace!("Input value"); match self.term.read_char() { Ok(ch) => { - self.cells[self.pointer].set_value(ch); + self.cells[self.pointer].set_value(ch); print!("{}", ch); match std::io::stdout().flush() { Ok(_) => Ok(()), @@ -207,9 +203,9 @@ impl BfCommand { #[cfg(test)] mod tests { - use console::Term; use super::*; use crate::utils; + use console::Term; use pretty_assertions::assert_eq; // for testing only #[test] @@ -226,8 +222,7 @@ mod tests { #[test] fn print_h_repl() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); assert_eq!(interpreter.run(String::from(">+++++++++")), Ok(0)); assert_eq!(interpreter.run(String::from("[<++++ ++++>-]<.")), Ok(0)); @@ -237,8 +232,7 @@ mod tests { #[test] fn nested_loop_level_1_combine() { - let mut interpreter = Interpreter::new(5, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(5, vec![], Term::stdout()); assert_eq!(interpreter.run(String::from("++[>++[>+<-]<-]")), Ok(0)); assert_eq!(interpreter.cells[2], Cell::new(4, &vec![])); @@ -248,8 +242,7 @@ mod tests { #[test] fn execute_hello_world_from_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -263,8 +256,7 @@ mod tests { #[test] fn execute_print_hi_from_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -278,8 +270,7 @@ mod tests { #[test] fn execute_print_hi_yooo_from_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -293,8 +284,7 @@ mod tests { #[test] fn execute_print_my_first_name_from_formatted_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -308,8 +298,7 @@ mod tests { #[test] fn execute_print_my_first_name_from_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -320,7 +309,6 @@ mod tests { Ok(0) ); - assert_eq!(interpreter.cells[0], Cell::default_cell(&vec![])); assert_eq!(interpreter.cells[1], Cell::default_cell(&vec![])); assert_eq!(interpreter.cells[2], Cell::new(115, &vec![])); @@ -331,8 +319,7 @@ mod tests { #[test] fn execute_print_my_first_name_and_last_name_from_formatted_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -346,8 +333,7 @@ mod tests { #[test] fn execute_print_my_first_name_and_last_name_from_file() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); println!(); @@ -361,8 +347,7 @@ mod tests { #[test] fn reset() { - let mut interpreter = Interpreter::new(30000, vec![], - Term::stdout()); + let mut interpreter = Interpreter::new(30000, vec![], Term::stdout()); assert_eq!(interpreter.run(String::from(">++++")), Ok(0)); diff --git a/src/bf_interpreter/mod.rs b/src/bf_interpreter/mod.rs index bd954d1..f6a95b2 100644 --- a/src/bf_interpreter/mod.rs +++ b/src/bf_interpreter/mod.rs @@ -1,3 +1,3 @@ +pub mod cell; pub mod error; pub mod interpreter; -pub mod cell; diff --git a/src/main.rs b/src/main.rs index d666817..79fa966 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,10 +22,11 @@ fn main() { let term = console::Term::stdout(); info!("Initializing interpreter"); - let mut interpreter = - Interpreter::new(args.array_size, - args.features.unwrap_or_else(|| vec![]), - term); + let mut interpreter = Interpreter::new( + args.array_size, + args.features.unwrap_or_else(|| vec![]), + term, + ); match args.source { Some(source) => { @@ -60,6 +61,6 @@ fn main() { } } } - None => repl::start(interpreter), + None => repl::start_repl::start(interpreter), } } diff --git a/src/repl.rs b/src/repl/impl_repl.rs similarity index 57% rename from src/repl.rs rename to src/repl/impl_repl.rs index 4f3e632..f791ee0 100644 --- a/src/repl.rs +++ b/src/repl/impl_repl.rs @@ -1,19 +1,9 @@ +use super::repl::Repl; use crate::bf_interpreter::interpreter::Interpreter; +use crate::repl::repl::{COMMAND_PREFIX, HISTORY_FILE, PROMPT}; use colored::Colorize; +use console::Key; use std::io::Write; -use console::{Term, Key}; - -struct Repl { - pub interpreter: Interpreter, - term: Term, - history: Vec, - loop_body: String, - loop_depth: usize, -} - -const PROMPT: &str = "bf-interpreter> "; -const HISTORY_FILE: &str = "bf-interpreter-history.bfr"; -const COMMAND_PREFIX: &str = "!"; impl Repl { pub fn new(interpreter: Interpreter) -> Repl { @@ -70,7 +60,9 @@ impl Repl { match key { Key::ArrowUp => { if !self.history.is_empty() && rev_index < self.history.len() { - let last = self.history.get(self.history.len() - 1 - rev_index) + let last = self + .history + .get(self.history.len() - 1 - rev_index) .unwrap(); rev_index += 1; self.term.clear_line()?; @@ -81,8 +73,7 @@ impl Repl { } Key::ArrowDown => { if !self.history.is_empty() && rev_index > 0 { - let first = self.history.get(self.history.len() - rev_index) - .unwrap(); + let first = self.history.get(self.history.len() - rev_index).unwrap(); rev_index -= 1; self.term.clear_line()?; self.print_prompt(); @@ -194,7 +185,9 @@ impl Repl { println!( "Current pointer value: {} = \'{}\' (char)", self.interpreter.cells[self.interpreter.pointer], - self.interpreter.cells[self.interpreter.pointer].to_char().unwrap_or_else(|_| '?') + self.interpreter.cells[self.interpreter.pointer] + .to_char() + .unwrap_or_else(|_| '?') ); } "history" | "h" => { @@ -287,7 +280,7 @@ impl Repl { user_input, (COMMAND_PREFIX.to_string() + "help").green() ) - .red() + .red() ), } } @@ -295,225 +288,3 @@ impl Repl { } } } - -/// Run the REPL -/// # Arguments -/// * `interpreter` - The interpreter to use -pub fn start(interpreter: Interpreter) { - info!("Entering REPL mode"); - println!( - "{}\n\ - Brainfuck interpreter v {}\nBy {}\n\ - {}\n\ - Type {} to exit :D\n\ - type {} to get more fu*king help", - "Welcome to the brainfuck REPL mode! :)".green(), - clap::crate_version!().to_string().yellow(), - clap::crate_authors!().to_string().green(), - "Enter your brainfuck code and press enter to run it." - .italic() - .blue(), - (COMMAND_PREFIX.to_string() + "fuck").bold().red(), - (COMMAND_PREFIX.to_string() + "help").bold().green(), - ); - - match Repl::new(interpreter).run() { - Ok(_) => { - info!("Successfully ran REPL"); - } - Err(e) => { - error!("Failed to run REPL: {}", e); - std::process::exit(1); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use pretty_assertions::assert_eq; - use crate::bf_interpreter::cell::Cell; - - #[test] - fn nested_loop_level_1() { - let term = Term::stdout(); - let interpreter = Interpreter::new(4, vec![], term); - - let mut repl = Repl::new(interpreter); - - repl.process("++".to_string()); - repl.process("[>++".to_string()); - repl.process("[>+<-]".to_string()); - repl.process("<-]".to_string()); - - let cells = &repl.interpreter.cells; - - assert_eq!(cells[0], Cell::default_cell(&vec![])); - assert_eq!(cells[1], Cell::default_cell(&vec![])); - assert_eq!(cells[2], Cell::new(4, &vec![])); - } - - #[test] - fn nested_loop_level_2() { - let term = Term::stdout(); - let interpreter = Interpreter::new(4, vec![], term); - - let mut repl = Repl::new(interpreter); - - repl.process("++".to_string()); - repl.process("[>++".to_string()); - repl.process("[>+<-]".to_string()); - repl.process("[>++".to_string()); - repl.process("[>+<-]".to_string()); - repl.process("<-]".to_string()); - repl.process("<-]".to_string()); - - let cells = &repl.interpreter.cells; - - assert_eq!(cells[0], Cell::default_cell(&vec![])); - assert_eq!(cells[1], Cell::default_cell(&vec![])); - assert_eq!(cells[2], Cell::new(4, &vec![])); - } - - #[test] - fn print_my_first_name() { - let term = Term::stdout(); - let interpreter = Interpreter::new(10, vec![], term); - - let mut repl = Repl::new(interpreter); - - let code = "++++ ++++ 8 - [ - >++++ - [ - >++ A - >+++ a - >++++ - >+ space - <<<<- - ] - - >>>>>>++ - [ - <<<- - >>>- - ] - - <<<<<<<- - ] - >>+. Print cell 2: A - <<++++ - [ - >+++ - [ - >+++ - <- - ] - >++ - <<- - ] - >>+. Print n - <<+++ - [ - >+++ - [ - >- - <- - ] - >- - <<- - ] - >>-. Print n - <<++++++ - [ - >>+++ - <<- - ] - >>. Print s" - .to_string() - .split("\n") - .map(|s| s.to_string()) - .collect::>(); - - for line in code { - repl.process(line); - } - - assert_eq!(repl.interpreter.cells[0], Cell::default_cell(&vec![])); - assert_eq!(repl.interpreter.cells[1], Cell::default_cell(&vec![])); - assert_eq!(repl.interpreter.cells[2], Cell::new(115, &vec![])); - assert_eq!(repl.interpreter.cells[3], Cell::new(96, &vec![])); - assert_eq!(repl.interpreter.cells[4], Cell::new(112, &vec![])); - assert_eq!(repl.interpreter.cells[5], Cell::new(32, &vec![])); - } - - #[test] - fn print_my_first_name_in_one_command() { - let term = Term::stdout(); - let interpreter = Interpreter::new(10, vec![], term); - - let mut repl = Repl::new(interpreter); - - let code = "++++++++[>++++[>++>+++>++++>+<<<<-]>>>>>>++[<<<->>>-]<<<<<<<-]>>+.\ - <<++++[>+++[>+++<-]>++<<-]>>+.<<+++[>+++[>-<-]>-<<-]>>-.<<++++++[>>+++<<-]>>." - .to_string(); - - repl.process(code); - - assert_eq!(repl.interpreter.cells[0], Cell::default_cell(&vec![])); - assert_eq!(repl.interpreter.cells[1], Cell::default_cell(&vec![])); - assert_eq!(repl.interpreter.cells[2], Cell::new(115, &vec![])); - assert_eq!(repl.interpreter.cells[3], Cell::new(96, &vec![])); - assert_eq!(repl.interpreter.cells[4], Cell::new(112, &vec![])); - assert_eq!(repl.interpreter.cells[5], Cell::new(32, &vec![])); - } - - #[test] - fn print_hello_world() { - let term = Term::stdout(); - let interpreter = Interpreter::new(10, vec![], term); - - let mut repl = Repl::new(interpreter); - - let _ = "[ This program prints \"Hello World!\" and a newline to the screen, its - length is 106 active command characters. [It is not the shortest.] - ] - ++++++++ Set Cell #0 to 8 - [ - >++++ Add 4 to Cell #1; this will always set Cell #1 to 4 - [ as the cell will be cleared by the loop - >++ Add 2 to Cell #2 - >+++ Add 3 to Cell #3 - >+++ Add 3 to Cell #4 - >+ Add 1 to Cell #5 - <<<<- Decrement the loop counter in Cell #1 - ] Loop until Cell #1 is zero; number of iterations is 4 - >+ Add 1 to Cell #2 - >+ Add 1 to Cell #3 - >- Subtract 1 from Cell #4 - >>+ Add 1 to Cell #6 - [<] Move back to the first zero cell you find; this will - be Cell #1 which was cleared by the previous loop - <- Decrement the loop Counter in Cell #0 - ] Loop until Cell #0 is zero; number of iterations is 8 - - The result of this is: - Cell no : 0 1 2 3 4 5 6 - Contents: 0 0 72 104 88 32 8 - Pointer : ^ - - >>. Cell #2 has value 72 which is 'H' - >---. Subtract 3 from Cell #3 to get 101 which is 'e' - +++++++..+++. Likewise for 'llo' from Cell #3 - >>. Cell #5 is 32 for the space - <-. Subtract 1 from Cell #4 for 87 to give a 'W' - <. Cell #3 was set to 'o' from the end of 'Hello' - +++.------.--------. Cell #3 for 'rl' and 'd' - >>+. Add 1 to Cell #5 gives us an exclamation point - >++. And finally a newline from Cell #6 - " - .to_string() - .split("\n") - .for_each(|s| repl.process(s.to_string())); - } -} diff --git a/src/repl/mod.rs b/src/repl/mod.rs new file mode 100644 index 0000000..eb1d02a --- /dev/null +++ b/src/repl/mod.rs @@ -0,0 +1,3 @@ +mod impl_repl; +mod repl; +pub mod start_repl; diff --git a/src/repl/repl.rs b/src/repl/repl.rs new file mode 100644 index 0000000..19602a2 --- /dev/null +++ b/src/repl/repl.rs @@ -0,0 +1,208 @@ +use crate::bf_interpreter::interpreter::Interpreter; +use console::Term; + +pub struct Repl { + pub interpreter: Interpreter, + pub term: Term, + pub history: Vec, + pub loop_body: String, + pub loop_depth: usize, +} + +/// The REPL prompt +pub const PROMPT: &str = "bf-interpreter> "; +/// History file name +pub const HISTORY_FILE: &str = "bf-interpreter-history.bfr"; +/// The command prefix +pub const COMMAND_PREFIX: &str = "!"; + +/// Tests :D +#[cfg(test)] +mod tests { + use super::*; + use crate::bf_interpreter::cell::Cell; + use pretty_assertions::assert_eq; + + #[test] + fn nested_loop_level_1() { + let term = Term::stdout(); + let interpreter = Interpreter::new(4, vec![], term); + + let mut repl = Repl::new(interpreter); + + repl.process("++".to_string()); + repl.process("[>++".to_string()); + repl.process("[>+<-]".to_string()); + repl.process("<-]".to_string()); + + let cells = &repl.interpreter.cells; + + assert_eq!(cells[0], Cell::default_cell(&vec![])); + assert_eq!(cells[1], Cell::default_cell(&vec![])); + assert_eq!(cells[2], Cell::new(4, &vec![])); + } + + #[test] + fn nested_loop_level_2() { + let term = Term::stdout(); + let interpreter = Interpreter::new(4, vec![], term); + + let mut repl = Repl::new(interpreter); + + repl.process("++".to_string()); + repl.process("[>++".to_string()); + repl.process("[>+<-]".to_string()); + repl.process("[>++".to_string()); + repl.process("[>+<-]".to_string()); + repl.process("<-]".to_string()); + repl.process("<-]".to_string()); + + let cells = &repl.interpreter.cells; + + assert_eq!(cells[0], Cell::default_cell(&vec![])); + assert_eq!(cells[1], Cell::default_cell(&vec![])); + assert_eq!(cells[2], Cell::new(4, &vec![])); + } + + #[test] + fn print_my_first_name() { + let term = Term::stdout(); + let interpreter = Interpreter::new(10, vec![], term); + + let mut repl = Repl::new(interpreter); + + let code = "++++ ++++ 8 + [ + >++++ + [ + >++ A + >+++ a + >++++ + >+ space + <<<<- + ] + + >>>>>>++ + [ + <<<- + >>>- + ] + + <<<<<<<- + ] + >>+. Print cell 2: A + <<++++ + [ + >+++ + [ + >+++ + <- + ] + >++ + <<- + ] + >>+. Print n + <<+++ + [ + >+++ + [ + >- + <- + ] + >- + <<- + ] + >>-. Print n + <<++++++ + [ + >>+++ + <<- + ] + >>. Print s" + .to_string() + .split("\n") + .map(|s| s.to_string()) + .collect::>(); + + for line in code { + repl.process(line); + } + + assert_eq!(repl.interpreter.cells[0], Cell::default_cell(&vec![])); + assert_eq!(repl.interpreter.cells[1], Cell::default_cell(&vec![])); + assert_eq!(repl.interpreter.cells[2], Cell::new(115, &vec![])); + assert_eq!(repl.interpreter.cells[3], Cell::new(96, &vec![])); + assert_eq!(repl.interpreter.cells[4], Cell::new(112, &vec![])); + assert_eq!(repl.interpreter.cells[5], Cell::new(32, &vec![])); + } + + #[test] + fn print_my_first_name_in_one_command() { + let term = Term::stdout(); + let interpreter = Interpreter::new(10, vec![], term); + + let mut repl = Repl::new(interpreter); + + let code = "++++++++[>++++[>++>+++>++++>+<<<<-]>>>>>>++[<<<->>>-]<<<<<<<-]>>+.\ + <<++++[>+++[>+++<-]>++<<-]>>+.<<+++[>+++[>-<-]>-<<-]>>-.<<++++++[>>+++<<-]>>." + .to_string(); + + repl.process(code); + + assert_eq!(repl.interpreter.cells[0], Cell::default_cell(&vec![])); + assert_eq!(repl.interpreter.cells[1], Cell::default_cell(&vec![])); + assert_eq!(repl.interpreter.cells[2], Cell::new(115, &vec![])); + assert_eq!(repl.interpreter.cells[3], Cell::new(96, &vec![])); + assert_eq!(repl.interpreter.cells[4], Cell::new(112, &vec![])); + assert_eq!(repl.interpreter.cells[5], Cell::new(32, &vec![])); + } + + #[test] + fn print_hello_world() { + let term = Term::stdout(); + let interpreter = Interpreter::new(10, vec![], term); + + let mut repl = Repl::new(interpreter); + + let _ = "[ This program prints \"Hello World!\" and a newline to the screen, its + length is 106 active command characters. [It is not the shortest.] + ] + ++++++++ Set Cell #0 to 8 + [ + >++++ Add 4 to Cell #1; this will always set Cell #1 to 4 + [ as the cell will be cleared by the loop + >++ Add 2 to Cell #2 + >+++ Add 3 to Cell #3 + >+++ Add 3 to Cell #4 + >+ Add 1 to Cell #5 + <<<<- Decrement the loop counter in Cell #1 + ] Loop until Cell #1 is zero; number of iterations is 4 + >+ Add 1 to Cell #2 + >+ Add 1 to Cell #3 + >- Subtract 1 from Cell #4 + >>+ Add 1 to Cell #6 + [<] Move back to the first zero cell you find; this will + be Cell #1 which was cleared by the previous loop + <- Decrement the loop Counter in Cell #0 + ] Loop until Cell #0 is zero; number of iterations is 8 + + The result of this is: + Cell no : 0 1 2 3 4 5 6 + Contents: 0 0 72 104 88 32 8 + Pointer : ^ + + >>. Cell #2 has value 72 which is 'H' + >---. Subtract 3 from Cell #3 to get 101 which is 'e' + +++++++..+++. Likewise for 'llo' from Cell #3 + >>. Cell #5 is 32 for the space + <-. Subtract 1 from Cell #4 for 87 to give a 'W' + <. Cell #3 was set to 'o' from the end of 'Hello' + +++.------.--------. Cell #3 for 'rl' and 'd' + >>+. Add 1 to Cell #5 gives us an exclamation point + >++. And finally a newline from Cell #6 + " + .to_string() + .split("\n") + .for_each(|s| repl.process(s.to_string())); + } +} diff --git a/src/repl/start_repl.rs b/src/repl/start_repl.rs new file mode 100644 index 0000000..455a567 --- /dev/null +++ b/src/repl/start_repl.rs @@ -0,0 +1,35 @@ +use crate::bf_interpreter::interpreter::Interpreter; +use crate::repl::repl::{Repl, COMMAND_PREFIX}; +use colored::Colorize; + +/// Run the REPL +/// # Arguments +/// * `interpreter` - The interpreter to use +pub fn start(interpreter: Interpreter) { + info!("Entering REPL mode"); + println!( + "{}\n\ + Brainfuck interpreter v {}\nBy {}\n\ + {}\n\ + Type {} to exit :D\n\ + type {} to get more fu*king help", + "Welcome to the brainfuck REPL mode! :)".green(), + clap::crate_version!().to_string().yellow(), + clap::crate_authors!().to_string().green(), + "Enter your brainfuck code and press enter to run it." + .italic() + .blue(), + (COMMAND_PREFIX.to_string() + "fuck").bold().red(), + (COMMAND_PREFIX.to_string() + "help").bold().green(), + ); + + match Repl::new(interpreter).run() { + Ok(_) => { + info!("Successfully ran REPL"); + } + Err(e) => { + error!("Failed to run REPL: {}", e); + std::process::exit(1); + } + } +}