1mod instruction;
2mod vm;
3
4use instruction::Instruction;
5use unicode_segmentation::UnicodeSegmentation;
6
7mod test;
8
9fn clean_file(file: &str) -> String {
11 file.lines()
12 .filter_map(|line: &str| line.split('#').next())
13 .collect::<Vec<&str>>()
14 .join("")
15}
16
17fn parse(commands: &str) -> Vec<Instruction> {
19 clean_file(commands)
20 .graphemes(true)
21 .filter_map(Instruction::from_glyph)
22 .collect()
23}
24
25fn execute_print(vm: &mut vm::State) -> Option<u8> {
27 loop {
28 match vm.step() {
29 Ok(()) => (),
30 Err(vm::Interrupt::End(top)) => break top,
31 Err(vm::Interrupt::Output(c)) => print!("{c}"),
32 Err(vm::Interrupt::StackUnderflow) => break None,
33 }
34 }
35}
36fn execute_buffer(vm: &mut vm::State, output_buffer: &mut String) -> Option<u8> {
38 loop {
39 match vm.step() {
40 Ok(()) => (),
41 Err(vm::Interrupt::End(top)) => break top,
42 Err(vm::Interrupt::Output(c)) => output_buffer.push(c),
43 Err(vm::Interrupt::StackUnderflow) => break None,
44 }
45 }
46}
47
48pub fn run_cli(program: &str, input: &str) -> Option<u8> {
50 let instructions: Vec<Instruction> = parse(program);
51 let mut vm = vm::State::init_with_input(instructions, input)?;
52 execute_print(&mut vm)
53}
54
55pub fn run_buffered(program: &str, input: &str) -> (Option<u8>, String) {
57 let instructions: Vec<Instruction> = parse(program);
58 let mut output_buffer = String::new();
59
60 (
61 vm::State::init_with_input(instructions, input)
62 .and_then(|mut vm| execute_buffer(&mut vm, &mut output_buffer)),
63 output_buffer,
64 )
65}