1use super::parser::{self, InsType, Instruction, Register};
2#[cfg(feature = "jit")]
3use super::{errors::jit::JitResult, jit::JIT};
4
5#[derive(Debug, Clone)]
6struct Memory {
7 register0: i64,
8 register1: i64,
9 stack: Vec<i64>,
10}
11
12impl Memory {
13 fn new() -> Memory {
14 Memory {
15 register0: 0,
16 register1: 0,
17 stack: vec![],
18 }
19 }
20
21 fn store_syllables(&mut self, register: Register, syllables: i64) {
22 match register {
23 Register::Register0 => self.register0 = syllables,
24 Register::Register1 => self.register1 = syllables,
25 }
26 }
27
28 fn push_to_stack(&mut self, val: i64) {
29 self.stack.push(val);
30 }
31
32 fn push(&mut self, register: Register) {
33 match register {
34 Register::Register0 => self.stack.push(self.register0),
35 Register::Register1 => self.stack.push(self.register1),
36 }
37 }
38
39 fn pop(&mut self, register: Register) {
40 if let Some(val) = self.stack.pop() {
41 match register {
42 Register::Register0 => self.register0 = val,
43 Register::Register1 => self.register1 = val,
44 }
45 }
46 }
47
48 fn multiply(&mut self, register: Register) {
49 match register {
50 Register::Register0 => self.register0 *= self.register1,
51 Register::Register1 => self.register1 *= self.register0,
52 }
53 }
54
55 fn add(&mut self, register: Register) {
56 match register {
57 Register::Register0 => self.register0 += self.register1,
58 Register::Register1 => self.register1 += self.register0,
59 }
60 }
61
62 fn get_active(&self, register: Register) -> i64 {
63 match register {
64 Register::Register0 => self.register0,
65 Register::Register1 => self.register1,
66 }
67 }
68
69 fn get_inactive(&self, register: Register) -> i64 {
70 match register {
71 Register::Register0 => self.register1,
72 Register::Register1 => self.register0,
73 }
74 }
75
76 fn negate(&mut self, register: Register) {
77 match register {
78 Register::Register0 => self.register0 = -self.register0,
79 Register::Register1 => self.register1 = -self.register1,
80 }
81 }
82}
83
84pub struct Program {
85 pub ast: Vec<Instruction>,
86}
87
88impl Program {
89 pub fn create(source: &str) -> Program {
90 Program {
91 ast: parser::parse(source),
92 }
93 }
94
95 pub fn execute(&self) -> String {
96 let mut mem = Memory::new();
97 let mut output: String = String::new();
98
99 let mut instruction_pointer: usize = 0;
100
101 log::info!(
102 "{: <51} | {: ^4} | {: ^4} | {: ^7}",
103 "instruction",
104 "r0",
105 "r1",
106 "stack"
107 );
108 log::info!("{:-<51} | {:-^4} | {:-^4} | {:-^7}", "", "", "", "");
109
110 'outer: while let Some(ins) = self.ast.get(instruction_pointer) {
111 let Instruction {
112 instruction,
113 register: reg,
114 ref line,
115 } = *ins;
116
117 match instruction {
118 InsType::ConditionalGoto(syllables) => {
119 if mem.get_active(reg) > syllables as i64 {
120 instruction_pointer =
121 (mem.get_inactive(reg).abs() as usize) % (self.ast.len() as usize);
122 continue 'outer;
123 }
124 }
125 InsType::Negate => mem.negate(reg),
126 InsType::Multiply => mem.multiply(reg),
127 InsType::Add => mem.add(reg),
128 InsType::PrintChar => {
129 let printable = (mem.get_active(reg).abs() % std::u8::MAX as i64) as u8;
130 output = format!("{}{}", output, printable as char);
131 }
132 InsType::PrintValue => output = format!("{}{}", output, mem.get_active(reg)),
133 InsType::Pop => mem.pop(reg),
134 InsType::Push => mem.push(reg),
135 InsType::Store(syllables) => mem.store_syllables(reg, syllables as i64),
136 InsType::ConditionalPush {
137 prev_syllables,
138 cur_syllables,
139 } => {
140 if mem.get_active(reg) < mem.get_inactive(reg) {
141 mem.push_to_stack(prev_syllables as i64);
142 } else {
143 mem.push_to_stack(cur_syllables as i64);
144 }
145 }
146 InsType::Goto => {
147 instruction_pointer =
148 (mem.get_active(reg).abs() as usize) % (self.ast.len() as usize);
149 continue 'outer;
150 }
151 InsType::Noop => (),
152 }
153
154 log::info!(
155 "{: <51} | {: ^4} | {: ^4} | {:^?}",
156 line,
157 mem.register0,
158 mem.register1,
159 mem.stack
160 );
161
162 instruction_pointer += 1;
163 }
164
165 output
166 }
167
168 #[cfg(feature = "jit")]
169 pub fn jit_execute(&self) -> JitResult<()> {
170 let mut jit = JIT::default();
171 let func = jit.compile(&self.ast)?;
172 func();
173
174 Ok(())
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use pretty_assertions::assert_eq;
182
183 #[test]
184 fn mem_get_inactive() {
185 let mut mem = Memory::new();
186 let r0 = 10;
187 let r1 = 11;
188 mem.store_syllables(Register::Register0, r0);
189 mem.store_syllables(Register::Register1, r1);
190
191 assert_eq!(mem.get_inactive(Register::Register0), r1);
192 assert_eq!(mem.get_inactive(Register::Register1), r0);
193 }
194
195 #[test]
196 fn mem_push() {
197 let mut mem = Memory::new();
198 let reg = Register::Register0;
199 mem.store_syllables(reg, 1);
200 mem.push(reg);
201 assert_eq!(mem.stack, vec![1]);
202 let reg = Register::Register1;
203 mem.store_syllables(reg, 2);
204 mem.push(reg);
205 assert_eq!(mem.stack, vec![1, 2]);
206 }
207
208 #[test]
209 fn alliteration() {
210 let alliteration_program = r#"
211poem or calculator or nothing
212 somebody once
213 fish fosh
214word.
215
216"#
217 .trim_start();
218
219 let program = Program::create(alliteration_program);
220 let result = program.execute();
221 assert_eq!(result, "");
222 }
223
224 #[test]
225 fn rhyming() {
226 let rhyming_program = r#"
227somebody once told me
228 he took a new elf
229and stabbed it with a shelf
230pop,
231print.
232then he took blue
233and stabbed it with some you
234pop,
235print.
236"#;
237
238 let program = Program::create(rhyming_program);
239 let result = program.execute();
240 assert_eq!(result, "64");
241 }
242
243 #[test]
244 fn factorial() {
245 let factorial_program = r#"
246
247 it is a calculator, like a
248 poem, is a poem, and finds
249 factori-
250 als
251 The input is the syllAbles
252in the title, count them, as one counts
253 (q) what other poem, programs can be writ
254 (a) anything a Turing
255 machine-machine-machine
256 would do
257re/cur
258 sion works too, in poems, programs, and this
259 a lovely.
260poem or calculator or nothing
261how lovely can it be?
262"#;
263 let four_factorial = format!("lovely poem\n{}", factorial_program);
264 println!("{}", four_factorial);
265 let four_factorial_res = "24\n".to_string();
266 let program = Program::create(&four_factorial);
267 assert_eq!(program.execute(), four_factorial_res);
268
269 let five_factorial = format!("lovely poem and\n{}", factorial_program);
270 let program = Program::create(&five_factorial);
271 let five_factorial_res = "120\n".to_string();
272 assert_eq!(program.execute(), five_factorial_res);
273 }
274
275 #[test]
276 fn logging() {
277 std::env::set_var("RUST_LOG", "info");
279 factorial();
280 }
281}