cardinal_c/
lib.rs

1//! A module for compiling Cardinal IR to functioning C code.
2
3use cardinal_codegen::entities::{AbiType, Named, NamedProperty, Type, Value, ValueInfo};
4use cardinal_codegen::function::{Function};
5use cardinal_codegen::instruction::{InstructionInfo, InstBlock, Opcode};
6use cardinal_codegen::module::Module;
7
8/// Cardinal's C backend for the code generator.
9pub struct CBackend {
10
11    /// The module to emit C code from.
12    module: Module,
13
14    /// A list of C header files to include at compile time.
15    imports: Vec<String>,
16
17}
18
19impl CBackend {
20
21    /// Creates a new CBackend that will generate C code from the provided Cardinal IR module.
22    pub fn new(module: Module) -> Self {
23        Self {
24            module,
25            imports: vec![],
26        }
27    }
28    
29    /// Displays an instruction.
30    fn display_instruction(&self, inst: &InstructionInfo, block: &InstBlock) -> String {
31        match inst.opcode {
32            Opcode::Add => {
33                self.display_value(inst.arguments[0], block) + " + " + &self.display_value(inst.arguments[1], block)
34            },
35            Opcode::Sub => {
36                self.display_value(inst.arguments[0], block) + " - " + &self.display_value(inst.arguments[1], block)
37            },
38            Opcode::Mul => {
39                self.display_value(inst.arguments[0], block) + " * " + &self.display_value(inst.arguments[1], block)
40            },
41            Opcode::Div => {
42                self.display_value(inst.arguments[0], block) + " / " + &self.display_value(inst.arguments[1], block)
43            },
44            Opcode::Mod => {
45                self.display_value(inst.arguments[0], block) + " % " + &self.display_value(inst.arguments[1], block)
46            },
47            Opcode::BitAnd => {
48                self.display_value(inst.arguments[0], block) + " & " + &self.display_value(inst.arguments[1], block)
49            },
50            Opcode::BitOr => {
51                self.display_value(inst.arguments[0], block) + " | " + &self.display_value(inst.arguments[1], block)
52            },
53            Opcode::BitXor => {
54                self.display_value(inst.arguments[0], block) + " ^ " + &self.display_value(inst.arguments[1], block)
55            },
56            Opcode::BitNot => {
57                "~".to_string() + &self.display_value(inst.arguments[0], block)
58            },
59            Opcode::BitLeft => {
60                self.display_value(inst.arguments[0], block) + " << " + &self.display_value(inst.arguments[1], block)
61            },
62            Opcode::BitRight => {
63                self.display_value(inst.arguments[0], block) + " >> " + &self.display_value(inst.arguments[1], block)
64            },
65            Opcode::TestEq => {
66                self.display_value(inst.arguments[0], block) + " == " + &self.display_value(inst.arguments[1], block)
67            },
68            Opcode::TestNeq => {
69                self.display_value(inst.arguments[0], block) + " != " + &self.display_value(inst.arguments[1], block)
70            },
71            Opcode::TestGt => {
72                self.display_value(inst.arguments[0], block) + " > " + &self.display_value(inst.arguments[1], block)
73            },
74            Opcode::TestGtEq => {
75                self.display_value(inst.arguments[0], block) + " >= " + &self.display_value(inst.arguments[1], block)
76            },
77            Opcode::TestLt => {
78                self.display_value(inst.arguments[0], block) + " < " + &self.display_value(inst.arguments[1], block)
79            },
80            Opcode::TestLtEq => {
81                self.display_value(inst.arguments[0], block) + " <= " + &self.display_value(inst.arguments[1], block)
82            },
83            Opcode::Not => {
84                "!".to_string() + &self.display_value(inst.arguments[0], block)
85            },
86            Opcode::Or => {
87                self.display_value(inst.arguments[0], block) + " || " + &self.display_value(inst.arguments[1], block)
88            },
89            Opcode::And => {
90                self.display_value(inst.arguments[0], block) + " && " + &self.display_value(inst.arguments[1], block)
91            },
92            Opcode::Jmp => {
93                "goto".to_string() + &self.display_value(inst.arguments[0], block)
94            },
95            Opcode::Set => {
96                self.display_value(inst.arguments[0], block) + " = " + &self.display_value(inst.arguments[1], block)
97            },
98            Opcode::Call => {
99                let mut args = vec![];
100
101                let mut i = 1;
102                while i < inst.arguments.len() {
103                    args.push(self.display_value(inst.arguments[i], block));
104                    i += 1;
105                }
106
107                self.display_value(inst.arguments[0], block) + "(" + &args.join(", ") + ")"
108            },
109            Opcode::Ret => {
110                "return ".to_string() + &self.display_value(inst.arguments[0], block)
111            },
112        }
113    }
114
115    /// Displays a value from a block.
116    fn display_value(&self, val: Value, block: &InstBlock) -> String {
117        let v = &block.values[val.0 as usize];
118
119        match v {
120            ValueInfo::Block(b) => {
121                format!("block{}", b.0)
122            },
123            ValueInfo::BooleanConstant(b) => {
124                b.to_string()
125            },
126            ValueInfo::DoubleConstant(b) => {
127                b.to_string()
128            },
129            ValueInfo::IntegerConstant(b) => {
130                b.to_string()
131            },
132            ValueInfo::FloatConstant(b) => {
133                b.to_string()
134            },
135            ValueInfo::Instruction(b) => {
136                self.display_instruction(b, block)
137            },
138            ValueInfo::Named(b) => {
139                self.display_named(b, block)
140            },
141            ValueInfo::StringConstant(b) => {
142                "\"".to_string() + &b + "\""
143            },
144            ValueInfo::CharConstant(b) => {
145                "'".to_string() + &b + "'"
146            },
147        }
148    }
149
150    fn display_named(&self, named: &Named, block: &InstBlock) -> String {
151        let mut name = named.name.to_string();
152
153        for item in &named.properties {
154            match item {
155                NamedProperty::Basic(n) => {
156                    name.push('.');
157                    name.push_str(&n);
158                },
159                NamedProperty::Index(n) => {
160                    name.push('[');
161                    name.push_str(&self.display_value(*n, block));
162                    name.push(']');
163                },
164                NamedProperty::Pointer(n) => {
165                    name.push_str("->");
166                    name.push_str(&n);
167                },
168                NamedProperty::Static(_) => {
169                    panic!("Static indexing isn't allowed with the C emitter.");
170                    //name.push_str("::");
171                    //name.push_str(&n);
172                }
173            }
174        }
175
176        name.to_string()
177    }
178
179    fn display_abitype(&self, abitype: &AbiType) -> String {
180        let t = &abitype.1;
181
182        match t {
183            Type::Plain => {
184                abitype.0.to_string()
185            },
186            Type::Array(n) => {
187                if n > &-1 {
188                    abitype.0.to_string() + "[]".into()
189                } else {
190                    abitype.0.to_string() + &format!("[{}]", n)
191                }
192            },
193            Type::Pointer => {
194                abitype.0.to_string() + "*".into()
195            }
196        }
197    }
198
199    /// Compiles a single function into C code.
200    pub fn compile_function(&self, func: &Function) -> (String, Vec<String>) {
201        let mut args = vec![];
202
203        for item in &func.signature.arguments {
204            args.push(format!("{} {}", self.display_abitype(&item.1), item.0));
205        }
206
207        let mut header = format!("{} {}({})", self.display_abitype(&func.signature.returns), func.name, args.join(", "));
208        if func.blocks.len() == 0 {
209            return (header, vec![]);
210        } else {
211            header.push_str(" {\n");
212            let mut imports = vec![];
213            let mut insts = vec![];
214
215            for (i, v) in func.blocks.iter().enumerate() {
216                let mut block = vec![];
217                imports.append(&mut v.imports.clone());
218                for inst in &v.insts {
219                    block.push(self.display_instruction(inst, v));
220                }
221                
222                insts.push(format!("block{}: {{\n", i) + &block.join(";\n") + ";\n}\n");
223            }
224
225            let mut vars = vec![];
226
227            for var in &func.variables {
228                vars.push(self.display_abitype(&var.1) + " " + var.0);
229            }
230
231            header.push_str(&(vars.join(";\n")));
232
233            if vars.len() > 0 {
234                header.push_str(";\n");
235            }
236
237            header.push_str(&(insts.join("\n")));
238
239            header.push('}');
240
241            return (header, imports);
242        }
243
244        
245    }
246
247    /// Compiles the provided module into a `String` of valid C code.
248    pub fn emit(&mut self) -> String {
249        let mut str = String::new();
250
251        let mut f = vec![];
252
253        for item in &self.module.functions {
254            let x = item.1;
255            let mut res = self.compile_function(x);
256            f.push(res.0);
257
258            self.imports.append(&mut res.1);
259        }
260
261        let mut includes = vec![];
262
263        for item in &self.imports {
264            includes.push(format!("#include <{}>", item));
265        }
266
267        str.push_str(&includes.join("\n"));
268        str.push('\n');
269
270        str.push_str(&f.join("\n"));
271
272        str
273    }
274
275}