rob/
lib.rs

1use log::{debug, info, warn};
2use std::io::Read;
3
4pub struct Intepreter {
5    code: Vec<u8>,
6    data: Vec<u8>,
7    match_stack: Vec<usize>,
8    code_ptr: usize,
9    data_ptr: usize,
10    max_output_size: usize,
11}
12
13impl Intepreter {
14    pub fn new(code: Vec<u8>, max_data_size: usize, max_output_size: usize) -> Self {
15        debug!("Creating new interpreter with code length: {}", code.len());
16        let mut match_stack = vec![0; code.len()];
17        let mut stack = Vec::new();
18        for (i, &c) in code.iter().enumerate() {
19            if c == 7 {
20                debug!("Found loop start at position {}", i);
21                stack.push(i);
22            } else if c == 8 {
23                if let Some(open) = stack.pop() {
24                    debug!("Matching loop end at {} with start at {}", i, open);
25                    match_stack[open] = i;
26                    match_stack[i] = open;
27                } else {
28                    warn!("Unmatched closing bracket at position {}", i);
29                }
30            }
31        }
32
33        if !stack.is_empty() {
34            warn!("Unmatched opening brackets at positions: {:?}", stack);
35        }
36
37        Intepreter {
38            code,
39            data: vec![0; max_data_size],
40            code_ptr: 0,
41            data_ptr: max_data_size / 2,
42            match_stack,
43            max_output_size,
44        }
45    }
46
47    pub fn run(&mut self) -> String {
48        info!("Starting interpreter execution");
49        let mut output = Vec::with_capacity(self.max_output_size);
50
51        while self.code_ptr < self.code.len() {
52            debug!(
53                "State: ptr={}, data_ptr={}, current_op={}, current_value={}",
54                self.code_ptr, self.data_ptr, self.code[self.code_ptr], self.data[self.data_ptr]
55            );
56
57            let mut normal = true;
58            match self.code[self.code_ptr] {
59                1 => self.data_ptr += 1,                            // >
60                2 => self.data_ptr -= 1,                            //<
61                3 => self.data[self.data_ptr] += 1,                 //+
62                4 => self.data[self.data_ptr] -= 1,                 // -
63                5 => output.push(self.data[self.data_ptr] as char), //.
64                6 => {
65                    warn!("There Shouldn't be any input in this mode");
66                    let mut input = [0; 1];
67                    std::io::stdin().read_exact(&mut input).unwrap();
68                    self.data[self.data_ptr] = input[0]
69                } // ,
70                7 => {
71                    if self.data[self.data_ptr] == 0 {
72                        self.code_ptr = self.match_stack[self.code_ptr];
73                        normal = false;
74                    }
75                } // [
76                8 => {
77                    if self.data[self.data_ptr] != 0 {
78                        self.code_ptr = self.match_stack[self.code_ptr];
79                        normal = false;
80                    }
81                } // ]
82                _ => {}
83            }
84            if normal {
85                self.code_ptr += 1;
86            }
87        }
88        info!("Execution completed");
89        // info!("output: {:?}", output);
90        output.into_iter().collect()
91    }
92}
93
94pub fn brainfuck_to_bytecode(code: &str) -> Vec<u8> {
95    debug!(
96        "Converting brainfuck code to bytecode, length: {}",
97        code.len()
98    );
99    let code = code.chars().filter_map(|c| match c {
100        '>' => Some(1),
101        '<' => Some(2),
102        '+' => Some(3),
103        '-' => Some(4),
104        '.' => Some(5),
105        ',' => Some(6),
106        '[' => Some(7),
107        ']' => Some(8),
108        _ => None,
109    });
110    code.collect()
111}
112
113pub fn ook_to_bytecode(code: &str) -> Vec<u8> {
114    debug!("Converting Ook code to bytecode, length: {}", code.len());
115    let words: Vec<&str> = code.split_whitespace().collect();
116
117    let mut commands = Vec::new();
118    for chunk in words.chunks(2) {
119        if chunk.len() == 2 {
120            commands.push((chunk[0].to_string(), chunk[1].to_string()));
121        }
122    }
123    commands
124        .iter()
125        .filter_map(|(first, second)| {
126            match (first.as_str(), second.as_str()) {
127                ("Ook.", "Ook?") => Some(1), // >
128                ("Ook?", "Ook.") => Some(2), // <
129                ("Ook.", "Ook.") => Some(3), // +
130                ("Ook!", "Ook!") => Some(4), // -
131                ("Ook!", "Ook.") => Some(5), // .
132                ("Ook.", "Ook!") => Some(6), // ,
133                ("Ook!", "Ook?") => Some(7), // [
134                ("Ook?", "Ook!") => Some(8), // ]
135                _ => None,
136            }
137        })
138        .collect()
139}
140
141pub fn parse_short_ook_commands(code: &str) -> Vec<u8> {
142    let iter: Vec<char> = code
143        .chars()
144        .filter(|c| matches!(c, '.' | '?' | '!'))
145        .collect();
146    let mut commands = vec![];
147    for chunk in iter.chunks(2) {
148        if chunk.len() == 2 {
149            commands.push((chunk[0], chunk[1]));
150        }
151    }
152    commands
153        .iter()
154        .filter_map(|(first, second)| match (*first, *second) {
155            ('.', '?') => Some(1),
156            ('?', '.') => Some(2),
157            ('.', '.') => Some(3),
158            ('!', '!') => Some(4),
159            ('!', '.') => Some(5),
160            ('.', '!') => Some(6),
161            ('!', '?') => Some(7),
162            ('?', '!') => Some(8),
163            _ => None,
164        })
165        .collect()
166}