1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
mod translate;

pub struct CBackend;

use std::fmt::Write;

use translate::Translate;

pub struct FileModule {
    name: String,
    text: String,
    label_idx: usize,
}

struct Label(String);

impl FileModule {
    pub fn new(name: String) -> Self {
        Self {
            name,
            text: String::from("#include <stdint.h>\n#include <stdbool.h>\n#include <math.h>\n"),
            label_idx: 0,
        }
    }

    fn label(&mut self) -> Label {
        let label = format!("L{}", self.label_idx);
        self.label_idx += 1;
        Label(label)
    }

    fn goto(&mut self, label: &Label) -> Result<(), std::fmt::Error> {
        write!(self, "goto {};", label.0)
    }

    fn eol(&mut self) -> Result<(), std::fmt::Error> {
        self.write_char(';')
    }

    fn if_else(
        &mut self,
        cond: &py_ir::value::Value,
        then: &Label,
        or: &Label,
    ) -> Result<(), std::fmt::Error> {
        self.write_str("if(")?;
        self.translate(cond)?;
        self.write_char(')')?;
        self.goto(then)?;
        self.write_str("else ")?;
        self.goto(or)
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn text(&self) -> &str {
        &self.text
    }
}

impl std::fmt::Write for FileModule {
    fn write_str(&mut self, s: &str) -> std::fmt::Result {
        self.text.write_str(s)
    }
}

impl py_codegen::Backend for CBackend {
    type Error = std::fmt::Error;

    type Config = ();

    type Module<'m> = FileModule
    where
        Self: 'm;

    fn init(_config: Self::Config) -> Self {
        CBackend
    }

    fn module(&self, name: &str, items: &[py_ir::Item]) -> Result<Self::Module<'_>, Self::Error> {
        let mut module = FileModule::new(name.to_string());
        for item in items {
            module.translate(item)?;
        }
        Ok(module)
    }
}