use std::error::Error;
use std::fmt::Write;
use crate::ir::ops::{LoopDecrement, Op, OpType};
use crate::parser::Program;
pub fn compile_to_rust(program: &Program) -> String {
let mut code = "".to_owned();
print_ops(&mut code, &program.ops).expect("No io error");
include_str!("rust.tpl").replace("{{CODE}}", &code)
}
fn print_ops(out: &mut String, ops: &[Op]) -> Result<(), Box<dyn Error>> {
for op in ops {
match &op.op_type {
OpType::Start => {
}
OpType::IncPtr(count) => writeln!(out, "rt.inc_ptr({});", count)?,
OpType::DecPtr(count) => writeln!(out, "rt.dec_ptr({});", count)?,
OpType::Inc(offset, count) => writeln!(out, "rt.inc({}, {});", offset, count)?,
OpType::Dec(offset, count) => writeln!(out, "rt.dec({}, {});", offset, count)?,
OpType::Set(offset, value) => writeln!(out, "rt.set({}, {});", offset, value)?,
OpType::Add(src_offset, dest_offset, multi) => {
writeln!(out, "rt.add({}, {}, {});", src_offset, dest_offset, multi)?
}
OpType::NzAdd(src_offset, dest_offset, multi) => writeln!(
out,
"rt.nz_add({}, {}, {});",
src_offset, dest_offset, multi
)?,
OpType::CAdd(src_offset, dest_offset, count) => {
writeln!(out, "rt.c_add({}, {}, {});", src_offset, dest_offset, count)?
}
OpType::NzCAdd(src_offset, dest_offset, count) => writeln!(
out,
"rt.nz_c_add({}, {}, {});",
src_offset, dest_offset, count
)?,
OpType::Sub(src_offset, dest_offset, multi) => {
writeln!(out, "rt.sub({}, {}, {});", src_offset, dest_offset, multi)?
}
OpType::NzSub(src_offset, dest_offset, multi) => writeln!(
out,
"rt.nz_sub({}, {}, {});",
src_offset, dest_offset, multi
)?,
OpType::CSub(src_offset, dest_offset, count) => {
writeln!(out, "rt.c_sub({}, {}, {});", src_offset, dest_offset, count)?
}
OpType::NzCSub(src_offset, dest_offset, count) => writeln!(
out,
"rt.nz_c_sub({}, {}, {});",
src_offset, dest_offset, count
)?,
OpType::Move(src_offset, dest_offset) => {
writeln!(out, "rt.move({}, {});", src_offset, dest_offset)?
}
OpType::Copy(src_offset, dest_offset) => {
writeln!(out, "rt.copy({}, {});", src_offset, dest_offset)?
}
OpType::Mul(src_offset, dest_offset, multi) => {
writeln!(out, "rt.mul({}, {}, {});", src_offset, dest_offset, multi)?
}
OpType::NzMul(src_offset, dest_offset, multi) => writeln!(
out,
"rt.nz_mul({}, {}, {});",
src_offset, dest_offset, multi
)?,
OpType::GetChar(offset) => writeln!(out, "rt.get_char({});", offset)?,
OpType::PutString(array) => writeln!(out, "rt.put_string({:?});", array)?,
OpType::PutChar(offset) => writeln!(out, "rt.put_char({});", offset)?,
OpType::DLoop(children, _) => {
writeln!(out, "{{")?;
writeln!(out, " while *rt.heap_value() > 0 {{")?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "}}")?;
}
OpType::LLoop(children, _) => {
writeln!(out, "{{")?;
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "while *rt.heap_value() > 0 {{")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "}}")?;
}
OpType::ILoop(children, step, decrement, _) => {
writeln!(out, "{{")?;
match decrement {
LoopDecrement::Pre => {
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "let mut left = *rt.heap_value();")?;
writeln!(out, "while left > 0 {{")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "left = left.wrapping_sub({});", step)?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
}
LoopDecrement::Post | LoopDecrement::Auto => {
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "let mut left = *rt.heap_value();")?;
writeln!(out, "while left > 0 {{")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
print_ops(out, children)?;
writeln!(out, "left = left.wrapping_sub({});", step)?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
}
}
writeln!(out, "}}")?;
}
OpType::CLoop(children, iterations, decrement, _) => {
writeln!(out, "{{")?;
match decrement {
LoopDecrement::Pre => {
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "*rt.heap_value() = {}", iterations)?;
writeln!(out, "let mut left = *rt.heap_value();")?;
writeln!(out, "while left > 0 {{")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "left = left.wrapping_sub(1);")?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
}
LoopDecrement::Post => {
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "*rt.heap_value() = {}", iterations)?;
writeln!(out, "let mut left = *rt.heap_value();")?;
writeln!(out, "while left > 0 {{")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
print_ops(out, children)?;
writeln!(out, "left = left.wrapping_sub(1);")?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
}
LoopDecrement::Auto => {
writeln!(out, "let heap_pointer = rt.pointer;")?;
writeln!(out, "for _ in 0..{} {{", iterations)?;
writeln!(out, "rt.pointer = heap_pointer;")?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
}
}
writeln!(out, "}}")?;
}
OpType::TNz(children, _) => {
writeln!(out, "{{")?;
writeln!(out, "if *rt.heap_value() != 0 {{")?;
writeln!(out, "let heap_pointer = self.pointer;")?;
writeln!(out, "rt.pointer = heap_pointer;")?;
print_ops(out, children)?;
writeln!(out, "rt.pointer = heap_pointer;")?;
writeln!(out, "*rt.heap_value() = 0;")?;
writeln!(out, "}}")?;
}
OpType::DTNz(children, _, _) => {
writeln!(out, "{{")?;
writeln!(out, " if *rt.heap_value() > 0 {{")?;
print_ops(out, children)?;
writeln!(out, "}}")?;
writeln!(out, "}}")?;
}
OpType::SearchZero(step, _) => writeln!(out, "rt.search_zero({});", step)?,
}
}
Ok(())
}