Skip to content

Commit 5145c03

Browse files
author
TheDevConnor
committed
Fixed weird issue with struct functions not being called from the module correctly as well as made a couple of otehr minor fixes
1 parent 9f72e2b commit 5145c03

File tree

9 files changed

+217
-79
lines changed

9 files changed

+217
-79
lines changed

src/helper/help.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/** Enable debug logs for arena allocator (comment to disable) */
2929
#define DEBUG_ARENA_ALLOC 1
3030

31-
#define Luma_Compiler_version "v0.1.4"
31+
#define Luma_Compiler_version "v0.1.6"
3232

3333
/** Error codes returned by the compiler */
3434
typedef enum {

src/llvm/expr.c

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -513,30 +513,49 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
513513
// Check if this is a method call (obj.method())
514514
if (callee->type == AST_EXPR_MEMBER && !callee->expr.member.is_compiletime) {
515515
// Method call: obj.method(arg1, arg2)
516-
// The typechecker has already injected 'self' as the first argument
517-
// So we just need to codegen all arguments as-is
518-
519-
// Get the method function
520516
const char *member_name = callee->expr.member.member;
517+
518+
// **FIX: The typechecker already injected self into args[0]!**
519+
// Just look up the method and use args as-is
520+
521+
LLVMValueRef method_func = NULL;
521522

522-
// Look up the method in the current module
523+
// First try current module
523524
LLVMModuleRef current_llvm_module =
524525
ctx->current_module ? ctx->current_module->module : ctx->module;
525-
LLVMValueRef method_func =
526-
LLVMGetNamedFunction(current_llvm_module, member_name);
526+
method_func = LLVMGetNamedFunction(current_llvm_module, member_name);
527527

528+
// If not found in current module, search all other modules
528529
if (!method_func) {
529-
fprintf(stderr, "Error: Method '%s' not found\n", member_name);
530+
for (ModuleCompilationUnit *unit = ctx->modules; unit;
531+
unit = unit->next) {
532+
if (unit == ctx->current_module)
533+
continue;
534+
535+
LLVMValueRef found_func = LLVMGetNamedFunction(unit->module, member_name);
536+
if (found_func) {
537+
// CRITICAL FIX: Create external declaration in current module
538+
LLVMTypeRef func_type = LLVMGlobalGetValueType(found_func);
539+
method_func = LLVMAddFunction(current_llvm_module, member_name, func_type);
540+
LLVMSetLinkage(method_func, LLVMExternalLinkage);
541+
break;
542+
}
543+
}
544+
}
545+
546+
if (!method_func) {
547+
fprintf(stderr, "Error: Method '%s' not found in any module\n",
548+
member_name);
530549
return NULL;
531550
}
532551

533552
callee_value = method_func;
534553

535-
// Allocate space for all arguments (including injected self)
554+
// Allocate space for arguments (typechecker already added self!)
536555
args = (LLVMValueRef *)arena_alloc(
537556
ctx->arena, sizeof(LLVMValueRef) * arg_count, alignof(LLVMValueRef));
538557

539-
// Codegen all arguments (self is already in args[0] from typechecker)
558+
// Generate all arguments (including self at index 0)
540559
for (size_t i = 0; i < arg_count; i++) {
541560
args[i] = codegen_expr(ctx, node->expr.call.args[i]);
542561
if (!args[i]) {
@@ -545,8 +564,7 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
545564
member_name);
546565
return NULL;
547566
}
548-
}
549-
567+
}
550568
} else {
551569
// Regular function call or compile-time member access (module::func)
552570
callee_value = codegen_expr(ctx, callee);
@@ -572,14 +590,10 @@ LLVMValueRef codegen_expr_call(CodeGenContext *ctx, AstNode *node) {
572590

573591
// Check if return type is void
574592
if (LLVMGetTypeKind(return_type) == LLVMVoidTypeKind) {
575-
// For void functions, don't assign a name to the call
576593
LLVMBuildCall2(ctx->builder, func_type, callee_value, args, arg_count, "");
577-
// Return a void constant since we can't return NULL
578594
return LLVMConstNull(LLVMVoidTypeInContext(ctx->context));
579595
} else {
580-
// For non-void functions, assign a name as usual
581-
return LLVMBuildCall2(ctx->builder, func_type, callee_value, args,
582-
arg_count, "call");
596+
return LLVMBuildCall2(ctx->builder, func_type, callee_value, args, arg_count, "call");
583597
}
584598
}
585599

src/llvm/llvm.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,25 @@ void generate_external_declarations(CodeGenContext *ctx,
5151
if (source_module == target_module)
5252
continue;
5353

54-
// Look through source module's symbols for public functions
55-
for (LLVM_Symbol *sym = source_module->symbols; sym; sym = sym->next) {
56-
if (sym->is_function) {
57-
// Check if this function is already declared in target module
58-
LLVMValueRef existing =
59-
LLVMGetNamedFunction(target_module->module, sym->name);
54+
// Iterate through ALL functions in the source module (not just symbols)
55+
LLVMValueRef func = LLVMGetFirstFunction(source_module->module);
56+
while (func) {
57+
// Check if this function has external linkage (is public)
58+
if (LLVMGetLinkage(func) == LLVMExternalLinkage) {
59+
const char *func_name = LLVMGetValueName(func);
60+
61+
// Check if already declared in target module
62+
LLVMValueRef existing = LLVMGetNamedFunction(target_module->module, func_name);
6063
if (!existing) {
6164
// Create external declaration
62-
LLVMTypeRef func_type = LLVMGlobalGetValueType(sym->value);
65+
LLVMTypeRef func_type = LLVMGlobalGetValueType(func);
6366
LLVMValueRef external_func =
64-
LLVMAddFunction(target_module->module, sym->name, func_type);
67+
LLVMAddFunction(target_module->module, func_name, func_type);
6568
LLVMSetLinkage(external_func, LLVMExternalLinkage);
66-
67-
// Add to target module's symbol table
68-
add_symbol_to_module(target_module, sym->name, external_func,
69-
func_type, true);
7069
}
7170
}
71+
72+
func = LLVMGetNextFunction(func);
7273
}
7374
}
7475
}

src/typechecker/expr.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -885,21 +885,20 @@ AstNode *typecheck_member_expr(AstNode *expr, Scope *scope,
885885
if (pointee && pointee->type == AST_TYPE_BASIC) {
886886
const char *type_name = pointee->type_data.basic.name;
887887

888-
// First try direct lookup
888+
// Try lookup through normal scope chain first
889889
Symbol *struct_symbol = scope_lookup(scope, type_name);
890890

891-
// If not found, try looking in imported modules
891+
// If not found through normal lookup, explicitly search imported modules
892892
if (!struct_symbol) {
893-
// Check each imported module for this type
894893
Scope *current = scope;
895894
while (current && !struct_symbol) {
896895
for (size_t i = 0; i < current->imported_modules.count; i++) {
897896
ModuleImport *import =
898897
(ModuleImport *)((char *)current->imported_modules.data +
899898
i * sizeof(ModuleImport));
900899

901-
// Try to find the type in the imported module's scope
902-
struct_symbol = scope_lookup_current_only_with_visibility(
900+
// CRITICAL FIX: Use full scope_lookup with visibility
901+
struct_symbol = scope_lookup_with_visibility(
903902
import->module_scope, type_name, scope);
904903

905904
if (struct_symbol && struct_symbol->type &&
@@ -925,10 +924,10 @@ AstNode *typecheck_member_expr(AstNode *expr, Scope *scope,
925924
if (base_type->type == AST_TYPE_BASIC) {
926925
const char *type_name = base_type->type_data.basic.name;
927926

928-
// First try direct lookup
927+
// Try lookup through normal scope chain first
929928
Symbol *struct_symbol = scope_lookup(scope, type_name);
930929

931-
// If not found, try looking in imported modules
930+
// If not found through normal lookup, explicitly search imported modules
932931
if (!struct_symbol) {
933932
Scope *current = scope;
934933
while (current && !struct_symbol) {
@@ -937,7 +936,8 @@ AstNode *typecheck_member_expr(AstNode *expr, Scope *scope,
937936
(ModuleImport *)((char *)current->imported_modules.data +
938937
i * sizeof(ModuleImport));
939938

940-
struct_symbol = scope_lookup_current_only_with_visibility(
939+
// CRITICAL FIX: Use full scope_lookup with visibility
940+
struct_symbol = scope_lookup_with_visibility(
941941
import->module_scope, type_name, scope);
942942

943943
if (struct_symbol && struct_symbol->type &&
@@ -977,7 +977,6 @@ AstNode *typecheck_member_expr(AstNode *expr, Scope *scope,
977977
}
978978
}
979979
}
980-
981980
AstNode *typecheck_deref_expr(AstNode *expr, Scope *scope,
982981
ArenaAllocator *arena) {
983982
if (expr->expr.deref.object->type == AST_EXPR_IDENTIFIER) {

src/typechecker/scope.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,21 @@ Symbol *scope_lookup_with_visibility(Scope *scope, const char *name,
168168
return NULL;
169169
}
170170
}
171+
172+
for (size_t i = 0; i < current->imported_modules.count; i++) {
173+
ModuleImport *import =
174+
(ModuleImport *)((char *)current->imported_modules.data +
175+
i * sizeof(ModuleImport));
176+
177+
// Search in the imported module's scope
178+
Symbol *found = scope_lookup_current_only_with_visibility(
179+
import->module_scope, name, scope);
180+
181+
if (found) {
182+
return found;
183+
}
184+
}
185+
171186
current = current->parent;
172187
}
173188

src/typechecker/type.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,10 @@ AstNode *get_struct_member_type(AstNode *struct_type, const char *member_name) {
326326
return NULL;
327327
}
328328

329+
// fprintf(stderr, "DEBUG: Looking for member '%s' in struct with %zu members:\n",
330+
// member_name, struct_type->type_data.struct_type.member_count);
329331
for (size_t i = 0; i < struct_type->type_data.struct_type.member_count; i++) {
332+
// fprintf(stderr, " - %s\n", struct_type->type_data.struct_type.member_names[i]);
330333
if (strcmp(struct_type->type_data.struct_type.member_names[i],
331334
member_name) == 0) {
332335
return struct_type->type_data.struct_type.member_types[i];

std/arena.lx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@use "io" as io
66

77
const ARENA_DEFAULT_SIZE: int = 1024 * 1024;
8+
const NULL: *void = cast<*void>(0);
89

910
pub const Arena -> struct {
1011
pub:
@@ -37,7 +38,7 @@ pub const reset_arena -> fn (a: *Arena) void {
3738
#takes_ownership
3839
pub const free_arena -> fn (a: *Arena) void {
3940
free(a.buf);
40-
a.buf = cast<*byte>(0);
41+
a.buf = NULL;
4142
a.buf_len = 0;
4243
a.curr_offset = 0;
4344
a.prev_offset = 0;
@@ -51,7 +52,7 @@ pub const alloc_arena -> fn (a: *Arena, size: int) *void {
5152
if (aligned_offset + size > a.buf_len) {
5253
io::print_err("Arena allocator: insufficient space (requested: %d bytes, available: %d bytes)\n",
5354
[size, (a.buf_len - aligned_offset)]);
54-
return cast<*void>(0);
55+
return NULL;
5556
}
5657

5758
let ptr: *void = cast<*void>(cast<int>(a.buf) + aligned_offset);

std/vector.lx

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
@module "vector"
2+
3+
@use "memory" as memory
4+
5+
const DEFAULT_VECTOR_CAPACITY: int = 1024;
6+
const NULL: *void = cast<*void>(0);
7+
8+
pub const Vector -> struct {
9+
pub:
10+
data: *void,
11+
capacity: int,
12+
size: int,
13+
element_size: int,
14+
15+
insert -> fn (elem: *void, index: int) int {
16+
if (index < 0 || index > self.size) return 0;
17+
18+
if (self.size >= self.capacity) {
19+
self.capacity = self.capacity * 2;
20+
self.data = memory::realloc(
21+
self.data,
22+
self.capacity * self.element_size
23+
);
24+
}
25+
26+
// shift elements right
27+
let src: *void = cast<*void>(
28+
cast<int>(self.data) + (index * self.element_size)
29+
);
30+
31+
let dst: *void = cast<*void>(
32+
cast<int>(self.data) + ((index + 1) * self.element_size)
33+
);
34+
35+
let bytes: int = (self.size - index) * self.element_size;
36+
memory::memcpy(dst, src, bytes);
37+
38+
// write new element
39+
memory::memcpy(src, elem, self.element_size);
40+
self.size = self.size + 1;
41+
return 1;
42+
},
43+
44+
push_back -> fn (elem: *void) void {
45+
if (self.size >= self.capacity) {
46+
self.capacity = self.capacity * 2;
47+
self.data = memory::realloc(self.data, self.capacity * self.element_size);
48+
}
49+
50+
let dest: *void = cast<*void>(
51+
cast<int>(self.data) + (self.size * self.element_size)
52+
);
53+
54+
memory::memcpy(dest, elem, self.element_size);
55+
self.size = self.size + 1;
56+
},
57+
58+
59+
pop_back -> fn (out: *void) int {
60+
if (self.size == 0) return 0;
61+
62+
self.size = self.size - 1;
63+
64+
if (out != NULL) {
65+
let src: *void = cast<*void>(
66+
cast<int>(self.data) + (self.size * self.element_size)
67+
);
68+
memory::memcpy(out, src, self.element_size);
69+
}
70+
71+
return 1;
72+
},
73+
74+
remove_at -> fn (index: int) int {
75+
if (index < 0 || index >= self.size) return 0;
76+
77+
let src: *void = cast<*void>(
78+
cast<int>(self.data) + ((index + 1) * self.element_size)
79+
);
80+
81+
let dst: *void = cast<*void>(
82+
cast<int>(self.data) + (index * self.element_size)
83+
);
84+
85+
let bytes_to_move: int =
86+
(self.size - index - 1) * self.element_size;
87+
88+
memory::memcpy(dst, src, bytes_to_move);
89+
90+
self.size = self.size - 1;
91+
return 1;
92+
},
93+
94+
get -> fn (index: int) *void {
95+
if (index < 0 || index >= self.size) return NULL;
96+
return cast<*void>(
97+
cast<int>(self.data) + (index * self.element_size)
98+
);
99+
}
100+
};
101+
102+
#returns_ownership
103+
pub const create_vector_capacity -> fn (init_capacity: int, element_size: int) Vector {
104+
let v: Vector;
105+
v.data = cast<*void>(alloc(init_capacity * element_size));
106+
v.size = 0;
107+
v.capacity = init_capacity;
108+
v.element_size = element_size;
109+
return v;
110+
}
111+
112+
#returns_ownership
113+
pub const create_vector -> fn (element_size: int) Vector {
114+
return create_vector_capacity(DEFAULT_VECTOR_CAPACITY, element_size);
115+
}
116+
117+
#takes_ownership
118+
pub const free_vector -> fn (v: *Vector) void {
119+
free(v.data);
120+
v.data = NULL;
121+
v.capacity = 0;
122+
v.size = 0;
123+
v.element_size = 0;
124+
}

0 commit comments

Comments
 (0)