Skip to content

Commit 42422f4

Browse files
author
TheDevConnor
committed
Fixed how member expr's and struct access is being handled in the codegen
1 parent 2e7c507 commit 42422f4

File tree

6 files changed

+301
-123
lines changed

6 files changed

+301
-123
lines changed

LPBS/lexer.lx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ pub const scan -> fn (path: *char) *Token {
217217
let word: *char = cast<*char>(alloc(length + 1));
218218

219219
if (word == cast<*char>(0)) {
220-
print_error("Failed to allocate memory for identifier", tks.line, start_col);
220+
print_error("Failed to allocate memory for identifier",
221+
tks.line, start_col);
221222
free_tokens(tks);
222223
return cast<*Token>(0);
223224
}
@@ -234,15 +235,17 @@ pub const scan -> fn (path: *char) *Token {
234235
let matched: int = 0;
235236
loop [j: int = 0](j < 10) : (++j) {
236237
if (string::strcmp(word, k_symbol[j].value) == 0) {
237-
tks.list[tks.size] = make_token(k_symbol[j].type, word, tks.line, start_col);
238+
tks.list[tks.size] = make_token(k_symbol[j].type, word,
239+
tks.line, start_col);
238240
tks.size = tks.size + 1;
239241
matched = 1;
240242
break;
241243
}
242244
}
243245

244246
if (matched == 0) {
245-
tks.list[tks.size] = make_token(TokenType::TOK_IDENT, word, tks.line, start_col);
247+
tks.list[tks.size] = make_token(TokenType::TOK_IDENT, word,
248+
tks.line, start_col);
246249
tks.size = tks.size + 1;
247250
}
248251

@@ -275,7 +278,8 @@ pub const scan -> fn (path: *char) *Token {
275278
}
276279
num[length] = '\0';
277280

278-
tks.list[tks.size] = make_token(TokenType::TOK_NUMBER, num, tks.line, start_col);
281+
tks.list[tks.size] = make_token(TokenType::TOK_NUMBER, num,
282+
tks.line, start_col);
279283
tks.size = tks.size + 1;
280284
continue;
281285
}
@@ -300,7 +304,8 @@ pub const scan -> fn (path: *char) *Token {
300304

301305
// Check if we reached end of file without closing quote
302306
if (i >= src_len) {
303-
print_error("Unterminated string literal (end of file)", tks.line, start_col);
307+
print_error("Unterminated string literal (end of file)",
308+
tks.line, start_col);
304309
free_tokens(tks);
305310
return cast<*Token>(0);
306311
}
@@ -321,7 +326,8 @@ pub const scan -> fn (path: *char) *Token {
321326
}
322327
str_val[length] = '\0';
323328

324-
tks.list[tks.size] = make_token(TokenType::TOK_STRING, str_val, tks.line, start_col);
329+
tks.list[tks.size] = make_token(TokenType::TOK_STRING, str_val,
330+
tks.line, start_col);
325331
tks.size = tks.size + 1;
326332

327333
i = i + 1; // Skip closing quote
@@ -347,7 +353,8 @@ pub const scan -> fn (path: *char) *Token {
347353
loop [k: int = 0](k < 4) : (++k) {
348354
if (string::strcmp(two, d_symbol[k].value) == 0) {
349355
let start_col: int = tks.col;
350-
tks.list[tks.size] = make_token(d_symbol[k].type, two, tks.line, start_col);
356+
tks.list[tks.size] = make_token(d_symbol[k].type, two,
357+
tks.line, start_col);
351358
tks.size = tks.size + 1;
352359
tks.col = tks.col + 2;
353360
i = i + 2;
@@ -369,14 +376,16 @@ pub const scan -> fn (path: *char) *Token {
369376
let start_col: int = tks.col;
370377

371378
if (ch == '\0') {
372-
print_error("Failed to allocate memory for symbol", tks.line, start_col);
379+
print_error("Failed to allocate memory for symbol", tks.line,
380+
start_col);
373381
free_tokens(tks);
374382
return cast<*Token>(0);
375383
}
376384

377385
// Ownership transferred to token - will be freed by free_tokens()
378386
tks.list[tks.size] =
379-
make_token(s_symbol[k].type, string::from_char(ch), tks.line, start_col);
387+
make_token(s_symbol[k].type, string::from_char(ch),
388+
tks.line, start_col);
380389
tks.size = tks.size + 1;
381390
tks.col = tks.col + 1;
382391
i = i + 1;

LPBS/main.lx

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
@use "string" as string
44
@use "lexer" as lexer
5+
@use "parser" as psr
56
@use "io" as io
67

78
#takes_ownership
@@ -12,22 +13,26 @@ const clean_up -> fn (path: *char, lex: *Token) void {
1213

1314
pub const main -> fn () int {
1415
let path: *char =
15-
io::read_file("/home/TheDevConnor/Luma/LPBS/build.lmb");
16+
io::read_file("/home/connor/Projects/Luma/LPBS/build.lmb");
1617
let lex: *Token = lexer::scan(path);
1718

18-
output("Token count: ");
19-
output(lex.size);
20-
output("\n");
21-
22-
loop [i: int = 0](i < lex.size) : (++i) {
23-
let tk: Token = lex.list[i];
24-
output("Token ");
25-
output(tk.type);
26-
output(": ");
27-
output(tk.value);
28-
output("\tline: ", tk.line, " col: ", tk.col);
29-
output("\n");
30-
}
19+
// output("Token count: ");
20+
// output(lex.size);
21+
// output("\n");
22+
//
23+
// loop [i: int = 0](i < lex.size) : (++i) {
24+
// let tk: Token = lex.list[i];
25+
// output("i: ", i, " Token ");
26+
// output(tk.type);
27+
// output(": ");
28+
// output(tk.value);
29+
// output("\n");
30+
// }
31+
32+
let parser: Parser;
33+
psr::init_parser(&parser, lex);
34+
35+
output(psr::peek(&parser, 45).value, "\n");
3136

3237
clean_up(path, lex);
3338
return 0;

LPBS/parser.lx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,21 @@ const BindingPower -> enum {
2626
};
2727

2828
pub const Parser -> struct {
29-
path: *char,
3029
tks: *Token,
31-
tk_count: int,
32-
capacity: int,
30+
path: *char,
3331
pos: int,
3432
};
33+
34+
pub const init_parser -> fn (psr: *Parser, tks: *Token) void {
35+
psr.path = path;
36+
psr.tks = tks;
37+
psr.pos = 0;
38+
}
39+
40+
pub const peek -> fn (psr: *Parser, index: int) Token {
41+
return psr.tks.list[index];
42+
}
43+
44+
pub const parse -> fn (tks: *Token, path: *char) void {
45+
46+
}

src/llvm/expr.c

Lines changed: 160 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <stdio.h>
12
#include <stdlib.h>
23

34
#include "llvm.h"
@@ -719,8 +720,6 @@ LLVMValueRef codegen_expr_assignment(CodeGenContext *ctx, AstNode *node) {
719720
// Final fallback: use value type
720721
if (!element_type) {
721722
element_type = value_type;
722-
fprintf(stderr, "Warning: Could not determine pointer element type, "
723-
"using value type\n");
724723
}
725724

726725
// Convert value to match element type if needed
@@ -948,6 +947,165 @@ LLVMValueRef codegen_expr_index(CodeGenContext *ctx, AstNode *node) {
948947
return NULL;
949948
}
950949

950+
// **NEW: Special handling for indexing member access (struct.field[index])**
951+
if (node->expr.index.object->type == AST_EXPR_MEMBER) {
952+
AstNode *member_expr = node->expr.index.object;
953+
const char *field_name = member_expr->expr.member.member;
954+
955+
// Generate the member access to get the pointer
956+
LLVMValueRef pointer = codegen_expr_struct_access(ctx, member_expr);
957+
if (!pointer) {
958+
fprintf(stderr, "Error: Failed to resolve member access for indexing\n");
959+
return NULL;
960+
}
961+
962+
// Generate the index expression
963+
LLVMValueRef index = codegen_expr(ctx, node->expr.index.index);
964+
if (!index) {
965+
return NULL;
966+
}
967+
968+
LLVMTypeRef pointer_type = LLVMTypeOf(pointer);
969+
LLVMTypeKind pointer_kind = LLVMGetTypeKind(pointer_type);
970+
971+
// The member access should have returned a pointer
972+
if (pointer_kind != LLVMPointerTypeKind) {
973+
fprintf(stderr, "Error: Member '%s' is not a pointer type for indexing\n",
974+
field_name);
975+
return NULL;
976+
}
977+
978+
// Find the struct that contains this field to get element type info
979+
LLVMTypeRef element_type = NULL;
980+
981+
// Build a list of field names in the chain (in reverse order)
982+
const char *field_chain[32];
983+
int chain_length = 0;
984+
AstNode *current_node = member_expr;
985+
986+
while (current_node && current_node->type == AST_EXPR_MEMBER &&
987+
chain_length < 32) {
988+
field_chain[chain_length++] = current_node->expr.member.member;
989+
current_node = current_node->expr.member.object;
990+
}
991+
992+
// Reverse the chain to get the correct order
993+
for (int i = 0; i < chain_length / 2; i++) {
994+
const char *temp = field_chain[i];
995+
field_chain[i] = field_chain[chain_length - 1 - i];
996+
field_chain[chain_length - 1 - i] = temp;
997+
}
998+
999+
// Find the base identifier
1000+
AstNode *base_obj = member_expr->expr.member.object;
1001+
while (base_obj->type == AST_EXPR_MEMBER) {
1002+
base_obj = base_obj->expr.member.object;
1003+
}
1004+
1005+
if (base_obj->type == AST_EXPR_IDENTIFIER) {
1006+
const char *base_name = base_obj->expr.identifier.name;
1007+
LLVM_Symbol *base_sym = find_symbol(ctx, base_name);
1008+
1009+
if (base_sym) {
1010+
// Find the initial struct type
1011+
StructInfo *current_struct = NULL;
1012+
LLVMTypeRef sym_type = base_sym->type;
1013+
LLVMTypeKind sym_kind = LLVMGetTypeKind(sym_type);
1014+
1015+
if (sym_kind == LLVMPointerTypeKind && base_sym->element_type) {
1016+
// It's a pointer to struct
1017+
for (StructInfo *info = ctx->struct_types; info; info = info->next) {
1018+
if (info->llvm_type == base_sym->element_type) {
1019+
current_struct = info;
1020+
break;
1021+
}
1022+
}
1023+
} else if (sym_kind == LLVMStructTypeKind) {
1024+
// Direct struct type
1025+
for (StructInfo *info = ctx->struct_types; info; info = info->next) {
1026+
if (info->llvm_type == sym_type) {
1027+
current_struct = info;
1028+
break;
1029+
}
1030+
}
1031+
}
1032+
1033+
// Trace through the field chain
1034+
for (int i = 0; i < chain_length && current_struct; i++) {
1035+
const char *current_field_name = field_chain[i];
1036+
int field_idx = get_field_index(current_struct, current_field_name);
1037+
1038+
if (field_idx < 0) {
1039+
fprintf(stderr, "Error: Field '%s' not found in struct '%s'\n",
1040+
current_field_name, current_struct->name);
1041+
break;
1042+
}
1043+
1044+
// If this is the last field in the chain, get its element type
1045+
if (i == chain_length - 1) {
1046+
element_type = current_struct->field_element_types[field_idx];
1047+
break;
1048+
}
1049+
1050+
// Otherwise, move to the next struct in the chain
1051+
LLVMTypeRef field_type = current_struct->field_types[field_idx];
1052+
LLVMTypeKind field_kind = LLVMGetTypeKind(field_type);
1053+
1054+
if (field_kind == LLVMStructTypeKind) {
1055+
// Field is a struct - find its info
1056+
StructInfo *next_struct = NULL;
1057+
for (StructInfo *info = ctx->struct_types; info;
1058+
info = info->next) {
1059+
if (info->llvm_type == field_type) {
1060+
next_struct = info;
1061+
break;
1062+
}
1063+
}
1064+
current_struct = next_struct;
1065+
} else if (field_kind == LLVMPointerTypeKind) {
1066+
// Field is a pointer - get what it points to
1067+
LLVMTypeRef pointee =
1068+
current_struct->field_element_types[field_idx];
1069+
if (pointee && LLVMGetTypeKind(pointee) == LLVMStructTypeKind) {
1070+
// Find the struct info for the pointee
1071+
StructInfo *next_struct = NULL;
1072+
for (StructInfo *info = ctx->struct_types; info;
1073+
info = info->next) {
1074+
if (info->llvm_type == pointee) {
1075+
next_struct = info;
1076+
break;
1077+
}
1078+
}
1079+
current_struct = next_struct;
1080+
} else {
1081+
// Not a struct pointer, can't continue
1082+
break;
1083+
}
1084+
} else {
1085+
// Field is not a struct or pointer, can't continue
1086+
break;
1087+
}
1088+
}
1089+
}
1090+
}
1091+
1092+
if (!element_type) {
1093+
fprintf(
1094+
stderr,
1095+
"Error: Could not determine pointer element type for indexing '%s'\n",
1096+
field_name);
1097+
return NULL;
1098+
}
1099+
1100+
// Build GEP for pointer arithmetic
1101+
LLVMValueRef element_ptr = LLVMBuildGEP2(
1102+
ctx->builder, element_type, pointer, &index, 1, "member_ptr_element");
1103+
1104+
// Load the actual value
1105+
return LLVMBuildLoad2(ctx->builder, element_type, element_ptr,
1106+
"member_element_val");
1107+
}
1108+
9511109
// Generate the object being indexed
9521110
LLVMValueRef object = codegen_expr(ctx, node->expr.index.object);
9531111
if (!object) {
@@ -1081,53 +1239,6 @@ LLVMValueRef codegen_expr_index(CodeGenContext *ctx, AstNode *node) {
10811239
cast_node->expr.cast.type->type_data.pointer.pointee_type;
10821240
pointee_type = codegen_type(ctx, pointee_node);
10831241
}
1084-
} else if (node->expr.index.object->type == AST_EXPR_MEMBER) {
1085-
AstNode *member_expr = node->expr.index.object;
1086-
const char *field_name = member_expr->expr.member.member;
1087-
1088-
// Need to get the base object to find which struct this field belongs to
1089-
AstNode *base_obj = member_expr->expr.member.object;
1090-
1091-
if (base_obj->type == AST_EXPR_IDENTIFIER) {
1092-
const char *base_name = base_obj->expr.identifier.name;
1093-
LLVM_Symbol *base_sym = find_symbol(ctx, base_name);
1094-
1095-
if (base_sym) {
1096-
// Determine the struct type
1097-
LLVMTypeRef base_type = base_sym->type;
1098-
StructInfo *struct_info = NULL;
1099-
1100-
// If base is a pointer to struct, get the pointee type
1101-
if (LLVMGetTypeKind(base_type) == LLVMPointerTypeKind &&
1102-
base_sym->element_type) {
1103-
// Find struct info by its LLVM type
1104-
for (StructInfo *info = ctx->struct_types; info;
1105-
info = info->next) {
1106-
if (info->llvm_type == base_sym->element_type) {
1107-
struct_info = info;
1108-
break;
1109-
}
1110-
}
1111-
} else {
1112-
// Direct struct type
1113-
for (StructInfo *info = ctx->struct_types; info;
1114-
info = info->next) {
1115-
if (info->llvm_type == base_type) {
1116-
struct_info = info;
1117-
break;
1118-
}
1119-
}
1120-
}
1121-
1122-
if (struct_info) {
1123-
int field_idx = get_field_index(struct_info, field_name);
1124-
if (field_idx >= 0) {
1125-
// Use the element type stored for this field
1126-
pointee_type = struct_info->field_element_types[field_idx];
1127-
}
1128-
}
1129-
}
1130-
}
11311242
}
11321243

11331244
// CRITICAL: Don't fall back to i8! This causes the bug.

0 commit comments

Comments
 (0)