1mod tokens;
2pub mod interpreter;
3pub mod interact;
4
5use crate::tokens::*;
6use anyhow::{Context, Result};
7
8fn lex(string: &str) -> Vec<Instruction> {
9 let mut tokens = string
10 .bytes()
11 .filter_map(|x| match x {
12 b'>' => Some(Instruction::POINTER_RIGHT),
13 b'<' => Some(Instruction::POINTER_LEFT),
14 b'+' => Some(Instruction::DATA_INCREMENT),
15 b'-' => Some(Instruction::DATA_DECREMENT),
16 b'.' => Some(Instruction::DATA_OUTPUT),
17 b',' => Some(Instruction::DATA_INPUT),
18 b'[' => Some(Instruction::CONDITIONAL_BEGIN),
19 b']' => Some(Instruction::CONDITIONAL_END),
20 _ => None,
21 })
22 .collect::<Vec<Instruction>>();
23
24 tokens.shrink_to_fit();
25 tokens
26}
27
28fn parse(instructions: &Vec<Instruction>, wait: bool) -> Result<Vec<(usize, usize)>> {
29 let mut stack: Vec<(usize, usize)> = Vec::with_capacity(instructions.len() / 2);
30 let mut bracket_pairs = Vec::with_capacity(instructions.len() / 2);
31
32 for (position, command) in instructions.iter().enumerate().filter(|&(_, &command)| {
33 command == Instruction::CONDITIONAL_BEGIN || command == Instruction::CONDITIONAL_END
34 }) {
35 match command {
36 Instruction::CONDITIONAL_BEGIN => stack.push((position, 0)),
37 Instruction::CONDITIONAL_END => {
38 match stack.pop() {
39 Some((begin, _)) => bracket_pairs.push((begin, position)),
40 None => return Err(Error::UNMATCHED_CONDITIONAL(position)).context("Syntax error encountered")
41 };
42 }
43 _ => (),
44 }
45 }
46
47 if !stack.is_empty() {
48 if !wait {
49 return Err(Error::UNMATCHED_CONDITIONAL(stack[0].1 + 1)).context("Syntax error encountered");
50 }
51
52 bracket_pairs.push((stack[0].1, 0));
53 }
54
55 bracket_pairs.sort();
56 bracket_pairs.shrink_to_fit();
57 Ok(bracket_pairs)
58}