Skip to content

Commit 669bb4e

Browse files
committed
feat: extend codegen for structs
1 parent 220bf7a commit 669bb4e

File tree

11 files changed

+365
-48
lines changed

11 files changed

+365
-48
lines changed

crates/codegen/src/builder/enums.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ impl<'a> CodeGenBuilder<'a> {
66
pub(crate) fn build_enum_def(&self, typed_enum: &TypedEnum) {
77
todo!()
88
}
9+
10+
pub(crate) fn build_local_enum_def(&self, typed_enum: &TypedEnum) {
11+
todo!();
12+
}
913
}

crates/codegen/src/builder/exprs.rs

Lines changed: 223 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ use crate::builder::{
55
values::{InternalValue, InternalValueKind},
66
};
77
use ast::{
8-
LiteralKind,
8+
FieldAccess, LiteralKind,
99
operators::{InfixOperator, PrefixOperator, UnaryOperator},
1010
token::Location,
1111
};
1212
use inkwell::{
1313
AddressSpace, FloatPredicate, IntPredicate,
14-
types::BasicTypeEnum,
15-
values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum},
14+
types::{BasicType, BasicTypeEnum},
15+
values::{ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum},
1616
};
1717
use resolver::scope::LocalScopeRef;
1818
use typed_ast::{
19-
SymbolID, TypedExpression, TypedExpressionKind, TypedFuncCall, TypedInfixExpression, TypedLiteral,
20-
TypedPrefixExpression, TypedUnaryExpression,
19+
SymbolID, TypedAddressOf, TypedArray, TypedAssignment, TypedCast, TypedDereference, TypedExpression,
20+
TypedExpressionKind, TypedFuncCall, TypedInfixExpression, TypedLiteral, TypedPrefixExpression, TypedStructInit,
21+
TypedUnaryExpression, TypedUnnamedStructValue,
2122
types::{BasicConcreteType, ConcreteType},
2223
};
2324

@@ -35,20 +36,230 @@ impl<'a> CodeGenBuilder<'a> {
3536
}
3637
TypedExpressionKind::Infix(typed_infix_expr) => self.build_infix_expr(local_scope_opt, typed_infix_expr),
3738
TypedExpressionKind::Unary(typed_unary_expr) => self.build_unary_expr(local_scope_opt, typed_unary_expr),
38-
TypedExpressionKind::Assignment(typed_assignment) => todo!(),
39-
TypedExpressionKind::Cast(typed_cast) => todo!(),
40-
TypedExpressionKind::Array(typed_array) => todo!(),
39+
TypedExpressionKind::Assignment(typed_assign) => self.build_assign(local_scope_opt, typed_assign),
40+
TypedExpressionKind::Cast(typed_cast) => self.build_cast_expr(local_scope_opt, typed_cast),
41+
TypedExpressionKind::Array(typed_array) => self.build_array_expr(local_scope_opt, typed_array),
4142
TypedExpressionKind::ArrayIndex(typed_array_index) => todo!(),
42-
TypedExpressionKind::AddressOf(typed_address_of) => todo!(),
43-
TypedExpressionKind::Dereference(typed_dereference) => todo!(),
44-
TypedExpressionKind::StructInit(typed_struct_init) => todo!(),
43+
TypedExpressionKind::AddressOf(typed_address_of) => {
44+
self.build_address_of(local_scope_opt, typed_address_of)
45+
}
46+
TypedExpressionKind::Dereference(typed_dereference) => {
47+
self.build_dereference(local_scope_opt, typed_dereference)
48+
}
49+
TypedExpressionKind::StructInit(typed_struct_init) => {
50+
self.build_struct_init(local_scope_opt, typed_struct_init)
51+
}
4552
TypedExpressionKind::FuncCall(typed_func_call) => self.build_func_call(local_scope_opt, typed_func_call),
4653
TypedExpressionKind::FieldAccess(typed_field_access) => todo!(),
4754
TypedExpressionKind::MethodCall(typed_method_call) => todo!(),
48-
TypedExpressionKind::UnnamedStructValue(typed_unnamed_struct_value) => todo!(),
55+
TypedExpressionKind::UnnamedStructValue(typed_unnamed_struct_value) => {
56+
self.build_unnamed_struct_value(local_scope_opt, typed_unnamed_struct_value)
57+
}
58+
}
59+
}
60+
61+
fn build_unnamed_struct_value(
62+
&self,
63+
local_scope_opt: Option<LocalScopeRef>,
64+
unnamed_struct_value: &TypedUnnamedStructValue,
65+
) -> InternalValue<'a> {
66+
let struct_type = self
67+
.build_unnamed_struct_type(
68+
local_scope_opt.clone(),
69+
&unnamed_struct_value.unnamed_struct_type.clone().unwrap(),
70+
)
71+
.into_struct_type();
72+
73+
let mut struct_value = struct_type.get_undef();
74+
75+
let mut all_const = true;
76+
let field_values: Vec<BasicValueEnum<'a>> = unnamed_struct_value
77+
.fields
78+
.iter()
79+
.map(|unnamed_struct_value_field| {
80+
let field_lvalue = self.build_expr(local_scope_opt.clone(), &unnamed_struct_value_field.field_value);
81+
let field_rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), field_lvalue);
82+
let field_basic_value = field_rvalue.as_basic_value();
83+
if !self.is_basic_value_constant(field_basic_value) {
84+
all_const = false;
85+
}
86+
field_basic_value
87+
})
88+
.collect();
89+
90+
if all_const {
91+
struct_value = struct_type.const_named_struct(&field_values);
92+
} else {
93+
field_values.iter().enumerate().for_each(|(index, field_value)| {
94+
struct_value = self
95+
.llvmbuilder
96+
.build_insert_value(struct_value, *field_value, index.try_into().unwrap(), "insert")
97+
.unwrap()
98+
.into_struct_value();
99+
});
100+
}
101+
102+
InternalValue::new(
103+
ConcreteType::UnnamedStruct(unnamed_struct_value.unnamed_struct_type.clone().unwrap()),
104+
InternalValueKind::RValue(struct_value.as_basic_value_enum()),
105+
)
106+
}
107+
108+
fn build_struct_init(
109+
&self,
110+
local_scope_opt: Option<LocalScopeRef>,
111+
typed_struct_init: &TypedStructInit,
112+
) -> InternalValue<'a> {
113+
let struct_type = self
114+
.build_concrete_type(
115+
local_scope_opt.clone(),
116+
ConcreteType::Symbol(typed_struct_init.symbol_id),
117+
)
118+
.into_struct_type();
119+
120+
let mut struct_value = struct_type.get_undef();
121+
122+
let mut all_const = true;
123+
let field_values: Vec<BasicValueEnum<'a>> = typed_struct_init
124+
.fields
125+
.iter()
126+
.map(|field_init| {
127+
let field_lvalue = self.build_expr(local_scope_opt.clone(), &field_init.value);
128+
let field_rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), field_lvalue);
129+
let field_basic_value = field_rvalue.as_basic_value();
130+
if !self.is_basic_value_constant(field_basic_value) {
131+
all_const = false;
132+
}
133+
field_basic_value
134+
})
135+
.collect();
136+
137+
if all_const {
138+
struct_value = struct_type.const_named_struct(&field_values);
139+
} else {
140+
field_values.iter().enumerate().for_each(|(index, field_value)| {
141+
struct_value = self
142+
.llvmbuilder
143+
.build_insert_value(struct_value, *field_value, index.try_into().unwrap(), "insert")
144+
.unwrap()
145+
.into_struct_value();
146+
});
147+
}
148+
149+
InternalValue::new(
150+
ConcreteType::Symbol(typed_struct_init.symbol_id),
151+
InternalValueKind::RValue(struct_value.as_basic_value_enum()),
152+
)
153+
}
154+
155+
fn build_assign(&self, local_scope_opt: Option<LocalScopeRef>, assign: &TypedAssignment) -> InternalValue<'a> {
156+
let lhs_lvalue = self.build_expr(local_scope_opt.clone(), &assign.lhs);
157+
let rhs_lvalue = self.build_expr(local_scope_opt.clone(), &assign.rhs);
158+
let rhs_rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), rhs_lvalue);
159+
160+
assert!(lhs_lvalue.as_basic_value().is_pointer_value() == true);
161+
let pointer_value = lhs_lvalue.as_basic_value().into_pointer_value();
162+
163+
self.llvmbuilder
164+
.build_store(pointer_value, rhs_rvalue.as_basic_value())
165+
.unwrap();
166+
rhs_rvalue
167+
}
168+
169+
fn build_dereference(&self, local_scope_opt: Option<LocalScopeRef>, deref: &TypedDereference) -> InternalValue<'a> {
170+
let operand_type = deref.operand.concrete_type.clone().unwrap();
171+
let lvalue = self.build_expr(local_scope_opt.clone(), &deref.operand);
172+
let rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), lvalue);
173+
174+
InternalValue::new(operand_type, InternalValueKind::RValue(rvalue.as_basic_value()))
175+
}
176+
177+
fn build_address_of(
178+
&self,
179+
local_scope_opt: Option<LocalScopeRef>,
180+
address_of: &TypedAddressOf,
181+
) -> InternalValue<'a> {
182+
let operand_type = address_of.operand.concrete_type.clone().unwrap();
183+
let lvalue = self.build_expr(local_scope_opt.clone(), &address_of.operand);
184+
185+
InternalValue::new(
186+
ConcreteType::Pointer(Box::new(operand_type)),
187+
InternalValueKind::RValue(lvalue.as_basic_value()),
188+
)
189+
}
190+
191+
fn build_array_expr(&self, local_scope_opt: Option<LocalScopeRef>, array: &TypedArray) -> InternalValue<'a> {
192+
let array_concrete_type = array.array_type.as_array_type().unwrap();
193+
let element_type = array_concrete_type.element_type.clone();
194+
let array_type = self
195+
.build_concrete_type(local_scope_opt.clone(), array.array_type.clone())
196+
.into_array_type();
197+
198+
let mut all_const = true;
199+
let elements: Vec<BasicValueEnum<'a>> = array
200+
.elements
201+
.iter()
202+
.map(|typed_expr| {
203+
let lvalue = self.build_expr(local_scope_opt.clone(), typed_expr);
204+
let rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), lvalue);
205+
let casted_rvalue = self
206+
.build_implicit_cast(local_scope_opt.clone(), *element_type.clone(), rvalue)
207+
.as_basic_value();
208+
if !self.is_basic_value_constant(casted_rvalue) {
209+
all_const = false;
210+
}
211+
casted_rvalue
212+
})
213+
.collect();
214+
215+
if all_const {
216+
let array_value = unsafe { ArrayValue::new_const_array(&array_type, &elements) };
217+
218+
InternalValue::new(
219+
array.array_type.clone(),
220+
InternalValueKind::RValue(array_value.as_basic_value_enum()),
221+
)
222+
} else {
223+
let mut array_value = array_type.get_undef();
224+
225+
elements.iter().enumerate().for_each(|(index, element)| {
226+
array_value = self
227+
.llvmbuilder
228+
.build_insert_value(array_value, *element, index.try_into().unwrap(), "insert")
229+
.unwrap()
230+
.into_array_value();
231+
});
232+
233+
InternalValue::new(
234+
array.array_type.clone(),
235+
InternalValueKind::RValue(array_value.as_basic_value_enum()),
236+
)
49237
}
50238
}
51239

240+
fn is_basic_value_constant(&self, basic_value: BasicValueEnum<'a>) -> bool {
241+
match basic_value {
242+
BasicValueEnum::IntValue(int_value) => int_value.is_const(),
243+
BasicValueEnum::FloatValue(float_value) => float_value.is_const(),
244+
BasicValueEnum::PointerValue(ptr_value) => ptr_value.is_const(),
245+
BasicValueEnum::StructValue(struct_value) => struct_value.is_const(),
246+
BasicValueEnum::ArrayValue(array_value) => array_value.is_const(),
247+
BasicValueEnum::VectorValue(vector_value) => vector_value.is_const(),
248+
}
249+
}
250+
251+
fn build_cast_expr(&self, local_scope_opt: Option<LocalScopeRef>, cast: &TypedCast) -> InternalValue<'a> {
252+
let lvalue = self.build_expr(local_scope_opt.clone(), &cast.operand);
253+
let rvalue = self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), lvalue);
254+
255+
let target_any_type = self.build_concrete_type(local_scope_opt, cast.target_type.clone());
256+
let any_value = self.build_cast(target_any_type, rvalue);
257+
InternalValue::new(
258+
cast.target_type.clone(),
259+
InternalValueKind::RValue(any_value.try_into().unwrap()),
260+
)
261+
}
262+
52263
fn build_func_call(&self, local_scope_opt: Option<LocalScopeRef>, func_call: &TypedFuncCall) -> InternalValue<'a> {
53264
let module_id = self.resolver.lookup_symbol_id_in_modules(func_call.symbol_id).unwrap();
54265
let symbol_entry = self

crates/codegen/src/builder/stmts.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,13 @@ impl<'a> CodeGenBuilder<'a> {
3131
let irreg = self.irreg.borrow();
3232
let fn_value = match irreg.get(&symbol_id) {
3333
Some(local_ir_value) => local_ir_value.as_func().unwrap().clone(),
34-
None => {
35-
self.build_func_decl(
36-
resolved_func.func_sig.name.clone(),
37-
resolved_func.func_sig.params.clone(),
38-
resolved_func.func_sig.return_type.clone(),
39-
resolved_func.func_sig.vis.clone(),
40-
None,
41-
)
42-
}
34+
None => self.build_func_decl(
35+
resolved_func.func_sig.name.clone(),
36+
resolved_func.func_sig.params.clone(),
37+
resolved_func.func_sig.return_type.clone(),
38+
resolved_func.func_sig.vis.clone(),
39+
None,
40+
),
4341
};
4442
drop(irreg);
4543
fn_value
@@ -105,6 +103,20 @@ impl<'a> CodeGenBuilder<'a> {
105103
self.llvmctx.opaque_struct_type(name)
106104
}
107105

106+
fn build_local_struct_def(&self, typed_struct: &TypedStruct) {
107+
let field_types: Vec<BasicTypeEnum<'a>> = typed_struct
108+
.fields
109+
.iter()
110+
.map(|field| self.build_concrete_type(None, field.ty.clone()).try_into().unwrap())
111+
.collect();
112+
113+
let struct_type = self.llvmctx.struct_type(&field_types, typed_struct.packed);
114+
115+
let mut irreg = self.irreg.borrow_mut();
116+
irreg.insert(typed_struct.symbol_id, LocalIRValue::Struct(struct_type));
117+
drop(irreg);
118+
}
119+
108120
fn build_struct_def(&self, typed_struct: &TypedStruct) {
109121
let field_types: Vec<BasicTypeEnum<'a>> = typed_struct
110122
.fields
@@ -143,8 +155,12 @@ impl<'a> CodeGenBuilder<'a> {
143155
TypedStatement::For(typed_for) => todo!(),
144156
TypedStatement::Foreach(typed_foreach) => todo!(),
145157
TypedStatement::Switch(typed_switch) => todo!(),
146-
TypedStatement::Struct(typed_struct) => todo!(),
147-
TypedStatement::Enum(typed_enum) => todo!(),
158+
TypedStatement::Struct(typed_struct) => {
159+
self.build_local_struct_def(typed_struct);
160+
}
161+
TypedStatement::Enum(typed_enum) => {
162+
self.build_local_enum_def(typed_enum);
163+
},
148164
TypedStatement::Expression(typed_expr) => {
149165
let lvalue = self.build_expr(local_scope_opt.clone(), typed_expr);
150166
self.build_load_lvalue_to_rvalue(local_scope_opt.clone(), lvalue);

0 commit comments

Comments
 (0)