summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-22 22:40:43 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-22 22:40:43 +0000
commited4bbfd8cf4a72fdf4a5d6cba94d537cab340356 (patch)
tree80f520cb36f25a210537b477007b0ac5a24e4b8e /src
parent3d1840e8690bef6e58a208d9ca33857a59a2e852 (diff)
Removing some duplicates and dissecting codegen/parser.
Diffstat (limited to 'src')
-rw-r--r--src/codegen/codegen.c1671
-rw-r--r--src/codegen/codegen.h3
-rw-r--r--src/codegen/codegen_decl.c90
-rw-r--r--src/codegen/codegen_main.c16
-rw-r--r--src/codegen/codegen_stmt.c1671
-rw-r--r--src/codegen/codegen_utils.c20
-rw-r--r--src/constants.h46
-rw-r--r--src/parser/parser_decl.c802
-rw-r--r--src/parser/parser_stmt.c1721
-rw-r--r--src/parser/parser_struct.c943
10 files changed, 3532 insertions, 3451 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index a43c902..3a93f91 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -1,6 +1,7 @@
#include "codegen.h"
#include "zprep.h"
+#include "../constants.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -10,534 +11,6 @@
#include "ast.h"
#include "zprep_plugin.h"
-// Helper: emit a single pattern condition (either a value, or a range)
-static void emit_single_pattern_cond(const char *pat, int id, int is_ptr, FILE *out)
-{
- // Check for range pattern: "start..end" or "start..=end"
- char *range_incl = strstr(pat, "..=");
- char *range_excl = strstr(pat, "..");
-
- if (range_incl)
- {
- // Inclusive range: start..=end -> _m_id >= start && _m_id <= end
- int start_len = (int)(range_incl - pat);
- char *start = xmalloc(start_len + 1);
- strncpy(start, pat, start_len);
- start[start_len] = 0;
- char *end = xstrdup(range_incl + 3);
- if (is_ptr)
- {
- fprintf(out, "(*_m_%d >= %s && *_m_%d <= %s)", id, start, id, end);
- }
- else
- {
- fprintf(out, "(_m_%d >= %s && _m_%d <= %s)", id, start, id, end);
- }
- free(start);
- free(end);
- }
- else if (range_excl)
- {
- // Exclusive range: start..end -> _m_id >= start && _m_id < end
- int start_len = (int)(range_excl - pat);
- char *start = xmalloc(start_len + 1);
- strncpy(start, pat, start_len);
- start[start_len] = 0;
- char *end = xstrdup(range_excl + 2);
- if (is_ptr)
- {
- fprintf(out, "(*_m_%d >= %s && *_m_%d < %s)", id, start, id, end);
- }
- else
- {
- fprintf(out, "(_m_%d >= %s && _m_%d < %s)", id, start, id, end);
- }
- free(start);
- free(end);
- }
- else if (pat[0] == '"')
- {
- // String pattern - string comparison, _m is char* or similar
- if (is_ptr)
- {
- fprintf(out, "strcmp(*_m_%d, %s) == 0", id, pat);
- }
- else
- {
- fprintf(out, "strcmp(_m_%d, %s) == 0", id, pat);
- }
- }
- else if (pat[0] == '\'')
- {
- // Char literal pattern
- if (is_ptr)
- {
- fprintf(out, "*_m_%d == %s", id, pat);
- }
- else
- {
- fprintf(out, "_m_%d == %s", id, pat);
- }
- }
- else
- {
- // Numeric or simple pattern
- if (is_ptr)
- {
- fprintf(out, "*_m_%d == %s", id, pat);
- }
- else
- {
- fprintf(out, "_m_%d == %s", id, pat);
- }
- }
-}
-
-// Helper: emit condition for a pattern (may contain OR patterns with '|')
-static void emit_pattern_condition(ParserContext *ctx, const char *pattern, int id, int is_ptr,
- FILE *out)
-{
- // Check if pattern contains '|' for OR patterns
- if (strchr(pattern, '|'))
- {
- // Split by '|' and emit OR conditions
- char *pattern_copy = xstrdup(pattern);
- char *saveptr;
- char *part = strtok_r(pattern_copy, "|", &saveptr);
- int first = 1;
- fprintf(out, "(");
- while (part)
- {
- if (!first)
- {
- fprintf(out, " || ");
- }
-
- // Check if part is an enum variant
- EnumVariantReg *reg = find_enum_variant(ctx, part);
- if (reg)
- {
- if (is_ptr)
- {
- fprintf(out, "_m_%d->tag == %d", id, reg->tag_id);
- }
- else
- {
- fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
- }
- }
- else
- {
- emit_single_pattern_cond(part, id, is_ptr, out);
- }
- first = 0;
- part = strtok_r(NULL, "|", &saveptr);
- }
- fprintf(out, ")");
- free(pattern_copy);
- }
- else
- {
- // Single pattern (may be a range)
- EnumVariantReg *reg = find_enum_variant(ctx, pattern);
- if (reg)
- {
- if (is_ptr)
- {
- fprintf(out, "_m_%d->tag == %d", id, reg->tag_id);
- }
- else
- {
- fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
- }
- }
- else
- {
- emit_single_pattern_cond(pattern, id, is_ptr, out);
- }
- }
-}
-
-// static function for internal use.
-static char *g_current_func_ret_type = NULL;
-static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result)
-{
- int id = tmp_counter++;
- int is_self = (node->match_stmt.expr->type == NODE_EXPR_VAR &&
- strcmp(node->match_stmt.expr->var_ref.name, "self") == 0);
-
- char *ret_type = infer_type(ctx, node);
- int is_expr = (use_result && ret_type && strcmp(ret_type, "void") != 0);
-
- fprintf(out, "({ ");
-
- // Check if any case uses ref binding - only take address if needed
- int has_ref_binding = 0;
- ASTNode *ref_check = node->match_stmt.cases;
- while (ref_check)
- {
- if (ref_check->match_case.is_ref)
- {
- has_ref_binding = 1;
- break;
- }
- ref_check = ref_check->next;
- }
-
- int is_lvalue_opt = (node->match_stmt.expr->type == NODE_EXPR_VAR ||
- node->match_stmt.expr->type == NODE_EXPR_MEMBER ||
- node->match_stmt.expr->type == NODE_EXPR_INDEX);
-
- if (is_self)
- {
- fprintf(out, "ZC_AUTO _m_%d = ", id);
- codegen_expression(ctx, node->match_stmt.expr, out);
- fprintf(out, "; ");
- }
- else if (has_ref_binding && is_lvalue_opt)
- {
- // Take address for ref bindings
- fprintf(out, "ZC_AUTO _m_%d = &", id);
- codegen_expression(ctx, node->match_stmt.expr, out);
- fprintf(out, "; ");
- }
- else if (has_ref_binding)
- {
- // Non-lvalue with ref binding: create temporary
- emit_auto_type(ctx, node->match_stmt.expr, node->token, out);
- fprintf(out, " _temp_%d = ", id);
- codegen_expression(ctx, node->match_stmt.expr, out);
- fprintf(out, "; ZC_AUTO _m_%d = &_temp_%d; ", id, id);
- }
- else
- {
- // No ref bindings: store value directly (not pointer)
- fprintf(out, "ZC_AUTO _m_%d = ", id);
- codegen_expression(ctx, node->match_stmt.expr, out);
- fprintf(out, "; ");
- }
-
- if (is_expr)
- {
- fprintf(out, "%s _r_%d; ", ret_type, id);
- }
-
- char *expr_type = infer_type(ctx, node->match_stmt.expr);
- int is_option = (expr_type && strncmp(expr_type, "Option_", 7) == 0);
- int is_result = (expr_type && strncmp(expr_type, "Result_", 7) == 0);
-
- char *enum_name = NULL;
- ASTNode *chk = node->match_stmt.cases;
- int has_wildcard = 0;
- while (chk)
- {
- if (strcmp(chk->match_case.pattern, "_") == 0)
- {
- has_wildcard = 1;
- }
- else if (!enum_name)
- {
- EnumVariantReg *reg = find_enum_variant(ctx, chk->match_case.pattern);
- if (reg)
- {
- enum_name = reg->enum_name;
- }
- }
- chk = chk->next;
- }
-
- if (enum_name && !has_wildcard)
- {
- // Iterate through all registered variants for this enum
- EnumVariantReg *v = ctx->enum_variants;
- while (v)
- {
- if (strcmp(v->enum_name, enum_name) == 0)
- {
- int covered = 0;
- ASTNode *c2 = node->match_stmt.cases;
- while (c2)
- {
- if (strcmp(c2->match_case.pattern, v->variant_name) == 0)
- {
- covered = 1;
- break;
- }
- c2 = c2->next;
- }
- if (!covered)
- {
- zwarn_at(node->token, "Non-exhaustive match: Missing variant '%s'",
- v->variant_name);
- }
- }
- v = v->next;
- }
- }
-
- ASTNode *c = node->match_stmt.cases;
- int first = 1;
- while (c)
- {
- if (!first)
- {
- fprintf(out, " else ");
- }
- fprintf(out, "if (");
- if (strcmp(c->match_case.pattern, "_") == 0)
- {
- fprintf(out, "1");
- }
- else if (is_option)
- {
- if (strcmp(c->match_case.pattern, "Some") == 0)
- {
- fprintf(out, "_m_%d->is_some", id);
- }
- else if (strcmp(c->match_case.pattern, "None") == 0)
- {
- fprintf(out, "!_m_%d->is_some", id);
- }
- else
- {
- fprintf(out, "1");
- }
- }
- else if (is_result)
- {
- if (strcmp(c->match_case.pattern, "Ok") == 0)
- {
- fprintf(out, "_m_%d->is_ok", id);
- }
- else if (strcmp(c->match_case.pattern, "Err") == 0)
- {
- fprintf(out, "!_m_%d->is_ok", id);
- }
- else
- {
- fprintf(out, "1");
- }
- }
- else
- {
- // Use helper for OR patterns, range patterns, and simple patterns
- emit_pattern_condition(ctx, c->match_case.pattern, id, has_ref_binding, out);
- }
- fprintf(out, ") { ");
- if (c->match_case.binding_name)
- {
- if (is_option)
- {
- if (strstr(g_config.cc, "tcc"))
- {
- if (c->match_case.is_ref)
- {
- fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
- c->match_case.binding_name, id);
- }
- }
- else
- {
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, id);
- }
- else if (has_ref_binding)
- {
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, id);
- }
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id);
- }
- }
- }
- else if (is_result) // FIX: Changed 'if' to 'else if' to match original logic structure
- // if needed, but original code had implicit fallthrough checks? No,
- // checks match pattern.
- {
- if (strcmp(c->match_case.pattern, "Ok") == 0)
- {
- if (strstr(g_config.cc, "tcc"))
- {
- if (c->match_case.is_ref)
- {
- fprintf(out, "__typeof__(&_m_%d->val) %s = &_m_%d->val; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__typeof__(_m_%d->val) %s = _m_%d->val; ", id,
- c->match_case.binding_name, id);
- }
- }
- else
- {
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name,
- id);
- }
- else if (has_ref_binding)
- {
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name,
- id);
- }
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name,
- id);
- }
- }
- }
- else
- {
- if (strstr(g_config.cc, "tcc"))
- {
- if (c->match_case.is_ref)
- {
- fprintf(out, "__typeof__(&_m_%d->err) %s = &_m_%d->err; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__typeof__(_m_%d->err) %s = _m_%d->err; ", id,
- c->match_case.binding_name, id);
- }
- }
- else
- {
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->err; ", c->match_case.binding_name,
- id);
- }
- else if (has_ref_binding)
- {
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->err; ", c->match_case.binding_name,
- id);
- }
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name,
- id);
- }
- }
- }
- }
- else
- {
- char *f = strrchr(c->match_case.pattern, '_');
- if (f)
- {
- f++;
- }
- else
- {
- f = c->match_case.pattern;
- }
- // Generic struct destructuring (for example, MyStruct_Variant)
- // Assuming data union or accessible field.
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", c->match_case.binding_name, id,
- f);
- }
- else if (has_ref_binding)
- {
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", c->match_case.binding_name, id,
- f);
- }
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f);
- }
- }
- }
-
- // Check if body is a string literal (should auto-print).
- ASTNode *body = c->match_case.body;
- int is_string_literal = (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2);
-
- if (is_expr)
- {
- fprintf(out, "_r_%d = ", id);
- if (is_string_literal)
- {
- codegen_node_single(ctx, body, out);
- }
- else
- {
- if (body->type == NODE_BLOCK)
- {
- int saved = defer_count;
- fprintf(out, "({ ");
- ASTNode *stmt = body->block.statements;
- while (stmt)
- {
- codegen_node_single(ctx, stmt, out);
- stmt = stmt->next;
- }
- for (int i = defer_count - 1; i >= saved; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- defer_count = saved;
- fprintf(out, " })");
- }
- else
- {
- codegen_node_single(ctx, body, out);
- }
- }
- fprintf(out, ";");
- }
- else
- {
- if (is_string_literal)
- {
- fprintf(out, "({ printf(\"%%s\", ");
- codegen_expression(ctx, body, out);
- fprintf(out, "); printf(\"\\n\"); 0; })");
- }
- else
- {
- codegen_node_single(ctx, body, out);
- }
- }
-
- fprintf(out, " }");
- first = 0;
- c = c->next;
- }
-
- if (is_expr)
- {
- fprintf(out, " _r_%d; })", id);
- }
- else
- {
- fprintf(out, " })");
- }
-}
-
// Emit literal expression (int, float, string, char)
static void codegen_literal_expr(ASTNode *node, FILE *out)
{
@@ -711,15 +184,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
}
- int is_basic = 0;
- if (t1)
- {
- is_basic = (strcmp(t1, "int") == 0 || strcmp(t1, "bool") == 0 ||
- strcmp(t1, "char") == 0 || strcmp(t1, "void") == 0 ||
- strcmp(t1, "float") == 0 || strcmp(t1, "double") == 0 ||
- strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 ||
- strcmp(t1, "ssize_t") == 0 || strcmp(t1, "__auto_type") == 0);
- }
+ int is_basic = IS_BASIC_TYPE(t1);
ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL;
if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic &&
@@ -1662,1135 +1127,3 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
break;
}
}
-
-void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- if (!node)
- {
- return;
- }
- switch (node->type)
- {
- case NODE_MATCH:
- codegen_match_internal(ctx, node, out, 0); // 0 = statement context
- fprintf(out, ";\n");
- break;
- case NODE_FUNCTION:
- if (!node->func.body)
- {
- break;
- }
-
- if (node->func.is_async)
- {
- fprintf(out, "struct %s_Args {\n", node->func.name);
- char *args_copy = xstrdup(node->func.args);
- char *token = strtok(args_copy, ",");
- int arg_count = 0;
- char **arg_names = xmalloc(32 * sizeof(char *));
-
- while (token)
- {
- while (*token == ' ')
- {
- token++; // trim leading
- }
- char *last_space = strrchr(token, ' ');
- if (last_space)
- {
- *last_space = 0;
- char *type = token;
- char *name = last_space + 1;
- fprintf(out, "%s %s;\n", type, name);
-
- arg_names[arg_count++] = xstrdup(name);
- }
- token = strtok(NULL, ",");
- }
- free(args_copy);
- fprintf(out, "};\n");
-
- fprintf(out, "void* _runner_%s(void* _args)\n", node->func.name);
- fprintf(out, "{\n");
- fprintf(out, " struct %s_Args* args = (struct %s_Args*)_args;\n", node->func.name,
- node->func.name);
-
- // Determine mechanism: struct/large-type? -> malloc; primitive -> cast
- int returns_struct = 0;
- char *rt = node->func.ret_type;
- if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
- {
- if (strstr(rt, "*") == NULL && strcmp(rt, "string") != 0 &&
- strcmp(rt, "int") != 0 && strcmp(rt, "bool") != 0 && strcmp(rt, "char") != 0 &&
- strcmp(rt, "float") != 0 && strcmp(rt, "double") != 0 &&
- strcmp(rt, "long") != 0 && strcmp(rt, "usize") != 0 &&
- strcmp(rt, "isize") != 0 && strncmp(rt, "uint", 4) != 0 &&
- strncmp(rt, "int", 3) != 0)
- {
- returns_struct = 1;
- }
- }
-
- // Call Impl
- if (returns_struct)
- {
- fprintf(out, " %s *res_ptr = malloc(sizeof(%s));\n", rt, rt);
- fprintf(out, " *res_ptr = ");
- }
- else if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
- {
- fprintf(out, " %s res = ", rt);
- }
- else
- {
- fprintf(out, " ");
- }
-
- fprintf(out, "_impl_%s(", node->func.name);
- for (int i = 0; i < arg_count; i++)
- {
- fprintf(out, "%sargs->%s", i > 0 ? ", " : "", arg_names[i]);
- }
- fprintf(out, ");\n");
- fprintf(out, " free(args);\n");
-
- if (returns_struct)
- {
- fprintf(out, " return (void*)res_ptr;\n");
- }
- else if (strcmp(rt, "void") != 0)
- {
- fprintf(out, " return (void*)(long)res;\n");
- }
- else
- {
- fprintf(out, " return NULL;\n");
- }
- fprintf(out, "}\n");
-
- fprintf(out, "%s _impl_%s(%s)\n", node->func.ret_type, node->func.name,
- node->func.args);
- fprintf(out, "{\n");
- defer_count = 0;
- codegen_walker(ctx, node->func.body, out);
- for (int i = defer_count - 1; i >= 0; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- fprintf(out, "}\n");
-
- // 4. Define Public Wrapper (Spawns Thread)
- fprintf(out, "Async %s(%s)\n", node->func.name, node->func.args);
- fprintf(out, "{\n");
- fprintf(out, " struct %s_Args* args = malloc(sizeof(struct %s_Args));\n",
- node->func.name, node->func.name);
- for (int i = 0; i < arg_count; i++)
- {
- fprintf(out, " args->%s = %s;\n", arg_names[i], arg_names[i]);
- }
-
- fprintf(out, " pthread_t th;\n");
- fprintf(out, " pthread_create(&th, NULL, _runner_%s, args);\n", node->func.name);
- fprintf(out, " return (Async){.thread=th, .result=NULL};\n");
- fprintf(out, "}\n");
-
- break;
- }
-
- defer_count = 0;
- fprintf(out, "\n");
-
- // Emit GCC attributes before function
- {
- int has_attrs = node->func.constructor || node->func.destructor ||
- node->func.noinline || node->func.unused || node->func.weak ||
- node->func.cold || node->func.hot || node->func.noreturn ||
- node->func.pure || node->func.section;
- if (has_attrs)
- {
- fprintf(out, "__attribute__((");
- int first = 1;
-#define EMIT_ATTR(cond, name) \
- if (cond) \
- { \
- if (!first) \
- fprintf(out, ", "); \
- fprintf(out, name); \
- first = 0; \
- }
- EMIT_ATTR(node->func.constructor, "constructor");
- EMIT_ATTR(node->func.destructor, "destructor");
- EMIT_ATTR(node->func.noinline, "noinline");
- EMIT_ATTR(node->func.unused, "unused");
- EMIT_ATTR(node->func.weak, "weak");
- EMIT_ATTR(node->func.cold, "cold");
- EMIT_ATTR(node->func.hot, "hot");
- EMIT_ATTR(node->func.noreturn, "noreturn");
- EMIT_ATTR(node->func.pure, "pure");
- if (node->func.section)
- {
- if (!first)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "section(\"%s\")", node->func.section);
- }
-#undef EMIT_ATTR
- fprintf(out, ")) ");
- }
- }
-
- if (node->func.is_inline)
- {
- fprintf(out, "inline ");
- }
- emit_func_signature(out, node, NULL);
- fprintf(out, "\n");
- fprintf(out, "{\n");
- char *prev_ret = g_current_func_ret_type;
- g_current_func_ret_type = node->func.ret_type;
- codegen_walker(ctx, node->func.body, out);
- for (int i = defer_count - 1; i >= 0; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- g_current_func_ret_type = prev_ret;
- fprintf(out, "}\n");
- break;
-
- case NODE_ASSERT:
- fprintf(out, "assert(");
- codegen_expression(ctx, node->assert_stmt.condition, out);
- if (node->assert_stmt.message)
- {
- fprintf(out, ", %s", node->assert_stmt.message);
- }
- else
- {
- fprintf(out, ", \"Assertion failed\"");
- }
- fprintf(out, ");\n");
- break;
-
- case NODE_DEFER:
- if (defer_count < MAX_DEFER)
- {
- defer_stack[defer_count++] = node->defer_stmt.stmt;
- }
- break;
- case NODE_IMPL:
- g_current_impl_type = node->impl.struct_name;
- codegen_walker(ctx, node->impl.methods, out);
- g_current_impl_type = NULL;
- break;
- case NODE_IMPL_TRAIT:
- g_current_impl_type = node->impl_trait.target_type;
- codegen_walker(ctx, node->impl_trait.methods, out);
-
- if (strcmp(node->impl_trait.trait_name, "Drop") == 0)
- {
- char *tname = node->impl_trait.target_type;
- fprintf(out, "\n// RAII Glue\n");
- fprintf(out, "void %s__Drop_glue(%s *self) {\n", tname, tname);
- fprintf(out, " %s__Drop_drop(self);\n", tname);
- fprintf(out, "}\n");
- }
- g_current_impl_type = NULL;
- break;
- case NODE_DESTRUCT_VAR:
- {
- int id = tmp_counter++;
- fprintf(out, " ");
- emit_auto_type(ctx, node->destruct.init_expr, node->token, out);
- fprintf(out, " _tmp_%d = ", id);
- codegen_expression(ctx, node->destruct.init_expr, out);
- fprintf(out, ";\n");
-
- if (node->destruct.is_guard)
- {
- // var Some(val) = opt else ...
- char *variant = node->destruct.guard_variant;
- char *check = "val"; // field to access
-
- if (strcmp(variant, "Some") == 0)
- {
- fprintf(out, " if (!_tmp_%d.is_some) {\n", id);
- }
- else if (strcmp(variant, "Ok") == 0)
- {
- fprintf(out, " if (!_tmp_%d.is_ok) {\n", id);
- }
- else if (strcmp(variant, "Err") == 0)
- {
- fprintf(out, " if (_tmp_%d.is_ok) {\n", id); // Err if NOT ok
- check = "err";
- }
- else
- {
- // Generic guard? Assume .is_variant present?
- fprintf(out, " if (!_tmp_%d.is_%s) {\n", id, variant);
- }
-
- // Else block
- codegen_walker(ctx, node->destruct.else_block->block.statements, out);
- fprintf(out, " }\n");
-
- // Bind value
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, check,
- node->destruct.names[0], id, check);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id,
- check);
- }
- }
- else
- {
- for (int i = 0; i < node->destruct.count; i++)
- {
- if (node->destruct.is_struct_destruct)
- {
- char *field = node->destruct.field_names ? node->destruct.field_names[i]
- : node->destruct.names[i];
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, field,
- node->destruct.names[i], id, field);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i],
- id, field);
- }
- }
- else
- {
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.v%d) %s = _tmp_%d.v%d;\n", id, i,
- node->destruct.names[i], id, i);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i],
- id, i);
- }
- }
- }
- }
- break;
- }
- case NODE_BLOCK:
- {
- int saved = defer_count;
- fprintf(out, " {\n");
- codegen_walker(ctx, node->block.statements, out);
- for (int i = defer_count - 1; i >= saved; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- defer_count = saved;
- fprintf(out, " }\n");
- break;
- }
- case NODE_VAR_DECL:
- fprintf(out, " ");
- if (node->var_decl.is_static)
- {
- fprintf(out, "static ");
- }
- if (node->var_decl.is_autofree)
- {
- fprintf(out, "__attribute__((cleanup(_z_autofree_impl))) ");
- }
- {
- char *tname = NULL;
- if (node->type_info &&
- (!node->var_decl.init_expr || node->var_decl.init_expr->type != NODE_AWAIT))
- {
- tname = codegen_type_to_string(node->type_info);
- }
- else if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0)
- {
- tname = node->var_decl.type_str;
- }
-
- if (tname && strcmp(tname, "void*") != 0 && strcmp(tname, "unknown") != 0)
- {
- char *clean_type = tname;
- if (strncmp(clean_type, "struct ", 7) == 0)
- {
- clean_type += 7;
- }
-
- ASTNode *def = find_struct_def(ctx, clean_type);
- if (def && def->type_info && def->type_info->traits.has_drop)
- {
- fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
- }
-
- // Emit Variable with Type
- emit_var_decl_type(ctx, out, tname, node->var_decl.name);
- add_symbol(ctx, node->var_decl.name, tname, node->type_info);
-
- if (node->var_decl.init_expr)
- {
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- }
- fprintf(out, ";\n");
-
- if (node->type_info)
- {
- free(tname); // Free if allocated by codegen_type_to_string
- }
- }
- else
- {
- // Inference Fallback
- char *inferred = NULL;
- if (node->var_decl.init_expr)
- {
- inferred = infer_type(ctx, node->var_decl.init_expr);
- }
-
- if (inferred && strcmp(inferred, "__auto_type") != 0)
- {
- char *clean_type = inferred;
- if (strncmp(clean_type, "struct ", 7) == 0)
- {
- clean_type += 7;
- }
-
- ASTNode *def = find_struct_def(ctx, clean_type);
- if (def && def->type_info && def->type_info->traits.has_drop)
- {
- fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
- }
-
- emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
- add_symbol(ctx, node->var_decl.name, inferred, NULL);
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- fprintf(out, ";\n");
- }
- else
- {
- emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
- fprintf(out, " %s", node->var_decl.name);
-
- if (inferred)
- {
- add_symbol(ctx, node->var_decl.name, inferred, NULL);
- }
-
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- fprintf(out, ";\n");
- }
- }
- }
- break;
- case NODE_CONST:
- fprintf(out, " const ");
- if (node->var_decl.type_str)
- {
- fprintf(out, "%s %s", node->var_decl.type_str, node->var_decl.name);
- }
- else
- {
- emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
- fprintf(out, " %s", node->var_decl.name);
- }
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- fprintf(out, ";\n");
- break;
- case NODE_FIELD:
- if (node->field.bit_width > 0)
- {
- fprintf(out, " %s %s : %d;\n", node->field.type, node->field.name,
- node->field.bit_width);
- }
- else
- {
- fprintf(out, " ");
- emit_var_decl_type(ctx, out, node->field.type, node->field.name);
- fprintf(out, ";\n");
- }
- break;
- case NODE_IF:
- fprintf(out, "if (");
- codegen_expression(ctx, node->if_stmt.condition, out);
- fprintf(out, ") ");
- codegen_node_single(ctx, node->if_stmt.then_body, out);
- if (node->if_stmt.else_body)
- {
- fprintf(out, " else ");
- codegen_node_single(ctx, node->if_stmt.else_body, out);
- }
- break;
- case NODE_UNLESS:
- fprintf(out, "if (!(");
- codegen_expression(ctx, node->unless_stmt.condition, out);
- fprintf(out, ")) ");
- codegen_node_single(ctx, node->unless_stmt.body, out);
- break;
- case NODE_GUARD:
- fprintf(out, "if (!(");
- codegen_expression(ctx, node->guard_stmt.condition, out);
- fprintf(out, ")) ");
- codegen_node_single(ctx, node->guard_stmt.body, out);
- break;
- case NODE_WHILE:
- {
- loop_defer_boundary[loop_depth++] = defer_count;
- fprintf(out, "while (");
- codegen_expression(ctx, node->while_stmt.condition, out);
- fprintf(out, ") ");
- codegen_node_single(ctx, node->while_stmt.body, out);
- loop_depth--;
- break;
- }
- case NODE_FOR:
- {
- loop_defer_boundary[loop_depth++] = defer_count;
- fprintf(out, "for (");
- if (node->for_stmt.init)
- {
- if (node->for_stmt.init->type == NODE_VAR_DECL)
- {
- ASTNode *v = node->for_stmt.init;
- if (v->var_decl.type_str && strcmp(v->var_decl.type_str, "__auto_type") != 0)
- {
- fprintf(out, "%s %s = (%s)(", v->var_decl.type_str, v->var_decl.name,
- v->var_decl.type_str);
- codegen_expression(ctx, v->var_decl.init_expr, out);
- fprintf(out, ")");
- }
- else
- {
- emit_auto_type(ctx, v->var_decl.init_expr, v->token, out);
- fprintf(out, " %s = ", v->var_decl.name);
- codegen_expression(ctx, v->var_decl.init_expr, out);
- }
- }
- else
- {
- codegen_expression(ctx, node->for_stmt.init, out);
- }
- }
- fprintf(out, "; ");
- if (node->for_stmt.condition)
- {
- codegen_expression(ctx, node->for_stmt.condition, out);
- }
- fprintf(out, "; ");
- if (node->for_stmt.step)
- {
- codegen_expression(ctx, node->for_stmt.step, out);
- }
- fprintf(out, ") ");
- codegen_node_single(ctx, node->for_stmt.body, out);
- loop_depth--;
- break;
- }
- case NODE_BREAK:
- // Run defers from current scope down to loop boundary before breaking
- if (loop_depth > 0)
- {
- int boundary = loop_defer_boundary[loop_depth - 1];
- for (int i = defer_count - 1; i >= boundary; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- }
- if (node->break_stmt.target_label)
- {
- fprintf(out, "goto __break_%s;\n", node->break_stmt.target_label);
- }
- else
- {
- fprintf(out, "break;\n");
- }
- break;
- case NODE_CONTINUE:
- // Run defers from current scope down to loop boundary before continuing
- if (loop_depth > 0)
- {
- int boundary = loop_defer_boundary[loop_depth - 1];
- for (int i = defer_count - 1; i >= boundary; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- }
- if (node->continue_stmt.target_label)
- {
- fprintf(out, "goto __continue_%s;\n", node->continue_stmt.target_label);
- }
- else
- {
- fprintf(out, "continue;\n");
- }
- break;
- case NODE_GOTO:
- if (node->goto_stmt.goto_expr)
- {
- // Computed goto: goto *expr;
- fprintf(out, "goto *(");
- codegen_expression(ctx, node->goto_stmt.goto_expr, out);
- fprintf(out, ");\n");
- }
- else
- {
- fprintf(out, "goto %s;\n", node->goto_stmt.label_name);
- }
- break;
- case NODE_LABEL:
- fprintf(out, "%s:;\n", node->label_stmt.label_name);
- break;
- case NODE_DO_WHILE:
- {
- loop_defer_boundary[loop_depth++] = defer_count;
- fprintf(out, "do ");
- codegen_node_single(ctx, node->do_while_stmt.body, out);
- fprintf(out, " while (");
- codegen_expression(ctx, node->do_while_stmt.condition, out);
- fprintf(out, ");\n");
- loop_depth--;
- break;
- }
- // Loop constructs: loop, repeat, for-in
- case NODE_LOOP:
- {
- // loop { ... } => while (1) { ... }
- loop_defer_boundary[loop_depth++] = defer_count;
- fprintf(out, "while (1) ");
- codegen_node_single(ctx, node->loop_stmt.body, out);
- loop_depth--;
- break;
- }
- case NODE_REPEAT:
- {
- loop_defer_boundary[loop_depth++] = defer_count;
- fprintf(out, "for (int _rpt_i = 0; _rpt_i < (%s); _rpt_i++) ", node->repeat_stmt.count);
- codegen_node_single(ctx, node->repeat_stmt.body, out);
- loop_depth--;
- break;
- }
- case NODE_FOR_RANGE:
- {
- // Track loop entry for defer boundary
- loop_defer_boundary[loop_depth++] = defer_count;
-
- fprintf(out, "for (");
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__((");
- codegen_expression(ctx, node->for_range.start, out);
- fprintf(out, ")) %s = ", node->for_range.var_name);
- }
- else
- {
- fprintf(out, "ZC_AUTO %s = ", node->for_range.var_name);
- }
- codegen_expression(ctx, node->for_range.start, out);
- if (node->for_range.is_inclusive)
- {
- fprintf(out, "; %s <= ", node->for_range.var_name);
- }
- else
- {
- fprintf(out, "; %s < ", node->for_range.var_name);
- }
- codegen_expression(ctx, node->for_range.end, out);
- fprintf(out, "; %s", node->for_range.var_name);
- if (node->for_range.step)
- {
- fprintf(out, " += %s) ", node->for_range.step);
- }
- else
- {
- fprintf(out, "++) ");
- }
- codegen_node_single(ctx, node->for_range.body, out);
-
- loop_depth--;
- break;
- }
- case NODE_ASM:
- {
- int is_extended = (node->asm_stmt.num_outputs > 0 || node->asm_stmt.num_inputs > 0 ||
- node->asm_stmt.num_clobbers > 0);
-
- if (node->asm_stmt.is_volatile)
- {
- fprintf(out, " __asm__ __volatile__(");
- }
- else
- {
- fprintf(out, " __asm__(");
- }
-
- char *code = node->asm_stmt.code;
- char *transformed = xmalloc(strlen(code) * 3); // Generous buffer
- char *dst = transformed;
-
- for (char *p = code; *p; p++)
- {
- if (*p == '{')
- {
- // Find matching }
- char *end = strchr(p + 1, '}');
- if (end)
- {
- // Extract variable name
- int var_len = end - p - 1;
- char var_name[64];
- strncpy(var_name, p + 1, var_len);
- var_name[var_len] = 0;
-
- // Find variable index
- int idx = -1;
-
- // Check outputs first
- for (int i = 0; i < node->asm_stmt.num_outputs; i++)
- {
- if (strcmp(node->asm_stmt.outputs[i], var_name) == 0)
- {
- idx = i;
- break;
- }
- }
-
- // Then check inputs
- if (idx == -1)
- {
- for (int i = 0; i < node->asm_stmt.num_inputs; i++)
- {
- if (strcmp(node->asm_stmt.inputs[i], var_name) == 0)
- {
- idx = node->asm_stmt.num_outputs + i;
- break;
- }
- }
- }
-
- if (idx >= 0)
- {
- // Replace with %N
- dst += sprintf(dst, "%%%d", idx);
- }
- else
- {
- // Variable not found - error or keep as-is?
- dst += sprintf(dst, "{%s}", var_name);
- }
-
- p = end; // Skip past }
- }
- else
- {
- *dst++ = *p;
- }
- }
- else if (*p == '%')
- {
- if (is_extended)
- {
- *dst++ = '%';
- *dst++ = '%';
- }
- else
- {
- *dst++ = '%';
- }
- }
- else
- {
- *dst++ = *p;
- }
- }
- *dst = 0;
-
- fprintf(out, "\"");
- for (char *p = transformed; *p; p++)
- {
- if (*p == '\n')
- {
- fprintf(out, "\\n\"\n \"");
- }
- else if (*p == '"')
- {
- fprintf(out, "\\\"");
- }
- else if (*p == '\\')
- {
- fprintf(out, "\\\\");
- }
- else
- {
- fputc(*p, out);
- }
- }
- fprintf(out, "\\n\"");
-
- if (node->asm_stmt.num_outputs > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_outputs; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
-
- // Determine constraint
- char *mode = node->asm_stmt.output_modes[i];
- if (strcmp(mode, "out") == 0)
- {
- fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
- }
- else if (strcmp(mode, "inout") == 0)
- {
- fprintf(out, "\"+r\"(%s)", node->asm_stmt.outputs[i]);
- }
- else
- {
- fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
- }
- }
- }
-
- if (node->asm_stmt.num_inputs > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_inputs; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "\"r\"(%s)", node->asm_stmt.inputs[i]);
- }
- }
- else if (node->asm_stmt.num_outputs > 0)
- {
- fprintf(out, "\n : ");
- }
-
- if (node->asm_stmt.num_clobbers > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_clobbers; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "\"%s\"", node->asm_stmt.clobbers[i]);
- }
- }
-
- fprintf(out, ");\n");
- break;
- }
- case NODE_RETURN:
- {
- int has_defers = (defer_count > func_defer_boundary);
- int handled = 0;
-
- if (node->ret.value && node->ret.value->type == NODE_EXPR_VAR)
- {
- char *tname = infer_type(ctx, node->ret.value);
- if (tname)
- {
- char *clean = tname;
- if (strncmp(clean, "struct ", 7) == 0)
- {
- clean += 7;
- }
-
- ASTNode *def = find_struct_def(ctx, clean);
- if (def && def->type_info && def->type_info->traits.has_drop)
- {
- fprintf(out, " return ({ ");
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__(");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, ")");
- }
- else
- {
- fprintf(out, "__auto_type");
- }
- fprintf(out, " _z_ret_mv = ");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, "; memset(&");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, ", 0, sizeof(_z_ret_mv)); ");
- // Run defers before returning
- for (int i = defer_count - 1; i >= func_defer_boundary; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- fprintf(out, "_z_ret_mv; });\n");
- handled = 1;
- }
- free(tname);
- }
- }
-
- if (!handled)
- {
- if (has_defers && node->ret.value)
- {
- // Save return value, run defers, then return
- fprintf(out, " { ");
- emit_auto_type(ctx, node->ret.value, node->token, out);
- fprintf(out, " _z_ret = ");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, "; ");
- for (int i = defer_count - 1; i >= func_defer_boundary; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- fprintf(out, "return _z_ret; }\n");
- }
- else if (has_defers)
- {
- // No return value, just run defers
- for (int i = defer_count - 1; i >= func_defer_boundary; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- fprintf(out, " return;\n");
- }
- else
- {
- // No defers, simple return
- fprintf(out, " return ");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, ";\n");
- }
- }
- break;
- }
- case NODE_EXPR_MEMBER:
- {
- codegen_expression(ctx, node->member.target, out);
- char *lt = infer_type(ctx, node->member.target);
- if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*")))
- {
- fprintf(out, "->%s", node->member.field);
- }
- else
- {
- fprintf(out, ".%s", node->member.field);
- }
- if (lt)
- {
- free(lt);
- }
- break;
- }
- case NODE_REPL_PRINT:
- {
- fprintf(out, "{ ");
- emit_auto_type(ctx, node->repl_print.expr, node->token, out);
- fprintf(out, " _zval = (");
- codegen_expression(ctx, node->repl_print.expr, out);
- fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, "
- "\"\\n\"); }\n");
- break;
- }
- case NODE_AWAIT:
- {
- char *ret_type = "void*";
- int free_ret = 0;
- if (node->type_info)
- {
- char *t = codegen_type_to_string(node->type_info);
- if (t)
- {
- ret_type = t;
- free_ret = 1;
- }
- }
- else if (node->resolved_type)
- {
- ret_type = node->resolved_type;
- }
-
- // Fallback: If type is still Async/void* (likely from Future type, not
- // Result type), try to infer
- if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0)
- {
- char *inf = infer_type(ctx, node);
- if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0)
- {
- if (free_ret)
- {
- free(ret_type);
- }
- ret_type = inf;
- free_ret = 0; // infer_type ownership ambiguous, avoid double free
- }
- }
-
- int needs_long_cast = 0;
- int returns_struct = 0;
- if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
- strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0)
- {
- if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
- strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
- strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
- strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
- strncmp(ret_type, "uint", 4) != 0 && strncmp(ret_type, "int", 3) != 0)
- {
- returns_struct = 1;
- }
- else
- {
- needs_long_cast = 1;
- }
-
- if (strncmp(ret_type, "struct", 6) == 0)
- {
- returns_struct = 1;
- }
- }
-
- fprintf(out, "({ Async _a = ");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
- if (strcmp(ret_type, "void") == 0)
- {
- fprintf(out, "})"); // result unused
- }
- else
- {
- if (returns_struct)
- {
- // Dereference and free
- fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type, ret_type);
- }
- else
- {
- if (needs_long_cast)
- {
- fprintf(out, "(%s)(long)_r; })", ret_type);
- }
- else
- {
- fprintf(out, "(%s)_r; })", ret_type);
- }
- }
- }
- if (free_ret)
- {
- free(ret_type);
- }
- fprintf(out, ";\n"); // Statement terminator
- break;
- }
- case NODE_EXPR_LITERAL:
- // String literal statement should auto-print
- if (node->literal.type_kind == 2 || node->literal.type_kind == TOK_STRING)
- {
- fprintf(out, " printf(\"%%s\\n\", ");
- codegen_expression(ctx, node, out);
- fprintf(out, ");\n");
- }
- else
- {
- // Non-string literals as statements - just evaluate
- codegen_expression(ctx, node, out);
- fprintf(out, ";\n");
- }
- break;
- case NODE_CUDA_LAUNCH:
- {
- // Emit CUDA kernel launch: kernel<<<grid, block, shared, stream>>>(args);
- ASTNode *call = node->cuda_launch.call;
-
- // Get kernel name from callee
- if (call->call.callee->type == NODE_EXPR_VAR)
- {
- fprintf(out, " %s<<<", call->call.callee->var_ref.name);
- }
- else
- {
- fprintf(out, " ");
- codegen_expression(ctx, call->call.callee, out);
- fprintf(out, "<<<");
- }
-
- // Grid dimension
- codegen_expression(ctx, node->cuda_launch.grid, out);
- fprintf(out, ", ");
-
- // Block dimension
- codegen_expression(ctx, node->cuda_launch.block, out);
-
- // Optional shared memory size
- if (node->cuda_launch.shared_mem || node->cuda_launch.stream)
- {
- fprintf(out, ", ");
- if (node->cuda_launch.shared_mem)
- {
- codegen_expression(ctx, node->cuda_launch.shared_mem, out);
- }
- else
- {
- fprintf(out, "0");
- }
- }
-
- // Optional CUDA stream
- if (node->cuda_launch.stream)
- {
- fprintf(out, ", ");
- codegen_expression(ctx, node->cuda_launch.stream, out);
- }
-
- fprintf(out, ">>>(");
-
- // Arguments
- ASTNode *arg = call->call.args;
- int first = 1;
- while (arg)
- {
- if (!first)
- {
- fprintf(out, ", ");
- }
- codegen_expression(ctx, arg, out);
- first = 0;
- arg = arg->next;
- }
-
- fprintf(out, ");\n");
- break;
- }
- default:
- codegen_expression(ctx, node, out);
- fprintf(out, ";\n");
- break;
- }
-}
-
-// Walks AST nodes and generates code.
-void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- while (node)
- {
- codegen_node_single(ctx, node, out);
- node = node->next;
- }
-}
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index caf7c0c..0a1cbaf 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -12,6 +12,7 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out);
void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out);
void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out);
void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out);
+void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result);
// Utility functions (codegen_utils.c).
char *infer_type(ParserContext *ctx, ASTNode *node);
@@ -24,6 +25,7 @@ const char *parse_original_method_name(const char *mangled);
void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out);
char *codegen_type_to_string(Type *t);
void emit_func_signature(FILE *out, ASTNode *func, const char *name_override);
+char *strip_template_suffix(const char *name);
// Declaration emission (codegen_decl.c).
void emit_preamble(ParserContext *ctx, FILE *out);
@@ -47,6 +49,7 @@ extern int tmp_counter;
extern int defer_count;
extern ASTNode *defer_stack[];
extern ASTNode *g_current_lambda;
+extern char *g_current_func_ret_type;
// Defer boundary tracking for proper defer execution on break/continue/return
#define MAX_DEFER 1024
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index e7bd3f1..4e6db6a 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -7,42 +7,44 @@
#include <stdlib.h>
#include <string.h>
-// Emit C preamble with standard includes and type definitions.
+static void emit_freestanding_preamble(FILE *out)
+{
+ fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
+ "<stdbool.h>\n#include <stdarg.h>\n",
+ out);
+ fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
+ fputs("typedef size_t usize;\ntypedef char* string;\n", out);
+ fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
+ "int16_t\n#define U16 uint16_t\n",
+ out);
+ fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
+ "int64_t\n#define U64 "
+ "uint64_t\n",
+ out);
+ fputs("#define F32 float\n#define F64 double\n", out);
+ fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
+ "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
+ "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
+ "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
+ "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
+ "char*: \"%s\", void*: \"%p\")\n",
+ out);
+ fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
+
+ fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n", out);
+ fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return "
+ "NULL; }\n",
+ out);
+ fputs("__attribute__((weak)) void z_free(void* ptr) { }\n", out);
+ fputs("__attribute__((weak)) void z_print(const char* fmt, ...) { }\n", out);
+ fputs("__attribute__((weak)) void z_panic(const char* msg) { while(1); }\n", out);
+}
+
void emit_preamble(ParserContext *ctx, FILE *out)
{
if (g_config.is_freestanding)
{
- // Freestanding preamble.
- // It actually needs more work, but yk.
- fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
- "<stdbool.h>\n#include <stdarg.h>\n",
- out);
- fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
- fputs("typedef size_t usize;\ntypedef char* string;\n", out);
- fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
- "int16_t\n#define U16 uint16_t\n",
- out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
- "int64_t\n#define U64 "
- "uint64_t\n",
- out);
- fputs("#define F32 float\n#define F64 double\n", out);
- fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
- "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
- "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
- "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
- "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
- "char*: \"%s\", void*: \"%p\")\n",
- out);
- fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
-
- fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n", out);
- fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return "
- "NULL; }\n",
- out);
- fputs("__attribute__((weak)) void z_free(void* ptr) { }\n", out);
- fputs("__attribute__((weak)) void z_print(const char* fmt, ...) { }\n", out);
- fputs("__attribute__((weak)) void z_panic(const char* msg) { while(1); }\n", out);
+ emit_freestanding_preamble(out);
}
else
{
@@ -705,13 +707,9 @@ void emit_protos(ASTNode *node, FILE *out)
}
else
{
- char *lt = strchr(sname, '<');
- if (lt)
+ char *buf = strip_template_suffix(sname);
+ if (buf)
{
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
def = find_struct_def_codegen(g_parser_ctx, buf);
if (def && def->strct.is_template)
{
@@ -782,13 +780,9 @@ void emit_protos(ASTNode *node, FILE *out)
}
else
{
- char *lt = strchr(sname, '<');
- if (lt)
+ char *buf = strip_template_suffix(sname);
+ if (buf)
{
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
def = find_struct_def_codegen(g_parser_ctx, buf);
if (def && def->strct.is_template)
{
@@ -896,13 +890,9 @@ void emit_impl_vtables(ParserContext *ctx, FILE *out)
}
else
{
- char *lt = strchr(strct, '<');
- if (lt)
+ char *buf = strip_template_suffix(strct);
+ if (buf)
{
- int len = lt - strct;
- char *buf = xmalloc(len + 1);
- strncpy(buf, strct, len);
- buf[len] = 0;
def = find_struct_def_codegen(ctx, buf);
if (def && def->strct.is_template)
{
diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c
index 97abfc7..7363e61 100644
--- a/src/codegen/codegen_main.c
+++ b/src/codegen/codegen_main.c
@@ -577,13 +577,9 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- char *lt = strchr(sname, '<');
- if (lt)
+ char *buf = strip_template_suffix(sname);
+ if (buf)
{
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
def = find_struct_def_codegen(ctx, buf);
if (def && def->strct.is_template)
{
@@ -623,13 +619,9 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- char *lt = strchr(sname, '<');
- if (lt)
+ char *buf = strip_template_suffix(sname);
+ if (buf)
{
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
def = find_struct_def_codegen(ctx, buf);
if (def && def->strct.is_template)
{
diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c
new file mode 100644
index 0000000..983130c
--- /dev/null
+++ b/src/codegen/codegen_stmt.c
@@ -0,0 +1,1671 @@
+
+#include "codegen.h"
+#include "zprep.h"
+#include "../constants.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../plugins/plugin_manager.h"
+#include "ast.h"
+#include "zprep_plugin.h"
+
+char *g_current_func_ret_type = NULL;
+
+// Helper: emit a single pattern condition (either a value, or a range)
+static void emit_single_pattern_cond(const char *pat, int id, int is_ptr, FILE *out)
+{
+ // Check for range pattern: "start..end" or "start..=end"
+ char *range_incl = strstr(pat, "..=");
+ char *range_excl = strstr(pat, "..");
+
+ if (range_incl)
+ {
+ // Inclusive range: start..=end -> _m_id >= start && _m_id <= end
+ int start_len = (int)(range_incl - pat);
+ char *start = xmalloc(start_len + 1);
+ strncpy(start, pat, start_len);
+ start[start_len] = 0;
+ char *end = xstrdup(range_incl + 3);
+ if (is_ptr)
+ {
+ fprintf(out, "(*_m_%d >= %s && *_m_%d <= %s)", id, start, id, end);
+ }
+ else
+ {
+ fprintf(out, "(_m_%d >= %s && _m_%d <= %s)", id, start, id, end);
+ }
+ free(start);
+ free(end);
+ }
+ else if (range_excl)
+ {
+ // Exclusive range: start..end -> _m_id >= start && _m_id < end
+ int start_len = (int)(range_excl - pat);
+ char *start = xmalloc(start_len + 1);
+ strncpy(start, pat, start_len);
+ start[start_len] = 0;
+ char *end = xstrdup(range_excl + 2);
+ if (is_ptr)
+ {
+ fprintf(out, "(*_m_%d >= %s && *_m_%d < %s)", id, start, id, end);
+ }
+ else
+ {
+ fprintf(out, "(_m_%d >= %s && _m_%d < %s)", id, start, id, end);
+ }
+ free(start);
+ free(end);
+ }
+ else if (pat[0] == '"')
+ {
+ // String pattern - string comparison, _m is char* or similar
+ if (is_ptr)
+ {
+ fprintf(out, "strcmp(*_m_%d, %s) == 0", id, pat);
+ }
+ else
+ {
+ fprintf(out, "strcmp(_m_%d, %s) == 0", id, pat);
+ }
+ }
+ else if (pat[0] == '\'')
+ {
+ // Char literal pattern
+ if (is_ptr)
+ {
+ fprintf(out, "*_m_%d == %s", id, pat);
+ }
+ else
+ {
+ fprintf(out, "_m_%d == %s", id, pat);
+ }
+ }
+ else
+ {
+ // Numeric or simple pattern
+ if (is_ptr)
+ {
+ fprintf(out, "*_m_%d == %s", id, pat);
+ }
+ else
+ {
+ fprintf(out, "_m_%d == %s", id, pat);
+ }
+ }
+}
+
+// Helper: emit condition for a pattern (may contain OR patterns with '|')
+static void emit_pattern_condition(ParserContext *ctx, const char *pattern, int id, int is_ptr,
+ FILE *out)
+{
+ // Check if pattern contains '|' for OR patterns
+ if (strchr(pattern, '|'))
+ {
+ // Split by '|' and emit OR conditions
+ char *pattern_copy = xstrdup(pattern);
+ char *saveptr;
+ char *part = strtok_r(pattern_copy, "|", &saveptr);
+ int first = 1;
+ fprintf(out, "(");
+ while (part)
+ {
+ if (!first)
+ {
+ fprintf(out, " || ");
+ }
+
+ // Check if part is an enum variant
+ EnumVariantReg *reg = find_enum_variant(ctx, part);
+ if (reg)
+ {
+ if (is_ptr)
+ {
+ fprintf(out, "_m_%d->tag == %d", id, reg->tag_id);
+ }
+ else
+ {
+ fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
+ }
+ }
+ else
+ {
+ emit_single_pattern_cond(part, id, is_ptr, out);
+ }
+ first = 0;
+ part = strtok_r(NULL, "|", &saveptr);
+ }
+ fprintf(out, ")");
+ free(pattern_copy);
+ }
+ else
+ {
+ // Single pattern (may be a range)
+ EnumVariantReg *reg = find_enum_variant(ctx, pattern);
+ if (reg)
+ {
+ if (is_ptr)
+ {
+ fprintf(out, "_m_%d->tag == %d", id, reg->tag_id);
+ }
+ else
+ {
+ fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
+ }
+ }
+ else
+ {
+ emit_single_pattern_cond(pattern, id, is_ptr, out);
+ }
+ }
+}
+
+void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result)
+{
+ int id = tmp_counter++;
+ int is_self = (node->match_stmt.expr->type == NODE_EXPR_VAR &&
+ strcmp(node->match_stmt.expr->var_ref.name, "self") == 0);
+
+ char *ret_type = infer_type(ctx, node);
+ int is_expr = (use_result && ret_type && strcmp(ret_type, "void") != 0);
+
+ fprintf(out, "({ ");
+
+ // Check if any case uses ref binding - only take address if needed
+ int has_ref_binding = 0;
+ ASTNode *ref_check = node->match_stmt.cases;
+ while (ref_check)
+ {
+ if (ref_check->match_case.is_ref)
+ {
+ has_ref_binding = 1;
+ break;
+ }
+ ref_check = ref_check->next;
+ }
+
+ int is_lvalue_opt = (node->match_stmt.expr->type == NODE_EXPR_VAR ||
+ node->match_stmt.expr->type == NODE_EXPR_MEMBER ||
+ node->match_stmt.expr->type == NODE_EXPR_INDEX);
+
+ if (is_self)
+ {
+ fprintf(out, "ZC_AUTO _m_%d = ", id);
+ codegen_expression(ctx, node->match_stmt.expr, out);
+ fprintf(out, "; ");
+ }
+ else if (has_ref_binding && is_lvalue_opt)
+ {
+ // Take address for ref bindings
+ fprintf(out, "ZC_AUTO _m_%d = &", id);
+ codegen_expression(ctx, node->match_stmt.expr, out);
+ fprintf(out, "; ");
+ }
+ else if (has_ref_binding)
+ {
+ // Non-lvalue with ref binding: create temporary
+ emit_auto_type(ctx, node->match_stmt.expr, node->token, out);
+ fprintf(out, " _temp_%d = ", id);
+ codegen_expression(ctx, node->match_stmt.expr, out);
+ fprintf(out, "; ZC_AUTO _m_%d = &_temp_%d; ", id, id);
+ }
+ else
+ {
+ // No ref bindings: store value directly (not pointer)
+ fprintf(out, "ZC_AUTO _m_%d = ", id);
+ codegen_expression(ctx, node->match_stmt.expr, out);
+ fprintf(out, "; ");
+ }
+
+ if (is_expr)
+ {
+ fprintf(out, "%s _r_%d; ", ret_type, id);
+ }
+
+ char *expr_type = infer_type(ctx, node->match_stmt.expr);
+ int is_option = (expr_type && strncmp(expr_type, "Option_", 7) == 0);
+ int is_result = (expr_type && strncmp(expr_type, "Result_", 7) == 0);
+
+ char *enum_name = NULL;
+ ASTNode *chk = node->match_stmt.cases;
+ int has_wildcard = 0;
+ while (chk)
+ {
+ if (strcmp(chk->match_case.pattern, "_") == 0)
+ {
+ has_wildcard = 1;
+ }
+ else if (!enum_name)
+ {
+ EnumVariantReg *reg = find_enum_variant(ctx, chk->match_case.pattern);
+ if (reg)
+ {
+ enum_name = reg->enum_name;
+ }
+ }
+ chk = chk->next;
+ }
+
+ if (enum_name && !has_wildcard)
+ {
+ // Iterate through all registered variants for this enum
+ EnumVariantReg *v = ctx->enum_variants;
+ while (v)
+ {
+ if (strcmp(v->enum_name, enum_name) == 0)
+ {
+ int covered = 0;
+ ASTNode *c2 = node->match_stmt.cases;
+ while (c2)
+ {
+ if (strcmp(c2->match_case.pattern, v->variant_name) == 0)
+ {
+ covered = 1;
+ break;
+ }
+ c2 = c2->next;
+ }
+ if (!covered)
+ {
+ zwarn_at(node->token, "Non-exhaustive match: Missing variant '%s'",
+ v->variant_name);
+ }
+ }
+ v = v->next;
+ }
+ }
+
+ ASTNode *c = node->match_stmt.cases;
+ int first = 1;
+ while (c)
+ {
+ if (!first)
+ {
+ fprintf(out, " else ");
+ }
+ fprintf(out, "if (");
+ if (strcmp(c->match_case.pattern, "_") == 0)
+ {
+ fprintf(out, "1");
+ }
+ else if (is_option)
+ {
+ if (strcmp(c->match_case.pattern, "Some") == 0)
+ {
+ fprintf(out, "_m_%d->is_some", id);
+ }
+ else if (strcmp(c->match_case.pattern, "None") == 0)
+ {
+ fprintf(out, "!_m_%d->is_some", id);
+ }
+ else
+ {
+ fprintf(out, "1");
+ }
+ }
+ else if (is_result)
+ {
+ if (strcmp(c->match_case.pattern, "Ok") == 0)
+ {
+ fprintf(out, "_m_%d->is_ok", id);
+ }
+ else if (strcmp(c->match_case.pattern, "Err") == 0)
+ {
+ fprintf(out, "!_m_%d->is_ok", id);
+ }
+ else
+ {
+ fprintf(out, "1");
+ }
+ }
+ else
+ {
+ // Use helper for OR patterns, range patterns, and simple patterns
+ emit_pattern_condition(ctx, c->match_case.pattern, id, has_ref_binding, out);
+ }
+ fprintf(out, ") { ");
+ if (c->match_case.binding_name)
+ {
+ if (is_option)
+ {
+ if (strstr(g_config.cc, "tcc"))
+ {
+ if (c->match_case.is_ref)
+ {
+ fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id,
+ c->match_case.binding_name, id);
+ }
+ else
+ {
+ fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
+ c->match_case.binding_name, id);
+ }
+ }
+ else
+ {
+ if (c->match_case.is_ref)
+ {
+ // _m is pointer when has_ref_binding, use ->
+ fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, id);
+ }
+ else if (has_ref_binding)
+ {
+ // _m is pointer, use -> but don't take address
+ fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, id);
+ }
+ else
+ {
+ // _m is value, use .
+ fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id);
+ }
+ }
+ }
+ else if (is_result) // FIX: Changed 'if' to 'else if' to match original logic structure
+ // if needed, but original code had implicit fallthrough checks? No,
+ // checks match pattern.
+ {
+ if (strcmp(c->match_case.pattern, "Ok") == 0)
+ {
+ if (strstr(g_config.cc, "tcc"))
+ {
+ if (c->match_case.is_ref)
+ {
+ fprintf(out, "__typeof__(&_m_%d->val) %s = &_m_%d->val; ", id,
+ c->match_case.binding_name, id);
+ }
+ else
+ {
+ fprintf(out, "__typeof__(_m_%d->val) %s = _m_%d->val; ", id,
+ c->match_case.binding_name, id);
+ }
+ }
+ else
+ {
+ if (c->match_case.is_ref)
+ {
+ // _m is pointer when has_ref_binding, use ->
+ fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name,
+ id);
+ }
+ else if (has_ref_binding)
+ {
+ // _m is pointer, use -> but don't take address
+ fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name,
+ id);
+ }
+ else
+ {
+ // _m is value, use .
+ fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name,
+ id);
+ }
+ }
+ }
+ else
+ {
+ if (strstr(g_config.cc, "tcc"))
+ {
+ if (c->match_case.is_ref)
+ {
+ fprintf(out, "__typeof__(&_m_%d->err) %s = &_m_%d->err; ", id,
+ c->match_case.binding_name, id);
+ }
+ else
+ {
+ fprintf(out, "__typeof__(_m_%d->err) %s = _m_%d->err; ", id,
+ c->match_case.binding_name, id);
+ }
+ }
+ else
+ {
+ if (c->match_case.is_ref)
+ {
+ // _m is pointer when has_ref_binding, use ->
+ fprintf(out, "ZC_AUTO %s = &_m_%d->err; ", c->match_case.binding_name,
+ id);
+ }
+ else if (has_ref_binding)
+ {
+ // _m is pointer, use -> but don't take address
+ fprintf(out, "ZC_AUTO %s = _m_%d->err; ", c->match_case.binding_name,
+ id);
+ }
+ else
+ {
+ // _m is value, use .
+ fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name,
+ id);
+ }
+ }
+ }
+ }
+ else
+ {
+ char *f = strrchr(c->match_case.pattern, '_');
+ if (f)
+ {
+ f++;
+ }
+ else
+ {
+ f = c->match_case.pattern;
+ }
+ // Generic struct destructuring (for example, MyStruct_Variant)
+ // Assuming data union or accessible field.
+ if (c->match_case.is_ref)
+ {
+ // _m is pointer when has_ref_binding, use ->
+ fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", c->match_case.binding_name, id,
+ f);
+ }
+ else if (has_ref_binding)
+ {
+ // _m is pointer, use -> but don't take address
+ fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", c->match_case.binding_name, id,
+ f);
+ }
+ else
+ {
+ // _m is value, use .
+ fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f);
+ }
+ }
+ }
+
+ // Check if body is a string literal (should auto-print).
+ ASTNode *body = c->match_case.body;
+ int is_string_literal = (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2);
+
+ if (is_expr)
+ {
+ fprintf(out, "_r_%d = ", id);
+ if (is_string_literal)
+ {
+ codegen_node_single(ctx, body, out);
+ }
+ else
+ {
+ if (body->type == NODE_BLOCK)
+ {
+ int saved = defer_count;
+ fprintf(out, "({ ");
+ ASTNode *stmt = body->block.statements;
+ while (stmt)
+ {
+ codegen_node_single(ctx, stmt, out);
+ stmt = stmt->next;
+ }
+ for (int i = defer_count - 1; i >= saved; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
+ fprintf(out, " })");
+ }
+ else
+ {
+ codegen_node_single(ctx, body, out);
+ }
+ }
+ fprintf(out, ";");
+ }
+ else
+ {
+ if (is_string_literal)
+ {
+ fprintf(out, "({ printf(\"%%s\", ");
+ codegen_expression(ctx, body, out);
+ fprintf(out, "); printf(\"\\n\"); 0; })");
+ }
+ else
+ {
+ codegen_node_single(ctx, body, out);
+ }
+ }
+
+ fprintf(out, " }");
+ first = 0;
+ c = c->next;
+ }
+
+ if (is_expr)
+ {
+ fprintf(out, " _r_%d; })", id);
+ }
+ else
+ {
+ fprintf(out, " })");
+ }
+}
+void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ if (!node)
+ {
+ return;
+ }
+ switch (node->type)
+ {
+ case NODE_MATCH:
+ codegen_match_internal(ctx, node, out, 0); // 0 = statement context
+ fprintf(out, ";\n");
+ break;
+ case NODE_FUNCTION:
+ if (!node->func.body)
+ {
+ break;
+ }
+
+ if (node->func.is_async)
+ {
+ fprintf(out, "struct %s_Args {\n", node->func.name);
+ char *args_copy = xstrdup(node->func.args);
+ char *token = strtok(args_copy, ",");
+ int arg_count = 0;
+ char **arg_names = xmalloc(32 * sizeof(char *));
+
+ while (token)
+ {
+ while (*token == ' ')
+ {
+ token++; // trim leading
+ }
+ char *last_space = strrchr(token, ' ');
+ if (last_space)
+ {
+ *last_space = 0;
+ char *type = token;
+ char *name = last_space + 1;
+ fprintf(out, "%s %s;\n", type, name);
+
+ arg_names[arg_count++] = xstrdup(name);
+ }
+ token = strtok(NULL, ",");
+ }
+ free(args_copy);
+ fprintf(out, "};\n");
+
+ fprintf(out, "void* _runner_%s(void* _args)\n", node->func.name);
+ fprintf(out, "{\n");
+ fprintf(out, " struct %s_Args* args = (struct %s_Args*)_args;\n", node->func.name,
+ node->func.name);
+
+ // Determine mechanism: struct/large-type? -> malloc; primitive -> cast
+ int returns_struct = 0;
+ char *rt = node->func.ret_type;
+ if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
+ {
+ if (strstr(rt, "*") == NULL && strcmp(rt, "string") != 0 &&
+ strcmp(rt, "int") != 0 && strcmp(rt, "bool") != 0 && strcmp(rt, "char") != 0 &&
+ strcmp(rt, "float") != 0 && strcmp(rt, "double") != 0 &&
+ strcmp(rt, "long") != 0 && strcmp(rt, "usize") != 0 &&
+ strcmp(rt, "isize") != 0 && strncmp(rt, "uint", 4) != 0 &&
+ strncmp(rt, "int", 3) != 0)
+ {
+ returns_struct = 1;
+ }
+ }
+
+ // Call Impl
+ if (returns_struct)
+ {
+ fprintf(out, " %s *res_ptr = malloc(sizeof(%s));\n", rt, rt);
+ fprintf(out, " *res_ptr = ");
+ }
+ else if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
+ {
+ fprintf(out, " %s res = ", rt);
+ }
+ else
+ {
+ fprintf(out, " ");
+ }
+
+ fprintf(out, "_impl_%s(", node->func.name);
+ for (int i = 0; i < arg_count; i++)
+ {
+ fprintf(out, "%sargs->%s", i > 0 ? ", " : "", arg_names[i]);
+ }
+ fprintf(out, ");\n");
+ fprintf(out, " free(args);\n");
+
+ if (returns_struct)
+ {
+ fprintf(out, " return (void*)res_ptr;\n");
+ }
+ else if (strcmp(rt, "void") != 0)
+ {
+ fprintf(out, " return (void*)(long)res;\n");
+ }
+ else
+ {
+ fprintf(out, " return NULL;\n");
+ }
+ fprintf(out, "}\n");
+
+ fprintf(out, "%s _impl_%s(%s)\n", node->func.ret_type, node->func.name,
+ node->func.args);
+ fprintf(out, "{\n");
+ defer_count = 0;
+ codegen_walker(ctx, node->func.body, out);
+ for (int i = defer_count - 1; i >= 0; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ fprintf(out, "}\n");
+
+ // 4. Define Public Wrapper (Spawns Thread)
+ fprintf(out, "Async %s(%s)\n", node->func.name, node->func.args);
+ fprintf(out, "{\n");
+ fprintf(out, " struct %s_Args* args = malloc(sizeof(struct %s_Args));\n",
+ node->func.name, node->func.name);
+ for (int i = 0; i < arg_count; i++)
+ {
+ fprintf(out, " args->%s = %s;\n", arg_names[i], arg_names[i]);
+ }
+
+ fprintf(out, " pthread_t th;\n");
+ fprintf(out, " pthread_create(&th, NULL, _runner_%s, args);\n", node->func.name);
+ fprintf(out, " return (Async){.thread=th, .result=NULL};\n");
+ fprintf(out, "}\n");
+
+ break;
+ }
+
+ defer_count = 0;
+ fprintf(out, "\n");
+
+ // Emit GCC attributes before function
+ {
+ int has_attrs = node->func.constructor || node->func.destructor ||
+ node->func.noinline || node->func.unused || node->func.weak ||
+ node->func.cold || node->func.hot || node->func.noreturn ||
+ node->func.pure || node->func.section;
+ if (has_attrs)
+ {
+ fprintf(out, "__attribute__((");
+ int first = 1;
+#define EMIT_ATTR(cond, name) \
+ if (cond) \
+ { \
+ if (!first) \
+ fprintf(out, ", "); \
+ fprintf(out, name); \
+ first = 0; \
+ }
+ EMIT_ATTR(node->func.constructor, "constructor");
+ EMIT_ATTR(node->func.destructor, "destructor");
+ EMIT_ATTR(node->func.noinline, "noinline");
+ EMIT_ATTR(node->func.unused, "unused");
+ EMIT_ATTR(node->func.weak, "weak");
+ EMIT_ATTR(node->func.cold, "cold");
+ EMIT_ATTR(node->func.hot, "hot");
+ EMIT_ATTR(node->func.noreturn, "noreturn");
+ EMIT_ATTR(node->func.pure, "pure");
+ if (node->func.section)
+ {
+ if (!first)
+ {
+ fprintf(out, ", ");
+ }
+ fprintf(out, "section(\"%s\")", node->func.section);
+ }
+#undef EMIT_ATTR
+ fprintf(out, ")) ");
+ }
+ }
+
+ if (node->func.is_inline)
+ {
+ fprintf(out, "inline ");
+ }
+ emit_func_signature(out, node, NULL);
+ fprintf(out, "\n");
+ fprintf(out, "{\n");
+ char *prev_ret = g_current_func_ret_type;
+ g_current_func_ret_type = node->func.ret_type;
+ codegen_walker(ctx, node->func.body, out);
+ for (int i = defer_count - 1; i >= 0; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ g_current_func_ret_type = prev_ret;
+ fprintf(out, "}\n");
+ break;
+
+ case NODE_ASSERT:
+ fprintf(out, "assert(");
+ codegen_expression(ctx, node->assert_stmt.condition, out);
+ if (node->assert_stmt.message)
+ {
+ fprintf(out, ", %s", node->assert_stmt.message);
+ }
+ else
+ {
+ fprintf(out, ", \"Assertion failed\"");
+ }
+ fprintf(out, ");\n");
+ break;
+
+ case NODE_DEFER:
+ if (defer_count < MAX_DEFER)
+ {
+ defer_stack[defer_count++] = node->defer_stmt.stmt;
+ }
+ break;
+ case NODE_IMPL:
+ g_current_impl_type = node->impl.struct_name;
+ codegen_walker(ctx, node->impl.methods, out);
+ g_current_impl_type = NULL;
+ break;
+ case NODE_IMPL_TRAIT:
+ g_current_impl_type = node->impl_trait.target_type;
+ codegen_walker(ctx, node->impl_trait.methods, out);
+
+ if (strcmp(node->impl_trait.trait_name, "Drop") == 0)
+ {
+ char *tname = node->impl_trait.target_type;
+ fprintf(out, "\n// RAII Glue\n");
+ fprintf(out, "void %s__Drop_glue(%s *self) {\n", tname, tname);
+ fprintf(out, " %s__Drop_drop(self);\n", tname);
+ fprintf(out, "}\n");
+ }
+ g_current_impl_type = NULL;
+ break;
+ case NODE_DESTRUCT_VAR:
+ {
+ int id = tmp_counter++;
+ fprintf(out, " ");
+ emit_auto_type(ctx, node->destruct.init_expr, node->token, out);
+ fprintf(out, " _tmp_%d = ", id);
+ codegen_expression(ctx, node->destruct.init_expr, out);
+ fprintf(out, ";\n");
+
+ if (node->destruct.is_guard)
+ {
+ // var Some(val) = opt else ...
+ char *variant = node->destruct.guard_variant;
+ char *check = "val"; // field to access
+
+ if (strcmp(variant, "Some") == 0)
+ {
+ fprintf(out, " if (!_tmp_%d.is_some) {\n", id);
+ }
+ else if (strcmp(variant, "Ok") == 0)
+ {
+ fprintf(out, " if (!_tmp_%d.is_ok) {\n", id);
+ }
+ else if (strcmp(variant, "Err") == 0)
+ {
+ fprintf(out, " if (_tmp_%d.is_ok) {\n", id); // Err if NOT ok
+ check = "err";
+ }
+ else
+ {
+ // Generic guard? Assume .is_variant present?
+ fprintf(out, " if (!_tmp_%d.is_%s) {\n", id, variant);
+ }
+
+ // Else block
+ codegen_walker(ctx, node->destruct.else_block->block.statements, out);
+ fprintf(out, " }\n");
+
+ // Bind value
+ if (strstr(g_config.cc, "tcc"))
+ {
+ fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, check,
+ node->destruct.names[0], id, check);
+ }
+ else
+ {
+ fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id,
+ check);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < node->destruct.count; i++)
+ {
+ if (node->destruct.is_struct_destruct)
+ {
+ char *field = node->destruct.field_names ? node->destruct.field_names[i]
+ : node->destruct.names[i];
+ if (strstr(g_config.cc, "tcc"))
+ {
+ fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, field,
+ node->destruct.names[i], id, field);
+ }
+ else
+ {
+ fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i],
+ id, field);
+ }
+ }
+ else
+ {
+ if (strstr(g_config.cc, "tcc"))
+ {
+ fprintf(out, " __typeof__(_tmp_%d.v%d) %s = _tmp_%d.v%d;\n", id, i,
+ node->destruct.names[i], id, i);
+ }
+ else
+ {
+ fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i],
+ id, i);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case NODE_BLOCK:
+ {
+ int saved = defer_count;
+ fprintf(out, " {\n");
+ codegen_walker(ctx, node->block.statements, out);
+ for (int i = defer_count - 1; i >= saved; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
+ fprintf(out, " }\n");
+ break;
+ }
+ case NODE_VAR_DECL:
+ fprintf(out, " ");
+ if (node->var_decl.is_static)
+ {
+ fprintf(out, "static ");
+ }
+ if (node->var_decl.is_autofree)
+ {
+ fprintf(out, "__attribute__((cleanup(_z_autofree_impl))) ");
+ }
+ {
+ char *tname = NULL;
+ if (node->type_info &&
+ (!node->var_decl.init_expr || node->var_decl.init_expr->type != NODE_AWAIT))
+ {
+ tname = codegen_type_to_string(node->type_info);
+ }
+ else if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0)
+ {
+ tname = node->var_decl.type_str;
+ }
+
+ if (tname && strcmp(tname, "void*") != 0 && strcmp(tname, "unknown") != 0)
+ {
+ char *clean_type = tname;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+
+ ASTNode *def = find_struct_def(ctx, clean_type);
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
+ }
+
+ // Emit Variable with Type
+ emit_var_decl_type(ctx, out, tname, node->var_decl.name);
+ add_symbol(ctx, node->var_decl.name, tname, node->type_info);
+
+ if (node->var_decl.init_expr)
+ {
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ }
+ fprintf(out, ";\n");
+
+ if (node->type_info)
+ {
+ free(tname); // Free if allocated by codegen_type_to_string
+ }
+ }
+ else
+ {
+ // Inference Fallback
+ char *inferred = NULL;
+ if (node->var_decl.init_expr)
+ {
+ inferred = infer_type(ctx, node->var_decl.init_expr);
+ }
+
+ if (inferred && strcmp(inferred, "__auto_type") != 0)
+ {
+ char *clean_type = inferred;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+
+ ASTNode *def = find_struct_def(ctx, clean_type);
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
+ }
+
+ emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
+ add_symbol(ctx, node->var_decl.name, inferred, NULL);
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ fprintf(out, ";\n");
+ }
+ else
+ {
+ emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
+ fprintf(out, " %s", node->var_decl.name);
+
+ if (inferred)
+ {
+ add_symbol(ctx, node->var_decl.name, inferred, NULL);
+ }
+
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ fprintf(out, ";\n");
+ }
+ }
+ }
+ break;
+ case NODE_CONST:
+ fprintf(out, " const ");
+ if (node->var_decl.type_str)
+ {
+ fprintf(out, "%s %s", node->var_decl.type_str, node->var_decl.name);
+ }
+ else
+ {
+ emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
+ fprintf(out, " %s", node->var_decl.name);
+ }
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ fprintf(out, ";\n");
+ break;
+ case NODE_FIELD:
+ if (node->field.bit_width > 0)
+ {
+ fprintf(out, " %s %s : %d;\n", node->field.type, node->field.name,
+ node->field.bit_width);
+ }
+ else
+ {
+ fprintf(out, " ");
+ emit_var_decl_type(ctx, out, node->field.type, node->field.name);
+ fprintf(out, ";\n");
+ }
+ break;
+ case NODE_IF:
+ fprintf(out, "if (");
+ codegen_expression(ctx, node->if_stmt.condition, out);
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->if_stmt.then_body, out);
+ if (node->if_stmt.else_body)
+ {
+ fprintf(out, " else ");
+ codegen_node_single(ctx, node->if_stmt.else_body, out);
+ }
+ break;
+ case NODE_UNLESS:
+ fprintf(out, "if (!(");
+ codegen_expression(ctx, node->unless_stmt.condition, out);
+ fprintf(out, ")) ");
+ codegen_node_single(ctx, node->unless_stmt.body, out);
+ break;
+ case NODE_GUARD:
+ fprintf(out, "if (!(");
+ codegen_expression(ctx, node->guard_stmt.condition, out);
+ fprintf(out, ")) ");
+ codegen_node_single(ctx, node->guard_stmt.body, out);
+ break;
+ case NODE_WHILE:
+ {
+ loop_defer_boundary[loop_depth++] = defer_count;
+ fprintf(out, "while (");
+ codegen_expression(ctx, node->while_stmt.condition, out);
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->while_stmt.body, out);
+ loop_depth--;
+ break;
+ }
+ case NODE_FOR:
+ {
+ loop_defer_boundary[loop_depth++] = defer_count;
+ fprintf(out, "for (");
+ if (node->for_stmt.init)
+ {
+ if (node->for_stmt.init->type == NODE_VAR_DECL)
+ {
+ ASTNode *v = node->for_stmt.init;
+ if (v->var_decl.type_str && strcmp(v->var_decl.type_str, "__auto_type") != 0)
+ {
+ fprintf(out, "%s %s = (%s)(", v->var_decl.type_str, v->var_decl.name,
+ v->var_decl.type_str);
+ codegen_expression(ctx, v->var_decl.init_expr, out);
+ fprintf(out, ")");
+ }
+ else
+ {
+ emit_auto_type(ctx, v->var_decl.init_expr, v->token, out);
+ fprintf(out, " %s = ", v->var_decl.name);
+ codegen_expression(ctx, v->var_decl.init_expr, out);
+ }
+ }
+ else
+ {
+ codegen_expression(ctx, node->for_stmt.init, out);
+ }
+ }
+ fprintf(out, "; ");
+ if (node->for_stmt.condition)
+ {
+ codegen_expression(ctx, node->for_stmt.condition, out);
+ }
+ fprintf(out, "; ");
+ if (node->for_stmt.step)
+ {
+ codegen_expression(ctx, node->for_stmt.step, out);
+ }
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->for_stmt.body, out);
+ loop_depth--;
+ break;
+ }
+ case NODE_BREAK:
+ // Run defers from current scope down to loop boundary before breaking
+ if (loop_depth > 0)
+ {
+ int boundary = loop_defer_boundary[loop_depth - 1];
+ for (int i = defer_count - 1; i >= boundary; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ }
+ if (node->break_stmt.target_label)
+ {
+ fprintf(out, "goto __break_%s;\n", node->break_stmt.target_label);
+ }
+ else
+ {
+ fprintf(out, "break;\n");
+ }
+ break;
+ case NODE_CONTINUE:
+ // Run defers from current scope down to loop boundary before continuing
+ if (loop_depth > 0)
+ {
+ int boundary = loop_defer_boundary[loop_depth - 1];
+ for (int i = defer_count - 1; i >= boundary; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ }
+ if (node->continue_stmt.target_label)
+ {
+ fprintf(out, "goto __continue_%s;\n", node->continue_stmt.target_label);
+ }
+ else
+ {
+ fprintf(out, "continue;\n");
+ }
+ break;
+ case NODE_GOTO:
+ if (node->goto_stmt.goto_expr)
+ {
+ // Computed goto: goto *expr;
+ fprintf(out, "goto *(");
+ codegen_expression(ctx, node->goto_stmt.goto_expr, out);
+ fprintf(out, ");\n");
+ }
+ else
+ {
+ fprintf(out, "goto %s;\n", node->goto_stmt.label_name);
+ }
+ break;
+ case NODE_LABEL:
+ fprintf(out, "%s:;\n", node->label_stmt.label_name);
+ break;
+ case NODE_DO_WHILE:
+ {
+ loop_defer_boundary[loop_depth++] = defer_count;
+ fprintf(out, "do ");
+ codegen_node_single(ctx, node->do_while_stmt.body, out);
+ fprintf(out, " while (");
+ codegen_expression(ctx, node->do_while_stmt.condition, out);
+ fprintf(out, ");\n");
+ loop_depth--;
+ break;
+ }
+ // Loop constructs: loop, repeat, for-in
+ case NODE_LOOP:
+ {
+ // loop { ... } => while (1) { ... }
+ loop_defer_boundary[loop_depth++] = defer_count;
+ fprintf(out, "while (1) ");
+ codegen_node_single(ctx, node->loop_stmt.body, out);
+ loop_depth--;
+ break;
+ }
+ case NODE_REPEAT:
+ {
+ loop_defer_boundary[loop_depth++] = defer_count;
+ fprintf(out, "for (int _rpt_i = 0; _rpt_i < (%s); _rpt_i++) ", node->repeat_stmt.count);
+ codegen_node_single(ctx, node->repeat_stmt.body, out);
+ loop_depth--;
+ break;
+ }
+ case NODE_FOR_RANGE:
+ {
+ // Track loop entry for defer boundary
+ loop_defer_boundary[loop_depth++] = defer_count;
+
+ fprintf(out, "for (");
+ if (strstr(g_config.cc, "tcc"))
+ {
+ fprintf(out, "__typeof__((");
+ codegen_expression(ctx, node->for_range.start, out);
+ fprintf(out, ")) %s = ", node->for_range.var_name);
+ }
+ else
+ {
+ fprintf(out, "ZC_AUTO %s = ", node->for_range.var_name);
+ }
+ codegen_expression(ctx, node->for_range.start, out);
+ if (node->for_range.is_inclusive)
+ {
+ fprintf(out, "; %s <= ", node->for_range.var_name);
+ }
+ else
+ {
+ fprintf(out, "; %s < ", node->for_range.var_name);
+ }
+ codegen_expression(ctx, node->for_range.end, out);
+ fprintf(out, "; %s", node->for_range.var_name);
+ if (node->for_range.step)
+ {
+ fprintf(out, " += %s) ", node->for_range.step);
+ }
+ else
+ {
+ fprintf(out, "++) ");
+ }
+ codegen_node_single(ctx, node->for_range.body, out);
+
+ loop_depth--;
+ break;
+ }
+ case NODE_ASM:
+ {
+ int is_extended = (node->asm_stmt.num_outputs > 0 || node->asm_stmt.num_inputs > 0 ||
+ node->asm_stmt.num_clobbers > 0);
+
+ if (node->asm_stmt.is_volatile)
+ {
+ fprintf(out, " __asm__ __volatile__(");
+ }
+ else
+ {
+ fprintf(out, " __asm__(");
+ }
+
+ char *code = node->asm_stmt.code;
+ char *transformed = xmalloc(strlen(code) * 3); // Generous buffer
+ char *dst = transformed;
+
+ for (char *p = code; *p; p++)
+ {
+ if (*p == '{')
+ {
+ // Find matching }
+ char *end = strchr(p + 1, '}');
+ if (end)
+ {
+ // Extract variable name
+ int var_len = end - p - 1;
+ char var_name[64];
+ strncpy(var_name, p + 1, var_len);
+ var_name[var_len] = 0;
+
+ // Find variable index
+ int idx = -1;
+
+ // Check outputs first
+ for (int i = 0; i < node->asm_stmt.num_outputs; i++)
+ {
+ if (strcmp(node->asm_stmt.outputs[i], var_name) == 0)
+ {
+ idx = i;
+ break;
+ }
+ }
+
+ // Then check inputs
+ if (idx == -1)
+ {
+ for (int i = 0; i < node->asm_stmt.num_inputs; i++)
+ {
+ if (strcmp(node->asm_stmt.inputs[i], var_name) == 0)
+ {
+ idx = node->asm_stmt.num_outputs + i;
+ break;
+ }
+ }
+ }
+
+ if (idx >= 0)
+ {
+ // Replace with %N
+ dst += sprintf(dst, "%%%d", idx);
+ }
+ else
+ {
+ // Variable not found - error or keep as-is?
+ dst += sprintf(dst, "{%s}", var_name);
+ }
+
+ p = end; // Skip past }
+ }
+ else
+ {
+ *dst++ = *p;
+ }
+ }
+ else if (*p == '%')
+ {
+ if (is_extended)
+ {
+ *dst++ = '%';
+ *dst++ = '%';
+ }
+ else
+ {
+ *dst++ = '%';
+ }
+ }
+ else
+ {
+ *dst++ = *p;
+ }
+ }
+ *dst = 0;
+
+ fprintf(out, "\"");
+ for (char *p = transformed; *p; p++)
+ {
+ if (*p == '\n')
+ {
+ fprintf(out, "\\n\"\n \"");
+ }
+ else if (*p == '"')
+ {
+ fprintf(out, "\\\"");
+ }
+ else if (*p == '\\')
+ {
+ fprintf(out, "\\\\");
+ }
+ else
+ {
+ fputc(*p, out);
+ }
+ }
+ fprintf(out, "\\n\"");
+
+ if (node->asm_stmt.num_outputs > 0)
+ {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_outputs; i++)
+ {
+ if (i > 0)
+ {
+ fprintf(out, ", ");
+ }
+
+ // Determine constraint
+ char *mode = node->asm_stmt.output_modes[i];
+ if (strcmp(mode, "out") == 0)
+ {
+ fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
+ }
+ else if (strcmp(mode, "inout") == 0)
+ {
+ fprintf(out, "\"+r\"(%s)", node->asm_stmt.outputs[i]);
+ }
+ else
+ {
+ fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
+ }
+ }
+ }
+
+ if (node->asm_stmt.num_inputs > 0)
+ {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_inputs; i++)
+ {
+ if (i > 0)
+ {
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\"r\"(%s)", node->asm_stmt.inputs[i]);
+ }
+ }
+ else if (node->asm_stmt.num_outputs > 0)
+ {
+ fprintf(out, "\n : ");
+ }
+
+ if (node->asm_stmt.num_clobbers > 0)
+ {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_clobbers; i++)
+ {
+ if (i > 0)
+ {
+ fprintf(out, ", ");
+ }
+ fprintf(out, "\"%s\"", node->asm_stmt.clobbers[i]);
+ }
+ }
+
+ fprintf(out, ");\n");
+ break;
+ }
+ case NODE_RETURN:
+ {
+ int has_defers = (defer_count > func_defer_boundary);
+ int handled = 0;
+
+ if (node->ret.value && node->ret.value->type == NODE_EXPR_VAR)
+ {
+ char *tname = infer_type(ctx, node->ret.value);
+ if (tname)
+ {
+ char *clean = tname;
+ if (strncmp(clean, "struct ", 7) == 0)
+ {
+ clean += 7;
+ }
+
+ ASTNode *def = find_struct_def(ctx, clean);
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ fprintf(out, " return ({ ");
+ if (strstr(g_config.cc, "tcc"))
+ {
+ fprintf(out, "__typeof__(");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, ")");
+ }
+ else
+ {
+ fprintf(out, "__auto_type");
+ }
+ fprintf(out, " _z_ret_mv = ");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, "; memset(&");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, ", 0, sizeof(_z_ret_mv)); ");
+ // Run defers before returning
+ for (int i = defer_count - 1; i >= func_defer_boundary; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ fprintf(out, "_z_ret_mv; });\n");
+ handled = 1;
+ }
+ free(tname);
+ }
+ }
+
+ if (!handled)
+ {
+ if (has_defers && node->ret.value)
+ {
+ // Save return value, run defers, then return
+ fprintf(out, " { ");
+ emit_auto_type(ctx, node->ret.value, node->token, out);
+ fprintf(out, " _z_ret = ");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, "; ");
+ for (int i = defer_count - 1; i >= func_defer_boundary; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ fprintf(out, "return _z_ret; }\n");
+ }
+ else if (has_defers)
+ {
+ // No return value, just run defers
+ for (int i = defer_count - 1; i >= func_defer_boundary; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ fprintf(out, " return;\n");
+ }
+ else
+ {
+ // No defers, simple return
+ fprintf(out, " return ");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, ";\n");
+ }
+ }
+ break;
+ }
+ case NODE_EXPR_MEMBER:
+ {
+ codegen_expression(ctx, node->member.target, out);
+ char *lt = infer_type(ctx, node->member.target);
+ if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*")))
+ {
+ fprintf(out, "->%s", node->member.field);
+ }
+ else
+ {
+ fprintf(out, ".%s", node->member.field);
+ }
+ if (lt)
+ {
+ free(lt);
+ }
+ break;
+ }
+ case NODE_REPL_PRINT:
+ {
+ fprintf(out, "{ ");
+ emit_auto_type(ctx, node->repl_print.expr, node->token, out);
+ fprintf(out, " _zval = (");
+ codegen_expression(ctx, node->repl_print.expr, out);
+ fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, "
+ "\"\\n\"); }\n");
+ break;
+ }
+ case NODE_AWAIT:
+ {
+ char *ret_type = "void*";
+ int free_ret = 0;
+ if (node->type_info)
+ {
+ char *t = codegen_type_to_string(node->type_info);
+ if (t)
+ {
+ ret_type = t;
+ free_ret = 1;
+ }
+ }
+ else if (node->resolved_type)
+ {
+ ret_type = node->resolved_type;
+ }
+
+ // Fallback: If type is still Async/void* (likely from Future type, not
+ // Result type), try to infer
+ if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0)
+ {
+ char *inf = infer_type(ctx, node);
+ if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0)
+ {
+ if (free_ret)
+ {
+ free(ret_type);
+ }
+ ret_type = inf;
+ free_ret = 0; // infer_type ownership ambiguous, avoid double free
+ }
+ }
+
+ int needs_long_cast = 0;
+ int returns_struct = 0;
+ if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
+ strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0)
+ {
+ if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
+ strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
+ strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
+ strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
+ strncmp(ret_type, "uint", 4) != 0 && strncmp(ret_type, "int", 3) != 0)
+ {
+ returns_struct = 1;
+ }
+ else
+ {
+ needs_long_cast = 1;
+ }
+
+ if (strncmp(ret_type, "struct", 6) == 0)
+ {
+ returns_struct = 1;
+ }
+ }
+
+ fprintf(out, "({ Async _a = ");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
+ if (strcmp(ret_type, "void") == 0)
+ {
+ fprintf(out, "})"); // result unused
+ }
+ else
+ {
+ if (returns_struct)
+ {
+ // Dereference and free
+ fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type, ret_type);
+ }
+ else
+ {
+ if (needs_long_cast)
+ {
+ fprintf(out, "(%s)(long)_r; })", ret_type);
+ }
+ else
+ {
+ fprintf(out, "(%s)_r; })", ret_type);
+ }
+ }
+ }
+ if (free_ret)
+ {
+ free(ret_type);
+ }
+ fprintf(out, ";\n"); // Statement terminator
+ break;
+ }
+ case NODE_EXPR_LITERAL:
+ // String literal statement should auto-print
+ if (node->literal.type_kind == 2 || node->literal.type_kind == TOK_STRING)
+ {
+ fprintf(out, " printf(\"%%s\\n\", ");
+ codegen_expression(ctx, node, out);
+ fprintf(out, ");\n");
+ }
+ else
+ {
+ // Non-string literals as statements - just evaluate
+ codegen_expression(ctx, node, out);
+ fprintf(out, ";\n");
+ }
+ break;
+ case NODE_CUDA_LAUNCH:
+ {
+ // Emit CUDA kernel launch: kernel<<<grid, block, shared, stream>>>(args);
+ ASTNode *call = node->cuda_launch.call;
+
+ // Get kernel name from callee
+ if (call->call.callee->type == NODE_EXPR_VAR)
+ {
+ fprintf(out, " %s<<<", call->call.callee->var_ref.name);
+ }
+ else
+ {
+ fprintf(out, " ");
+ codegen_expression(ctx, call->call.callee, out);
+ fprintf(out, "<<<");
+ }
+
+ // Grid dimension
+ codegen_expression(ctx, node->cuda_launch.grid, out);
+ fprintf(out, ", ");
+
+ // Block dimension
+ codegen_expression(ctx, node->cuda_launch.block, out);
+
+ // Optional shared memory size
+ if (node->cuda_launch.shared_mem || node->cuda_launch.stream)
+ {
+ fprintf(out, ", ");
+ if (node->cuda_launch.shared_mem)
+ {
+ codegen_expression(ctx, node->cuda_launch.shared_mem, out);
+ }
+ else
+ {
+ fprintf(out, "0");
+ }
+ }
+
+ // Optional CUDA stream
+ if (node->cuda_launch.stream)
+ {
+ fprintf(out, ", ");
+ codegen_expression(ctx, node->cuda_launch.stream, out);
+ }
+
+ fprintf(out, ">>>(");
+
+ // Arguments
+ ASTNode *arg = call->call.args;
+ int first = 1;
+ while (arg)
+ {
+ if (!first)
+ {
+ fprintf(out, ", ");
+ }
+ codegen_expression(ctx, arg, out);
+ first = 0;
+ arg = arg->next;
+ }
+
+ fprintf(out, ");\n");
+ break;
+ }
+ default:
+ codegen_expression(ctx, node, out);
+ fprintf(out, ";\n");
+ break;
+ }
+}
+
+// Walks AST nodes and generates code.
+void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ while (node)
+ {
+ codegen_node_single(ctx, node, out);
+ node = node->next;
+ }
+}
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index e490789..fe580bf 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -20,6 +20,26 @@ int loop_defer_boundary[MAX_LOOP_DEPTH];
int loop_depth = 0;
int func_defer_boundary = 0;
+// Strip template suffix from a type name (for example, "MyStruct<T>" -> "MyStruct")
+// Returns newly allocated string, caller must free.
+char *strip_template_suffix(const char *name)
+{
+ if (!name)
+ {
+ return NULL;
+ }
+ char *lt = strchr(name, '<');
+ if (lt)
+ {
+ int len = lt - name;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, name, len);
+ buf[len] = 0;
+ return buf;
+ }
+ return xstrdup(name);
+}
+
// Helper to emit variable declarations with array types.
void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
{
diff --git a/src/constants.h b/src/constants.h
new file mode 100644
index 0000000..15bb19f
--- /dev/null
+++ b/src/constants.h
@@ -0,0 +1,46 @@
+
+#ifndef ZEN_CONSTANTS_H
+#define ZEN_CONSTANTS_H
+
+// Buffer sizes
+#define MAX_TYPE_NAME_LEN 256
+#define MAX_FUNC_NAME_LEN 512
+#define MAX_ERROR_MSG_LEN 1024
+#define MAX_MANGLED_NAME_LEN 512
+#define MAX_PATH_LEN 4096
+
+// Type checking helpers
+#define IS_INT_TYPE(t) ((t) && strcmp((t), "int") == 0)
+#define IS_BOOL_TYPE(t) ((t) && strcmp((t), "bool") == 0)
+#define IS_CHAR_TYPE(t) ((t) && strcmp((t), "char") == 0)
+#define IS_VOID_TYPE(t) ((t) && strcmp((t), "void") == 0)
+#define IS_FLOAT_TYPE(t) ((t) && strcmp((t), "float") == 0)
+#define IS_DOUBLE_TYPE(t) ((t) && strcmp((t), "double") == 0)
+#define IS_USIZE_TYPE(t) ((t) && (strcmp((t), "usize") == 0 || strcmp((t), "size_t") == 0))
+#define IS_STRING_TYPE(t) \
+ ((t) && \
+ (strcmp((t), "string") == 0 || strcmp((t), "char*") == 0 || strcmp((t), "const char*") == 0))
+
+// Composite type checks
+#define IS_BASIC_TYPE(t) \
+ ((t) && (IS_INT_TYPE(t) || IS_BOOL_TYPE(t) || IS_CHAR_TYPE(t) || IS_VOID_TYPE(t) || \
+ IS_FLOAT_TYPE(t) || IS_DOUBLE_TYPE(t) || IS_USIZE_TYPE(t) || \
+ strcmp((t), "ssize_t") == 0 || strcmp((t), "__auto_type") == 0))
+
+#define IS_NUMERIC_TYPE(t) \
+ ((t) && (IS_INT_TYPE(t) || IS_FLOAT_TYPE(t) || IS_DOUBLE_TYPE(t) || IS_USIZE_TYPE(t)))
+
+// Pointer type check
+#define IS_PTR_TYPE(t) ((t) && strchr((t), '*') != NULL)
+
+// Struct prefix check
+#define IS_STRUCT_PREFIX(t) ((t) && strncmp((t), "struct ", 7) == 0)
+#define STRIP_STRUCT_PREFIX(t) (IS_STRUCT_PREFIX(t) ? ((t) + 7) : (t))
+
+// Generic type checks
+#define IS_OPTION_TYPE(t) ((t) && strncmp((t), "Option_", 7) == 0)
+#define IS_RESULT_TYPE(t) ((t) && strncmp((t), "Result_", 7) == 0)
+#define IS_VEC_TYPE(t) ((t) && strncmp((t), "Vec_", 4) == 0)
+#define IS_SLICE_TYPE(t) ((t) && strncmp((t), "Slice_", 6) == 0)
+
+#endif // ZEN_CONSTANTS_H
diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c
new file mode 100644
index 0000000..63ec329
--- /dev/null
+++ b/src/parser/parser_decl.c
@@ -0,0 +1,802 @@
+
+#include "parser.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../ast/ast.h"
+#include "../plugins/plugin_manager.h"
+#include "../zen/zen_facts.h"
+#include "zprep_plugin.h"
+#include "../codegen/codegen.h"
+
+ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
+{
+ lexer_next(l); // eat 'fn'
+ Token name_tok = lexer_next(l);
+ char *name = token_strdup(name_tok);
+
+ if (is_async)
+ {
+ ctx->has_async = 1;
+ }
+
+ // Check for C reserved word conflict
+ if (is_c_reserved_word(name))
+ {
+ warn_c_reserved_word(name_tok, name);
+ }
+
+ char *gen_param = NULL;
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ lexer_next(l); // eat <
+
+ char buf[1024];
+ buf[0] = 0;
+
+ while (1)
+ {
+ Token gt = lexer_next(l);
+ if (gt.type != TOK_IDENT)
+ {
+ zpanic_at(gt, "Expected generic parameter name");
+ }
+ char *s = token_strdup(gt);
+
+ if (strlen(buf) + strlen(s) + 2 >= sizeof(buf))
+ {
+ zpanic_at(gt, "Too many generic parameters");
+ }
+
+ if (buf[0])
+ {
+ strcat(buf, ",");
+ }
+ strcat(buf, s);
+ free(s);
+
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+ break;
+ }
+
+ if (lexer_next(l).type != TOK_RANGLE)
+ {
+ zpanic_at(lexer_peek(l), "Expected >");
+ }
+ gen_param = xstrdup(buf);
+ }
+
+ // Register generic parameters so type parsing recognizes them
+ int saved_generic_count = ctx->known_generics_count;
+ if (gen_param)
+ {
+ char *tmp = xstrdup(gen_param);
+ char *tok = strtok(tmp, ",");
+ while (tok)
+ {
+ register_generic(ctx, tok);
+ tok = strtok(NULL, ",");
+ }
+ free(tmp);
+ }
+
+ enter_scope(ctx);
+ char **defaults;
+ int count;
+ Type **arg_types;
+ char **param_names;
+ int is_varargs = 0;
+
+ char *args =
+ parse_and_convert_args(ctx, l, &defaults, &count, &arg_types, &param_names, &is_varargs);
+
+ char *ret = "void";
+ Type *ret_type_obj = type_new(TYPE_VOID);
+
+ if (strcmp(name, "main") == 0)
+ {
+ ret = "int";
+ ret_type_obj = type_new(TYPE_INT);
+ }
+
+ if (lexer_peek(l).type == TOK_ARROW)
+ {
+ lexer_next(l);
+ ret_type_obj = parse_type_formal(ctx, l);
+ ret = type_to_string(ret_type_obj);
+ }
+
+ extern char *curr_func_ret;
+ curr_func_ret = ret;
+
+ // Auto-prefix function name if in module context
+ // Don't prefix generic templates or functions inside impl blocks (already
+ // mangled)
+ if (ctx->current_module_prefix && !gen_param && !ctx->current_impl_struct)
+ {
+ char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
+ sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name);
+ free(name);
+ name = prefixed_name;
+ }
+
+ // Register if concrete (Global functions only)
+ if (!gen_param && !ctx->current_impl_struct)
+ {
+ register_func(ctx, name, count, defaults, arg_types, ret_type_obj, is_varargs, is_async,
+ name_tok);
+ // Note: must_use is set after return by caller (parser_core.c)
+ }
+
+ ASTNode *body = NULL;
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l); // consume ;
+ }
+ else
+ {
+ body = parse_block(ctx, l);
+ }
+
+ // Check for unused parameters
+ // The current scope contains arguments (since parse_block creates a new child
+ // scope for body) Only check if we parsed a body (not a prototype) function
+ if (body && ctx->current_scope)
+ {
+ Symbol *sym = ctx->current_scope->symbols;
+ while (sym)
+ {
+ // Check if unused and not prefixed with '_' (conventional ignore)
+ // also ignore 'self' as it is often mandated by traits
+ if (!sym->is_used && sym->name[0] != '_' && strcmp(sym->name, "self") != 0 &&
+ strcmp(name, "main") != 0)
+ {
+ warn_unused_parameter(sym->decl_token, sym->name, name);
+ }
+ sym = sym->next;
+ }
+ }
+
+ exit_scope(ctx);
+
+ // Restore generic count to unregister function-scoped generics
+ ctx->known_generics_count = saved_generic_count;
+
+ curr_func_ret = NULL;
+
+ ASTNode *node = ast_create(NODE_FUNCTION);
+ node->token = name_tok; // Save definition location
+ node->func.name = name;
+ node->func.args = args;
+ node->func.ret_type = ret;
+ node->func.body = body;
+
+ node->func.arg_types = arg_types;
+ node->func.param_names = param_names;
+ node->func.arg_count = count;
+ node->func.defaults = defaults;
+ node->func.ret_type_info = ret_type_obj;
+ node->func.is_varargs = is_varargs;
+
+ if (gen_param)
+ {
+ register_func_template(ctx, name, gen_param, node);
+ return NULL;
+ }
+ if (!ctx->current_impl_struct)
+ {
+ add_to_func_list(ctx, node);
+ }
+ return node;
+}
+
+char *patch_self_args(const char *args, const char *struct_name)
+{
+ if (!args)
+ {
+ return NULL;
+ }
+ char *new_args = xmalloc(strlen(args) + strlen(struct_name) + 10);
+
+ // Check if it starts with "void* self"
+ if (strncmp(args, "void* self", 10) == 0)
+ {
+ sprintf(new_args, "%s* self%s", struct_name, args + 10);
+ }
+ else
+ {
+ strcpy(new_args, args);
+ }
+ return new_args;
+}
+// Helper for Value-Returning Defer
+static void replace_it_with_var(ASTNode *node, char *var_name)
+{
+ if (!node)
+ {
+ return;
+ }
+ if (node->type == NODE_EXPR_VAR)
+ {
+ if (strcmp(node->var_ref.name, "it") == 0)
+ {
+ // Replace 'it' with var_name
+ node->var_ref.name = xstrdup(var_name);
+ }
+ }
+ else if (node->type == NODE_EXPR_CALL)
+ {
+ replace_it_with_var(node->call.callee, var_name);
+ ASTNode *arg = node->call.args;
+ while (arg)
+ {
+ replace_it_with_var(arg, var_name);
+ arg = arg->next;
+ }
+ }
+ else if (node->type == NODE_EXPR_MEMBER)
+ {
+ replace_it_with_var(node->member.target, var_name);
+ }
+ else if (node->type == NODE_EXPR_BINARY)
+ {
+ replace_it_with_var(node->binary.left, var_name);
+ replace_it_with_var(node->binary.right, var_name);
+ }
+ else if (node->type == NODE_EXPR_UNARY)
+ {
+ replace_it_with_var(node->unary.operand, var_name);
+ }
+ else if (node->type == NODE_BLOCK)
+ {
+ ASTNode *s = node->block.statements;
+ while (s)
+ {
+ replace_it_with_var(s, var_name);
+ s = s->next;
+ }
+ }
+}
+
+ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
+{
+ lexer_next(l); // eat 'var'
+
+ // Destructuring: var {x, y} = ...
+ if (lexer_peek(l).type == TOK_LBRACE || lexer_peek(l).type == TOK_LPAREN)
+ {
+ int is_struct = (lexer_peek(l).type == TOK_LBRACE);
+ lexer_next(l);
+ char **names = xmalloc(16 * sizeof(char *));
+ int count = 0;
+ while (1)
+ {
+ Token t = lexer_next(l);
+ char *nm = token_strdup(t);
+ // UPDATE: Pass NULL to add_symbol
+ names[count++] = nm;
+ add_symbol(ctx, nm, "unknown", NULL);
+ Token next = lexer_next(l);
+ if (next.type == (is_struct ? TOK_RBRACE : TOK_RPAREN))
+ {
+ break;
+ }
+ if (next.type != TOK_COMMA)
+ {
+ zpanic_at(next, "Expected comma");
+ }
+ }
+ if (lexer_next(l).type != TOK_OP)
+ {
+ zpanic_at(lexer_peek(l), "Expected =");
+ }
+ ASTNode *init = parse_expression(ctx, l);
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+ ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
+ n->destruct.names = names;
+ n->destruct.count = count;
+ n->destruct.init_expr = init;
+ n->destruct.is_struct_destruct = is_struct;
+ return n;
+ }
+
+ // Normal Declaration OR Named Struct Destructuring
+ Token name_tok = lexer_next(l);
+ char *name = token_strdup(name_tok);
+
+ // Check for Struct Destructuring: var Point { x, y }
+ if (lexer_peek(l).type == TOK_LBRACE)
+ {
+ lexer_next(l); // eat {
+ char **names = xmalloc(16 * sizeof(char *));
+ char **fields = xmalloc(16 * sizeof(char *));
+ int count = 0;
+
+ while (1)
+ {
+ // Parse field:name or just name
+ Token t = lexer_next(l);
+ char *ident = token_strdup(t);
+
+ if (lexer_peek(l).type == TOK_COLON)
+ {
+ // field: var_name
+ lexer_next(l); // eat :
+ Token v = lexer_next(l);
+ fields[count] = ident;
+ names[count] = token_strdup(v);
+ }
+ else
+ {
+ // Shorthand: field (implies var name = field)
+ fields[count] = ident;
+ names[count] = ident; // Share pointer or duplicate? duplicate safer if we free
+ }
+ // Register symbol for variable
+ add_symbol(ctx, names[count], "unknown", NULL);
+
+ count++;
+
+ Token next = lexer_next(l);
+ if (next.type == TOK_RBRACE)
+ {
+ break;
+ }
+ if (next.type != TOK_COMMA)
+ {
+ zpanic_at(next, "Expected comma in struct pattern");
+ }
+ }
+
+ if (lexer_next(l).type != TOK_OP)
+ {
+ zpanic_at(lexer_peek(l), "Expected =");
+ }
+ ASTNode *init = parse_expression(ctx, l);
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+
+ ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
+ n->destruct.names = names;
+ n->destruct.field_names = fields;
+ n->destruct.count = count;
+ n->destruct.init_expr = init;
+ n->destruct.is_struct_destruct = 1;
+ n->destruct.struct_name = name; // "Point"
+ return n;
+ }
+
+ // Check for Guard Pattern: var Some(val) = opt else { ... }
+ if (lexer_peek(l).type == TOK_LPAREN)
+ {
+ lexer_next(l); // eat (
+ Token val_tok = lexer_next(l);
+ char *val_name = token_strdup(val_tok);
+
+ if (lexer_next(l).type != TOK_RPAREN)
+ {
+ zpanic_at(lexer_peek(l), "Expected ')' in guard pattern");
+ }
+
+ if (lexer_next(l).type != TOK_OP)
+ {
+ zpanic_at(lexer_peek(l), "Expected '=' after guard pattern");
+ }
+
+ ASTNode *init = parse_expression(ctx, l);
+
+ Token t = lexer_next(l);
+ if (t.type != TOK_IDENT || strncmp(t.start, "else", 4) != 0)
+ {
+ zpanic_at(t, "Expected 'else' in guard statement");
+ }
+
+ ASTNode *else_blk;
+ if (lexer_peek(l).type == TOK_LBRACE)
+ {
+ else_blk = parse_block(ctx, l);
+ }
+ else
+ {
+ else_blk = ast_create(NODE_BLOCK);
+ else_blk->block.statements = parse_statement(ctx, l);
+ }
+
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+
+ ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
+ n->destruct.names = xmalloc(sizeof(char *));
+ n->destruct.names[0] = val_name;
+ n->destruct.count = 1;
+ n->destruct.init_expr = init;
+ n->destruct.is_guard = 1;
+ n->destruct.guard_variant = name;
+ n->destruct.else_block = else_blk;
+
+ add_symbol(ctx, val_name, "unknown", NULL);
+
+ return n;
+ }
+
+ char *type = NULL;
+ Type *type_obj = NULL; // --- NEW: Formal Type Object ---
+
+ if (lexer_peek(l).type == TOK_COLON)
+ {
+ lexer_next(l);
+ // Hybrid Parse: Get Object AND String
+ type_obj = parse_type_formal(ctx, l);
+ type = type_to_string(type_obj);
+ }
+
+ ASTNode *init = NULL;
+ if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "="))
+ {
+ lexer_next(l);
+
+ // Peek for special initializers
+ Token next = lexer_peek(l);
+ if (next.type == TOK_IDENT && strncmp(next.start, "embed", 5) == 0)
+ {
+ init = parse_embed(ctx, l);
+
+ if (!type && init->type_info)
+ {
+ type = type_to_string(init->type_info);
+ }
+ if (!type)
+ {
+ register_slice(ctx, "char");
+ type = xstrdup("Slice_char");
+ }
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+ }
+ else if (next.type == TOK_LBRACKET && type && strncmp(type, "Slice_", 6) == 0)
+ {
+ char *code = parse_array_literal(ctx, l, type);
+ init = ast_create(NODE_RAW_STMT);
+ init->raw_stmt.content = code;
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+ }
+ else if (next.type == TOK_LPAREN && type && strncmp(type, "Tuple_", 6) == 0)
+ {
+ char *code = parse_tuple_literal(ctx, l, type);
+ init = ast_create(NODE_RAW_STMT);
+ init->raw_stmt.content = code;
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+ }
+ else
+ {
+ init = parse_expression(ctx, l);
+ }
+
+ if (init && type)
+ {
+ char *rhs_type = init->resolved_type;
+ if (!rhs_type && init->type_info)
+ {
+ rhs_type = type_to_string(init->type_info);
+ }
+
+ if (rhs_type && strchr(type, '*') && strchr(rhs_type, '*'))
+ {
+ // Strip stars to get struct names
+ char target_struct[256];
+ strcpy(target_struct, type);
+ target_struct[strlen(target_struct) - 1] = 0;
+ char source_struct[256];
+ strcpy(source_struct, rhs_type);
+ source_struct[strlen(source_struct) - 1] = 0;
+
+ ASTNode *def = find_struct_def(ctx, source_struct);
+
+ if (def && def->strct.parent && strcmp(def->strct.parent, target_struct) == 0)
+ {
+ // Create Cast Node
+ ASTNode *cast = ast_create(NODE_EXPR_CAST);
+ cast->cast.target_type = xstrdup(type);
+ cast->cast.expr = init;
+ cast->type_info = type_obj; // Inherit formal type
+
+ init = cast; // Replace init with cast
+ }
+ }
+ }
+
+ // ** Type Inference Logic **
+ if (!type && init)
+ {
+ if (init->type_info)
+ {
+ type_obj = init->type_info;
+ type = type_to_string(type_obj);
+ }
+ else if (init->type == NODE_EXPR_SLICE)
+ {
+ zpanic_at(init->token, "Slice Node has NO Type Info!");
+ }
+ // Fallbacks for literals
+ else if (init->type == NODE_EXPR_LITERAL)
+ {
+ if (init->literal.type_kind == 0)
+ {
+ type = xstrdup("int");
+ type_obj = type_new(TYPE_INT);
+ }
+ else if (init->literal.type_kind == 1)
+ {
+ type = xstrdup("float");
+ type_obj = type_new(TYPE_FLOAT);
+ }
+ else if (init->literal.type_kind == 2)
+ {
+ type = xstrdup("string");
+ type_obj = type_new(TYPE_STRING);
+ }
+ }
+ else if (init->type == NODE_EXPR_STRUCT_INIT)
+ {
+ type = xstrdup(init->struct_init.struct_name);
+ type_obj = type_new(TYPE_STRUCT);
+ type_obj->name = xstrdup(type);
+ }
+ }
+ }
+
+ if (!type && !init)
+ {
+ zpanic_at(name_tok, "Variable '%s' requires a type or initializer", name);
+ }
+
+ // Register in symbol table with actual token
+ add_symbol_with_token(ctx, name, type, type_obj, name_tok);
+
+ // NEW: Capture Const Integer Values
+ if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == 0)
+ {
+ Symbol *s = find_symbol_entry(ctx, name); // Helper to find the struct
+ if (s)
+ {
+ s->is_const_value = 1;
+ s->const_int_val = init->literal.int_val;
+ }
+ }
+
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+
+ ASTNode *n = ast_create(NODE_VAR_DECL);
+ n->token = name_tok; // Save location
+ n->var_decl.name = name;
+ n->var_decl.type_str = type;
+ n->type_info = type_obj;
+
+ // Auto-construct Trait Object
+ if (type && is_trait(type) && init && init->type == NODE_EXPR_UNARY &&
+ strcmp(init->unary.op, "&") == 0 && init->unary.operand->type == NODE_EXPR_VAR)
+ {
+ char *var_ref_name = init->unary.operand->var_ref.name;
+ char *struct_type = find_symbol_type(ctx, var_ref_name);
+ if (struct_type)
+ {
+ char *code = xmalloc(512);
+ sprintf(code, "(%s){.self=&%s, .vtable=&%s_%s_VTable}", type, var_ref_name, struct_type,
+ type);
+ ASTNode *wrapper = ast_create(NODE_RAW_STMT);
+ wrapper->raw_stmt.content = code;
+ init = wrapper;
+ }
+ }
+
+ n->var_decl.init_expr = init;
+
+ // Move Semantics Logic for Initialization
+ check_move_usage(ctx, init, init ? init->token : name_tok);
+ if (init && init->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, init->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+ if (!is_type_copy(ctx, t))
+ {
+ Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
+ // Global detection: Either no scope (yet) OR root scope (no parent)
+ if (!ctx->current_scope || !ctx->current_scope->parent)
+ {
+ add_to_global_list(ctx, n);
+ }
+
+ // Check for 'defer' (Value-Returning Defer)
+ // Only capture if it is NOT a block defer (defer { ... })
+ // If it is a block defer, we leave it for the next parse_statement call.
+ if (lexer_peek(l).type == TOK_DEFER)
+ {
+ Lexer lookahead = *l;
+ lexer_next(&lookahead); // Eat defer
+ if (lexer_peek(&lookahead).type != TOK_LBRACE)
+ {
+ // Proceed to consume
+ lexer_next(l); // eat defer (real)
+
+ // Parse the defer expression/statement
+ // Usually defer close(it);
+ // We parse expression.
+ ASTNode *expr = parse_expression(ctx, l);
+
+ // Handle "it" substitution
+ replace_it_with_var(expr, name);
+
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+
+ ASTNode *d = ast_create(NODE_DEFER);
+ d->defer_stmt.stmt = expr;
+
+ // Chain it: var_decl -> defer
+ n->next = d;
+ }
+ }
+
+ return n;
+}
+
+ASTNode *parse_const(ParserContext *ctx, Lexer *l)
+{
+ lexer_next(l); // eat const
+ Token n = lexer_next(l);
+
+ char *type_str = NULL;
+ Type *type_obj = NULL;
+
+ if (lexer_peek(l).type == TOK_COLON)
+ {
+ lexer_next(l);
+ // Hybrid Parse
+ type_obj = parse_type_formal(ctx, l);
+ type_str = type_to_string(type_obj);
+ }
+
+ char *ns = token_strdup(n);
+ if (!type_obj)
+ {
+ type_obj = type_new(TYPE_UNKNOWN); // Ensure we have an object
+ }
+ type_obj->is_const = 1;
+ add_symbol(ctx, ns, type_str ? type_str : "unknown", type_obj);
+
+ ASTNode *i = 0;
+ if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "="))
+ {
+ lexer_next(l);
+
+ // Check for constant integer literal
+ if (lexer_peek(l).type == TOK_INT)
+ {
+ Token val_tok = lexer_peek(l);
+ int val = atoi(token_strdup(val_tok)); // quick check
+
+ Symbol *s = find_symbol_entry(ctx, ns);
+ if (s)
+ {
+ s->is_const_value = 1;
+ s->const_int_val = val;
+
+ if (!s->type_name || strcmp(s->type_name, "unknown") == 0)
+ {
+ if (s->type_name)
+ {
+ free(s->type_name);
+ }
+ s->type_name = xstrdup("int");
+ if (s->type_info)
+ {
+ free(s->type_info);
+ }
+ s->type_info = type_new(TYPE_INT);
+ }
+ }
+ }
+
+ if (lexer_peek(l).type == TOK_LPAREN && type_str && strncmp(type_str, "Tuple_", 6) == 0)
+ {
+ char *code = parse_tuple_literal(ctx, l, type_str);
+ i = ast_create(NODE_RAW_STMT);
+ i->raw_stmt.content = code;
+ }
+ else
+ {
+ i = parse_expression(ctx, l);
+ }
+ }
+ else
+ {
+ lexer_next(l);
+ }
+
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ }
+
+ ASTNode *o = ast_create(NODE_CONST);
+ o->var_decl.name = ns;
+ o->var_decl.type_str = type_str;
+ o->var_decl.init_expr = i;
+
+ if (!ctx->current_scope || !ctx->current_scope->parent)
+ {
+ add_to_global_list(ctx, o);
+ }
+
+ return o;
+}
+
+ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l)
+{
+ lexer_next(l); // consume 'type' or 'alias'
+ Token n = lexer_next(l);
+ if (n.type != TOK_IDENT)
+ {
+ zpanic_at(n, "Expected identifier for type alias");
+ }
+
+ lexer_next(l); // consume '='
+
+ char *o = parse_type(ctx, l);
+
+ lexer_next(l); // consume ';' (parse_type doesn't consume it? parse_type calls parse_type_formal
+ // which doesn't consume ;?)
+ // Note: parse_type_stmt usually expects ; but parse_type just parses type expression.
+ // Check previous implementation: it had lexer_next(l) at end. This assumes ;.
+
+ ASTNode *node = ast_create(NODE_TYPE_ALIAS);
+ node->type_alias.alias = xmalloc(n.len + 1);
+ strncpy(node->type_alias.alias, n.start, n.len);
+ node->type_alias.alias[n.len] = 0;
+ node->type_alias.original_type = o;
+
+ register_type_alias(ctx, node->type_alias.alias, o);
+
+ return node;
+}
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 67045ea..5eefb81 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -12,7 +12,7 @@
#include "zprep_plugin.h"
#include "../codegen/codegen.h"
-static char *curr_func_ret = NULL;
+char *curr_func_ret = NULL;
char *run_comptime_block(ParserContext *ctx, Lexer *l);
static void check_assignment_condition(ASTNode *cond)
@@ -31,211 +31,6 @@ static void check_assignment_condition(ASTNode *cond)
}
}
-ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
-{
- lexer_next(l); // eat 'fn'
- Token name_tok = lexer_next(l);
- char *name = token_strdup(name_tok);
-
- if (is_async)
- {
- ctx->has_async = 1;
- }
-
- // Check for C reserved word conflict
- if (is_c_reserved_word(name))
- {
- warn_c_reserved_word(name_tok, name);
- }
-
- char *gen_param = NULL;
- if (lexer_peek(l).type == TOK_LANGLE)
- {
- lexer_next(l); // eat <
-
- char buf[1024];
- buf[0] = 0;
-
- while (1)
- {
- Token gt = lexer_next(l);
- if (gt.type != TOK_IDENT)
- {
- zpanic_at(gt, "Expected generic parameter name");
- }
- char *s = token_strdup(gt);
-
- if (strlen(buf) + strlen(s) + 2 >= sizeof(buf))
- {
- zpanic_at(gt, "Too many generic parameters");
- }
-
- if (buf[0])
- {
- strcat(buf, ",");
- }
- strcat(buf, s);
- free(s);
-
- if (lexer_peek(l).type == TOK_COMMA)
- {
- lexer_next(l);
- continue;
- }
- break;
- }
-
- if (lexer_next(l).type != TOK_RANGLE)
- {
- zpanic_at(lexer_peek(l), "Expected >");
- }
- gen_param = xstrdup(buf);
- }
-
- // Register generic parameters so type parsing recognizes them
- int saved_generic_count = ctx->known_generics_count;
- if (gen_param)
- {
- char *tmp = xstrdup(gen_param);
- char *tok = strtok(tmp, ",");
- while (tok)
- {
- register_generic(ctx, tok);
- tok = strtok(NULL, ",");
- }
- free(tmp);
- }
-
- enter_scope(ctx);
- char **defaults;
- int count;
- Type **arg_types;
- char **param_names;
- int is_varargs = 0;
-
- char *args =
- parse_and_convert_args(ctx, l, &defaults, &count, &arg_types, &param_names, &is_varargs);
-
- char *ret = "void";
- Type *ret_type_obj = type_new(TYPE_VOID);
-
- if (strcmp(name, "main") == 0)
- {
- ret = "int";
- ret_type_obj = type_new(TYPE_INT);
- }
-
- if (lexer_peek(l).type == TOK_ARROW)
- {
- lexer_next(l);
- ret_type_obj = parse_type_formal(ctx, l);
- ret = type_to_string(ret_type_obj);
- }
-
- extern char *curr_func_ret;
- curr_func_ret = ret;
-
- // Auto-prefix function name if in module context
- // Don't prefix generic templates or functions inside impl blocks (already
- // mangled)
- if (ctx->current_module_prefix && !gen_param && !ctx->current_impl_struct)
- {
- char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
- sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name);
- free(name);
- name = prefixed_name;
- }
-
- // Register if concrete (Global functions only)
- if (!gen_param && !ctx->current_impl_struct)
- {
- register_func(ctx, name, count, defaults, arg_types, ret_type_obj, is_varargs, is_async,
- name_tok);
- // Note: must_use is set after return by caller (parser_core.c)
- }
-
- ASTNode *body = NULL;
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l); // consume ;
- }
- else
- {
- body = parse_block(ctx, l);
- }
-
- // Check for unused parameters
- // The current scope contains arguments (since parse_block creates a new child
- // scope for body) Only check if we parsed a body (not a prototype) function
- if (body && ctx->current_scope)
- {
- Symbol *sym = ctx->current_scope->symbols;
- while (sym)
- {
- // Check if unused and not prefixed with '_' (conventional ignore)
- // also ignore 'self' as it is often mandated by traits
- if (!sym->is_used && sym->name[0] != '_' && strcmp(sym->name, "self") != 0 &&
- strcmp(name, "main") != 0)
- {
- warn_unused_parameter(sym->decl_token, sym->name, name);
- }
- sym = sym->next;
- }
- }
-
- exit_scope(ctx);
-
- // Restore generic count to unregister function-scoped generics
- ctx->known_generics_count = saved_generic_count;
-
- curr_func_ret = NULL;
-
- ASTNode *node = ast_create(NODE_FUNCTION);
- node->token = name_tok; // Save definition location
- node->func.name = name;
- node->func.args = args;
- node->func.ret_type = ret;
- node->func.body = body;
-
- node->func.arg_types = arg_types;
- node->func.param_names = param_names;
- node->func.arg_count = count;
- node->func.defaults = defaults;
- node->func.ret_type_info = ret_type_obj;
- node->func.is_varargs = is_varargs;
-
- if (gen_param)
- {
- register_func_template(ctx, name, gen_param, node);
- return NULL;
- }
- if (!ctx->current_impl_struct)
- {
- add_to_func_list(ctx, node);
- }
- return node;
-}
-
-char *patch_self_args(const char *args, const char *struct_name)
-{
- if (!args)
- {
- return NULL;
- }
- char *new_args = xmalloc(strlen(args) + strlen(struct_name) + 10);
-
- // Check if it starts with "void* self"
- if (strncmp(args, "void* self", 10) == 0)
- {
- sprintf(new_args, "%s* self%s", struct_name, args + 10);
- }
- else
- {
- strcpy(new_args, args);
- }
- return new_args;
-}
-
ASTNode *parse_match(ParserContext *ctx, Lexer *l)
{
init_builtins();
@@ -956,591 +751,6 @@ ASTNode *parse_assert(ParserContext *ctx, Lexer *l)
return n;
}
-// Helper for Value-Returning Defer
-static void replace_it_with_var(ASTNode *node, char *var_name)
-{
- if (!node)
- {
- return;
- }
- if (node->type == NODE_EXPR_VAR)
- {
- if (strcmp(node->var_ref.name, "it") == 0)
- {
- // Replace 'it' with var_name
- node->var_ref.name = xstrdup(var_name);
- }
- }
- else if (node->type == NODE_EXPR_CALL)
- {
- replace_it_with_var(node->call.callee, var_name);
- ASTNode *arg = node->call.args;
- while (arg)
- {
- replace_it_with_var(arg, var_name);
- arg = arg->next;
- }
- }
- else if (node->type == NODE_EXPR_MEMBER)
- {
- replace_it_with_var(node->member.target, var_name);
- }
- else if (node->type == NODE_EXPR_BINARY)
- {
- replace_it_with_var(node->binary.left, var_name);
- replace_it_with_var(node->binary.right, var_name);
- }
- else if (node->type == NODE_EXPR_UNARY)
- {
- replace_it_with_var(node->unary.operand, var_name);
- }
- else if (node->type == NODE_BLOCK)
- {
- ASTNode *s = node->block.statements;
- while (s)
- {
- replace_it_with_var(s, var_name);
- s = s->next;
- }
- }
-}
-
-ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
-{
- lexer_next(l); // eat 'var'
-
- // Destructuring: var {x, y} = ...
- if (lexer_peek(l).type == TOK_LBRACE || lexer_peek(l).type == TOK_LPAREN)
- {
- int is_struct = (lexer_peek(l).type == TOK_LBRACE);
- lexer_next(l);
- char **names = xmalloc(16 * sizeof(char *));
- int count = 0;
- while (1)
- {
- Token t = lexer_next(l);
- char *nm = token_strdup(t);
- // UPDATE: Pass NULL to add_symbol
- names[count++] = nm;
- add_symbol(ctx, nm, "unknown", NULL);
- Token next = lexer_next(l);
- if (next.type == (is_struct ? TOK_RBRACE : TOK_RPAREN))
- {
- break;
- }
- if (next.type != TOK_COMMA)
- {
- zpanic_at(next, "Expected comma");
- }
- }
- if (lexer_next(l).type != TOK_OP)
- {
- zpanic_at(lexer_peek(l), "Expected =");
- }
- ASTNode *init = parse_expression(ctx, l);
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
- ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
- n->destruct.names = names;
- n->destruct.count = count;
- n->destruct.init_expr = init;
- n->destruct.is_struct_destruct = is_struct;
- return n;
- }
-
- // Normal Declaration OR Named Struct Destructuring
- Token name_tok = lexer_next(l);
- char *name = token_strdup(name_tok);
-
- // Check for Struct Destructuring: var Point { x, y }
- if (lexer_peek(l).type == TOK_LBRACE)
- {
- lexer_next(l); // eat {
- char **names = xmalloc(16 * sizeof(char *));
- char **fields = xmalloc(16 * sizeof(char *));
- int count = 0;
-
- while (1)
- {
- // Parse field:name or just name
- Token t = lexer_next(l);
- char *ident = token_strdup(t);
-
- if (lexer_peek(l).type == TOK_COLON)
- {
- // field: var_name
- lexer_next(l); // eat :
- Token v = lexer_next(l);
- fields[count] = ident;
- names[count] = token_strdup(v);
- }
- else
- {
- // Shorthand: field (implies var name = field)
- fields[count] = ident;
- names[count] = ident; // Share pointer or duplicate? duplicate safer if we free
- }
- // Register symbol for variable
- add_symbol(ctx, names[count], "unknown", NULL);
-
- count++;
-
- Token next = lexer_next(l);
- if (next.type == TOK_RBRACE)
- {
- break;
- }
- if (next.type != TOK_COMMA)
- {
- zpanic_at(next, "Expected comma in struct pattern");
- }
- }
-
- if (lexer_next(l).type != TOK_OP)
- {
- zpanic_at(lexer_peek(l), "Expected =");
- }
- ASTNode *init = parse_expression(ctx, l);
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
-
- ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
- n->destruct.names = names;
- n->destruct.field_names = fields;
- n->destruct.count = count;
- n->destruct.init_expr = init;
- n->destruct.is_struct_destruct = 1;
- n->destruct.struct_name = name; // "Point"
- return n;
- }
-
- // Check for Guard Pattern: var Some(val) = opt else { ... }
- if (lexer_peek(l).type == TOK_LPAREN)
- {
- lexer_next(l); // eat (
- Token val_tok = lexer_next(l);
- char *val_name = token_strdup(val_tok);
-
- if (lexer_next(l).type != TOK_RPAREN)
- {
- zpanic_at(lexer_peek(l), "Expected ')' in guard pattern");
- }
-
- if (lexer_next(l).type != TOK_OP)
- {
- zpanic_at(lexer_peek(l), "Expected '=' after guard pattern");
- }
-
- ASTNode *init = parse_expression(ctx, l);
-
- Token t = lexer_next(l);
- if (t.type != TOK_IDENT || strncmp(t.start, "else", 4) != 0)
- {
- zpanic_at(t, "Expected 'else' in guard statement");
- }
-
- ASTNode *else_blk;
- if (lexer_peek(l).type == TOK_LBRACE)
- {
- else_blk = parse_block(ctx, l);
- }
- else
- {
- else_blk = ast_create(NODE_BLOCK);
- else_blk->block.statements = parse_statement(ctx, l);
- }
-
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
-
- ASTNode *n = ast_create(NODE_DESTRUCT_VAR);
- n->destruct.names = xmalloc(sizeof(char *));
- n->destruct.names[0] = val_name;
- n->destruct.count = 1;
- n->destruct.init_expr = init;
- n->destruct.is_guard = 1;
- n->destruct.guard_variant = name;
- n->destruct.else_block = else_blk;
-
- add_symbol(ctx, val_name, "unknown", NULL);
-
- return n;
- }
-
- char *type = NULL;
- Type *type_obj = NULL; // --- NEW: Formal Type Object ---
-
- if (lexer_peek(l).type == TOK_COLON)
- {
- lexer_next(l);
- // Hybrid Parse: Get Object AND String
- type_obj = parse_type_formal(ctx, l);
- type = type_to_string(type_obj);
- }
-
- ASTNode *init = NULL;
- if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "="))
- {
- lexer_next(l);
-
- // Peek for special initializers
- Token next = lexer_peek(l);
- if (next.type == TOK_IDENT && strncmp(next.start, "embed", 5) == 0)
- {
- init = parse_embed(ctx, l);
-
- if (!type && init->type_info)
- {
- type = type_to_string(init->type_info);
- }
- if (!type)
- {
- register_slice(ctx, "char");
- type = xstrdup("Slice_char");
- }
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
- }
- else if (next.type == TOK_LBRACKET && type && strncmp(type, "Slice_", 6) == 0)
- {
- char *code = parse_array_literal(ctx, l, type);
- init = ast_create(NODE_RAW_STMT);
- init->raw_stmt.content = code;
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
- }
- else if (next.type == TOK_LPAREN && type && strncmp(type, "Tuple_", 6) == 0)
- {
- char *code = parse_tuple_literal(ctx, l, type);
- init = ast_create(NODE_RAW_STMT);
- init->raw_stmt.content = code;
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
- }
- else
- {
- init = parse_expression(ctx, l);
- }
-
- if (init && type)
- {
- char *rhs_type = init->resolved_type;
- if (!rhs_type && init->type_info)
- {
- rhs_type = type_to_string(init->type_info);
- }
-
- if (rhs_type && strchr(type, '*') && strchr(rhs_type, '*'))
- {
- // Strip stars to get struct names
- char target_struct[256];
- strcpy(target_struct, type);
- target_struct[strlen(target_struct) - 1] = 0;
- char source_struct[256];
- strcpy(source_struct, rhs_type);
- source_struct[strlen(source_struct) - 1] = 0;
-
- ASTNode *def = find_struct_def(ctx, source_struct);
-
- if (def && def->strct.parent && strcmp(def->strct.parent, target_struct) == 0)
- {
- // Create Cast Node
- ASTNode *cast = ast_create(NODE_EXPR_CAST);
- cast->cast.target_type = xstrdup(type);
- cast->cast.expr = init;
- cast->type_info = type_obj; // Inherit formal type
-
- init = cast; // Replace init with cast
- }
- }
- }
-
- // ** Type Inference Logic **
- if (!type && init)
- {
- if (init->type_info)
- {
- type_obj = init->type_info;
- type = type_to_string(type_obj);
- }
- else if (init->type == NODE_EXPR_SLICE)
- {
- zpanic_at(init->token, "Slice Node has NO Type Info!");
- }
- // Fallbacks for literals
- else if (init->type == NODE_EXPR_LITERAL)
- {
- if (init->literal.type_kind == 0)
- {
- type = xstrdup("int");
- type_obj = type_new(TYPE_INT);
- }
- else if (init->literal.type_kind == 1)
- {
- type = xstrdup("float");
- type_obj = type_new(TYPE_FLOAT);
- }
- else if (init->literal.type_kind == 2)
- {
- type = xstrdup("string");
- type_obj = type_new(TYPE_STRING);
- }
- }
- else if (init->type == NODE_EXPR_STRUCT_INIT)
- {
- type = xstrdup(init->struct_init.struct_name);
- type_obj = type_new(TYPE_STRUCT);
- type_obj->name = xstrdup(type);
- }
- }
- }
-
- if (!type && !init)
- {
- zpanic_at(name_tok, "Variable '%s' requires a type or initializer", name);
- }
-
- // Register in symbol table with actual token
- add_symbol_with_token(ctx, name, type, type_obj, name_tok);
-
- // NEW: Capture Const Integer Values
- if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == 0)
- {
- Symbol *s = find_symbol_entry(ctx, name); // Helper to find the struct
- if (s)
- {
- s->is_const_value = 1;
- s->const_int_val = init->literal.int_val;
- }
- }
-
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
-
- ASTNode *n = ast_create(NODE_VAR_DECL);
- n->token = name_tok; // Save location
- n->var_decl.name = name;
- n->var_decl.type_str = type;
- n->type_info = type_obj;
-
- // Auto-construct Trait Object
- if (type && is_trait(type) && init && init->type == NODE_EXPR_UNARY &&
- strcmp(init->unary.op, "&") == 0 && init->unary.operand->type == NODE_EXPR_VAR)
- {
- char *var_ref_name = init->unary.operand->var_ref.name;
- char *struct_type = find_symbol_type(ctx, var_ref_name);
- if (struct_type)
- {
- char *code = xmalloc(512);
- sprintf(code, "(%s){.self=&%s, .vtable=&%s_%s_VTable}", type, var_ref_name, struct_type,
- type);
- ASTNode *wrapper = ast_create(NODE_RAW_STMT);
- wrapper->raw_stmt.content = code;
- init = wrapper;
- }
- }
-
- n->var_decl.init_expr = init;
-
- // Move Semantics Logic for Initialization
- check_move_usage(ctx, init, init ? init->token : name_tok);
- if (init && init->type == NODE_EXPR_VAR)
- {
- Type *t = find_symbol_type_info(ctx, init->var_ref.name);
- if (!t)
- {
- Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
- if (s)
- {
- t = s->type_info;
- }
- }
- if (!is_type_copy(ctx, t))
- {
- Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
- if (s)
- {
- s->is_moved = 1;
- }
- }
- }
-
- // Global detection: Either no scope (yet) OR root scope (no parent)
- if (!ctx->current_scope || !ctx->current_scope->parent)
- {
- add_to_global_list(ctx, n);
- }
-
- // Check for 'defer' (Value-Returning Defer)
- // Only capture if it is NOT a block defer (defer { ... })
- // If it is a block defer, we leave it for the next parse_statement call.
- if (lexer_peek(l).type == TOK_DEFER)
- {
- Lexer lookahead = *l;
- lexer_next(&lookahead); // Eat defer
- if (lexer_peek(&lookahead).type != TOK_LBRACE)
- {
- // Proceed to consume
- lexer_next(l); // eat defer (real)
-
- // Parse the defer expression/statement
- // Usually defer close(it);
- // We parse expression.
- ASTNode *expr = parse_expression(ctx, l);
-
- // Handle "it" substitution
- replace_it_with_var(expr, name);
-
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
-
- ASTNode *d = ast_create(NODE_DEFER);
- d->defer_stmt.stmt = expr;
-
- // Chain it: var_decl -> defer
- n->next = d;
- }
- }
-
- return n;
-}
-
-ASTNode *parse_const(ParserContext *ctx, Lexer *l)
-{
- lexer_next(l); // eat const
- Token n = lexer_next(l);
-
- char *type_str = NULL;
- Type *type_obj = NULL;
-
- if (lexer_peek(l).type == TOK_COLON)
- {
- lexer_next(l);
- // Hybrid Parse
- type_obj = parse_type_formal(ctx, l);
- type_str = type_to_string(type_obj);
- }
-
- char *ns = token_strdup(n);
- if (!type_obj)
- {
- type_obj = type_new(TYPE_UNKNOWN); // Ensure we have an object
- }
- type_obj->is_const = 1;
- add_symbol(ctx, ns, type_str ? type_str : "unknown", type_obj);
-
- ASTNode *i = 0;
- if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "="))
- {
- lexer_next(l);
-
- // Check for constant integer literal
- if (lexer_peek(l).type == TOK_INT)
- {
- Token val_tok = lexer_peek(l);
- int val = atoi(token_strdup(val_tok)); // quick check
-
- Symbol *s = find_symbol_entry(ctx, ns);
- if (s)
- {
- s->is_const_value = 1;
- s->const_int_val = val;
-
- if (!s->type_name || strcmp(s->type_name, "unknown") == 0)
- {
- if (s->type_name)
- {
- free(s->type_name);
- }
- s->type_name = xstrdup("int");
- if (s->type_info)
- {
- free(s->type_info);
- }
- s->type_info = type_new(TYPE_INT);
- }
- }
- }
-
- if (lexer_peek(l).type == TOK_LPAREN && type_str && strncmp(type_str, "Tuple_", 6) == 0)
- {
- char *code = parse_tuple_literal(ctx, l, type_str);
- i = ast_create(NODE_RAW_STMT);
- i->raw_stmt.content = code;
- }
- else
- {
- i = parse_expression(ctx, l);
- }
- }
- else
- {
- lexer_next(l);
- }
-
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- }
-
- ASTNode *o = ast_create(NODE_CONST);
- o->var_decl.name = ns;
- o->var_decl.type_str = type_str;
- o->var_decl.init_expr = i;
-
- if (!ctx->current_scope || !ctx->current_scope->parent)
- {
- add_to_global_list(ctx, o);
- }
-
- return o;
-}
-
-ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l)
-{
- lexer_next(l); // consume 'type' or 'alias'
- Token n = lexer_next(l);
- if (n.type != TOK_IDENT)
- {
- zpanic_at(n, "Expected identifier for type alias");
- }
-
- lexer_next(l); // consume '='
-
- char *o = parse_type(ctx, l);
-
- lexer_next(l); // consume ';' (parse_type doesn't consume it? parse_type calls parse_type_formal
- // which doesn't consume ;?)
- // Note: parse_type_stmt usually expects ; but parse_type just parses type expression.
- // Check previous implementation: it had lexer_next(l) at end. This assumes ;.
-
- ASTNode *node = ast_create(NODE_TYPE_ALIAS);
- node->type_alias.alias = xmalloc(n.len + 1);
- strncpy(node->type_alias.alias, n.start, n.len);
- node->type_alias.alias[n.len] = 0;
- node->type_alias.original_type = o;
-
- register_type_alias(ctx, node->type_alias.alias, o);
-
- return node;
-}
-
ASTNode *parse_return(ParserContext *ctx, Lexer *l)
{
Token return_token = lexer_next(l); // eat 'return'
@@ -3294,935 +2504,6 @@ ASTNode *parse_block(ParserContext *ctx, Lexer *l)
return b;
}
-// Trait Parsing
-ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
-{
- lexer_next(l); // eat trait
- Token n = lexer_next(l);
- if (n.type != TOK_IDENT)
- {
- zpanic_at(n, "Expected trait name");
- }
- char *name = xmalloc(n.len + 1);
- strncpy(name, n.start, n.len);
- name[n.len] = 0;
-
- // Generics <T>
- char **generic_params = NULL;
- int generic_count = 0;
- if (lexer_peek(l).type == TOK_LANGLE)
- {
- lexer_next(l); // eat <
- generic_params = xmalloc(sizeof(char *) * 8); // simplified
- while (1)
- {
- Token p = lexer_next(l);
- if (p.type != TOK_IDENT)
- {
- zpanic_at(p, "Expected generic parameter name");
- }
- generic_params[generic_count] = xmalloc(p.len + 1);
- strncpy(generic_params[generic_count], p.start, p.len);
- generic_params[generic_count][p.len] = 0;
- generic_count++;
-
- Token sep = lexer_peek(l);
- if (sep.type == TOK_COMMA)
- {
- lexer_next(l);
- continue;
- }
- else if (sep.type == TOK_RANGLE)
- {
- lexer_next(l);
- break;
- }
- else
- {
- zpanic_at(sep, "Expected , or > in generic params");
- }
- }
- }
-
- if (generic_count > 0)
- {
- for (int i = 0; i < generic_count; i++)
- {
- register_generic(ctx, generic_params[i]);
- }
- }
-
- lexer_next(l); // eat {
-
- ASTNode *methods = NULL, *tail = NULL;
- while (1)
- {
- skip_comments(l);
- if (lexer_peek(l).type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
-
- // Parse method signature: fn name(args...) -> ret;
- Token ft = lexer_next(l);
- if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0)
- {
- zpanic_at(ft, "Expected fn in trait");
- }
-
- Token mn = lexer_next(l);
- char *mname = xmalloc(mn.len + 1);
- strncpy(mname, mn.start, mn.len);
- mname[mn.len] = 0;
-
- char **defaults = NULL;
- int arg_count = 0;
- Type **arg_types = NULL;
- char **param_names = NULL;
- int is_varargs = 0;
- char *args = parse_and_convert_args(ctx, l, &defaults, &arg_count, &arg_types, &param_names,
- &is_varargs);
-
- char *ret = xstrdup("void");
- if (lexer_peek(l).type == TOK_ARROW)
- {
- lexer_next(l);
- char *rt = parse_type(ctx, l);
- free(ret);
- ret = rt;
- }
-
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- ASTNode *m = ast_create(NODE_FUNCTION);
- m->func.param_names = param_names;
- m->func.name = mname;
- m->func.args = args;
- m->func.ret_type = ret;
- m->func.body = NULL;
- if (!methods)
- {
- methods = m;
- }
- else
- {
- tail->next = m;
- }
- tail = m;
- }
- else
- {
- // Default implementation? Not supported yet.
- zpanic_at(lexer_peek(l), "Trait methods must end with ; for now");
- }
- }
-
- ASTNode *n_node = ast_create(NODE_TRAIT);
- n_node->trait.name = name;
- n_node->trait.methods = methods;
- n_node->trait.generic_params = generic_params;
- n_node->trait.generic_param_count = generic_count;
- register_trait(name);
- return n_node;
-}
-
-ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
-{
-
- lexer_next(l); // eat impl
- Token t1 = lexer_next(l);
- char *name1 = token_strdup(t1);
-
- char *gen_param = NULL;
- // Check for <T> on the struct name
- if (lexer_peek(l).type == TOK_LANGLE)
- {
- lexer_next(l); // eat <
- Token gt = lexer_next(l);
- gen_param = token_strdup(gt);
- if (lexer_next(l).type != TOK_RANGLE)
- {
- zpanic_at(lexer_peek(l), "Expected >");
- }
- }
-
- // Check for "for" (Trait impl)
- Token pk = lexer_peek(l);
- if (pk.type == TOK_FOR ||
- (pk.type == TOK_IDENT && strncmp(pk.start, "for", 3) == 0 && pk.len == 3))
- {
- if (pk.type != TOK_FOR)
- {
- lexer_next(l);
- }
- else
- {
- lexer_next(l); // eat for
- }
- Token t2 = lexer_next(l);
- char *name2 = token_strdup(t2);
-
- register_impl(ctx, name1, name2);
-
- // RAII: Check for "Drop" trait implementation
- if (strcmp(name1, "Drop") == 0)
- {
- Symbol *s = find_symbol_entry(ctx, name2);
- if (s && s->type_info)
- {
- s->type_info->traits.has_drop = 1;
- }
- else
- {
- // Try finding struct definition
- ASTNode *def = find_struct_def(ctx, name2);
- if (def && def->type_info)
- {
- def->type_info->traits.has_drop = 1;
- }
- }
- }
-
- // Iterator: Check for "Iterable" trait implementation
- else if (strcmp(name1, "Iterable") == 0)
- {
- Symbol *s = find_symbol_entry(ctx, name2);
- if (s && s->type_info)
- {
- s->type_info->traits.has_iterable = 1;
- }
- else
- {
- // Try finding struct definition
- ASTNode *def = find_struct_def(ctx, name2);
- if (def && def->type_info)
- {
- def->type_info->traits.has_iterable = 1;
- }
- }
- }
-
- ctx->current_impl_struct = name2; // Set context to prevent duplicate emission and prefixing
-
- lexer_next(l); // eat {
- ASTNode *h = 0, *tl = 0;
- while (1)
- {
- skip_comments(l);
- if (lexer_peek(l).type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
- if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 0);
- // Mangle: Type_Trait_Method
- char *mangled = xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 4);
- sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
- char *na = patch_self_args(f->func.args, name2);
- free(f->func.args);
- f->func.args = na;
-
- // Register function for lookup
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types,
- f->func.ret_type_info, f->func.is_varargs, f->func.is_async,
- f->token);
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else if (lexer_peek(l).type == TOK_ASYNC)
- {
- lexer_next(l); // eat async
- if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 1);
- f->func.is_async = 1;
- // Mangle: Type_Trait_Method
- char *mangled =
- xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 5);
- sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
- char *na = patch_self_args(f->func.args, name2);
- free(f->func.args);
- f->func.args = na;
-
- // Register function for lookup
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
- f->func.is_async, f->token);
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else
- {
- zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
- }
- }
- else
- {
- lexer_next(l);
- }
- }
- ctx->current_impl_struct = NULL; // Restore context
- ASTNode *n = ast_create(NODE_IMPL_TRAIT);
- n->impl_trait.trait_name = name1;
- n->impl_trait.target_type = name2;
- n->impl_trait.methods = h;
- add_to_impl_list(ctx, n);
-
- // If target struct is generic, register this impl as a template
- ASTNode *def = find_struct_def(ctx, name2);
- if (def && ((def->type == NODE_STRUCT && def->strct.is_template) ||
- (def->type == NODE_ENUM && def->enm.is_template)))
- {
- const char *gp = "T";
- if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0)
- {
- gp = def->strct.generic_params[0];
- }
- // TODO: Enum generic params support if needed
- register_impl_template(ctx, name2, gp, n);
- }
-
- return n;
- }
- else
- {
- // Regular impl Struct (impl Box or impl Box<T>)
-
- // Auto-prefix struct name if in module context
- if (ctx->current_module_prefix && !gen_param)
- {
- char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name1) + 2);
- sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name1);
- free(name1);
- name1 = prefixed_name;
- }
-
- ctx->current_impl_struct = name1; // For patch_self_args inside parse_function
-
- if (gen_param)
- {
- // GENERIC IMPL TEMPLATE: impl Box<T>
- if (lexer_next(l).type != TOK_LBRACE)
- {
- zpanic_at(lexer_peek(l), "Expected {");
- }
- char *full_struct_name = xmalloc(strlen(name1) + strlen(gen_param) + 3);
- sprintf(full_struct_name, "%s<%s>", name1, gen_param);
-
- ASTNode *h = 0, *tl = 0;
- ctx->current_impl_methods = NULL;
- while (1)
- {
- ctx->current_impl_methods = h;
- skip_comments(l);
- if (lexer_peek(l).type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
- if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 0);
- // Standard Mangle for template: Box_method
- char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
- sprintf(mangled, "%s__%s", name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
-
- // Update args string
- char *na = patch_self_args(f->func.args, full_struct_name);
- free(f->func.args);
- f->func.args = na;
-
- // Manual Type construction for self: Foo<T>*
- if (f->func.arg_count > 0 && f->func.param_names &&
- strcmp(f->func.param_names[0], "self") == 0)
- {
- Type *t_struct = type_new(TYPE_STRUCT);
- t_struct->name = xstrdup(name1);
- t_struct->arg_count = 1;
- t_struct->args = xmalloc(sizeof(Type *));
- t_struct->args[0] = type_new(TYPE_GENERIC);
- t_struct->args[0]->name = xstrdup(gen_param);
-
- Type *t_ptr = type_new(TYPE_POINTER);
- t_ptr->inner = t_struct;
-
- f->func.arg_types[0] = t_ptr;
- }
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else if (lexer_peek(l).type == TOK_ASYNC)
- {
- lexer_next(l); // eat async
- if (lexer_peek(l).type == TOK_IDENT &&
- strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 1);
- f->func.is_async = 1;
- char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
- sprintf(mangled, "%s__%s", name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
-
- char *na = patch_self_args(f->func.args, full_struct_name);
- free(f->func.args);
- f->func.args = na;
-
- if (f->func.arg_count > 0 && f->func.param_names &&
- strcmp(f->func.param_names[0], "self") == 0)
- {
- Type *t_struct = type_new(TYPE_STRUCT);
- t_struct->name = xstrdup(name1);
- t_struct->arg_count = 1;
- t_struct->args = xmalloc(sizeof(Type *));
- t_struct->args[0] = type_new(TYPE_GENERIC);
- t_struct->args[0]->name = xstrdup(gen_param);
-
- Type *t_ptr = type_new(TYPE_POINTER);
- t_ptr->inner = t_struct;
-
- f->func.arg_types[0] = t_ptr;
- }
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else
- {
- zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
- }
- }
- else
- {
- lexer_next(l);
- }
- }
- free(full_struct_name);
- // Register Template
- ASTNode *n = ast_create(NODE_IMPL);
- n->impl.struct_name = name1;
- n->impl.methods = h;
- register_impl_template(ctx, name1, gen_param, n);
- ctx->current_impl_struct = NULL;
- return NULL; // Do not emit generic template
- }
- else
- {
- // REGULAR IMPL
- lexer_next(l); // eat {
- ASTNode *h = 0, *tl = 0;
- while (1)
- {
- skip_comments(l);
- if (lexer_peek(l).type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
- if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 0);
-
- // Standard Mangle: Struct_method
- char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
- sprintf(mangled, "%s__%s", name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
-
- char *na = patch_self_args(f->func.args, name1);
- free(f->func.args);
- f->func.args = na;
-
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 0,
- f->token);
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else if (lexer_peek(l).type == TOK_ASYNC)
- {
- lexer_next(l);
- if (lexer_peek(l).type == TOK_IDENT &&
- strncmp(lexer_peek(l).start, "fn", 2) == 0)
- {
- ASTNode *f = parse_function(ctx, l, 1);
- f->func.is_async = 1;
- char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
- sprintf(mangled, "%s__%s", name1, f->func.name);
- free(f->func.name);
- f->func.name = mangled;
- char *na = patch_self_args(f->func.args, name1);
- free(f->func.args);
- f->func.args = na;
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
- 1, f->token);
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
- }
- else
- {
- zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
- }
- }
- else
- {
- lexer_next(l);
- }
- }
- ctx->current_impl_struct = NULL;
- ASTNode *n = ast_create(NODE_IMPL);
- n->impl.struct_name = name1;
- n->impl.methods = h;
- add_to_impl_list(ctx, n);
- return n;
- }
- }
-}
-
-ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
-{
-
- lexer_next(l); // eat struct or union
- Token n = lexer_next(l);
- char *name = token_strdup(n);
-
- // Generic Params <T> or <K, V>
- char **gps = NULL;
- int gp_count = 0;
- if (lexer_peek(l).type == TOK_LANGLE)
- {
- lexer_next(l); // eat <
- while (1)
- {
- Token g = lexer_next(l);
- gps = realloc(gps, sizeof(char *) * (gp_count + 1));
- gps[gp_count++] = token_strdup(g);
-
- Token next = lexer_peek(l);
- if (next.type == TOK_COMMA)
- {
- lexer_next(l); // eat ,
- }
- else if (next.type == TOK_RANGLE)
- {
- lexer_next(l); // eat >
- break;
- }
- else
- {
- zpanic_at(next, "Expected ',' or '>' in generic parameter list");
- }
- }
- register_generic(ctx, name);
- }
-
- // Check for prototype (forward declaration)
- if (lexer_peek(l).type == TOK_SEMICOLON)
- {
- lexer_next(l);
- ASTNode *n = ast_create(NODE_STRUCT);
- n->strct.name = name;
- n->strct.is_template = (gp_count > 0);
- n->strct.generic_params = gps;
- n->strct.generic_param_count = gp_count;
- n->strct.is_union = is_union;
- n->strct.fields = NULL;
- n->strct.is_incomplete = 1;
-
- return n;
- }
-
- lexer_next(l); // eat {
- ASTNode *h = 0, *tl = 0;
-
- // Temp storage for used structs
- char **temp_used_structs = NULL;
- int temp_used_count = 0;
-
- while (1)
- {
- skip_comments(l);
- Token t = lexer_peek(l);
- // printf("DEBUG: parse_struct loop seeing '%.*s'\n", t.len, t.start);
- if (t.type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
- if (t.type == TOK_SEMICOLON || t.type == TOK_COMMA)
- {
- lexer_next(l);
- continue;
- }
-
- // Handle 'use' (Struct Embedding)
- if (t.type == TOK_USE)
- {
- lexer_next(l); // eat use
-
- // Check for named use: use name: Type;
- Token t1 = lexer_peek(l);
- Token t2 = lexer_peek2(l);
-
- if (t1.type == TOK_IDENT && t2.type == TOK_COLON)
- {
- // Named use -> Composition (Add field, don't flatten)
- Token field_name = lexer_next(l);
- lexer_next(l); // eat :
- char *field_type_str = parse_type(ctx, l);
- expect(l, TOK_SEMICOLON, "Expected ;");
-
- ASTNode *nf = ast_create(NODE_FIELD);
- nf->field.name = token_strdup(field_name);
- nf->field.type = field_type_str;
-
- if (!h)
- {
- h = nf;
- }
- else
- {
- tl->next = nf;
- }
- tl = nf;
- continue;
- }
-
- // Normal use -> Mixin (Flatten)
- // Parse the type (e.g. Header<I32>)
- Type *use_type = parse_type_formal(ctx, l);
- char *use_name = type_to_string(use_type);
-
- expect(l, TOK_SEMICOLON, "Expected ; after use");
-
- // Find the definition and COPY fields
- ASTNode *def = find_struct_def(ctx, use_name);
- if (!def && is_known_generic(ctx, use_type->name))
- {
- // Try to force instantiation if not found?
- // For now, rely on parse_type having triggered instantiation.
- char *mangled =
- type_to_string(use_type); // This works if type_to_string returns mangled name
- def = find_struct_def(ctx, mangled);
- free(mangled);
- }
-
- if (def && def->type == NODE_STRUCT)
- {
- if (!temp_used_structs)
- {
- temp_used_structs = xmalloc(sizeof(char *) * 8);
- }
- temp_used_structs[temp_used_count++] = xstrdup(use_name);
-
- ASTNode *f = def->strct.fields;
- while (f)
- {
- ASTNode *nf = ast_create(NODE_FIELD);
- nf->field.name = xstrdup(f->field.name);
- nf->field.type = xstrdup(f->field.type);
- if (!h)
- {
- h = nf;
- }
- else
- {
- tl->next = nf;
- }
- tl = nf;
- f = f->next;
- }
- }
- else
- {
- // If definition not found (e.g. user struct defined later), we can't
- // embed fields yet. Compiler limitation: 'use' requires struct to be
- // defined before. Fallback: Emit a placeholder field so compilation
- // doesn't crash, but layout will be wrong. printf("Warning: Could not
- // find struct '%s' for embedding.\n", use_name);
- }
- free(use_name);
- continue;
- }
- // ---------------------------------------
-
- if (t.type == TOK_IDENT)
- {
- Token f_name = lexer_next(l);
- expect(l, TOK_COLON, "Expected :");
- char *f_type = parse_type(ctx, l);
-
- ASTNode *f = ast_create(NODE_FIELD);
- f->field.name = token_strdup(f_name);
- f->field.type = f_type;
- f->field.bit_width = 0;
-
- // Optional bit width: name: type : 3
- if (lexer_peek(l).type == TOK_COLON)
- {
- lexer_next(l); // eat :
- Token width_tok = lexer_next(l);
- if (width_tok.type != TOK_INT)
- {
- zpanic_at(width_tok, "Expected bit width integer");
- }
- f->field.bit_width = atoi(token_strdup(width_tok));
- }
-
- if (!h)
- {
- h = f;
- }
- else
- {
- tl->next = f;
- }
- tl = f;
-
- if (lexer_peek(l).type == TOK_SEMICOLON || lexer_peek(l).type == TOK_COMMA)
- {
- lexer_next(l);
- }
- }
- else
- {
- lexer_next(l);
- }
- }
-
- ASTNode *node = ast_create(NODE_STRUCT);
- add_to_struct_list(ctx, node);
-
- // Auto-prefix struct name if in module context
- if (ctx->current_module_prefix && gp_count == 0)
- { // Don't prefix generic templates
- char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
- sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name);
- free(name);
- name = prefixed_name;
- }
-
- node->strct.name = name;
-
- // Initialize Type Info so we can track traits (like Drop)
- node->type_info = type_new(TYPE_STRUCT);
- node->type_info->name = xstrdup(name);
- if (gp_count > 0)
- {
- node->type_info->kind = TYPE_GENERIC;
- // TODO: track generic params
- }
-
- node->strct.fields = h;
- node->strct.generic_params = gps;
- node->strct.generic_param_count = gp_count;
- node->strct.is_union = is_union;
- node->strct.used_structs = temp_used_structs;
- node->strct.used_struct_count = temp_used_count;
-
- if (gp_count > 0)
- {
- node->strct.is_template = 1;
- register_template(ctx, name, node);
- }
-
- // Register definition for 'use' lookups and LSP
- if (gp_count == 0)
- {
- register_struct_def(ctx, name, node);
- }
-
- return node;
-}
-
-Type *parse_type_obj(ParserContext *ctx, Lexer *l)
-{
- // Parse the base type (int, U32, MyStruct, etc.)
- Type *t = parse_type_base(ctx, l);
-
- // Handle Pointers
- while (lexer_peek(l).type == TOK_OP && lexer_peek(l).start[0] == '*')
- {
- lexer_next(l); // eat *
- // Wrap the current type in a Pointer type
- Type *ptr = type_new(TYPE_POINTER);
- ptr->inner = t;
- t = ptr;
- }
-
- return t;
-}
-
-ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
-{
- lexer_next(l);
- Token n = lexer_next(l);
-
- // 1. Check for Generic <T>
- char *gp = NULL;
- if (lexer_peek(l).type == TOK_LANGLE)
- {
- lexer_next(l); // eat <
- Token g = lexer_next(l);
- gp = token_strdup(g);
- lexer_next(l); // eat >
- register_generic(ctx, n.start ? token_strdup(n) : "anon");
- }
-
- lexer_next(l); // eat {
-
- ASTNode *h = 0, *tl = 0;
- int v = 0;
- char *ename = token_strdup(n); // Store enum name
-
- while (1)
- {
- skip_comments(l);
- Token t = lexer_peek(l);
- if (t.type == TOK_RBRACE)
- {
- lexer_next(l);
- break;
- }
- if (t.type == TOK_COMMA)
- {
- lexer_next(l);
- continue;
- }
-
- if (t.type == TOK_IDENT)
- {
- Token vt = lexer_next(l);
- char *vname = token_strdup(vt);
-
- // 2. Parse Payload Type (Ok(int))
- Type *payload = NULL;
- if (lexer_peek(l).type == TOK_LPAREN)
- {
- lexer_next(l);
- payload = parse_type_obj(ctx, l);
- if (lexer_next(l).type != TOK_RPAREN)
- {
- zpanic_at(lexer_peek(l), "Expected )");
- }
- }
-
- ASTNode *va = ast_create(NODE_ENUM_VARIANT);
- va->variant.name = vname;
- va->variant.tag_id = v++; // Use tag_id instead of value
- va->variant.payload = payload; // Store Type*
-
- // Register Variant (Mangled name to avoid collisions: Result_Ok)
- char mangled[256];
- sprintf(mangled, "%s_%s", ename, vname);
- register_enum_variant(ctx, ename, mangled, va->variant.tag_id);
-
- // Handle explicit assignment: Ok = 5
- if (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '=')
- {
- lexer_next(l);
- va->variant.tag_id = atoi(lexer_next(l).start);
- v = va->variant.tag_id + 1;
- }
-
- if (!h)
- {
- h = va;
- }
- else
- {
- tl->next = va;
- }
- tl = va;
- }
- else
- {
- lexer_next(l);
- }
- }
-
- // Auto-prefix enum name if in module context
- if (ctx->current_module_prefix && !gp)
- { // Don't prefix generic templates
- char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(ename) + 2);
- sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, ename);
- free(ename);
- ename = prefixed_name;
- }
-
- ASTNode *node = ast_create(NODE_ENUM);
- node->enm.name = ename;
-
- node->enm.variants = h;
- node->enm.generic_param = gp; // 3. Store generic param
-
- if (gp)
- {
- node->enm.is_template = 1;
- register_template(ctx, node->enm.name, node);
- }
-
- add_to_enum_list(ctx, node); // Register globally
-
- return node;
-}
ASTNode *parse_include(ParserContext *ctx, Lexer *l)
{
lexer_next(l); // eat 'include'
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
new file mode 100644
index 0000000..600d60d
--- /dev/null
+++ b/src/parser/parser_struct.c
@@ -0,0 +1,943 @@
+
+#include "parser.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../ast/ast.h"
+#include "../plugins/plugin_manager.h"
+#include "../zen/zen_facts.h"
+#include "zprep_plugin.h"
+#include "../codegen/codegen.h"
+
+// Trait Parsing
+ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
+{
+ lexer_next(l); // eat trait
+ Token n = lexer_next(l);
+ if (n.type != TOK_IDENT)
+ {
+ zpanic_at(n, "Expected trait name");
+ }
+ char *name = xmalloc(n.len + 1);
+ strncpy(name, n.start, n.len);
+ name[n.len] = 0;
+
+ // Generics <T>
+ char **generic_params = NULL;
+ int generic_count = 0;
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ lexer_next(l); // eat <
+ generic_params = xmalloc(sizeof(char *) * 8); // simplified
+ while (1)
+ {
+ Token p = lexer_next(l);
+ if (p.type != TOK_IDENT)
+ {
+ zpanic_at(p, "Expected generic parameter name");
+ }
+ generic_params[generic_count] = xmalloc(p.len + 1);
+ strncpy(generic_params[generic_count], p.start, p.len);
+ generic_params[generic_count][p.len] = 0;
+ generic_count++;
+
+ Token sep = lexer_peek(l);
+ if (sep.type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+ else if (sep.type == TOK_RANGLE)
+ {
+ lexer_next(l);
+ break;
+ }
+ else
+ {
+ zpanic_at(sep, "Expected , or > in generic params");
+ }
+ }
+ }
+
+ if (generic_count > 0)
+ {
+ for (int i = 0; i < generic_count; i++)
+ {
+ register_generic(ctx, generic_params[i]);
+ }
+ }
+
+ lexer_next(l); // eat {
+
+ ASTNode *methods = NULL, *tail = NULL;
+ while (1)
+ {
+ skip_comments(l);
+ if (lexer_peek(l).type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+
+ // Parse method signature: fn name(args...) -> ret;
+ Token ft = lexer_next(l);
+ if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0)
+ {
+ zpanic_at(ft, "Expected fn in trait");
+ }
+
+ Token mn = lexer_next(l);
+ char *mname = xmalloc(mn.len + 1);
+ strncpy(mname, mn.start, mn.len);
+ mname[mn.len] = 0;
+
+ char **defaults = NULL;
+ int arg_count = 0;
+ Type **arg_types = NULL;
+ char **param_names = NULL;
+ int is_varargs = 0;
+ char *args = parse_and_convert_args(ctx, l, &defaults, &arg_count, &arg_types, &param_names,
+ &is_varargs);
+
+ char *ret = xstrdup("void");
+ if (lexer_peek(l).type == TOK_ARROW)
+ {
+ lexer_next(l);
+ char *rt = parse_type(ctx, l);
+ free(ret);
+ ret = rt;
+ }
+
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ ASTNode *m = ast_create(NODE_FUNCTION);
+ m->func.param_names = param_names;
+ m->func.name = mname;
+ m->func.args = args;
+ m->func.ret_type = ret;
+ m->func.body = NULL;
+ if (!methods)
+ {
+ methods = m;
+ }
+ else
+ {
+ tail->next = m;
+ }
+ tail = m;
+ }
+ else
+ {
+ // Default implementation? Not supported yet.
+ zpanic_at(lexer_peek(l), "Trait methods must end with ; for now");
+ }
+ }
+
+ ASTNode *n_node = ast_create(NODE_TRAIT);
+ n_node->trait.name = name;
+ n_node->trait.methods = methods;
+ n_node->trait.generic_params = generic_params;
+ n_node->trait.generic_param_count = generic_count;
+ register_trait(name);
+ return n_node;
+}
+
+ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
+{
+
+ lexer_next(l); // eat impl
+ Token t1 = lexer_next(l);
+ char *name1 = token_strdup(t1);
+
+ char *gen_param = NULL;
+ // Check for <T> on the struct name
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ lexer_next(l); // eat <
+ Token gt = lexer_next(l);
+ gen_param = token_strdup(gt);
+ if (lexer_next(l).type != TOK_RANGLE)
+ {
+ zpanic_at(lexer_peek(l), "Expected >");
+ }
+ }
+
+ // Check for "for" (Trait impl)
+ Token pk = lexer_peek(l);
+ if (pk.type == TOK_FOR ||
+ (pk.type == TOK_IDENT && strncmp(pk.start, "for", 3) == 0 && pk.len == 3))
+ {
+ if (pk.type != TOK_FOR)
+ {
+ lexer_next(l);
+ }
+ else
+ {
+ lexer_next(l); // eat for
+ }
+ Token t2 = lexer_next(l);
+ char *name2 = token_strdup(t2);
+
+ register_impl(ctx, name1, name2);
+
+ // RAII: Check for "Drop" trait implementation
+ if (strcmp(name1, "Drop") == 0)
+ {
+ Symbol *s = find_symbol_entry(ctx, name2);
+ if (s && s->type_info)
+ {
+ s->type_info->traits.has_drop = 1;
+ }
+ else
+ {
+ // Try finding struct definition
+ ASTNode *def = find_struct_def(ctx, name2);
+ if (def && def->type_info)
+ {
+ def->type_info->traits.has_drop = 1;
+ }
+ }
+ }
+
+ // Iterator: Check for "Iterable" trait implementation
+ else if (strcmp(name1, "Iterable") == 0)
+ {
+ Symbol *s = find_symbol_entry(ctx, name2);
+ if (s && s->type_info)
+ {
+ s->type_info->traits.has_iterable = 1;
+ }
+ else
+ {
+ // Try finding struct definition
+ ASTNode *def = find_struct_def(ctx, name2);
+ if (def && def->type_info)
+ {
+ def->type_info->traits.has_iterable = 1;
+ }
+ }
+ }
+
+ ctx->current_impl_struct = name2; // Set context to prevent duplicate emission and prefixing
+
+ lexer_next(l); // eat {
+ ASTNode *h = 0, *tl = 0;
+ while (1)
+ {
+ skip_comments(l);
+ if (lexer_peek(l).type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+ if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 0);
+ // Mangle: Type_Trait_Method
+ char *mangled = xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 4);
+ sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+ char *na = patch_self_args(f->func.args, name2);
+ free(f->func.args);
+ f->func.args = na;
+
+ // Register function for lookup
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types,
+ f->func.ret_type_info, f->func.is_varargs, f->func.is_async,
+ f->token);
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else if (lexer_peek(l).type == TOK_ASYNC)
+ {
+ lexer_next(l); // eat async
+ if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 1);
+ f->func.is_async = 1;
+ // Mangle: Type_Trait_Method
+ char *mangled =
+ xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 5);
+ sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+ char *na = patch_self_args(f->func.args, name2);
+ free(f->func.args);
+ f->func.args = na;
+
+ // Register function for lookup
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
+ f->func.is_async, f->token);
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else
+ {
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
+ }
+ }
+ else
+ {
+ lexer_next(l);
+ }
+ }
+ ctx->current_impl_struct = NULL; // Restore context
+ ASTNode *n = ast_create(NODE_IMPL_TRAIT);
+ n->impl_trait.trait_name = name1;
+ n->impl_trait.target_type = name2;
+ n->impl_trait.methods = h;
+ add_to_impl_list(ctx, n);
+
+ // If target struct is generic, register this impl as a template
+ ASTNode *def = find_struct_def(ctx, name2);
+ if (def && ((def->type == NODE_STRUCT && def->strct.is_template) ||
+ (def->type == NODE_ENUM && def->enm.is_template)))
+ {
+ const char *gp = "T";
+ if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0)
+ {
+ gp = def->strct.generic_params[0];
+ }
+ // TODO: Enum generic params support if needed
+ register_impl_template(ctx, name2, gp, n);
+ }
+
+ return n;
+ }
+ else
+ {
+ // Regular impl Struct (impl Box or impl Box<T>)
+
+ // Auto-prefix struct name if in module context
+ if (ctx->current_module_prefix && !gen_param)
+ {
+ char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name1) + 2);
+ sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name1);
+ free(name1);
+ name1 = prefixed_name;
+ }
+
+ ctx->current_impl_struct = name1; // For patch_self_args inside parse_function
+
+ if (gen_param)
+ {
+ // GENERIC IMPL TEMPLATE: impl Box<T>
+ if (lexer_next(l).type != TOK_LBRACE)
+ {
+ zpanic_at(lexer_peek(l), "Expected {");
+ }
+ char *full_struct_name = xmalloc(strlen(name1) + strlen(gen_param) + 3);
+ sprintf(full_struct_name, "%s<%s>", name1, gen_param);
+
+ ASTNode *h = 0, *tl = 0;
+ ctx->current_impl_methods = NULL;
+ while (1)
+ {
+ ctx->current_impl_methods = h;
+ skip_comments(l);
+ if (lexer_peek(l).type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+ if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 0);
+ // Standard Mangle for template: Box_method
+ char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
+ sprintf(mangled, "%s__%s", name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+
+ // Update args string
+ char *na = patch_self_args(f->func.args, full_struct_name);
+ free(f->func.args);
+ f->func.args = na;
+
+ // Manual Type construction for self: Foo<T>*
+ if (f->func.arg_count > 0 && f->func.param_names &&
+ strcmp(f->func.param_names[0], "self") == 0)
+ {
+ Type *t_struct = type_new(TYPE_STRUCT);
+ t_struct->name = xstrdup(name1);
+ t_struct->arg_count = 1;
+ t_struct->args = xmalloc(sizeof(Type *));
+ t_struct->args[0] = type_new(TYPE_GENERIC);
+ t_struct->args[0]->name = xstrdup(gen_param);
+
+ Type *t_ptr = type_new(TYPE_POINTER);
+ t_ptr->inner = t_struct;
+
+ f->func.arg_types[0] = t_ptr;
+ }
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else if (lexer_peek(l).type == TOK_ASYNC)
+ {
+ lexer_next(l); // eat async
+ if (lexer_peek(l).type == TOK_IDENT &&
+ strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 1);
+ f->func.is_async = 1;
+ char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
+ sprintf(mangled, "%s__%s", name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+
+ char *na = patch_self_args(f->func.args, full_struct_name);
+ free(f->func.args);
+ f->func.args = na;
+
+ if (f->func.arg_count > 0 && f->func.param_names &&
+ strcmp(f->func.param_names[0], "self") == 0)
+ {
+ Type *t_struct = type_new(TYPE_STRUCT);
+ t_struct->name = xstrdup(name1);
+ t_struct->arg_count = 1;
+ t_struct->args = xmalloc(sizeof(Type *));
+ t_struct->args[0] = type_new(TYPE_GENERIC);
+ t_struct->args[0]->name = xstrdup(gen_param);
+
+ Type *t_ptr = type_new(TYPE_POINTER);
+ t_ptr->inner = t_struct;
+
+ f->func.arg_types[0] = t_ptr;
+ }
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else
+ {
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
+ }
+ }
+ else
+ {
+ lexer_next(l);
+ }
+ }
+ free(full_struct_name);
+ // Register Template
+ ASTNode *n = ast_create(NODE_IMPL);
+ n->impl.struct_name = name1;
+ n->impl.methods = h;
+ register_impl_template(ctx, name1, gen_param, n);
+ ctx->current_impl_struct = NULL;
+ return NULL; // Do not emit generic template
+ }
+ else
+ {
+ // REGULAR IMPL
+ lexer_next(l); // eat {
+ ASTNode *h = 0, *tl = 0;
+ while (1)
+ {
+ skip_comments(l);
+ if (lexer_peek(l).type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+ if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 0);
+
+ // Standard Mangle: Struct_method
+ char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
+ sprintf(mangled, "%s__%s", name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+
+ char *na = patch_self_args(f->func.args, name1);
+ free(f->func.args);
+ f->func.args = na;
+
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 0,
+ f->token);
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else if (lexer_peek(l).type == TOK_ASYNC)
+ {
+ lexer_next(l);
+ if (lexer_peek(l).type == TOK_IDENT &&
+ strncmp(lexer_peek(l).start, "fn", 2) == 0)
+ {
+ ASTNode *f = parse_function(ctx, l, 1);
+ f->func.is_async = 1;
+ char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3);
+ sprintf(mangled, "%s__%s", name1, f->func.name);
+ free(f->func.name);
+ f->func.name = mangled;
+ char *na = patch_self_args(f->func.args, name1);
+ free(f->func.args);
+ f->func.args = na;
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
+ 1, f->token);
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+ }
+ else
+ {
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
+ }
+ }
+ else
+ {
+ lexer_next(l);
+ }
+ }
+ ctx->current_impl_struct = NULL;
+ ASTNode *n = ast_create(NODE_IMPL);
+ n->impl.struct_name = name1;
+ n->impl.methods = h;
+ add_to_impl_list(ctx, n);
+ return n;
+ }
+ }
+}
+
+ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
+{
+
+ lexer_next(l); // eat struct or union
+ Token n = lexer_next(l);
+ char *name = token_strdup(n);
+
+ // Generic Params <T> or <K, V>
+ char **gps = NULL;
+ int gp_count = 0;
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ lexer_next(l); // eat <
+ while (1)
+ {
+ Token g = lexer_next(l);
+ gps = realloc(gps, sizeof(char *) * (gp_count + 1));
+ gps[gp_count++] = token_strdup(g);
+
+ Token next = lexer_peek(l);
+ if (next.type == TOK_COMMA)
+ {
+ lexer_next(l); // eat ,
+ }
+ else if (next.type == TOK_RANGLE)
+ {
+ lexer_next(l); // eat >
+ break;
+ }
+ else
+ {
+ zpanic_at(next, "Expected ',' or '>' in generic parameter list");
+ }
+ }
+ register_generic(ctx, name);
+ }
+
+ // Check for prototype (forward declaration)
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ ASTNode *n = ast_create(NODE_STRUCT);
+ n->strct.name = name;
+ n->strct.is_template = (gp_count > 0);
+ n->strct.generic_params = gps;
+ n->strct.generic_param_count = gp_count;
+ n->strct.is_union = is_union;
+ n->strct.fields = NULL;
+ n->strct.is_incomplete = 1;
+
+ return n;
+ }
+
+ lexer_next(l); // eat {
+ ASTNode *h = 0, *tl = 0;
+
+ // Temp storage for used structs
+ char **temp_used_structs = NULL;
+ int temp_used_count = 0;
+
+ while (1)
+ {
+ skip_comments(l);
+ Token t = lexer_peek(l);
+ // printf("DEBUG: parse_struct loop seeing '%.*s'\n", t.len, t.start);
+ if (t.type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+ if (t.type == TOK_SEMICOLON || t.type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+
+ // Handle 'use' (Struct Embedding)
+ if (t.type == TOK_USE)
+ {
+ lexer_next(l); // eat use
+
+ // Check for named use: use name: Type;
+ Token t1 = lexer_peek(l);
+ Token t2 = lexer_peek2(l);
+
+ if (t1.type == TOK_IDENT && t2.type == TOK_COLON)
+ {
+ // Named use -> Composition (Add field, don't flatten)
+ Token field_name = lexer_next(l);
+ lexer_next(l); // eat :
+ char *field_type_str = parse_type(ctx, l);
+ expect(l, TOK_SEMICOLON, "Expected ;");
+
+ ASTNode *nf = ast_create(NODE_FIELD);
+ nf->field.name = token_strdup(field_name);
+ nf->field.type = field_type_str;
+
+ if (!h)
+ {
+ h = nf;
+ }
+ else
+ {
+ tl->next = nf;
+ }
+ tl = nf;
+ continue;
+ }
+
+ // Normal use -> Mixin (Flatten)
+ // Parse the type (e.g. Header<I32>)
+ Type *use_type = parse_type_formal(ctx, l);
+ char *use_name = type_to_string(use_type);
+
+ expect(l, TOK_SEMICOLON, "Expected ; after use");
+
+ // Find the definition and COPY fields
+ ASTNode *def = find_struct_def(ctx, use_name);
+ if (!def && is_known_generic(ctx, use_type->name))
+ {
+ // Try to force instantiation if not found?
+ // For now, rely on parse_type having triggered instantiation.
+ char *mangled =
+ type_to_string(use_type); // This works if type_to_string returns mangled name
+ def = find_struct_def(ctx, mangled);
+ free(mangled);
+ }
+
+ if (def && def->type == NODE_STRUCT)
+ {
+ if (!temp_used_structs)
+ {
+ temp_used_structs = xmalloc(sizeof(char *) * 8);
+ }
+ temp_used_structs[temp_used_count++] = xstrdup(use_name);
+
+ ASTNode *f = def->strct.fields;
+ while (f)
+ {
+ ASTNode *nf = ast_create(NODE_FIELD);
+ nf->field.name = xstrdup(f->field.name);
+ nf->field.type = xstrdup(f->field.type);
+ if (!h)
+ {
+ h = nf;
+ }
+ else
+ {
+ tl->next = nf;
+ }
+ tl = nf;
+ f = f->next;
+ }
+ }
+ else
+ {
+ // If definition not found (e.g. user struct defined later), we can't
+ // embed fields yet. Compiler limitation: 'use' requires struct to be
+ // defined before. Fallback: Emit a placeholder field so compilation
+ // doesn't crash, but layout will be wrong. printf("Warning: Could not
+ // find struct '%s' for embedding.\n", use_name);
+ }
+ free(use_name);
+ continue;
+ }
+ // ---------------------------------------
+
+ if (t.type == TOK_IDENT)
+ {
+ Token f_name = lexer_next(l);
+ expect(l, TOK_COLON, "Expected :");
+ char *f_type = parse_type(ctx, l);
+
+ ASTNode *f = ast_create(NODE_FIELD);
+ f->field.name = token_strdup(f_name);
+ f->field.type = f_type;
+ f->field.bit_width = 0;
+
+ // Optional bit width: name: type : 3
+ if (lexer_peek(l).type == TOK_COLON)
+ {
+ lexer_next(l); // eat :
+ Token width_tok = lexer_next(l);
+ if (width_tok.type != TOK_INT)
+ {
+ zpanic_at(width_tok, "Expected bit width integer");
+ }
+ f->field.bit_width = atoi(token_strdup(width_tok));
+ }
+
+ if (!h)
+ {
+ h = f;
+ }
+ else
+ {
+ tl->next = f;
+ }
+ tl = f;
+
+ if (lexer_peek(l).type == TOK_SEMICOLON || lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ }
+ }
+ else
+ {
+ lexer_next(l);
+ }
+ }
+
+ ASTNode *node = ast_create(NODE_STRUCT);
+ add_to_struct_list(ctx, node);
+
+ // Auto-prefix struct name if in module context
+ if (ctx->current_module_prefix && gp_count == 0)
+ { // Don't prefix generic templates
+ char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
+ sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name);
+ free(name);
+ name = prefixed_name;
+ }
+
+ node->strct.name = name;
+
+ // Initialize Type Info so we can track traits (like Drop)
+ node->type_info = type_new(TYPE_STRUCT);
+ node->type_info->name = xstrdup(name);
+ if (gp_count > 0)
+ {
+ node->type_info->kind = TYPE_GENERIC;
+ // TODO: track generic params
+ }
+
+ node->strct.fields = h;
+ node->strct.generic_params = gps;
+ node->strct.generic_param_count = gp_count;
+ node->strct.is_union = is_union;
+ node->strct.used_structs = temp_used_structs;
+ node->strct.used_struct_count = temp_used_count;
+
+ if (gp_count > 0)
+ {
+ node->strct.is_template = 1;
+ register_template(ctx, name, node);
+ }
+
+ // Register definition for 'use' lookups and LSP
+ if (gp_count == 0)
+ {
+ register_struct_def(ctx, name, node);
+ }
+
+ return node;
+}
+
+Type *parse_type_obj(ParserContext *ctx, Lexer *l)
+{
+ // Parse the base type (int, U32, MyStruct, etc.)
+ Type *t = parse_type_base(ctx, l);
+
+ // Handle Pointers
+ while (lexer_peek(l).type == TOK_OP && lexer_peek(l).start[0] == '*')
+ {
+ lexer_next(l); // eat *
+ // Wrap the current type in a Pointer type
+ Type *ptr = type_new(TYPE_POINTER);
+ ptr->inner = t;
+ t = ptr;
+ }
+
+ return t;
+}
+
+ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
+{
+ lexer_next(l);
+ Token n = lexer_next(l);
+
+ // 1. Check for Generic <T>
+ char *gp = NULL;
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ lexer_next(l); // eat <
+ Token g = lexer_next(l);
+ gp = token_strdup(g);
+ lexer_next(l); // eat >
+ register_generic(ctx, n.start ? token_strdup(n) : "anon");
+ }
+
+ lexer_next(l); // eat {
+
+ ASTNode *h = 0, *tl = 0;
+ int v = 0;
+ char *ename = token_strdup(n); // Store enum name
+
+ while (1)
+ {
+ skip_comments(l);
+ Token t = lexer_peek(l);
+ if (t.type == TOK_RBRACE)
+ {
+ lexer_next(l);
+ break;
+ }
+ if (t.type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+
+ if (t.type == TOK_IDENT)
+ {
+ Token vt = lexer_next(l);
+ char *vname = token_strdup(vt);
+
+ // 2. Parse Payload Type (Ok(int))
+ Type *payload = NULL;
+ if (lexer_peek(l).type == TOK_LPAREN)
+ {
+ lexer_next(l);
+ payload = parse_type_obj(ctx, l);
+ if (lexer_next(l).type != TOK_RPAREN)
+ {
+ zpanic_at(lexer_peek(l), "Expected )");
+ }
+ }
+
+ ASTNode *va = ast_create(NODE_ENUM_VARIANT);
+ va->variant.name = vname;
+ va->variant.tag_id = v++; // Use tag_id instead of value
+ va->variant.payload = payload; // Store Type*
+
+ // Register Variant (Mangled name to avoid collisions: Result_Ok)
+ char mangled[256];
+ sprintf(mangled, "%s_%s", ename, vname);
+ register_enum_variant(ctx, ename, mangled, va->variant.tag_id);
+
+ // Handle explicit assignment: Ok = 5
+ if (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '=')
+ {
+ lexer_next(l);
+ va->variant.tag_id = atoi(lexer_next(l).start);
+ v = va->variant.tag_id + 1;
+ }
+
+ if (!h)
+ {
+ h = va;
+ }
+ else
+ {
+ tl->next = va;
+ }
+ tl = va;
+ }
+ else
+ {
+ lexer_next(l);
+ }
+ }
+
+ // Auto-prefix enum name if in module context
+ if (ctx->current_module_prefix && !gp)
+ { // Don't prefix generic templates
+ char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(ename) + 2);
+ sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, ename);
+ free(ename);
+ ename = prefixed_name;
+ }
+
+ ASTNode *node = ast_create(NODE_ENUM);
+ node->enm.name = ename;
+
+ node->enm.variants = h;
+ node->enm.generic_param = gp; // 3. Store generic param
+
+ if (gp)
+ {
+ node->enm.is_template = 1;
+ register_template(ctx, node->enm.name, node);
+ }
+
+ add_to_enum_list(ctx, node); // Register globally
+
+ return node;
+}