2022-10-08 10:01:28 +00:00
|
|
|
use crate::bf_interpreter::interpreter::Interpreter;
|
2022-10-12 11:50:22 +00:00
|
|
|
use colored::Colorize;
|
2022-10-12 16:59:12 +00:00
|
|
|
use std::io::Write;
|
2022-10-12 21:21:21 +00:00
|
|
|
use console::{Term, Key};
|
2022-10-07 22:28:14 +00:00
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
struct Repl {
|
2022-10-12 16:56:26 +00:00
|
|
|
pub interpreter: Interpreter,
|
2022-10-12 21:21:21 +00:00
|
|
|
term: console::Term,
|
2022-10-07 22:28:14 +00:00
|
|
|
history: Vec<String>,
|
2022-10-12 16:31:07 +00:00
|
|
|
loop_body: String,
|
|
|
|
loop_depth: usize,
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 20:11:13 +00:00
|
|
|
const PROMPT: &str = "bf-interpreter> ";
|
|
|
|
const HISTORY_FILE: &str = "bf-interpreter-history.bfr";
|
|
|
|
const COMMAND_PREFIX: &str = "!";
|
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
impl Repl {
|
2022-10-12 21:21:21 +00:00
|
|
|
pub fn new(interpreter: Interpreter, term: Term) -> Repl {
|
2022-10-12 11:50:22 +00:00
|
|
|
Repl {
|
2022-10-07 22:28:14 +00:00
|
|
|
interpreter,
|
2022-10-12 21:21:21 +00:00
|
|
|
term,
|
2022-10-07 22:28:14 +00:00
|
|
|
history: Vec::new(),
|
2022-10-12 16:31:07 +00:00
|
|
|
loop_body: String::new(),
|
|
|
|
loop_depth: 0,
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
// #[no_panic]
|
|
|
|
pub fn run(mut self) -> Result<(), std::io::Error> {
|
2022-10-07 22:28:14 +00:00
|
|
|
loop {
|
2022-10-12 21:21:21 +00:00
|
|
|
self.print_prompt();
|
2022-10-12 16:31:07 +00:00
|
|
|
|
|
|
|
std::io::stdout().flush()?;
|
2022-10-10 20:55:50 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
match self.read_input() {
|
|
|
|
Ok(input) => {
|
|
|
|
let user_input = input.trim().to_string(); // Remove trailing newline
|
2022-10-07 22:28:14 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
if !user_input.is_empty() && user_input.len() > 0 {
|
|
|
|
self.history.push(user_input.clone()); // Save input to history
|
|
|
|
self.process(user_input); // Process the input
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 22:28:14 +00:00
|
|
|
Err(e) => {
|
2022-10-12 21:21:21 +00:00
|
|
|
eprintln!("Error: {}", e);
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-12 21:21:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_prompt(&self) {
|
|
|
|
print!(
|
|
|
|
"{}",
|
|
|
|
if self.loop_depth != 0 {
|
|
|
|
"........ ".yellow()
|
|
|
|
} else {
|
|
|
|
PROMPT.to_string().truecolor(54, 76, 76)
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_input(&mut self) -> Result<String, std::io::Error> {
|
|
|
|
let mut input = String::new();
|
|
|
|
let mut rev_index = 0;
|
2022-10-07 22:28:14 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
loop {
|
|
|
|
let key = self.term.read_key()?; // Read key from terminal
|
|
|
|
|
|
|
|
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)
|
|
|
|
.unwrap();
|
|
|
|
rev_index += 1;
|
|
|
|
self.term.clear_line()?;
|
|
|
|
self.print_prompt();
|
|
|
|
self.term.write_str(last)?;
|
|
|
|
input = last.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Key::ArrowDown => {
|
|
|
|
if !self.history.is_empty() && rev_index > 0 {
|
|
|
|
let first = self.history.get(self.history.len() - rev_index)
|
|
|
|
.unwrap();
|
|
|
|
rev_index -= 1;
|
|
|
|
self.term.clear_line()?;
|
|
|
|
self.print_prompt();
|
|
|
|
self.term.write_str(first)?;
|
|
|
|
input = first.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Key::Char(c) => {
|
|
|
|
self.term.write_str(&c.to_string())?;
|
|
|
|
input.push(c);
|
|
|
|
}
|
|
|
|
Key::Backspace => {
|
|
|
|
self.term.clear_line()?;
|
|
|
|
self.term.write_str(&input[0..input.len() - 1])?;
|
|
|
|
self.term.move_cursor_left(1)?;
|
|
|
|
input.pop();
|
|
|
|
}
|
|
|
|
Key::Enter => {
|
|
|
|
self.term.write_str("\n")?;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => {}
|
2022-10-10 20:55:50 +00:00
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
}
|
2022-10-12 21:21:21 +00:00
|
|
|
Ok(input)
|
2022-10-12 16:31:07 +00:00
|
|
|
}
|
2022-10-10 20:55:50 +00:00
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
pub fn process(&mut self, mut user_input: String) {
|
|
|
|
match user_input.find('[') {
|
|
|
|
Some(index) if self.loop_depth == 0 => {
|
|
|
|
self.loop_body.push_str(&user_input[index..]);
|
|
|
|
self.loop_depth = 1;
|
|
|
|
user_input = user_input[..index].to_string();
|
2022-10-12 16:53:53 +00:00
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
Some(_) => {
|
|
|
|
self.loop_body.push_str(&user_input);
|
|
|
|
user_input.matches('[').for_each(|_| self.loop_depth += 1);
|
|
|
|
user_input.matches(']').for_each(|_| self.loop_depth -= 1);
|
|
|
|
return;
|
2022-10-12 16:53:53 +00:00
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
_ => {
|
|
|
|
if user_input.contains(']') {
|
|
|
|
if self.loop_depth == 0 {
|
|
|
|
error!("Found ']' without matching '['");
|
|
|
|
return;
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
self.loop_depth -= 1;
|
|
|
|
if self.loop_depth == 0 {
|
|
|
|
self.loop_body.push_str(&user_input);
|
|
|
|
user_input = self.loop_body.clone();
|
|
|
|
self.loop_body = String::new();
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
if self.loop_depth != 0 {
|
|
|
|
self.loop_body.push_str(&user_input);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if user_input.is_empty() || user_input.len() == 0 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if user_input.starts_with(COMMAND_PREFIX) {
|
|
|
|
self.run_repl_cmd(user_input);
|
|
|
|
} else {
|
|
|
|
match self.interpreter.run(user_input) {
|
|
|
|
Ok(_) => {
|
|
|
|
info!("Successfully ran brainfuck source code from REPL");
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Failed to run brainfuck source code from REPL: {}", e);
|
|
|
|
}
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
fn run_repl_cmd(&mut self, user_input: String) {
|
2022-10-12 11:50:22 +00:00
|
|
|
let mut cmd = user_input.split_whitespace();
|
2022-10-07 22:52:43 +00:00
|
|
|
match cmd.next() {
|
|
|
|
Some(repl_cmd) => {
|
2022-10-08 20:11:13 +00:00
|
|
|
match repl_cmd.get(COMMAND_PREFIX.len()..).unwrap_or("") {
|
2022-10-07 22:52:43 +00:00
|
|
|
"fuck" => {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!("{}", "Bye bye :D".green());
|
2022-10-07 22:52:43 +00:00
|
|
|
std::process::exit(0);
|
|
|
|
}
|
|
|
|
"array" | "a" => {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!("{}", format!("Current array: {:?}", self.interpreter.cells));
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
|
|
|
"array_size" | "as" => {
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!(
|
|
|
|
"Current array size: {}",
|
|
|
|
self.interpreter.cells.len().to_string().bold().green()
|
|
|
|
)
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
|
|
|
"pointer" | "p" => {
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!(
|
|
|
|
"Current pointer: {}",
|
|
|
|
self.interpreter.pointer.to_string().bold().green()
|
|
|
|
)
|
|
|
|
);
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-08 10:01:28 +00:00
|
|
|
"pointer_value" | "pv" => {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!(
|
|
|
|
"Current pointer value: {} = \'{}\' (char)",
|
2022-10-08 10:01:28 +00:00
|
|
|
self.interpreter.cells[self.interpreter.pointer],
|
2022-10-12 21:21:21 +00:00
|
|
|
self.interpreter.cells[self.interpreter.pointer].to_char().unwrap_or_else(|_| '?')
|
2022-10-08 10:01:28 +00:00
|
|
|
);
|
|
|
|
}
|
2022-10-07 22:52:43 +00:00
|
|
|
"history" | "h" => {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!("{}", "History:".underline().green());
|
2022-10-07 22:52:43 +00:00
|
|
|
for (i, cmd) in self.history.iter().enumerate() {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!("{}", format!("{}: {}", i, cmd));
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-07 22:52:43 +00:00
|
|
|
"save" | "s" => {
|
2022-10-08 20:11:13 +00:00
|
|
|
let file_name = cmd.next().unwrap_or(HISTORY_FILE);
|
2022-10-07 22:52:43 +00:00
|
|
|
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!("Saving history to file: {file_name}").yellow()
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
match std::fs::write(file_name, self.history.join("\n")) {
|
|
|
|
Ok(_) => {
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!("Successfully saved history to file: {file_name}")
|
|
|
|
.green()
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Failed to save history to file: {}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"load" | "l" => {
|
2022-10-08 20:11:13 +00:00
|
|
|
let file_name = cmd.next().unwrap_or(HISTORY_FILE);
|
2022-10-07 22:52:43 +00:00
|
|
|
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!("Loading history from file: {file_name}").yellow()
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
match std::fs::read_to_string(file_name) {
|
|
|
|
Ok(history) => {
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
format!("Successfully loaded history from file: {file_name}")
|
|
|
|
.green()
|
|
|
|
);
|
2022-10-07 23:06:35 +00:00
|
|
|
self.history = history.split("\n").map(|s| s.to_string()).collect();
|
2022-10-07 22:52:43 +00:00
|
|
|
|
|
|
|
// Run all commands in history
|
|
|
|
for cmd in self.history.iter() {
|
2022-10-10 20:55:50 +00:00
|
|
|
match self.interpreter.run(cmd.clone()) {
|
2022-10-07 22:52:43 +00:00
|
|
|
Ok(_) => {
|
2022-10-07 23:06:35 +00:00
|
|
|
info!(
|
|
|
|
"Successfully ran brainfuck source code from REPL"
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
2022-10-07 23:05:21 +00:00
|
|
|
Err(e) => {
|
2022-10-07 23:06:35 +00:00
|
|
|
error!(
|
|
|
|
"Failed to run brainfuck source code from REPL: {}",
|
|
|
|
e
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Failed to load history from file: {}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"reset" | "r" => {
|
2022-10-12 16:31:07 +00:00
|
|
|
println!("{}", "Resetting REPL".truecolor(56, 33, 102));
|
2022-10-07 22:52:43 +00:00
|
|
|
self.interpreter.reset();
|
2022-10-12 11:50:22 +00:00
|
|
|
self.history = Vec::new();
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
|
|
|
"help" => {
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"!array, !a: print the current array\n\
|
2022-10-12 11:50:22 +00:00
|
|
|
!array_size, !as: print the current array size\n\
|
|
|
|
!pointer, !p: print the current pointer\n\
|
|
|
|
!pointer_value, !pv: print the current pointer value\n\
|
|
|
|
!history, !h: print the REPL history\n\
|
|
|
|
!save, !s: save the REPL history to a file\n\
|
|
|
|
!load, !l: load the REPL history from a file\n\
|
|
|
|
!reset, !r: reset the REPL\n\
|
|
|
|
!help: print this help message\n\
|
2022-10-12 16:59:12 +00:00
|
|
|
!fuck: exit the REPL"
|
|
|
|
);
|
2022-10-07 22:52:43 +00:00
|
|
|
}
|
2022-10-12 16:59:12 +00:00
|
|
|
_ => println!(
|
|
|
|
"{}",
|
|
|
|
format!(
|
|
|
|
"Unknown command: {}, type {} to show the help",
|
|
|
|
user_input,
|
|
|
|
(COMMAND_PREFIX.to_string() + "help").green()
|
|
|
|
)
|
2022-10-12 21:21:21 +00:00
|
|
|
.red()
|
2022-10-12 16:59:12 +00:00
|
|
|
),
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-07 23:06:35 +00:00
|
|
|
}
|
2022-10-07 22:52:43 +00:00
|
|
|
None => {}
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-12 16:31:07 +00:00
|
|
|
}
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 20:11:13 +00:00
|
|
|
/// Run the REPL
|
|
|
|
/// # Arguments
|
|
|
|
/// * `interpreter` - The interpreter to use
|
2022-10-12 21:21:21 +00:00
|
|
|
pub fn start(interpreter: Interpreter, term: Term) {
|
2022-10-07 22:28:14 +00:00
|
|
|
info!("Entering REPL mode");
|
2022-10-12 16:59:12 +00:00
|
|
|
println!(
|
|
|
|
"{}\n\
|
2022-10-12 11:50:22 +00:00
|
|
|
Brainfuck interpreter v {}\nBy {}\n\
|
|
|
|
{}\n\
|
|
|
|
Type {} to exit :D\n\
|
2022-10-12 16:31:07 +00:00
|
|
|
type {} to get more fu*king help",
|
2022-10-12 16:59:12 +00:00
|
|
|
"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(),
|
2022-10-12 16:31:07 +00:00
|
|
|
);
|
2022-10-12 11:50:22 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
match Repl::new(interpreter, term).run() {
|
2022-10-12 11:50:22 +00:00
|
|
|
Ok(_) => {
|
|
|
|
info!("Successfully ran REPL");
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Failed to run REPL: {}", e);
|
|
|
|
std::process::exit(1);
|
|
|
|
}
|
|
|
|
}
|
2022-10-07 22:28:14 +00:00
|
|
|
}
|
2022-10-10 20:55:50 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2022-10-12 16:31:07 +00:00
|
|
|
use pretty_assertions::assert_eq;
|
2022-10-12 21:21:21 +00:00
|
|
|
use crate::bf_interpreter::cell::Cell;
|
2022-10-10 20:55:50 +00:00
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
#[test]
|
2022-10-10 20:55:50 +00:00
|
|
|
fn nested_loop_level_1() {
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut term = Term::stdout();
|
|
|
|
let interpreter = Interpreter::new(4, vec![], &mut term);
|
2022-10-12 16:31:07 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut repl = Repl::new(interpreter, term);
|
2022-10-12 16:31:07 +00:00
|
|
|
|
|
|
|
repl.process("++".to_string());
|
|
|
|
repl.process("[>++".to_string());
|
|
|
|
repl.process("[>+<-]".to_string());
|
|
|
|
repl.process("<-]".to_string());
|
|
|
|
|
2022-10-12 16:56:26 +00:00
|
|
|
let cells = &repl.interpreter.cells;
|
2022-10-12 16:31:07 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
assert_eq!(cells[0], Cell::default_cell(&vec![]));
|
|
|
|
assert_eq!(cells[1], Cell::default_cell(&vec![]));
|
|
|
|
assert_eq!(cells[2], Cell::new(4, &vec![]));
|
2022-10-12 16:31:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nested_loop_level_2() {
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut term = console::Term::stdout();
|
|
|
|
let interpreter = Interpreter::new(4, vec![], &mut term);
|
2022-10-10 20:55:50 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut repl = Repl::new(interpreter, term);
|
2022-10-12 16:31:07 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
2022-10-12 16:57:40 +00:00
|
|
|
let cells = &repl.interpreter.cells;
|
2022-10-12 16:31:07 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
assert_eq!(cells[0], Cell::default_cell(&vec![]));
|
|
|
|
assert_eq!(cells[1], Cell::default_cell(&vec![]));
|
|
|
|
assert_eq!(cells[2], Cell::new(4, &vec![]));
|
2022-10-12 16:31:07 +00:00
|
|
|
}
|
2022-10-10 20:55:50 +00:00
|
|
|
|
2022-10-12 16:31:07 +00:00
|
|
|
#[test]
|
|
|
|
fn print_my_first_name() {
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut term = console::Term::stdout();
|
|
|
|
let interpreter = Interpreter::new(10, vec![], &mut term);
|
2022-10-12 16:31:07 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut repl = Repl::new(interpreter, term);
|
2022-10-12 16:31:07 +00:00
|
|
|
|
|
|
|
let code = "++++ ++++ 8
|
|
|
|
[
|
|
|
|
>++++
|
|
|
|
[
|
|
|
|
>++ A
|
|
|
|
>+++ a
|
|
|
|
>++++
|
|
|
|
>+ space
|
|
|
|
<<<<-
|
|
|
|
]
|
|
|
|
|
|
|
|
>>>>>>++
|
|
|
|
[
|
|
|
|
<<<-
|
|
|
|
>>>-
|
|
|
|
]
|
|
|
|
|
|
|
|
<<<<<<<-
|
|
|
|
]
|
|
|
|
>>+. Print cell 2: A
|
|
|
|
<<++++
|
|
|
|
[
|
|
|
|
>+++
|
|
|
|
[
|
|
|
|
>+++
|
|
|
|
<-
|
|
|
|
]
|
|
|
|
>++
|
|
|
|
<<-
|
|
|
|
]
|
|
|
|
>>+. Print n
|
|
|
|
<<+++
|
|
|
|
[
|
|
|
|
>+++
|
|
|
|
[
|
|
|
|
>-
|
|
|
|
<-
|
|
|
|
]
|
|
|
|
>-
|
|
|
|
<<-
|
|
|
|
]
|
|
|
|
>>-. Print n
|
|
|
|
<<++++++
|
|
|
|
[
|
|
|
|
>>+++
|
|
|
|
<<-
|
|
|
|
]
|
2022-10-12 16:59:12 +00:00
|
|
|
>>. Print s"
|
|
|
|
.to_string()
|
|
|
|
.split("\n")
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
.collect::<Vec<String>>();
|
2022-10-12 16:31:07 +00:00
|
|
|
|
|
|
|
for line in code {
|
|
|
|
repl.process(line);
|
|
|
|
}
|
|
|
|
}
|
2022-10-12 16:53:53 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn print_my_first_name_in_one_command() {
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut term = console::Term::stdout();
|
|
|
|
let interpreter = Interpreter::new(10, vec![], &mut term);
|
2022-10-12 16:53:53 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut repl = Repl::new(interpreter, term);
|
2022-10-12 16:53:53 +00:00
|
|
|
|
|
|
|
let code = "++++++++[>++++[>++<-]>>>>>>++[<<<->>>-]<<<<<<<-]>>+.<<++++[>+++
|
2022-10-12 16:59:12 +00:00
|
|
|
[>+++<-]>++<<-]>>+.<<+++[>+++[>-<-]>-<<-]>>-.<<++++++[>>+++<<-]>>."
|
|
|
|
.to_string();
|
2022-10-12 16:53:53 +00:00
|
|
|
|
|
|
|
repl.process(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn print_hello_world() {
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut term = console::Term::stdout();
|
|
|
|
let interpreter = Interpreter::new(10, vec![], &mut term);
|
2022-10-12 16:53:53 +00:00
|
|
|
|
2022-10-12 21:21:21 +00:00
|
|
|
let mut repl = Repl::new(interpreter, term);
|
2022-10-12 16:53:53 +00:00
|
|
|
|
|
|
|
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
|
2022-10-12 16:59:12 +00:00
|
|
|
"
|
2022-10-12 21:21:21 +00:00
|
|
|
.to_string()
|
|
|
|
.split("\n")
|
|
|
|
.for_each(|s| repl.process(s.to_string()));
|
2022-10-12 16:53:53 +00:00
|
|
|
}
|
2022-10-12 16:59:12 +00:00
|
|
|
}
|