cranefack/backends/
rust.rs

1use std::error::Error;
2use std::fmt::Write;
3
4use crate::ir::ops::{LoopDecrement, Op, OpType};
5use crate::parser::Program;
6
7/// Compile program into a rust file that can be compiled with rustc
8pub fn compile_to_rust(program: &Program) -> String {
9    let mut code = "".to_owned();
10
11    print_ops(&mut code, &program.ops).expect("No io error");
12
13    include_str!("rust.tpl").replace("{{CODE}}", &code)
14}
15
16fn print_ops(out: &mut String, ops: &[Op]) -> Result<(), Box<dyn Error>> {
17    for op in ops {
18        match &op.op_type {
19            OpType::Start => {
20                // ignore
21            }
22            OpType::IncPtr(count) => writeln!(out, "rt.inc_ptr({});", count)?,
23            OpType::DecPtr(count) => writeln!(out, "rt.dec_ptr({});", count)?,
24            OpType::Inc(offset, count) => writeln!(out, "rt.inc({}, {});", offset, count)?,
25            OpType::Dec(offset, count) => writeln!(out, "rt.dec({}, {});", offset, count)?,
26            OpType::Set(offset, value) => writeln!(out, "rt.set({}, {});", offset, value)?,
27            OpType::Add(src_offset, dest_offset, multi) => {
28                writeln!(out, "rt.add({}, {}, {});", src_offset, dest_offset, multi)?
29            }
30            OpType::NzAdd(src_offset, dest_offset, multi) => writeln!(
31                out,
32                "rt.nz_add({}, {}, {});",
33                src_offset, dest_offset, multi
34            )?,
35            OpType::CAdd(src_offset, dest_offset, count) => {
36                writeln!(out, "rt.c_add({}, {}, {});", src_offset, dest_offset, count)?
37            }
38            OpType::NzCAdd(src_offset, dest_offset, count) => writeln!(
39                out,
40                "rt.nz_c_add({}, {}, {});",
41                src_offset, dest_offset, count
42            )?,
43            OpType::Sub(src_offset, dest_offset, multi) => {
44                writeln!(out, "rt.sub({}, {}, {});", src_offset, dest_offset, multi)?
45            }
46            OpType::NzSub(src_offset, dest_offset, multi) => writeln!(
47                out,
48                "rt.nz_sub({}, {}, {});",
49                src_offset, dest_offset, multi
50            )?,
51            OpType::CSub(src_offset, dest_offset, count) => {
52                writeln!(out, "rt.c_sub({}, {}, {});", src_offset, dest_offset, count)?
53            }
54            OpType::NzCSub(src_offset, dest_offset, count) => writeln!(
55                out,
56                "rt.nz_c_sub({}, {}, {});",
57                src_offset, dest_offset, count
58            )?,
59            OpType::Move(src_offset, dest_offset) => {
60                writeln!(out, "rt.move({}, {});", src_offset, dest_offset)?
61            }
62            OpType::Copy(src_offset, dest_offset) => {
63                writeln!(out, "rt.copy({}, {});", src_offset, dest_offset)?
64            }
65            OpType::Mul(src_offset, dest_offset, multi) => {
66                writeln!(out, "rt.mul({}, {}, {});", src_offset, dest_offset, multi)?
67            }
68            OpType::NzMul(src_offset, dest_offset, multi) => writeln!(
69                out,
70                "rt.nz_mul({}, {}, {});",
71                src_offset, dest_offset, multi
72            )?,
73            OpType::GetChar(offset) => writeln!(out, "rt.get_char({});", offset)?,
74            OpType::PutString(array) => writeln!(out, "rt.put_string({:?});", array)?,
75            OpType::PutChar(offset) => writeln!(out, "rt.put_char({});", offset)?,
76            OpType::DLoop(children, _) => {
77                writeln!(out, "{{")?;
78
79                writeln!(out, " while *rt.heap_value() > 0 {{")?;
80                print_ops(out, children)?;
81                writeln!(out, "}}")?;
82
83                writeln!(out, "}}")?;
84            }
85            OpType::LLoop(children, _) => {
86                writeln!(out, "{{")?;
87
88                writeln!(out, "let heap_pointer = rt.pointer;")?;
89                writeln!(out, "while *rt.heap_value() > 0 {{")?;
90                writeln!(out, "rt.pointer = heap_pointer;")?;
91                print_ops(out, children)?;
92                writeln!(out, "}}")?;
93                writeln!(out, "rt.pointer = heap_pointer;")?;
94
95                writeln!(out, "}}")?;
96            }
97            OpType::ILoop(children, step, decrement, _) => {
98                writeln!(out, "{{")?;
99
100                match decrement {
101                    LoopDecrement::Pre => {
102                        writeln!(out, "let heap_pointer = rt.pointer;")?;
103                        writeln!(out, "let mut left = *rt.heap_value();")?;
104                        writeln!(out, "while left > 0 {{")?;
105                        writeln!(out, "rt.pointer = heap_pointer;")?;
106                        writeln!(out, "left = left.wrapping_sub({});", step)?;
107                        print_ops(out, children)?;
108                        writeln!(out, "}}")?;
109                        writeln!(out, "rt.pointer = heap_pointer;")?;
110                        writeln!(out, "*rt.heap_value() = 0;")?;
111                    }
112                    LoopDecrement::Post | LoopDecrement::Auto => {
113                        writeln!(out, "let heap_pointer = rt.pointer;")?;
114                        writeln!(out, "let mut left = *rt.heap_value();")?;
115                        writeln!(out, "while left > 0 {{")?;
116                        writeln!(out, "rt.pointer = heap_pointer;")?;
117                        print_ops(out, children)?;
118                        writeln!(out, "left = left.wrapping_sub({});", step)?;
119                        writeln!(out, "}}")?;
120                        writeln!(out, "rt.pointer = heap_pointer;")?;
121                        writeln!(out, "*rt.heap_value() = 0;")?;
122                    }
123                }
124
125                writeln!(out, "}}")?;
126            }
127            OpType::CLoop(children, iterations, decrement, _) => {
128                writeln!(out, "{{")?;
129
130                match decrement {
131                    LoopDecrement::Pre => {
132                        writeln!(out, "let heap_pointer = rt.pointer;")?;
133                        writeln!(out, "*rt.heap_value() = {}", iterations)?;
134                        writeln!(out, "let mut left = *rt.heap_value();")?;
135                        writeln!(out, "while left > 0 {{")?;
136                        writeln!(out, "rt.pointer = heap_pointer;")?;
137                        writeln!(out, "left = left.wrapping_sub(1);")?;
138                        print_ops(out, children)?;
139                        writeln!(out, "}}")?;
140                        writeln!(out, "rt.pointer = heap_pointer;")?;
141                        writeln!(out, "*rt.heap_value() = 0;")?;
142                    }
143                    LoopDecrement::Post => {
144                        writeln!(out, "let heap_pointer = rt.pointer;")?;
145                        writeln!(out, "*rt.heap_value() = {}", iterations)?;
146                        writeln!(out, "let mut left = *rt.heap_value();")?;
147                        writeln!(out, "while left > 0 {{")?;
148                        writeln!(out, "rt.pointer = heap_pointer;")?;
149                        print_ops(out, children)?;
150                        writeln!(out, "left = left.wrapping_sub(1);")?;
151                        writeln!(out, "}}")?;
152                        writeln!(out, "rt.pointer = heap_pointer;")?;
153                        writeln!(out, "*rt.heap_value() = 0;")?;
154                    }
155                    LoopDecrement::Auto => {
156                        writeln!(out, "let heap_pointer = rt.pointer;")?;
157                        writeln!(out, "for _ in 0..{} {{", iterations)?;
158                        writeln!(out, "rt.pointer = heap_pointer;")?;
159                        print_ops(out, children)?;
160                        writeln!(out, "}}")?;
161                        writeln!(out, "rt.pointer = heap_pointer;")?;
162                        writeln!(out, "*rt.heap_value() = 0;")?;
163                    }
164                }
165
166                writeln!(out, "}}")?;
167            }
168            OpType::TNz(children, _) => {
169                writeln!(out, "{{")?;
170
171                writeln!(out, "if *rt.heap_value() != 0 {{")?;
172                writeln!(out, "let heap_pointer = self.pointer;")?;
173                writeln!(out, "rt.pointer = heap_pointer;")?;
174                print_ops(out, children)?;
175                writeln!(out, "rt.pointer = heap_pointer;")?;
176                writeln!(out, "*rt.heap_value() = 0;")?;
177
178                writeln!(out, "}}")?;
179            }
180            OpType::DTNz(children, _, _) => {
181                writeln!(out, "{{")?;
182
183                writeln!(out, " if *rt.heap_value() > 0 {{")?;
184                print_ops(out, children)?;
185                writeln!(out, "}}")?;
186
187                writeln!(out, "}}")?;
188            }
189            OpType::SearchZero(step, _) => writeln!(out, "rt.search_zero({});", step)?,
190        }
191    }
192
193    Ok(())
194}