brainfuck_hcy/
lib.rs

1mod errors;
2mod interpreter;
3mod parse_args;
4
5use std::fmt;
6use std::io::{self, Write};
7
8pub use errors::MyError;
9pub use parse_args::Config;
10
11pub fn run(mut config: Config) -> Result<(), MyError> {
12    config.token_vec = raw_code_to_token_vec(&config.raw_code)?;
13    match config.show_ir {
14        true => show_ir(config.token_vec),
15        false => interpreter::run(config)?,
16    }
17    Ok(())
18}
19
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum Token {
22    PtrIncrease(u32),
23    PtrDecreate(u32),
24    DataIncrease(u32),
25    DataDecrease(u32),
26    JumpForward(u32),
27    JumpBack(u32),
28    Output,
29    Input,
30}
31
32#[derive(Debug, PartialEq)]
33pub enum OutputMode {
34    Individually,
35    Bulk,
36}
37
38struct IO {
39    output_mode: OutputMode,
40    output_buffer: Vec<u32>,
41}
42
43impl IO {
44    fn new(output_mode: OutputMode) -> Self {
45        IO {
46            output_mode,
47            output_buffer: Vec::new(),
48        }
49    }
50
51    fn buffer_to_string(&self) -> String {
52        let mut result = String::new();
53        for &n in self.output_buffer.iter() {
54            result.push(char::from_u32(n).unwrap());
55        }
56        result
57    }
58
59    fn output(&mut self, runtime_memory: &Memory) -> Result<char, MyError> {
60        let n = runtime_memory.output();
61        let char = match char::from_u32(n) {
62            Some(c) => c,
63            None => {
64                return Err(MyError::Custom(format!(
65                    "Invalid Unicode scalar value: {}",
66                    n
67                )))
68            }
69        };
70        self.output_buffer.push(n);
71        Ok(char)
72    }
73
74    fn input(&self, runtime_memory: &mut Memory) -> Result<(), MyError> {
75        print!("Input:");
76
77        match io::stdout().flush() {
78            Ok(_) => {}
79            Err(e) => return Err(MyError::Io(e)),
80        }
81        let mut buffer = String::new();
82        if let Err(e) = io::stdin().read_line(&mut buffer) {
83            return Err(MyError::Io(e));
84        }
85        let (n, eof) = input_to_u32(buffer)?;
86        if eof {
87            println!();
88        }
89        if n > runtime_memory.cell_max {
90            return Err(MyError::Custom(format!(
91                "Input value {} exceeds the maximum cell value {}",
92                n, runtime_memory.cell_max
93            )));
94        }
95        runtime_memory.input(n);
96        Ok(())
97    }
98}
99
100struct Memory {
101    view: Vec<u32>,
102    ptr: u32,
103    cell_max: u32,
104}
105
106impl fmt::Display for Memory {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        let mut s = String::new();
109        for (i, &cell) in self.view.iter().enumerate() {
110            if i == self.ptr as usize {
111                s.push('>');
112            }
113            s.push_str(&cell.to_string());
114            if i != self.view.len() - 1 {
115                s.push_str(", ");
116            }
117        }
118        write!(f, "[{}]", s)
119    }
120}
121
122impl Memory {
123    fn new(cell_max: u32) -> Self {
124        Memory {
125            view: vec![0],
126            ptr: 0,
127            cell_max,
128        }
129    }
130
131    fn ptr_increase(&mut self, n: u32) {
132        self.ptr += n;
133        if self.view.len() <= self.ptr as usize {
134            self.view.resize(self.ptr as usize + 1, 0);
135        }
136    }
137
138    fn ptr_decrease(&mut self, n: u32) -> Result<(), MyError> {
139        if n > self.ptr {
140            return Err(MyError::Custom(format!(
141                "The current pointer is at position {} and cannot move left by {} positions",
142                self.ptr, n
143            )));
144        }
145        self.ptr -= n;
146        Ok(())
147    }
148
149    fn data_increase(&mut self, n: u32) {
150        let v = &mut self.view[self.ptr as usize];
151        *v = if self.cell_max - *v >= n {
152            *v + n
153        } else {
154            n - (self.cell_max - *v + 1)
155        };
156    }
157
158    fn data_decrease(&mut self, n: u32) {
159        let v = &mut self.view[self.ptr as usize];
160        *v = if *v >= n {
161            *v - n
162        } else {
163            self.cell_max - (n - *v - 1)
164        };
165    }
166
167    fn output(&self) -> u32 {
168        self.view[self.ptr as usize]
169    }
170
171    fn input(&mut self, n: u32) {
172        self.view[self.ptr as usize] = n;
173    }
174}
175
176fn raw_code_to_token_vec(raw_code: &str) -> Result<Vec<Token>, MyError> {
177    let mut vec = Vec::new();
178    let mut stack = Vec::new();
179    let chars = raw_code.chars().enumerate();
180    for (i, char) in chars {
181        match char {
182            '>' => {
183                if let Some(Token::PtrIncrease(n)) = vec.last_mut() {
184                    *n += 1;
185                } else {
186                    vec.push(Token::PtrIncrease(1));
187                }
188            }
189            '<' => {
190                if let Some(Token::PtrDecreate(n)) = vec.last_mut() {
191                    *n += 1;
192                } else {
193                    vec.push(Token::PtrDecreate(1));
194                }
195            }
196            '+' => {
197                if let Some(Token::DataIncrease(n)) = vec.last_mut() {
198                    *n += 1;
199                } else {
200                    vec.push(Token::DataIncrease(1));
201                }
202            }
203            '-' => {
204                if let Some(Token::DataDecrease(n)) = vec.last_mut() {
205                    *n += 1;
206                } else {
207                    vec.push(Token::DataDecrease(1));
208                }
209            }
210            '.' => vec.push(Token::Output),
211            ',' => vec.push(Token::Input),
212            '[' => {
213                vec.push(Token::JumpForward(0));
214                stack.push(vec.len() as u32);
215            }
216            ']' => {
217                if let Some(start) = stack.pop() {
218                    vec.push(Token::JumpBack(start));
219                    *vec.get_mut(start as usize - 1).unwrap() =
220                        Token::JumpForward(vec.len() as u32);
221                } else {
222                    return Err(MyError::Custom(format!(
223                        "Unmatched JumpBack found at [{}]",
224                        i
225                    )));
226                }
227            }
228            _ => (),
229        }
230    }
231
232    if !stack.is_empty() {
233        return Err(MyError::Custom(format!(
234            "Unmatched JumpForward found at {:?}",
235            stack
236        )));
237    }
238
239    Ok(vec)
240}
241
242fn input_to_u32(mut s: String) -> Result<(u32, bool), MyError> {
243    let trimed = s.trim();
244    if trimed.ends_with("u32") {
245        s.truncate(trimed.len() - 3);
246        return match s.parse::<u32>() {
247            Ok(value) => Ok((value, false)),
248            Err(e) => Err(MyError::Parse(e)),
249        };
250    }
251
252    match s.as_bytes() {
253        x if x.ends_with(&[13, 10]) => {
254            // Windows
255            match s.chars().count() {
256                3 => {
257                    let c = s.chars().next().unwrap();
258                    Ok((c as u32, false))
259                }
260                2 => Ok(('\n' as u32, false)),
261                _ => Err(MyError::Custom(
262                    "The length of the input string is greater than 1, unable to parse into char"
263                        .to_string(),
264                )),
265            }
266        }
267
268        x if x.ends_with(&[10]) => {
269            // Unix & Unix like
270            match s.chars().count() {
271                2 => {
272                    let c = s.chars().next().unwrap();
273                    Ok((c as u32, false))
274                }
275                1 => Ok(('\n' as u32, false)),
276                _ => Err(MyError::Custom(
277                    "The length of the input string is greater than 1, unable to parse into char"
278                        .to_string(),
279                )),
280            }
281        }
282
283        _ => {
284            // EOF
285            Ok((0, true))
286        }
287    }
288}
289
290fn show_ir(token_vec: Vec<Token>) {
291    for token in token_vec {
292        match token {
293            Token::PtrIncrease(n) => println!("PtrIncrease  {}", n),
294            Token::PtrDecreate(n) => println!("PtrDecreate  {}", n),
295            Token::DataIncrease(n) => println!("DataIncrease {}", n),
296            Token::DataDecrease(n) => println!("DataDecrease {}", n),
297            Token::JumpForward(n) => println!("JumpForward  {}", n),
298            Token::JumpBack(n) => println!("JumpBack     {}", n),
299            Token::Output => println!("Output"),
300            Token::Input => println!("Input"),
301        }
302    }
303}