fr 0.1.1

A programming language with an unusual compiler backend
Documentation
use crate::Program;

pub trait Simplify {
    fn prelude() -> String;
    fn postlude() -> String;
    fn simplify(s: impl ToString) -> String;
}

pub struct C;
impl C {
    pub fn new() -> Self {
        Self
    }
}

impl Simplify for C {
    fn prelude() -> String {
        format!(
            r#"#include <stdio.h>
const int TAPE_SIZE = {TAPE_SIZE};
const int REF_TAPE_SIZE = {REF_TAPE_SIZE};

unsigned short tape[{TAPE_SIZE}];
unsigned int ref_tape[{TAPE_SIZE}];
unsigned int ptr = 0;
unsigned int ref_ptr = 0;

unsigned int allocate() {{
    unsigned int size = tape[ptr]; 
    int cons_empty_spaces = 0; 
    for (int i=TAPE_SIZE-1; i>0; i--) {{
        if (tape[i] == 0) {{ cons_empty_spaces++; }}
        else {{ cons_empty_spaces = 0; }}
        if (cons_empty_spaces == size) {{ return i; }}
    }}
    return 0;
}}


void plus(int n) {{
    tape[ptr] += n;
}}

void minus(int n) {{
    tape[ptr] -= n;
}}

void set(int n) {{
    tape[ptr] = n;
}}

void left(int n) {{
    ptr -= n;
}}

void right(int n) {{
    ptr += n;
}}

void deref() {{
    ref_tape[ref_ptr++ % REF_TAPE_SIZE] = ptr;
    ptr = tape[ptr];
}}

void refer() {{
    ptr = ref_tape[--ref_ptr % REF_TAPE_SIZE];
}}

int main() {{
"#,
            TAPE_SIZE = Program::tape_size(),
            REF_TAPE_SIZE = 256
        )
    }

    fn postlude() -> String {
        String::from("}")
    }

    fn simplify(s: impl ToString) -> String {
        let mut result = Self::prelude();
        let mut repeated = 0;
        let mut last = '\0';

        let mut filtered = s
            .to_string()
            .chars()
            .filter(|c| ['>', '<', '+', '-', '*', '&', '?', '[', ']', '.', ','].contains(c))
            .collect::<String>();
        filtered = filtered.replace("[-]", "0");

        for ch in filtered.chars() {
            if ch == last {
                repeated += 1;
            } else {
                let line = match last {
                    '>' => format!("right({});", repeated),
                    '<' => format!("left({});", repeated),
                    '+' => format!("plus({});", repeated),
                    '-' => format!("minus({});", repeated),
                    '0' => "set(0);".repeat(repeated),
                    '*' => "deref();".repeat(repeated),
                    '&' => "refer();".repeat(repeated),
                    '?' => "tape[ptr] = allocate();".repeat(repeated),
                    '[' => "while (tape[ptr]) {".repeat(repeated),
                    ']' => "}\n".repeat(repeated),
                    '.' => "printf(\"%c\",(char)(tape[ptr]%256));".repeat(repeated),
                    ',' => "scanf(\"%c\", (char*)&tape[ptr]);".repeat(repeated),
                    _ => String::new(),
                };
                result += &(line + "\n");
                repeated = 1;
                last = ch;
            }
        }

        result + &Self::postlude()
    }
}