1mod interpreter;
24
25mod memory;
27
28use std::{
29 fs,
30 io::{self, Read, Write},
31};
32
33use clap::Parser;
34
35pub use interpreter::Interpreter;
37
38#[derive(Parser, Debug)]
42#[command(author, version, about)]
43pub struct Args {
44 #[arg()]
46 input_file: String,
47
48 #[arg(short, long, default_value_t = 30000)]
50 memory_size: usize,
51}
52
53pub fn run_cmd(args: Args, input: &mut impl Read, output: &mut impl Write) -> Result<(), String> {
55 let source_code = read_file_contents(&args.input_file)?;
56 let mut interpreter = Interpreter::new(input, output, args.memory_size);
57 interpreter.execute(&source_code);
58 Ok(())
59}
60
61fn read_file_contents(input_file_path: &str) -> Result<String, String> {
62 fs::read_to_string(input_file_path).map_err(|error| match error.kind() {
63 io::ErrorKind::NotFound => format!("no such file: '{input_file_path}'"),
64 _ => error.to_string(),
65 })
66}
67
68#[cfg(test)]
69mod tests {
70 use io::Cursor;
71 use std::str;
72
73 use super::*;
74
75 #[test]
76 fn run_cmd_can_be_invoked() {
77 let args = Args {
78 input_file: String::from(""),
79 memory_size: 1,
80 };
81 let mut input = Cursor::new(vec![]);
82 let mut output = vec![];
83 let _ = run_cmd(args, &mut input, &mut output);
84 }
85
86 #[test]
87 fn run_cmd_with_wrong_input_file_returns_no_such_file() {
88 let invalid_file_name = "./examples/invalid.bf";
89 let args = Args {
90 input_file: String::from(invalid_file_name),
91 memory_size: 1,
92 };
93 let mut input = Cursor::new(vec![]);
94 let mut output = vec![];
95 let result = run_cmd(args, &mut input, &mut output);
96 assert!(result.is_err());
97 let expected_error_message = format!("no such file: '{}'", invalid_file_name);
98 assert_eq!(expected_error_message, result.err().unwrap())
99 }
100
101 #[test]
102 fn run_cmd_can_execute_hello_world() {
103 let args = Args {
104 input_file: String::from("./examples/hello_world.bf"),
105 memory_size: 30000,
106 };
107 let mut input = Cursor::new(vec![]);
108 let mut output = vec![];
109 let result = run_cmd(args, &mut input, &mut output);
110 assert!(result.is_ok());
111 assert_eq!("Hello World!\n", str::from_utf8(output.as_slice()).unwrap());
112 }
113}