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}