summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-31 01:15:25 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-31 01:15:25 +0000
commit856c9fe56b412779e045ef86a767b93d5c7f563b (patch)
tree6f851bb9bf300970c4a0d7186db0de86e510a18d /src
parent03a6a57f500ee4230ce2cee887866b3850ed7ed9 (diff)
Improvements for slice + better iteration for arrays
Diffstat (limited to 'src')
-rw-r--r--src/codegen/codegen.c88
-rw-r--r--src/codegen/codegen_utils.c25
-rw-r--r--src/parser/parser_stmt.c152
3 files changed, 243 insertions, 22 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index a66f179..7a67428 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -65,6 +65,52 @@ static void codegen_var_expr(ParserContext *ctx, ASTNode *node, FILE *out)
zwarn_at(node->token, "%s\n = help: %s", msg, help);
}
}
+
+ // Check for static method call pattern: Type::method or Slice<T>::method
+ char *double_colon = strstr(node->var_ref.name, "::");
+ if (double_colon)
+ {
+ // Extract type name and method name
+ int type_len = double_colon - node->var_ref.name;
+ char *type_name = xmalloc(type_len + 1);
+ strncpy(type_name, node->var_ref.name, type_len);
+ type_name[type_len] = 0;
+
+ char *method_name = double_colon + 2; // Skip ::
+
+ // Handle generic types: Slice<int> -> Slice_int
+ char mangled_type[256];
+ if (strchr(type_name, '<'))
+ {
+ // Generic type - need to mangle it
+ char *lt = strchr(type_name, '<');
+ char *gt = strchr(type_name, '>');
+
+ if (lt && gt)
+ {
+ // Extract base type and type argument
+ *lt = 0;
+ char *type_arg = lt + 1;
+ *gt = 0;
+
+ sprintf(mangled_type, "%s_%s", type_name, type_arg);
+ }
+ else
+ {
+ strcpy(mangled_type, type_name);
+ }
+ }
+ else
+ {
+ strcpy(mangled_type, type_name);
+ }
+
+ // Output as Type__method
+ fprintf(out, "%s__%s", mangled_type, method_name);
+ free(type_name);
+ return;
+ }
+
fprintf(out, "%s", node->var_ref.name);
}
@@ -348,6 +394,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
// Check for Static Enum Variant Call: Enum.Variant(...)
+
if (target->type == NODE_EXPR_VAR)
{
ASTNode *def = find_struct_def(ctx, target->var_ref.name);
@@ -418,11 +465,43 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
base += 7;
}
+ char *mangled_base = base;
+ char base_buf[256];
+
+ // Mangle generic types: Slice<int> -> Slice_int, Vec<Point> -> Vec_Point
+ char *lt = strchr(base, '<');
+ if (lt)
+ {
+ char *gt = strchr(lt, '>');
+ if (gt)
+ {
+ int prefix_len = lt - base;
+ int arg_len = gt - lt - 1;
+ snprintf(base_buf, 255, "%.*s_%.*s", prefix_len, base, arg_len, lt + 1);
+ mangled_base = base_buf;
+ }
+ }
+
if (!strchr(type, '*') && target->type == NODE_EXPR_CALL)
{
- fprintf(out, "({ %s _t = ", type);
+ char *type_mangled = type;
+ char type_buf[256];
+ char *t_lt = strchr(type, '<');
+ if (t_lt)
+ {
+ char *t_gt = strchr(t_lt, '>');
+ if (t_gt)
+ {
+ int p_len = t_lt - type;
+ int a_len = t_gt - t_lt - 1;
+ snprintf(type_buf, 255, "%.*s_%.*s", p_len, type, a_len, t_lt + 1);
+ type_mangled = type_buf;
+ }
+ }
+
+ fprintf(out, "({ %s _t = ", type_mangled);
codegen_expression(ctx, target, out);
- fprintf(out, "; %s__%s(&_t", base, method);
+ fprintf(out, "; %s__%s(&_t", mangled_base, method);
ASTNode *arg = node->call.args;
while (arg)
{
@@ -435,10 +514,11 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else
{
// Mixin Lookup Logic
- char *call_base = base;
+ char *call_base = mangled_base;
+
int need_cast = 0;
char mixin_func_name[128];
- sprintf(mixin_func_name, "%s__%s", base, method);
+ sprintf(mixin_func_name, "%s__%s", call_base, method);
char *resolved_method_suffix = NULL;
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index 0d03661..8d9cb28 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -64,13 +64,28 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name)
}
else if (generic && (!bracket || generic < bracket))
{
- // Strip generic part for C output
- int base_len = generic - type_str;
- fprintf(out, "%.*s %s", base_len, type_str, name);
+ char *gt = strchr(generic, '>');
+ if (gt)
+ {
+ int base_len = generic - type_str;
+ int arg_len = gt - generic - 1;
+
+ fprintf(out, "%.*s_%.*s %s", base_len, type_str, arg_len, generic + 1, name);
- if (bracket)
+ if (bracket)
+ {
+ fprintf(out, "%s", bracket);
+ }
+ }
+ else
{
- fprintf(out, "%s", bracket);
+ int base_len = generic - type_str;
+ fprintf(out, "%.*s %s", base_len, type_str, name);
+
+ if (bracket)
+ {
+ fprintf(out, "%s", bracket);
+ }
}
}
else if (bracket)
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index a471fe6..4c24de3 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -1133,6 +1133,7 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *obj_expr = start_expr;
char *iter_method = "iterator";
+ ASTNode *slice_decl = NULL; // Track if we need to add a slice declaration
// Check for reference iteration: for x in &vec
if (obj_expr->type == NODE_EXPR_UNARY && obj_expr->unary.op &&
@@ -1142,6 +1143,78 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
iter_method = "iter_ref";
}
+ // Check for array iteration: wrap with Slice<T>::from_array
+ if (obj_expr->type_info && obj_expr->type_info->kind == TYPE_ARRAY &&
+ obj_expr->type_info->array_size > 0)
+ {
+ // Create a var decl for the slice
+ slice_decl = ast_create(NODE_VAR_DECL);
+ slice_decl->var_decl.name = xstrdup("__zc_arr_slice");
+
+ // Build type string: Slice<elem_type>
+ char *elem_type_str = type_to_string(obj_expr->type_info->inner);
+ char slice_type[256];
+ sprintf(slice_type, "Slice<%s>", elem_type_str);
+ slice_decl->var_decl.type_str = xstrdup(slice_type);
+
+ ASTNode *from_array_call = ast_create(NODE_EXPR_CALL);
+ ASTNode *static_method = ast_create(NODE_EXPR_VAR);
+
+ // The function name for static methods is Type::method format
+ char func_name[512];
+ snprintf(func_name, 511, "%s::from_array", slice_type);
+ static_method->var_ref.name = xstrdup(func_name);
+
+ from_array_call->call.callee = static_method;
+
+ // Create arguments
+ ASTNode *arr_addr = ast_create(NODE_EXPR_UNARY);
+ arr_addr->unary.op = xstrdup("&");
+ arr_addr->unary.operand = obj_expr;
+
+ ASTNode *arr_cast = ast_create(NODE_EXPR_CAST);
+ char cast_type[256];
+ sprintf(cast_type, "%s*", elem_type_str);
+ arr_cast->cast.target_type = xstrdup(cast_type);
+ arr_cast->cast.expr = arr_addr;
+
+ ASTNode *size_arg = ast_create(NODE_EXPR_LITERAL);
+ size_arg->literal.type_kind = LITERAL_INT;
+ size_arg->literal.int_val = obj_expr->type_info->array_size;
+ char size_buf[32];
+ sprintf(size_buf, "%d", obj_expr->type_info->array_size);
+ size_arg->literal.string_val = xstrdup(size_buf);
+
+ arr_cast->next = size_arg;
+ from_array_call->call.args = arr_cast;
+ from_array_call->call.arg_count = 2;
+
+ slice_decl->var_decl.init_expr = from_array_call;
+
+ // Manually trigger generic instantiation for Slice<T>
+ // This ensures that Slice_int, Slice_float, etc. structures are generated
+ Token dummy_tok = {0};
+ instantiate_generic(ctx, "Slice", elem_type_str, elem_type_str, dummy_tok);
+
+ // Instantiate SliceIter and Option too for the loop logic
+ char iter_type[256];
+ sprintf(iter_type, "SliceIter<%s>", elem_type_str);
+ instantiate_generic(ctx, "SliceIter", elem_type_str, elem_type_str, dummy_tok);
+
+ char option_type[256];
+ sprintf(option_type, "Option<%s>", elem_type_str);
+ instantiate_generic(ctx, "Option", elem_type_str, elem_type_str, dummy_tok);
+
+ // Replace obj_expr with a reference to the slice variable
+ ASTNode *slice_ref = ast_create(NODE_EXPR_VAR);
+ slice_ref->var_ref.name = xstrdup("__zc_arr_slice");
+ slice_ref->resolved_type =
+ xstrdup(slice_type); // Explicitly set type for codegen
+ obj_expr = slice_ref;
+
+ free(elem_type_str);
+ }
+
// var __it = obj.iterator();
ASTNode *it_decl = ast_create(NODE_VAR_DECL);
it_decl->var_decl.name = xstrdup("__it");
@@ -1182,6 +1255,34 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
stmts_tail = node; \
}
+ char *iter_type_ptr = NULL;
+ char *option_type_ptr = NULL;
+
+ if (slice_decl)
+ {
+ char *slice_t = slice_decl->var_decl.type_str;
+ char *start = strchr(slice_t, '<');
+ if (start)
+ {
+ char *end = strrchr(slice_t, '>');
+ if (end)
+ {
+ int len = end - start - 1;
+ char *elem = xmalloc(len + 1);
+ strncpy(elem, start + 1, len);
+ elem[len] = 0;
+
+ iter_type_ptr = xmalloc(256);
+ sprintf(iter_type_ptr, "SliceIter<%s>", elem);
+
+ option_type_ptr = xmalloc(256);
+ sprintf(option_type_ptr, "Option<%s>", elem);
+
+ free(elem);
+ }
+ }
+ }
+
// var __opt = __it.next();
ASTNode *opt_decl = ast_create(NODE_VAR_DECL);
opt_decl->var_decl.name = xstrdup("__opt");
@@ -1192,6 +1293,10 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_next = ast_create(NODE_EXPR_MEMBER);
ASTNode *it_ref = ast_create(NODE_EXPR_VAR);
it_ref->var_ref.name = xstrdup("__it");
+ if (iter_type_ptr)
+ {
+ it_ref->resolved_type = xstrdup(iter_type_ptr);
+ }
memb_next->member.target = it_ref;
memb_next->member.field = xstrdup("next");
call_next->call.callee = memb_next;
@@ -1204,15 +1309,22 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_is_none = ast_create(NODE_EXPR_MEMBER);
ASTNode *opt_ref1 = ast_create(NODE_EXPR_VAR);
opt_ref1->var_ref.name = xstrdup("__opt");
+ if (option_type_ptr)
+ {
+ opt_ref1->resolved_type = xstrdup(option_type_ptr);
+ }
memb_is_none->member.target = opt_ref1;
memb_is_none->member.field = xstrdup("is_none");
call_is_none->call.callee = memb_is_none;
+ call_is_none->call.args = NULL;
+ call_is_none->call.arg_count = 0;
- ASTNode *break_stmt = ast_create(NODE_BREAK);
-
+ // if (__opt.is_none()) break;
ASTNode *if_break = ast_create(NODE_IF);
if_break->if_stmt.condition = call_is_none;
+ ASTNode *break_stmt = ast_create(NODE_BREAK);
if_break->if_stmt.then_body = break_stmt;
+ if_break->if_stmt.else_body = NULL;
APPEND_STMT(if_break);
// var <user_var> = __opt.unwrap();
@@ -1225,25 +1337,28 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_unwrap = ast_create(NODE_EXPR_MEMBER);
ASTNode *opt_ref2 = ast_create(NODE_EXPR_VAR);
opt_ref2->var_ref.name = xstrdup("__opt");
+ if (option_type_ptr)
+ {
+ opt_ref2->resolved_type = xstrdup(option_type_ptr);
+ }
memb_unwrap->member.target = opt_ref2;
memb_unwrap->member.field = xstrdup("unwrap");
call_unwrap->call.callee = memb_unwrap;
+ call_unwrap->call.args = NULL;
+ call_unwrap->call.arg_count = 0;
user_var_decl->var_decl.init_expr = call_unwrap;
APPEND_STMT(user_var_decl);
- // User Body
+ // User body statements
enter_scope(ctx);
add_symbol(ctx, var_name, NULL, NULL);
- ASTNode *user_body_node;
- if (lexer_peek(l).type == TOK_LBRACE)
- {
- user_body_node = parse_block(ctx, l);
- }
- else
+ // Body block
+ ASTNode *stmt = parse_statement(ctx, l);
+ ASTNode *user_body_node = stmt;
+ if (stmt && stmt->type != NODE_BLOCK)
{
- ASTNode *stmt = parse_statement(ctx, l);
ASTNode *blk = ast_create(NODE_BLOCK);
blk->block.statements = stmt;
user_body_node = blk;
@@ -1256,10 +1371,21 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
loop_body->block.statements = stmts_head;
while_loop->while_stmt.body = loop_body;
- // Wrap entire thing in a block to scope _it
+ // Wrap entire thing in a block to scope __it (and __zc_arr_slice if present)
ASTNode *outer_block = ast_create(NODE_BLOCK);
- it_decl->next = while_loop;
- outer_block->block.statements = it_decl;
+ if (slice_decl)
+ {
+ // Chain: slice_decl -> it_decl -> while_loop
+ slice_decl->next = it_decl;
+ it_decl->next = while_loop;
+ outer_block->block.statements = slice_decl;
+ }
+ else
+ {
+ // Chain: it_decl -> while_loop
+ it_decl->next = while_loop;
+ outer_block->block.statements = it_decl;
+ }
return outer_block;
}