bf_lib/
bf.rs

1use crate::Error;
2use subprocess::{Exec, NullFile};
3
4pub mod interpreter;
5
6pub mod transpiler;
7
8#[derive(Debug)]
9pub enum Instruction {
10    Add(u32),
11    Sub(u32),
12    Left(u32),
13    Right(u32),
14    Print,
15    Read,
16    LoopStart,
17    LoopEnd,
18    //Clear,
19    //Copy(i32),
20    //Mult(i32, i32),
21    //Scan(bool),
22}
23
24enum Prev {
25    Move,
26    Add,
27}
28
29trait AsInst {
30    fn to_inst(&self) -> Result<Vec<Instruction>, Error>;
31}
32
33impl AsInst for str {
34    fn to_inst(&self) -> Result<Vec<Instruction>, Error> {
35        firstpass(self.as_bytes())
36    }
37}
38
39impl AsInst for String {
40    fn to_inst(&self) -> Result<Vec<Instruction>, Error> {
41        firstpass(self.as_bytes())
42    }
43}
44
45pub fn run(
46    program: &str,
47    input: Option<String>,
48    time: Option<std::time::Duration>,
49    tmp_path: Option<std::path::PathBuf>,
50) -> Result<String, crate::Error> {
51    match Exec::cmd("rustc").stdout(NullFile).stderr(NullFile).join() {
52        Ok(_) => transpiler::run(program, input, time, tmp_path),
53        Err(_) => interpreter::run(program, input, time),
54    }
55}
56
57fn firstpass(bytes: &[u8]) -> Result<Vec<Instruction>, Error> {
58    fn changed(prev: Prev, ac: i32, mc: i32) -> Instruction {
59        match prev {
60            Prev::Add => {
61                if ac >= 0 {
62                    Instruction::Add(ac as u32)
63                } else {
64                    Instruction::Sub(ac.abs() as u32)
65                }
66            }
67            Prev::Move => {
68                if mc >= 0 {
69                    Instruction::Right(mc as u32)
70                } else {
71                    Instruction::Left(mc.abs() as u32)
72                }
73            }
74        }
75    }
76    let (mut ac, mut mc) = (0i32, 0i32);
77    let mut prev = None;
78    let mut inst: Vec<Instruction> = vec![];
79    for b in bytes.iter() {
80        match b {
81            b'>' => {
82                if let Some(Prev::Move) = prev {
83                    mc += 1
84                } else {
85                    if let Some(p) = prev.take() {
86                        inst.push(changed(p, ac, mc))
87                    }
88                    ac = 0;
89                    mc = 1;
90                    prev = Some(Prev::Move)
91                }
92            }
93            b'<' => {
94                if let Some(Prev::Move) = prev {
95                    mc -= 1
96                } else {
97                    if let Some(p) = prev.take() {
98                        inst.push(changed(p, ac, mc))
99                    }
100                    ac = 0;
101                    mc = -1;
102                    prev = Some(Prev::Move)
103                }
104            }
105            b'+' => {
106                if let Some(Prev::Add) = prev {
107                    ac += 1
108                } else {
109                    if let Some(p) = prev.take() {
110                        inst.push(changed(p, ac, mc))
111                    }
112                    ac = 1;
113                    mc = 0;
114                    prev = Some(Prev::Add)
115                }
116            }
117            b'-' => {
118                if let Some(Prev::Add) = prev {
119                    ac -= 1
120                } else {
121                    if let Some(p) = prev.take() {
122                        inst.push(changed(p, ac, mc))
123                    }
124                    ac = -1;
125                    mc = 0;
126                    prev = Some(Prev::Add)
127                }
128            }
129            b'.' => {
130                if let Some(p) = prev.take() {
131                    inst.push(changed(p, ac, mc))
132                }
133                ac = 0;
134                mc = 0;
135                inst.push(Instruction::Print);
136            }
137            b',' => {
138                if let Some(p) = prev.take() {
139                    inst.push(changed(p, ac, mc))
140                }
141                ac = 0;
142                mc = 0;
143                inst.push(Instruction::Read);
144            }
145            b'[' => {
146                if let Some(p) = prev.take() {
147                    inst.push(changed(p, ac, mc))
148                }
149                ac = 0;
150                mc = 0;
151                inst.push(Instruction::LoopStart);
152            }
153            b']' => {
154                if let Some(p) = prev.take() {
155                    inst.push(changed(p, ac, mc))
156                }
157                ac = 0;
158                mc = 0;
159                inst.push(Instruction::LoopEnd);
160            }
161            _ => (),
162        }
163    }
164    if let Some(p) = prev.take() {
165        inst.push(changed(p, ac, mc))
166    }
167    Ok(inst)
168}