llvm_assembler/builder/
mod.rs1use crate::program::LLvmProgram;
2use oak_llvm_ir::ast::{LLirBlock, LLirFunction, LLirGlobal, LLirInstruction, LLirItem, LLirParameter};
3
4pub struct LLvmProgramBuilder {
6 program: LLvmProgram,
7}
8
9impl LLvmProgramBuilder {
10 pub fn new() -> Self {
11 Self { program: LLvmProgram::new() }
12 }
13
14 pub fn add_function<F>(mut self, name: impl Into<String>, return_type: impl Into<String>, f: F) -> Self
15 where
16 F: FnOnce(LLvmFunctionBuilder) -> LLvmFunctionBuilder,
17 {
18 let builder = LLvmFunctionBuilder::new(name.into(), return_type.into());
19 let function = f(builder).build();
20 self.program.root.items.push(LLirItem::Function(function));
21 self
22 }
23
24 pub fn add_global(
25 mut self,
26 name: impl Into<String>,
27 ty: impl Into<String>,
28 value: impl Into<String>,
29 is_constant: bool,
30 ) -> Self {
31 self.program.root.items.push(LLirItem::Global(LLirGlobal {
32 name: name.into(),
33 ty: ty.into(),
34 value: value.into(),
35 is_constant,
36 }));
37 self
38 }
39
40 pub fn build(self) -> LLvmProgram {
41 self.program
42 }
43}
44
45pub struct LLvmFunctionBuilder {
47 function: LLirFunction,
48}
49
50impl LLvmFunctionBuilder {
51 pub fn new(name: String, return_type: String) -> Self {
52 Self { function: LLirFunction { name, return_type, parameters: Vec::new(), blocks: Vec::new(), span: (0..0).into() } }
53 }
54
55 pub fn add_parameter(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
56 self.function.parameters.push(LLirParameter { name: name.into(), ty: ty.into() });
57 self
58 }
59
60 pub fn add_block<F>(mut self, label: impl Into<String>, f: F) -> Self
61 where
62 F: FnOnce(LLvmBlockBuilder) -> LLvmBlockBuilder,
63 {
64 let builder = LLvmBlockBuilder::new(Some(label.into()));
65 let block = f(builder).build();
66 self.function.blocks.push(block);
67 self
68 }
69
70 pub fn build(self) -> LLirFunction {
71 self.function
72 }
73}
74
75pub struct LLvmBlockBuilder {
77 block: LLirBlock,
78}
79
80impl LLvmBlockBuilder {
81 pub fn new(label: Option<String>) -> Self {
82 Self { block: LLirBlock { label, instructions: Vec::new() } }
83 }
84
85 pub fn add_instruction(
86 mut self,
87 opcode: impl Into<String>,
88 operands: Vec<impl Into<String>>,
89 result: Option<impl Into<String>>,
90 ) -> Self {
91 self.block.instructions.push(LLirInstruction {
92 opcode: opcode.into(),
93 operands: operands.into_iter().map(|o| o.into()).collect(),
94 result: result.map(|r| r.into()),
95 });
96 self
97 }
98
99 pub fn ret(self, ty: impl Into<String>, val: impl Into<String>) -> Self {
101 let ty = ty.into();
102 let val = val.into();
103 self.add_instruction("ret", vec![format!("{} {}", ty, val)], None::<String>)
104 }
105
106 pub fn add(self, result: impl Into<String>, ty: impl Into<String>, lhs: impl Into<String>, rhs: impl Into<String>) -> Self {
107 let ty = ty.into();
108 let lhs = lhs.into();
109 let rhs = rhs.into();
110 self.add_instruction("add", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
111 }
112
113 pub fn sub(self, result: impl Into<String>, ty: impl Into<String>, lhs: impl Into<String>, rhs: impl Into<String>) -> Self {
114 let ty = ty.into();
115 let lhs = lhs.into();
116 let rhs = rhs.into();
117 self.add_instruction("sub", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
118 }
119
120 pub fn mul(self, result: impl Into<String>, ty: impl Into<String>, lhs: impl Into<String>, rhs: impl Into<String>) -> Self {
121 let ty = ty.into();
122 let lhs = lhs.into();
123 let rhs = rhs.into();
124 self.add_instruction("mul", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
125 }
126
127 pub fn call(
128 self,
129 result: Option<impl Into<String>>,
130 ty: impl Into<String>,
131 name: impl Into<String>,
132 args: Vec<impl Into<String>>,
133 ) -> Self {
134 let ty = ty.into();
135 let name = name.into();
136 let mut operands = vec![ty, name];
137 operands.extend(args.into_iter().map(|a| a.into()));
138 self.add_instruction("call", operands, result)
139 }
140
141 pub fn build(self) -> LLirBlock {
142 self.block
143 }
144}