1use 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 {
12 program: LLvmProgram::new(),
13 }
14 }
15
16 pub fn add_function<F>(mut self, name: impl Into<String>, return_type: impl Into<String>, f: F) -> Self
17 where
18 F: FnOnce(LLvmFunctionBuilder) -> LLvmFunctionBuilder,
19 {
20 let builder = LLvmFunctionBuilder::new(name.into(), return_type.into());
21 let function = f(builder).build();
22 self.program.root.items.push(LLirItem::Function(function));
23 self
24 }
25
26 pub fn add_global(
27 mut self,
28 name: impl Into<String>,
29 ty: impl Into<String>,
30 value: impl Into<String>,
31 is_constant: bool,
32 ) -> Self {
33 self.program.root.items.push(LLirItem::Global(LLirGlobal {
34 name: name.into(),
35 ty: ty.into(),
36 value: value.into(),
37 is_constant,
38 }));
39 self
40 }
41
42 pub fn build(self) -> LLvmProgram {
43 self.program
44 }
45}
46
47pub struct LLvmFunctionBuilder {
49 function: LLirFunction,
50}
51
52impl LLvmFunctionBuilder {
53 pub fn new(name: String, return_type: String) -> Self {
54 Self {
55 function: LLirFunction {
56 name,
57 return_type,
58 parameters: Vec::new(),
59 blocks: Vec::new(),
60 span: (0..0).into(),
61 },
62 }
63 }
64
65 pub fn add_parameter(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
66 self.function.parameters.push(LLirParameter {
67 name: name.into(),
68 ty: ty.into(),
69 });
70 self
71 }
72
73 pub fn add_block<F>(mut self, label: impl Into<String>, f: F) -> Self
74 where
75 F: FnOnce(LLvmBlockBuilder) -> LLvmBlockBuilder,
76 {
77 let builder = LLvmBlockBuilder::new(Some(label.into()));
78 let block = f(builder).build();
79 self.function.blocks.push(block);
80 self
81 }
82
83 pub fn build(self) -> LLirFunction {
84 self.function
85 }
86}
87
88pub struct LLvmBlockBuilder {
90 block: LLirBlock,
91}
92
93impl LLvmBlockBuilder {
94 pub fn new(label: Option<String>) -> Self {
95 Self {
96 block: LLirBlock {
97 label,
98 instructions: Vec::new(),
99 },
100 }
101 }
102
103 pub fn add_instruction(
104 mut self,
105 opcode: impl Into<String>,
106 operands: Vec<impl Into<String>>,
107 result: Option<impl Into<String>>,
108 ) -> Self {
109 self.block.instructions.push(LLirInstruction {
110 opcode: opcode.into(),
111 operands: operands.into_iter().map(|o| o.into()).collect(),
112 result: result.map(|r| r.into()),
113 });
114 self
115 }
116
117 pub fn ret(self, ty: impl Into<String>, val: impl Into<String>) -> Self {
119 let ty = ty.into();
120 let val = val.into();
121 self.add_instruction("ret", vec![format!("{} {}", ty, val)], None::<String>)
122 }
123
124 pub fn add(
125 self,
126 result: impl Into<String>,
127 ty: impl Into<String>,
128 lhs: impl Into<String>,
129 rhs: impl Into<String>,
130 ) -> Self {
131 let ty = ty.into();
132 let lhs = lhs.into();
133 let rhs = rhs.into();
134 self.add_instruction("add", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
135 }
136
137 pub fn sub(
138 self,
139 result: impl Into<String>,
140 ty: impl Into<String>,
141 lhs: impl Into<String>,
142 rhs: impl Into<String>,
143 ) -> Self {
144 let ty = ty.into();
145 let lhs = lhs.into();
146 let rhs = rhs.into();
147 self.add_instruction("sub", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
148 }
149
150 pub fn mul(
151 self,
152 result: impl Into<String>,
153 ty: impl Into<String>,
154 lhs: impl Into<String>,
155 rhs: impl Into<String>,
156 ) -> Self {
157 let ty = ty.into();
158 let lhs = lhs.into();
159 let rhs = rhs.into();
160 self.add_instruction("mul", vec![format!("{} {}, {}", ty, lhs, rhs)], Some(result))
161 }
162
163 pub fn call(
164 self,
165 result: Option<impl Into<String>>,
166 ty: impl Into<String>,
167 name: impl Into<String>,
168 args: Vec<impl Into<String>>,
169 ) -> Self {
170 let ty = ty.into();
171 let name = name.into();
172 let mut operands = vec![ty, name];
173 operands.extend(args.into_iter().map(|a| a.into()));
174 self.add_instruction("call", operands, result)
175 }
176
177 pub fn build(self) -> LLirBlock {
178 self.block
179 }
180}