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 }
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}