py_codegen_c/
lib.rs

1mod translate;
2
3pub struct CBackend;
4
5use std::fmt::Write;
6
7use translate::Translate;
8
9#[derive(Clone, Copy, PartialEq)]
10pub enum Buffer {
11    C,
12    H,
13}
14
15pub struct FileModule {
16    name: String,
17    buffer: Buffer,
18    c_file: String,
19    h_file: String,
20    label_idx: usize,
21}
22
23struct Label(String);
24
25impl FileModule {
26    pub fn new(name: String) -> Self {
27        const HEADER_FILES: &str = "#include <math.h>\n#include <stdbool.h>\n#include <stdint.h>\n";
28        Self {
29            name,
30            buffer: Buffer::C,
31            c_file: String::from(HEADER_FILES),
32            h_file: String::from(HEADER_FILES),
33            label_idx: 0,
34        }
35    }
36
37    fn label(&mut self) -> Label {
38        let label = format!("L{}", self.label_idx);
39        self.label_idx += 1;
40        Label(label)
41    }
42
43    fn goto(&mut self, label: &Label) -> Result<(), std::fmt::Error> {
44        write!(self, "goto {};", label.0)
45    }
46
47    fn swap_to(&mut self, target: Buffer) {
48        if self.buffer != target {
49            std::mem::swap(&mut self.c_file, &mut self.h_file);
50            self.buffer = target;
51        }
52    }
53
54    pub fn write_header_file(
55        &mut self,
56        writer: impl FnOnce(&mut Self) -> std::fmt::Result,
57    ) -> std::fmt::Result {
58        self.swap_to(Buffer::H);
59        writer(self)?;
60        self.swap_to(Buffer::C);
61        Ok(())
62    }
63
64    pub fn write_source_file(
65        &mut self,
66        writer: impl FnOnce(&mut Self) -> std::fmt::Result,
67    ) -> std::fmt::Result {
68        self.swap_to(Buffer::C);
69        writer(self)
70    }
71
72    fn eol(&mut self) -> Result<(), std::fmt::Error> {
73        self.write_char(';')
74    }
75
76    fn if_else(
77        &mut self,
78        cond: &py_ir::value::Value,
79        then: &Label,
80        or: &Label,
81    ) -> Result<(), std::fmt::Error> {
82        self.write_str("if(")?;
83        self.translate(cond)?;
84        self.write_char(')')?;
85        self.goto(then)?;
86        self.write_str("else ")?;
87        self.goto(or)
88    }
89
90    #[inline]
91    pub fn name(&self) -> &str {
92        &self.name
93    }
94
95    #[inline]
96    pub fn c_file(&self) -> &str {
97        &self.c_file
98    }
99
100    #[inline]
101    pub fn h_file(&self) -> &str {
102        &self.h_file
103    }
104}
105
106impl std::fmt::Write for FileModule {
107    fn write_str(&mut self, s: &str) -> std::fmt::Result {
108        self.c_file.write_str(s)
109    }
110}
111
112impl py_codegen::Backend for CBackend {
113    type Error = std::fmt::Error;
114
115    type Config = ();
116
117    type Module<'m> = FileModule
118    where
119        Self: 'm;
120
121    fn init(_config: Self::Config) -> Self {
122        CBackend
123    }
124
125    fn module(&self, name: &str, items: &[py_ir::Item]) -> Result<Self::Module<'_>, Self::Error> {
126        let mut module = FileModule::new(name.to_string());
127        for item in items {
128            module.translate(item)?;
129        }
130        Ok(module)
131    }
132}