Skip to content

Commit 7ea4045

Browse files
author
TheDevConnor
committed
Made it so that arrays are padded
1 parent a4e4e69 commit 7ea4045

10 files changed

Lines changed: 228 additions & 25 deletions

File tree

src/ast/ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ struct AstNode {
234234
struct {
235235
AstNode **elements; // Changed from Expr** to AstNode**
236236
size_t element_count;
237+
size_t target_size;
237238
} array;
238239

239240
// Deref expression

src/ast/ast_definistions/expr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ AstNode *create_array_expr(ArenaAllocator *arena, AstNode **elements,
131131
AstNode *node = create_expr(arena, AST_EXPR_ARRAY, line, column);
132132
node->expr.array.elements = elements;
133133
node->expr.array.element_count = element_count;
134+
node->expr.array.target_size = 0; // Default to 0 (no explicit size)
134135
return node;
135136
}
136137

src/helper/run.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,13 @@ bool link_object_files(const char *output_dir, const char *executable_name, int
128128
char command[2048];
129129

130130
// Build the linking command with PIE-compatible flags
131-
snprintf(command, sizeof(command), "cc -O%d -pie %s/*.o -o %s",
132-
opt_level, output_dir, executable_name);
131+
if (opt_level > 0) { // If optimization level is specified
132+
snprintf(command, sizeof(command), "cc -O%d -pie %s/*.o -o %s",
133+
opt_level, output_dir, executable_name);
134+
} else { // No optimization
135+
snprintf(command, sizeof(command), "cc -pie %s/*.o -o %s",
136+
output_dir, executable_name);
137+
}
133138

134139
int result = system(command);
135140
if (result != 0) {

src/llvm/expr.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,7 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
874874

875875
AstNode **elements = node->expr.array.elements;
876876
size_t element_count = node->expr.array.element_count;
877+
size_t target_size = node->expr.array.target_size; // NEW: Get target size for padding
877878

878879
if (element_count == 0) {
879880
fprintf(stderr, "Error: Empty array literals not supported\n");
@@ -888,16 +889,21 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
888889
}
889890

890891
LLVMTypeRef element_type = LLVMTypeOf(first_element);
891-
LLVMTypeRef array_type = LLVMArrayType(element_type, element_count);
892+
893+
// NEW: Use target_size if set (for padding), otherwise use actual element_count
894+
size_t actual_array_size = (target_size > 0) ? target_size : element_count;
895+
LLVMTypeRef array_type = LLVMArrayType(element_type, actual_array_size);
892896

893897
// Check if all elements are constants
894898
bool all_constants = LLVMIsConstant(first_element);
899+
900+
// NEW: Allocate for the FULL size (including padding)
895901
LLVMValueRef *element_values = (LLVMValueRef *)arena_alloc(
896-
ctx->arena, sizeof(LLVMValueRef) * element_count, alignof(LLVMValueRef));
902+
ctx->arena, sizeof(LLVMValueRef) * actual_array_size, alignof(LLVMValueRef));
897903

898904
element_values[0] = first_element;
899905

900-
// Generate remaining elements and check for constants
906+
// Generate provided elements
901907
for (size_t i = 1; i < element_count; i++) {
902908
element_values[i] = codegen_expr(ctx, elements[i]);
903909
if (!element_values[i]) {
@@ -922,9 +928,21 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
922928
}
923929
}
924930

925-
// *** ADD THE NEW CODE HERE ***
931+
// NEW: Pad remaining elements with zeros if target_size > element_count
932+
if (target_size > element_count) {
933+
LLVMValueRef zero_value = LLVMConstNull(element_type);
934+
935+
for (size_t i = element_count; i < target_size; i++) {
936+
element_values[i] = zero_value;
937+
}
938+
939+
// If we're padding, we can't be all constants unless zeros count
940+
// (which they do, so keep checking)
941+
// zero_value is always constant, so all_constants remains unchanged
942+
}
943+
926944
// Check if any element references a global from another module
927-
for (size_t i = 0; i < element_count && all_constants; i++) {
945+
for (size_t i = 0; i < actual_array_size && all_constants; i++) {
928946
if (LLVMIsConstant(element_values[i]) &&
929947
LLVMIsAGlobalVariable(element_values[i])) {
930948
// Check if it's from a different module
@@ -937,17 +955,16 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
937955
}
938956
}
939957
}
940-
// *** END NEW CODE ***
941958

942959
if (all_constants) {
943-
// Create constant array
944-
return LLVMConstArray(element_type, element_values, element_count);
960+
// Create constant array (now with padding)
961+
return LLVMConstArray(element_type, element_values, actual_array_size);
945962
} else {
946-
// Create runtime array
963+
// Create runtime array (now with padding)
947964
LLVMValueRef array_alloca =
948965
LLVMBuildAlloca(ctx->builder, array_type, "array_literal");
949966

950-
for (size_t i = 0; i < element_count; i++) {
967+
for (size_t i = 0; i < actual_array_size; i++) {
951968
// Create GEP to element
952969
LLVMValueRef indices[2];
953970
indices[0] = LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false);

src/typechecker/expr.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,57 @@ AstNode *typecheck_call_expr(AstNode *expr, Scope *scope,
457457
}
458458

459459
TypeMatchResult match = types_match(param_types[i], arg_type);
460+
461+
// NEW: Special handling for array argument padding
462+
// If the parameter expects a larger array than provided, allow it with padding
463+
if (match == TYPE_MATCH_NONE &&
464+
param_types[i]->type == AST_TYPE_ARRAY &&
465+
arg_type->type == AST_TYPE_ARRAY) {
466+
467+
// Check if element types match
468+
TypeMatchResult element_match =
469+
types_match(param_types[i]->type_data.array.element_type,
470+
arg_type->type_data.array.element_type);
471+
472+
if (element_match != TYPE_MATCH_NONE) {
473+
// Element types match, check sizes
474+
AstNode *param_size = param_types[i]->type_data.array.size;
475+
AstNode *arg_size = arg_type->type_data.array.size;
476+
477+
if (param_size && arg_size &&
478+
param_size->type == AST_EXPR_LITERAL &&
479+
arg_size->type == AST_EXPR_LITERAL &&
480+
param_size->expr.literal.lit_type == LITERAL_INT &&
481+
arg_size->expr.literal.lit_type == LITERAL_INT) {
482+
483+
long long param_size_val = param_size->expr.literal.value.int_val;
484+
long long arg_size_val = arg_size->expr.literal.value.int_val;
485+
486+
// If argument array is smaller than parameter, allow it with padding
487+
if (arg_size_val <= param_size_val) {
488+
// Set a flag on the argument node to indicate it needs padding
489+
// This will be handled by the code generator
490+
if (arguments[i]->type == AST_EXPR_ARRAY) {
491+
// Mark this array for padding to param_size_val elements
492+
// Store the target size for the code generator to use
493+
arguments[i]->expr.array.target_size = (size_t)param_size_val;
494+
}
495+
496+
// Continue to next argument - this is valid
497+
continue;
498+
} else {
499+
// Argument array is LARGER than parameter - this is an error
500+
tc_error_help(
501+
expr, "Array Size Mismatch",
502+
"Cannot pass larger array to function expecting smaller array",
503+
"Argument %zu: parameter expects array of size %lld, got size %lld",
504+
i + 1, param_size_val, arg_size_val);
505+
return NULL;
506+
}
507+
}
508+
}
509+
}
510+
460511
if (match == TYPE_MATCH_NONE) {
461512
const char *param_str = type_to_string(param_types[i], arena);
462513
const char *arg_str = type_to_string(arg_type, arena);
@@ -1301,7 +1352,12 @@ AstNode *typecheck_array_expr(AstNode *expr, Scope *scope,
13011352
}
13021353
}
13031354

1304-
// Create array size literal
1355+
// NEW: Check if this array is being used in a context with an expected size
1356+
// This happens during function call argument checking
1357+
// We'll set a flag on the array expression to indicate it should be padded
1358+
1359+
// For now, just create the array type with the actual element count
1360+
// The padding will be handled during code generation or in a separate pass
13051361
long long size_val = (long long)element_count;
13061362
AstNode *size_expr = create_literal_expr(arena, LITERAL_INT, &size_val,
13071363
expr->line, expr->column);

std/string.lx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
@module "string"
22

3+
pub const cat -> fn (dest: *char, s1: *char, s2: *char) *char;
4+
pub const strlen -> fn (s: *char) int;
5+
36
#returns_ownership
47
pub const from_char -> fn (c: char) *char {
58
let s: *char = cast<*char>(alloc(2 * sizeof<char>));
@@ -45,6 +48,34 @@ pub const from_int -> fn (n: int) *char {
4548
return s;
4649
}
4750

51+
#returns_ownership
52+
pub const from_float -> fn (f: float, precision: int) *char {
53+
let int_part: int = cast<int>(f);
54+
let frac_part: float = f - cast<float>(int_part);
55+
56+
let int_str: *char = from_int(int_part);
57+
defer { free(int_str); }
58+
59+
let frac_str: *char = cast<*char>(alloc((precision + 2) * sizeof<char>)); // +1 for '.' +1 for null
60+
frac_str[0] = '.';
61+
62+
loop [i: int = 1](i <= precision) : (++i) {
63+
frac_part = frac_part * 10.0;
64+
let digit: int = cast<int>(frac_part);
65+
frac_str[i] = cast<char>(digit + cast<int>('0'));
66+
frac_part = frac_part - cast<float>(digit);
67+
}
68+
69+
frac_str[precision + 1] = cast<char>(0); // null terminator
70+
71+
let result_len: int = strlen(int_str) + strlen(frac_str) + 1;
72+
let result: *char = cast<*char>(alloc(result_len * sizeof<char>));
73+
74+
cat(result, int_str, frac_str);
75+
76+
return result;
77+
}
78+
4879
pub const int_to_str -> fn (num: int, buf: *char, buf_size: int) void {
4980
let idx: int = 0;
5081
let temp: int = num;

std/sys.lx

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
@module "sys"
2020

21+
@use "string" as string
22+
2123
// TODO: Allow enums to have a custom assigned value
2224
// Syscall numbers (Linux x86_64)
2325
pub const SYS_READ: int = 0;
@@ -296,8 +298,88 @@ pub const write_str -> fn (fd: int, s: *char) int {
296298
}
297299

298300
// Print to stdout
299-
pub const print -> fn (s: *char) int {
300-
return write_str(STDOUT, s);
301+
// This takes in a msg and an array of args to format into the msg
302+
pub const print_int -> fn (s: *char, args: [int; 256]) int {
303+
// Simple implementation: only supports %d for integers
304+
let buffer: *char = cast<*char>(alloc(1024 * sizeof<char>));
305+
let buf_index: int = 0;
306+
let arg_index: int = 0;
307+
defer { free(buffer); }
308+
309+
let i: int = 0;
310+
loop (s[i] != cast<char>(0)) : (++i) {
311+
if (s[i] == '%' && s[i + 1] == 'd' && arg_index < 256) {
312+
let num_str: *char = string::from_int(args[arg_index]);
313+
defer { free(num_str); }
314+
315+
loop [j: int = 0](num_str[j] != cast<char>(0)) : (++j) {
316+
buffer[buf_index] = num_str[j];
317+
buf_index = buf_index + 1;
318+
}
319+
arg_index = arg_index + 1;
320+
i = i + 1; // Skip 'd'
321+
} else {
322+
buffer[buf_index] = s[i];
323+
buf_index = buf_index + 1;
324+
}
325+
}
326+
buffer[buf_index] = cast<char>(0); // Null-terminate
327+
328+
let written: int = write_str(STDOUT, buffer);
329+
return written;
330+
}
331+
332+
pub const print_str -> fn (s: *char, args: [*char; 256]) int {
333+
// Simple implementation: only supports %s for strings
334+
let buffer: *char = cast<*char>(alloc(1024 * sizeof<char>));
335+
let buf_index: int = 0;
336+
let arg_index: int = 0;
337+
defer { free(buffer); }
338+
339+
let i: int = 0;
340+
loop (s[i] != cast<char>(0)) : (++i) {
341+
if (s[i] == '%' && s[i + 1] == 's' && arg_index < 256) {
342+
let str_arg: *char = args[arg_index];
343+
loop [j: int = 0](str_arg[j] != cast<char>(0)) : (++j) {
344+
buffer[buf_index] = str_arg[j];
345+
buf_index = buf_index + 1;
346+
}
347+
arg_index = arg_index + 1;
348+
i = i + 1; // Skip 's'
349+
} else {
350+
buffer[buf_index] = s[i];
351+
buf_index = buf_index + 1;
352+
}
353+
}
354+
buffer[buf_index] = cast<char>(0); // Null-terminate
355+
356+
let written: int = write_str(STDOUT, buffer);
357+
return written;
358+
}
359+
360+
pub const print_char -> fn (s: *char, args: [char; 256]) int {
361+
// Simple implementation: only supports %c for characters
362+
let buffer: *char = cast<*char>(alloc(1024 * sizeof<char>));
363+
let buf_index: int = 0;
364+
let arg_index: int = 0;
365+
defer { free(buffer); }
366+
367+
let i: int = 0;
368+
loop (s[i] != cast<char>(0)) : (++i) {
369+
if (s[i] == '%' && s[i + 1] == 'c' && arg_index < 256) {
370+
buffer[buf_index] = args[arg_index];
371+
buf_index = buf_index + 1;
372+
arg_index = arg_index + 1;
373+
i = i + 1; // Skip 'c'
374+
} else {
375+
buffer[buf_index] = s[i];
376+
buf_index = buf_index + 1;
377+
}
378+
}
379+
buffer[buf_index] = cast<char>(0); // Null-terminate
380+
381+
let written: int = write_str(STDOUT, buffer);
382+
return written;
301383
}
302384

303385
// Print to stderr

std/termfx.lx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ pub const INVERT: *char = "\x1b[7m"; // swap fg/bg
4848
pub const HIDDEN: *char = "\x1b[8m"; // invisible text
4949
pub const STRIKETHROUGH: *char = "\x1b[9m";
5050

51-
pub const CLEAR_SCREEN: *char = "\x1b[2J";
52-
pub const CLEAR_LINE: *char = "\x1b[2K";
53-
pub const CURSOR_HOME: *char = "\x1b[H";
54-
pub const CURSOR_HIDE: *char = "\x1b[?25l";
55-
pub const CURSOR_SHOW: *char = "\x1b[?25h";
51+
pub const CLEAR_SCREEN: *char = "\x1b[2J";
52+
pub const CLEAR_LINE: *char = "\x1b[2K";
53+
pub const CURSOR_HOME: *char = "\x1b[H";
54+
pub const CURSOR_HIDE: *char = "\x1b[?25l";
55+
pub const CURSOR_SHOW: *char = "\x1b[?25h";
5656

5757
pub const SAVE_CURSOR: *char = "\x1b[s";
5858
pub const RESTORE_CURSOR: *char = "\x1b[u";

tests/chess_engine/board.lx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ pub const Board -> struct {
1515
length_fen: int,
1616
squares: *char,
1717

18-
white_can_castle_kingside: int,
18+
white_can_castle_kingside: int,
1919
white_can_castle_queenside: int,
20-
black_can_castle_kingside: int,
20+
black_can_castle_kingside: int,
2121
black_can_castle_queenside: int,
2222
};
2323

tests/test.lx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
@module "main"
22

3-
const Point -> struct { x: int, y: int };
3+
@use "sys" as sys
4+
5+
pub const Point -> struct {
6+
vertex: *char,
7+
x: int,
8+
y: int
9+
};
410

511
pub const main -> fn () int {
6-
let y: Point = Point { x: 50, y: 10 };
7-
output(y.x, " ", y.y, "\n");
12+
let y: Point = Point { vertex: "A" ,x: 50, y: 10 };
13+
14+
sys::print_int("Point coordinates: (%d, %d)\n", [y.x, y.y]);
15+
sys::print_str("Point vertex: %s\n", [y.vertex]);
16+
sys::print_char("Point vertex first char: %c\n", [y.vertex[0]]);
17+
818
return 0;
919
}

0 commit comments

Comments
 (0)