diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/codegen.c | 3531 | ||||
| -rw-r--r-- | src/codegen/codegen.h | 6 | ||||
| -rw-r--r-- | src/codegen/codegen_decl.c | 1519 | ||||
| -rw-r--r-- | src/codegen/codegen_main.c | 902 | ||||
| -rw-r--r-- | src/codegen/codegen_utils.c | 782 |
5 files changed, 2989 insertions, 3751 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 86295e4..e3e1ac6 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -20,2073 +20,1652 @@ // 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); +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, "({ "); + emit_auto_type(ctx, node->match_stmt.expr, node->token, out); + fprintf(out, " _m_%d = ", id); + if (is_self) { + fprintf(out, "*("); + } + codegen_expression(ctx, node->match_stmt.expr, out); + if (is_self) { + fprintf(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; + } + } - fprintf(out, "({ "); - emit_auto_type(ctx, node->match_stmt.expr, node->token, out); - fprintf(out, " _m_%d = ", id); - if (is_self) - { - fprintf(out, "*("); + ASTNode *c = node->match_stmt.cases; + int first = 1; + while (c) { + if (!first) { + fprintf(out, " else "); } - codegen_expression(ctx, node->match_stmt.expr, out); - if (is_self) - { - fprintf(out, ")"); + 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 { + EnumVariantReg *reg = find_enum_variant(ctx, c->match_case.pattern); + if (reg) { + fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); + } else if (c->match_case.pattern[0] == '"') { + fprintf(out, "strcmp(_m_%d, %s) == 0", id, c->match_case.pattern); + } else if (isdigit(c->match_case.pattern[0]) || + c->match_case.pattern[0] == '-') { + // Numeric pattern + fprintf(out, "_m_%d == %s", id, c->match_case.pattern); + } else if (c->match_case.pattern[0] == '\'') { + // Char literal pattern + fprintf(out, "_m_%d == %s", id, c->match_case.pattern); + } else { + fprintf(out, "1"); + } + } + fprintf(out, ") { "); + if (c->match_case.binding_name) { + if (is_option) { + if (strstr(g_config.cc, "tcc")) { + fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, + c->match_case.binding_name, id); + } else { + fprintf(out, "__auto_type %s = _m_%d.val; ", + c->match_case.binding_name, id); + } + } + if (is_result) { + if (strcmp(c->match_case.pattern, "Ok") == 0) { + if (strstr(g_config.cc, "tcc")) { + fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, + c->match_case.binding_name, id); + } else { + fprintf(out, "__auto_type %s = _m_%d.val; ", + c->match_case.binding_name, id); + } + } else { + if (strstr(g_config.cc, "tcc")) { + fprintf(out, "__typeof__(_m_%d.err) %s = _m_%d.err; ", id, + c->match_case.binding_name, id); + } else { + fprintf(out, "__auto_type %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; + } + fprintf(out, "__auto_type %s = _m_%d.data.%s; ", + c->match_case.binding_name, id, f); + } } - fprintf(out, "; "); - if (is_expr) - { - fprintf(out, "%s _r_%d; ", ret_type, id); + // 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); + } } - 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); + fprintf(out, " }"); + first = 0; + c = c->next; + } - 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 (is_expr) { + fprintf(out, " _r_%d; })", id); + } else { + fprintf(out, " })"); + } +} - 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); - } +void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { + if (!node) { + return; + } + switch (node->type) { + case NODE_MATCH: + codegen_match_internal(ctx, node, out, 1); + break; + case NODE_EXPR_BINARY: + if (strncmp(node->binary.op, "??", 2) == 0 && + strlen(node->binary.op) == 2) { + fprintf(out, "({ "); + emit_auto_type(ctx, node->binary.left, node->token, out); + fprintf(out, " _l = ("); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, "); _l ? _l : ("); + codegen_expression(ctx, node->binary.right, out); + fprintf(out, "); })"); + } else if (strcmp(node->binary.op, "?\?=") == 0) { + fprintf(out, "({ if (!("); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, ")) "); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, " = ("); + codegen_expression(ctx, node->binary.right, out); + fprintf(out, "); "); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, "; })"); + } else if ((strcmp(node->binary.op, "==") == 0 || + strcmp(node->binary.op, "!=") == 0)) { + char *t1 = infer_type(ctx, node->binary.left); + + int is_ptr = 0; + if (t1) { + char *check = t1; + int depth = 0; + while (depth++ < 10) { + if (strchr(check, '*')) { + is_ptr = 1; + break; + } + int resolved = 0; + ASTNode *alias = global_user_structs; + if (alias) { + while (alias) { + if (alias->type == NODE_TYPE_ALIAS && + strcmp(check, alias->type_alias.alias) == 0) { + check = alias->type_alias.original_type; + resolved = 1; + break; + } + alias = alias->next; } - v = v->next; + } + if (!resolved) { + break; + } + } + } + + 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); + } + + ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL; + if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && + !is_basic && !is_ptr) { + char *base = t1; + if (strncmp(base, "struct ", 7) == 0) { + base += 7; + } + + if (strcmp(node->binary.op, "!=") == 0) { + fprintf(out, "(!"); + } + fprintf(out, "%s_eq(&", base); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, ", "); + codegen_expression(ctx, node->binary.right, out); + fprintf(out, ")"); + if (strcmp(node->binary.op, "!=") == 0) { + fprintf(out, ")"); } + } else { + fprintf(out, "("); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, " %s ", node->binary.op); + codegen_expression(ctx, node->binary.right, out); + fprintf(out, ")"); + } + } else { + fprintf(out, "("); + codegen_expression(ctx, node->binary.left, out); + fprintf(out, " %s ", node->binary.op); + codegen_expression(ctx, node->binary.right, out); + fprintf(out, ")"); + } + break; + case NODE_EXPR_VAR: + if (g_current_lambda) { + for (int i = 0; i < g_current_lambda->lambda.num_captures; i++) { + if (strcmp(node->var_ref.name, + g_current_lambda->lambda.captured_vars[i]) == 0) { + fprintf(out, "ctx->%s", node->var_ref.name); + return; + } + } } - 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 - { - EnumVariantReg *reg = find_enum_variant(ctx, c->match_case.pattern); - if (reg) - { - fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); - } - else if (c->match_case.pattern[0] == '"') - { - fprintf(out, "strcmp(_m_%d, %s) == 0", id, c->match_case.pattern); - } - else if (isdigit(c->match_case.pattern[0]) || c->match_case.pattern[0] == '-') - { - // Numeric pattern - fprintf(out, "_m_%d == %s", id, c->match_case.pattern); - } - else if (c->match_case.pattern[0] == '\'') - { - // Char literal pattern - fprintf(out, "_m_%d == %s", id, c->match_case.pattern); - } - else - { - fprintf(out, "1"); - } - } - fprintf(out, ") { "); - if (c->match_case.binding_name) - { - if (is_option) - { - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__auto_type %s = _m_%d.val; ", c->match_case.binding_name, id); - } - } - if (is_result) - { - if (strcmp(c->match_case.pattern, "Ok") == 0) - { - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__auto_type %s = _m_%d.val; ", c->match_case.binding_name, - id); - } - } - else - { - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, "__typeof__(_m_%d.err) %s = _m_%d.err; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__auto_type %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; - } - fprintf(out, "__auto_type %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 (node->resolved_type && strcmp(node->resolved_type, "unknown") == 0) { + if (node->var_ref.suggestion) { + char msg[256]; + sprintf(msg, "Undefined variable '%s'", node->var_ref.name); + char help[256]; + sprintf(help, "Did you mean '%s'?", node->var_ref.suggestion); - 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); - } + zwarn_at(node->token, "%s\n = help: %s", msg, help); + } + } + fprintf(out, "%s", node->var_ref.name); + break; + case NODE_LAMBDA: + if (node->lambda.num_captures > 0) { + fprintf(out, + "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct " + "Lambda_%d_Ctx));\n", + node->lambda.lambda_id, node->lambda.lambda_id); + for (int i = 0; i < node->lambda.num_captures; i++) { + fprintf(out, "ctx->%s = ", node->lambda.captured_vars[i]); + int found = 0; + if (g_current_lambda) { + for (int k = 0; k < g_current_lambda->lambda.num_captures; k++) { + if (strcmp(node->lambda.captured_vars[i], + g_current_lambda->lambda.captured_vars[k]) == 0) { + fprintf(out, "ctx->%s", node->lambda.captured_vars[i]); + found = 1; + break; + } + } + } + if (!found) { + fprintf(out, "%s", node->lambda.captured_vars[i]); } - - fprintf(out, " }"); - first = 0; - c = c->next; + fprintf(out, ";\n"); + } + fprintf(out, "(z_closure_T){.func = _lambda_%d, .ctx = ctx}; })", + node->lambda.lambda_id); + } else { + fprintf(out, "((z_closure_T){.func = (void*)_lambda_%d, .ctx = NULL})", + node->lambda.lambda_id); + } + break; + case NODE_EXPR_LITERAL: + if (node->literal.type_kind == TOK_STRING) { + fprintf(out, "\"%s\"", node->literal.string_val); + } else if (node->literal.type_kind == TOK_CHAR) { + fprintf(out, "%s", node->literal.string_val); + } else if (node->literal.type_kind == 1) { + fprintf(out, "%f", node->literal.float_val); } - if (is_expr) - { - fprintf(out, " _r_%d; })", id); + else { + if (node->literal.int_val > 9223372036854775807ULL) { + fprintf(out, "%lluULL", (unsigned long long)node->literal.int_val); + } else { + fprintf(out, "%llu", (unsigned long long)node->literal.int_val); + } } - else - { - fprintf(out, " })"); + break; + case NODE_EXPR_CALL: { + if (node->call.callee->type == NODE_EXPR_MEMBER) { + ASTNode *target = node->call.callee->member.target; + char *method = node->call.callee->member.field; + + if (strcmp(method, "len") == 0) { + if (target->type_info && target->type_info->kind == TYPE_ARRAY) { + if (target->type_info->array_size > 0) { + fprintf(out, "%d", target->type_info->array_size); + } else { + codegen_expression(ctx, target, out); + fprintf(out, ".len"); + } + return; + } + } + + char *type = infer_type(ctx, target); + if (type) { + char *clean = xstrdup(type); + char *ptr = strchr(clean, '*'); + if (ptr) { + *ptr = 0; + } + + char *base = clean; + if (strncmp(base, "struct ", 7) == 0) { + base += 7; + } + + if (!strchr(type, '*') && target->type == NODE_EXPR_CALL) { + fprintf(out, "({ %s _t = ", type); + codegen_expression(ctx, target, out); + fprintf(out, "; %s_%s(&_t", base, method); + ASTNode *arg = node->call.args; + while (arg) { + fprintf(out, ", "); + codegen_expression(ctx, arg, out); + arg = arg->next; + } + fprintf(out, "); })"); + } else { + fprintf(out, "%s_%s(", base, method); + if (!strchr(type, '*')) { + fprintf(out, "&"); + } + codegen_expression(ctx, target, out); + ASTNode *arg = node->call.args; + while (arg) { + fprintf(out, ", "); + codegen_expression(ctx, arg, out); + arg = arg->next; + } + fprintf(out, ")"); + } + free(clean); + return; + } } -} - -void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) -{ - if (!node) - { + if (node->call.callee->type == NODE_EXPR_VAR) { + ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name); + if (def && def->type == NODE_STRUCT) { + fprintf(out, "(struct %s){0}", node->call.callee->var_ref.name); return; + } } - switch (node->type) - { - case NODE_MATCH: - codegen_match_internal(ctx, node, out, 1); - break; - case NODE_EXPR_BINARY: - if (strncmp(node->binary.op, "??", 2) == 0 && strlen(node->binary.op) == 2) - { - fprintf(out, "({ "); - emit_auto_type(ctx, node->binary.left, node->token, out); - fprintf(out, " _l = ("); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, "); _l ? _l : ("); - codegen_expression(ctx, node->binary.right, out); - fprintf(out, "); })"); - } - else if (strcmp(node->binary.op, "?\?=") == 0) - { - fprintf(out, "({ if (!("); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, ")) "); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, " = ("); - codegen_expression(ctx, node->binary.right, out); - fprintf(out, "); "); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, "; })"); - } - else if ((strcmp(node->binary.op, "==") == 0 || strcmp(node->binary.op, "!=") == 0)) - { - char *t1 = infer_type(ctx, node->binary.left); - - int is_ptr = 0; - if (t1) - { - char *check = t1; - int depth = 0; - while (depth++ < 10) - { - if (strchr(check, '*')) - { - is_ptr = 1; - break; - } - int resolved = 0; - ASTNode *alias = global_user_structs; - if (alias) - { - while (alias) - { - if (alias->type == NODE_TYPE_ALIAS && - strcmp(check, alias->type_alias.alias) == 0) - { - check = alias->type_alias.original_type; - resolved = 1; - break; - } - alias = alias->next; - } - } - if (!resolved) - { - break; - } - } - } - 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); - } + if (node->call.callee->type_info && + node->call.callee->type_info->kind == TYPE_FUNCTION) { + fprintf(out, "({ z_closure_T _c = "); + codegen_expression(ctx, node->call.callee, out); + fprintf(out, "; "); + + Type *ft = node->call.callee->type_info; + char *ret = type_to_string(ft->inner); + if (strcmp(ret, "string") == 0) { + free(ret); + ret = xstrdup("char*"); + } + + fprintf(out, "((%s (*)(void*", ret); + for (int i = 0; i < ft->arg_count; i++) { + char *as = type_to_string(ft->args[i]); + fprintf(out, ", %s", as); + free(as); + } + if (ft->is_varargs) { + fprintf(out, ", ..."); + } + fprintf(out, "))_c.func)(_c.ctx"); + + ASTNode *arg = node->call.args; + while (arg) { + fprintf(out, ", "); + codegen_expression(ctx, arg, out); + arg = arg->next; + } + fprintf(out, "); })"); + free(ret); + break; + } - ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL; - if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic && - !is_ptr) - { - char *base = t1; - if (strncmp(base, "struct ", 7) == 0) - { - base += 7; - } - - if (strcmp(node->binary.op, "!=") == 0) - { - fprintf(out, "(!"); - } - fprintf(out, "%s_eq(&", base); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, ", "); - codegen_expression(ctx, node->binary.right, out); - fprintf(out, ")"); - if (strcmp(node->binary.op, "!=") == 0) - { - fprintf(out, ")"); - } - } - else - { - fprintf(out, "("); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, " %s ", node->binary.op); - codegen_expression(ctx, node->binary.right, out); - fprintf(out, ")"); - } - } - else - { - fprintf(out, "("); - codegen_expression(ctx, node->binary.left, out); - fprintf(out, " %s ", node->binary.op); - codegen_expression(ctx, node->binary.right, out); - fprintf(out, ")"); - } - break; - case NODE_EXPR_VAR: - if (g_current_lambda) - { - for (int i = 0; i < g_current_lambda->lambda.num_captures; i++) - { - if (strcmp(node->var_ref.name, g_current_lambda->lambda.captured_vars[i]) == 0) - { - fprintf(out, "ctx->%s", node->var_ref.name); - return; - } - } - } + codegen_expression(ctx, node->call.callee, out); + fprintf(out, "("); - if (node->resolved_type && strcmp(node->resolved_type, "unknown") == 0) - { - if (node->var_ref.suggestion) - { - char msg[256]; - sprintf(msg, "Undefined variable '%s'", node->var_ref.name); - char help[256]; - sprintf(help, "Did you mean '%s'?", node->var_ref.suggestion); + if (node->call.arg_names && node->call.callee->type == NODE_EXPR_VAR) { + char *fn_name = node->call.callee->var_ref.name; + FuncSig *sig = find_func(ctx, fn_name); - zwarn_at(node->token, "%s\n = help: %s", msg, help); - } - } - fprintf(out, "%s", node->var_ref.name); - break; - case NODE_LAMBDA: - if (node->lambda.num_captures > 0) - { - fprintf(out, - "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct " - "Lambda_%d_Ctx));\n", - node->lambda.lambda_id, node->lambda.lambda_id); - for (int i = 0; i < node->lambda.num_captures; i++) - { - fprintf(out, "ctx->%s = ", node->lambda.captured_vars[i]); - int found = 0; - if (g_current_lambda) - { - for (int k = 0; k < g_current_lambda->lambda.num_captures; k++) - { - if (strcmp(node->lambda.captured_vars[i], - g_current_lambda->lambda.captured_vars[k]) == 0) - { - fprintf(out, "ctx->%s", node->lambda.captured_vars[i]); - found = 1; - break; - } - } - } - if (!found) - { - fprintf(out, "%s", node->lambda.captured_vars[i]); - } - fprintf(out, ";\n"); - } - fprintf(out, "(z_closure_T){.func = _lambda_%d, .ctx = ctx}; })", - node->lambda.lambda_id); - } - else - { - fprintf(out, "((z_closure_T){.func = (void*)_lambda_%d, .ctx = NULL})", - node->lambda.lambda_id); - } - break; - case NODE_EXPR_LITERAL: - if (node->literal.type_kind == TOK_STRING) - { - fprintf(out, "\"%s\"", node->literal.string_val); - } - else if (node->literal.type_kind == TOK_CHAR) - { - fprintf(out, "%s", node->literal.string_val); - } - else if (node->literal.type_kind == 1) - { - fprintf(out, "%f", node->literal.float_val); - } - - else - { - if (node->literal.int_val > 9223372036854775807ULL) - { - fprintf(out, "%lluULL", (unsigned long long)node->literal.int_val); - } - else - { - fprintf(out, "%llu", (unsigned long long)node->literal.int_val); - } - } - break; - case NODE_EXPR_CALL: - { - if (node->call.callee->type == NODE_EXPR_MEMBER) - { - ASTNode *target = node->call.callee->member.target; - char *method = node->call.callee->member.field; - - if (strcmp(method, "len") == 0) - { - if (target->type_info && target->type_info->kind == TYPE_ARRAY) - { - if (target->type_info->array_size > 0) - { - fprintf(out, "%d", target->type_info->array_size); - } - else - { - codegen_expression(ctx, target, out); - fprintf(out, ".len"); - } - return; - } - } - - char *type = infer_type(ctx, target); - if (type) - { - char *clean = xstrdup(type); - char *ptr = strchr(clean, '*'); - if (ptr) - { - *ptr = 0; - } - - char *base = clean; - if (strncmp(base, "struct ", 7) == 0) - { - base += 7; - } - - if (!strchr(type, '*') && target->type == NODE_EXPR_CALL) - { - fprintf(out, "({ %s _t = ", type); - codegen_expression(ctx, target, out); - fprintf(out, "; %s_%s(&_t", base, method); - ASTNode *arg = node->call.args; - while (arg) - { - fprintf(out, ", "); - codegen_expression(ctx, arg, out); - arg = arg->next; - } - fprintf(out, "); })"); - } - else - { - fprintf(out, "%s_%s(", base, method); - if (!strchr(type, '*')) - { - fprintf(out, "&"); - } - codegen_expression(ctx, target, out); - ASTNode *arg = node->call.args; - while (arg) - { - fprintf(out, ", "); - codegen_expression(ctx, arg, out); - arg = arg->next; - } - fprintf(out, ")"); - } - free(clean); - return; - } - } - if (node->call.callee->type == NODE_EXPR_VAR) - { - ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name); - if (def && def->type == NODE_STRUCT) - { - fprintf(out, "(struct %s){0}", node->call.callee->var_ref.name); - return; - } - } + if (sig && sig->arg_types) { + for (int p = 0; p < sig->total_args; p++) { + ASTNode *arg = node->call.args; - if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION) - { - fprintf(out, "({ z_closure_T _c = "); - codegen_expression(ctx, node->call.callee, out); - fprintf(out, "; "); - - Type *ft = node->call.callee->type_info; - char *ret = type_to_string(ft->inner); - if (strcmp(ret, "string") == 0) - { - free(ret); - ret = xstrdup("char*"); - } + for (int i = 0; i < node->call.arg_count && arg; + i++, arg = arg->next) { + if (node->call.arg_names[i] && p < node->call.arg_count) { - fprintf(out, "((%s (*)(void*", ret); - for (int i = 0; i < ft->arg_count; i++) - { - char *as = type_to_string(ft->args[i]); - fprintf(out, ", %s", as); - free(as); - } - if (ft->is_varargs) - { - fprintf(out, ", ..."); - } - fprintf(out, "))_c.func)(_c.ctx"); - - ASTNode *arg = node->call.args; - while (arg) - { - fprintf(out, ", "); - codegen_expression(ctx, arg, out); - arg = arg->next; + // For now, emit in order provided... } - fprintf(out, "); })"); - free(ret); - break; + } } + } - codegen_expression(ctx, node->call.callee, out); - fprintf(out, "("); - - if (node->call.arg_names && node->call.callee->type == NODE_EXPR_VAR) - { - char *fn_name = node->call.callee->var_ref.name; - FuncSig *sig = find_func(ctx, fn_name); - - if (sig && sig->arg_types) - { - for (int p = 0; p < sig->total_args; p++) - { - ASTNode *arg = node->call.args; - - for (int i = 0; i < node->call.arg_count && arg; i++, arg = arg->next) - { - if (node->call.arg_names[i] && p < node->call.arg_count) - { - - // For now, emit in order provided... - } - } - } - } - - ASTNode *arg = node->call.args; - int first = 1; - while (arg) - { - if (!first) - { - fprintf(out, ", "); - } - first = 0; - codegen_expression(ctx, arg, out); - arg = arg->next; - } - } - else - { - ASTNode *arg = node->call.args; - while (arg) - { - codegen_expression(ctx, arg, out); - if (arg->next) - { - fprintf(out, ", "); - } - arg = arg->next; - } + ASTNode *arg = node->call.args; + int first = 1; + while (arg) { + if (!first) { + fprintf(out, ", "); } - fprintf(out, ")"); - break; + first = 0; + codegen_expression(ctx, arg, out); + arg = arg->next; + } + } else { + ASTNode *arg = node->call.args; + while (arg) { + codegen_expression(ctx, arg, out); + if (arg->next) { + fprintf(out, ", "); + } + arg = arg->next; + } } - case NODE_EXPR_MEMBER: - if (strcmp(node->member.field, "len") == 0) - { - if (node->member.target->type_info) - { - if (node->member.target->type_info->kind == TYPE_ARRAY) - { - if (node->member.target->type_info->array_size > 0) - { - fprintf(out, "%d", node->member.target->type_info->array_size); - break; - } - } - } - } - - if (node->member.is_pointer_access == 2) - { - fprintf(out, "({ "); - emit_auto_type(ctx, node->member.target, node->token, out); - fprintf(out, " _t = ("); - codegen_expression(ctx, node->member.target, out); - fprintf(out, "); _t ? _t->%s : 0; })", node->member.field); - } - else - { - codegen_expression(ctx, node->member.target, out); - fprintf(out, "%s%s", node->member.is_pointer_access ? "->" : ".", node->member.field); - } - break; - case NODE_EXPR_INDEX: - { - int is_slice_struct = 0; - if (node->index.array->type_info) - { - if (node->index.array->type_info->kind == TYPE_ARRAY && - node->index.array->type_info->array_size == 0) - { - is_slice_struct = 1; - } - } - if (node->index.array->resolved_type) - { - if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0) - { - is_slice_struct = 1; - } - } - - if (is_slice_struct) - { - if (node->index.array->type == NODE_EXPR_VAR) - { - codegen_expression(ctx, node->index.array, out); - fprintf(out, ".data[_z_check_bounds("); - codegen_expression(ctx, node->index.index, out); - fprintf(out, ", "); - codegen_expression(ctx, node->index.array, out); - fprintf(out, ".len)]"); - } - else - { - codegen_expression(ctx, node->index.array, out); - fprintf(out, ".data["); - codegen_expression(ctx, node->index.index, out); - fprintf(out, "]"); - } + fprintf(out, ")"); + break; + } + case NODE_EXPR_MEMBER: + if (strcmp(node->member.field, "len") == 0) { + if (node->member.target->type_info) { + if (node->member.target->type_info->kind == TYPE_ARRAY) { + if (node->member.target->type_info->array_size > 0) { + fprintf(out, "%d", node->member.target->type_info->array_size); + break; + } } - else - { - int fixed_size = -1; - if (node->index.array->type_info && node->index.array->type_info->kind == TYPE_ARRAY) - { - fixed_size = node->index.array->type_info->array_size; - } + } + } - codegen_expression(ctx, node->index.array, out); - fprintf(out, "["); - if (fixed_size > 0) - { - fprintf(out, "_z_check_bounds("); - } - codegen_expression(ctx, node->index.index, out); - if (fixed_size > 0) - { - fprintf(out, ", %d)", fixed_size); - } - fprintf(out, "]"); - } + if (node->member.is_pointer_access == 2) { + fprintf(out, "({ "); + emit_auto_type(ctx, node->member.target, node->token, out); + fprintf(out, " _t = ("); + codegen_expression(ctx, node->member.target, out); + fprintf(out, "); _t ? _t->%s : 0; })", node->member.field); + } else { + codegen_expression(ctx, node->member.target, out); + fprintf(out, "%s%s", node->member.is_pointer_access ? "->" : ".", + node->member.field); } break; - case NODE_EXPR_SLICE: - { - int known_size = -1; - int is_slice_struct = 0; - if (node->slice.array->type_info) - { - if (node->slice.array->type_info->kind == TYPE_ARRAY) - { - known_size = node->slice.array->type_info->array_size; - if (known_size == 0) - { - is_slice_struct = 1; - } - } - } - - char *tname = "unknown"; - if (node->type_info && node->type_info->inner) - { - tname = type_to_string(node->type_info->inner); - } + case NODE_EXPR_INDEX: { + int is_slice_struct = 0; + if (node->index.array->type_info) { + if (node->index.array->type_info->kind == TYPE_ARRAY && + node->index.array->type_info->array_size == 0) { + is_slice_struct = 1; + } + } + if (node->index.array->resolved_type) { + if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0) { + is_slice_struct = 1; + } + } - fprintf(out, "({ "); - emit_auto_type(ctx, node->slice.array, node->token, out); - fprintf(out, " _arr = "); - codegen_expression(ctx, node->slice.array, out); - fprintf(out, "; int _start = "); - if (node->slice.start) - { - codegen_expression(ctx, node->slice.start, out); - } - else - { - fprintf(out, "0"); - } - fprintf(out, "; int _len = "); + if (is_slice_struct) { + if (node->index.array->type == NODE_EXPR_VAR) { + codegen_expression(ctx, node->index.array, out); + fprintf(out, ".data[_z_check_bounds("); + codegen_expression(ctx, node->index.index, out); + fprintf(out, ", "); + codegen_expression(ctx, node->index.array, out); + fprintf(out, ".len)]"); + } else { + codegen_expression(ctx, node->index.array, out); + fprintf(out, ".data["); + codegen_expression(ctx, node->index.index, out); + fprintf(out, "]"); + } + } else { + int fixed_size = -1; + if (node->index.array->type_info && + node->index.array->type_info->kind == TYPE_ARRAY) { + fixed_size = node->index.array->type_info->array_size; + } + + codegen_expression(ctx, node->index.array, out); + fprintf(out, "["); + if (fixed_size > 0) { + fprintf(out, "_z_check_bounds("); + } + codegen_expression(ctx, node->index.index, out); + if (fixed_size > 0) { + fprintf(out, ", %d)", fixed_size); + } + fprintf(out, "]"); + } + } break; + case NODE_EXPR_SLICE: { + int known_size = -1; + int is_slice_struct = 0; + if (node->slice.array->type_info) { + if (node->slice.array->type_info->kind == TYPE_ARRAY) { + known_size = node->slice.array->type_info->array_size; + if (known_size == 0) { + is_slice_struct = 1; + } + } + } - if (node->slice.end) - { - codegen_expression(ctx, node->slice.end, out); - fprintf(out, " - _start; "); - } - else - { - if (known_size > 0) - { - fprintf(out, "%d - _start; ", known_size); - } - else if (is_slice_struct) - { - fprintf(out, "_arr.len - _start; "); - } - else - { - fprintf(out, "/* UNSAFE: Full Slice on unknown size */ 0; "); - } - } + char *tname = "unknown"; + if (node->type_info && node->type_info->inner) { + tname = type_to_string(node->type_info->inner); + } - if (is_slice_struct) - { - fprintf(out, - "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = " - "_len }; })", - tname); - } - else - { - fprintf(out, "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })", - tname); - } - break; + fprintf(out, "({ "); + emit_auto_type(ctx, node->slice.array, node->token, out); + fprintf(out, " _arr = "); + codegen_expression(ctx, node->slice.array, out); + fprintf(out, "; int _start = "); + if (node->slice.start) { + codegen_expression(ctx, node->slice.start, out); + } else { + fprintf(out, "0"); } - case NODE_BLOCK: - { - int saved = defer_count; - fprintf(out, "({ "); - 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, " })"); - break; + fprintf(out, "; int _len = "); + + if (node->slice.end) { + codegen_expression(ctx, node->slice.end, out); + fprintf(out, " - _start; "); + } else { + if (known_size > 0) { + fprintf(out, "%d - _start; ", known_size); + } else if (is_slice_struct) { + fprintf(out, "_arr.len - _start; "); + } else { + fprintf(out, "/* UNSAFE: Full Slice on unknown size */ 0; "); + } } - case NODE_TRY: - { - char *type_name = "Result"; - if (g_current_func_ret_type) - { - type_name = g_current_func_ret_type; - } - else if (node->try_stmt.expr->type_info && node->try_stmt.expr->type_info->name) - { - type_name = node->try_stmt.expr->type_info->name; - } - if (strcmp(type_name, "__auto_type") == 0 || strcmp(type_name, "unknown") == 0) - { - type_name = "Result"; - } + if (is_slice_struct) { + fprintf(out, + "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = " + "_len }; })", + tname); + } else { + fprintf( + out, + "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })", + tname); + } + break; + } + case NODE_BLOCK: { + int saved = defer_count; + fprintf(out, "({ "); + 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, " })"); + break; + } + case NODE_TRY: { + char *type_name = "Result"; + if (g_current_func_ret_type) { + type_name = g_current_func_ret_type; + } else if (node->try_stmt.expr->type_info && + node->try_stmt.expr->type_info->name) { + type_name = node->try_stmt.expr->type_info->name; + } - char *search_name = type_name; - if (strncmp(search_name, "struct ", 7) == 0) - { - search_name += 7; - } + if (strcmp(type_name, "__auto_type") == 0 || + strcmp(type_name, "unknown") == 0) { + type_name = "Result"; + } - int is_enum = 0; - StructRef *er = ctx->parsed_enums_list; - while (er) - { - if (er->node && er->node->type == NODE_ENUM && - strcmp(er->node->enm.name, search_name) == 0) - { - is_enum = 1; - break; - } - er = er->next; - } - if (!is_enum) - { - ASTNode *ins = ctx->instantiated_structs; - while (ins) - { - if (ins->type == NODE_ENUM && strcmp(ins->enm.name, search_name) == 0) - { - is_enum = 1; - break; - } - ins = ins->next; - } - } + char *search_name = type_name; + if (strncmp(search_name, "struct ", 7) == 0) { + search_name += 7; + } - fprintf(out, "({ "); - emit_auto_type(ctx, node->try_stmt.expr, node->token, out); - fprintf(out, " _try = "); - codegen_expression(ctx, node->try_stmt.expr, out); - - if (is_enum) - { - fprintf(out, - "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); " - "_try.data.Ok; })", - search_name, search_name); - } - else - { - fprintf(out, - "; if (!_try.is_ok) return %s_Err(_try.err); " - "_try.val; })", - search_name); - } + int is_enum = 0; + StructRef *er = ctx->parsed_enums_list; + while (er) { + if (er->node && er->node->type == NODE_ENUM && + strcmp(er->node->enm.name, search_name) == 0) { + is_enum = 1; break; + } + er = er->next; } - case NODE_RAW_STMT: - fprintf(out, "%s", node->raw_stmt.content); - break; - case NODE_PLUGIN: - { - // Plugin registry - declare external plugins - ZPlugin *found = zptr_find_plugin(node->plugin_stmt.plugin_name); - - if (found) - { - ZApi api = {.filename = g_current_filename ? g_current_filename : "input.zc", - .current_line = node->line, - .out = out, - .hoist_out = ctx->hoist_out}; - found->fn(node->plugin_stmt.body, &api); - } - else - { - fprintf(out, "/* Unknown plugin: %s */\n", node->plugin_stmt.plugin_name); - } - break; + if (!is_enum) { + ASTNode *ins = ctx->instantiated_structs; + while (ins) { + if (ins->type == NODE_ENUM && strcmp(ins->enm.name, search_name) == 0) { + is_enum = 1; + break; + } + ins = ins->next; + } } - case NODE_EXPR_UNARY: - if (node->unary.op && strcmp(node->unary.op, "&_rval") == 0) - { - fprintf(out, "({ "); - emit_auto_type(ctx, node->unary.operand, node->token, out); - fprintf(out, " _t = ("); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, "); &_t; })"); - } - else if (node->unary.op && strcmp(node->unary.op, "?") == 0) - { - fprintf(out, "({ "); - emit_auto_type(ctx, node->unary.operand, node->token, out); - fprintf(out, " _t = ("); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, "); if (_t.tag != 0) return _t; _t.data.Ok; })"); - } - else if (node->unary.op && strcmp(node->unary.op, "_post++") == 0) - { - fprintf(out, "("); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, "++)"); - } - else if (node->unary.op && strcmp(node->unary.op, "_post--") == 0) - { - fprintf(out, "("); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, "--)"); - } - else - { - fprintf(out, "(%s", node->unary.op); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, ")"); - } - break; - case NODE_EXPR_CAST: - fprintf(out, "(%s)(", node->cast.target_type); - codegen_expression(ctx, node->cast.expr, out); - fprintf(out, ")"); - break; - case NODE_EXPR_SIZEOF: - if (node->size_of.target_type) - { - fprintf(out, "sizeof(%s)", node->size_of.target_type); - } - else - { - fprintf(out, "sizeof("); - codegen_expression(ctx, node->size_of.expr, out); - fprintf(out, ")"); - } - break; - case NODE_TYPEOF: - if (node->size_of.target_type) - { - fprintf(out, "typeof(%s)", node->size_of.target_type); - } - else - { - fprintf(out, "typeof("); - codegen_expression(ctx, node->size_of.expr, out); - fprintf(out, ")"); - } - break; - - case NODE_REFLECTION: - { - Type *t = node->reflection.target_type; - if (node->reflection.kind == 0) - { // @type_name - char *s = type_to_string(t); - fprintf(out, "\"%s\"", s); - free(s); - } - else - { // @fields - if (t->kind != TYPE_STRUCT || !t->name) - { - fprintf(out, "((void*)0)"); - break; - } - char *sname = t->name; - // Find definition - ASTNode *def = find_struct_def(ctx, sname); - if (!def) - { - fprintf(out, "((void*)0)"); - break; - } - fprintf(out, - "({ static struct { char *name; char *type; unsigned long offset; } " - "_fields_%s[] = {", - sname); - ASTNode *f = def->strct.fields; - while (f) - { - if (f->type == NODE_FIELD) - { - fprintf(out, "{ \"%s\", \"%s\", __builtin_offsetof(struct %s, %s) }, ", - f->field.name, f->field.type, sname, f->field.name); - } - f = f->next; - } - fprintf(out, "{ 0 } }; (void*)_fields_%s; })", sname); - } - break; + fprintf(out, "({ "); + emit_auto_type(ctx, node->try_stmt.expr, node->token, out); + fprintf(out, " _try = "); + codegen_expression(ctx, node->try_stmt.expr, out); + + if (is_enum) { + fprintf(out, + "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); " + "_try.data.Ok; })", + search_name, search_name); + } else { + fprintf(out, + "; if (!_try.is_ok) return %s_Err(_try.err); " + "_try.val; })", + search_name); } - case NODE_EXPR_STRUCT_INIT: - { - const char *struct_name = node->struct_init.struct_name; - if (strcmp(struct_name, "Self") == 0 && g_current_impl_type) - { - struct_name = g_current_impl_type; - } - fprintf(out, "(struct %s){", struct_name); - ASTNode *f = node->struct_init.fields; - while (f) - { - fprintf(out, ".%s = ", f->var_decl.name); - codegen_expression(ctx, f->var_decl.init_expr, out); - if (f->next) - { - fprintf(out, ", "); - } - f = f->next; - } - fprintf(out, "}"); - break; + break; + } + case NODE_RAW_STMT: + fprintf(out, "%s", node->raw_stmt.content); + break; + case NODE_PLUGIN: { + // Plugin registry - declare external plugins + ZPlugin *found = zptr_find_plugin(node->plugin_stmt.plugin_name); + + if (found) { + ZApi api = {.filename = + g_current_filename ? g_current_filename : "input.zc", + .current_line = node->line, + .out = out, + .hoist_out = ctx->hoist_out}; + found->fn(node->plugin_stmt.body, &api); + } else { + fprintf(out, "/* Unknown plugin: %s */\n", node->plugin_stmt.plugin_name); } - case NODE_EXPR_ARRAY_LITERAL: - fprintf(out, "{"); - ASTNode *elem = node->array_literal.elements; - int first = 1; - while (elem) - { - if (!first) - { - fprintf(out, ", "); - } - codegen_expression(ctx, elem, out); - elem = elem->next; - first = 0; - } - fprintf(out, "}"); + break; + } + case NODE_EXPR_UNARY: + if (node->unary.op && strcmp(node->unary.op, "&_rval") == 0) { + fprintf(out, "({ "); + emit_auto_type(ctx, node->unary.operand, node->token, out); + fprintf(out, " _t = ("); + codegen_expression(ctx, node->unary.operand, out); + fprintf(out, "); &_t; })"); + } else if (node->unary.op && strcmp(node->unary.op, "?") == 0) { + fprintf(out, "({ "); + emit_auto_type(ctx, node->unary.operand, node->token, out); + fprintf(out, " _t = ("); + codegen_expression(ctx, node->unary.operand, out); + fprintf(out, "); if (_t.tag != 0) return _t; _t.data.Ok; })"); + } else if (node->unary.op && strcmp(node->unary.op, "_post++") == 0) { + fprintf(out, "("); + codegen_expression(ctx, node->unary.operand, out); + fprintf(out, "++)"); + } else if (node->unary.op && strcmp(node->unary.op, "_post--") == 0) { + fprintf(out, "("); + codegen_expression(ctx, node->unary.operand, out); + fprintf(out, "--)"); + } else { + fprintf(out, "(%s", node->unary.op); + codegen_expression(ctx, node->unary.operand, out); + fprintf(out, ")"); + } + break; + case NODE_EXPR_CAST: + fprintf(out, "(%s)(", node->cast.target_type); + codegen_expression(ctx, node->cast.expr, out); + fprintf(out, ")"); + break; + case NODE_EXPR_SIZEOF: + if (node->size_of.target_type) { + fprintf(out, "sizeof(%s)", node->size_of.target_type); + } else { + fprintf(out, "sizeof("); + codegen_expression(ctx, node->size_of.expr, out); + fprintf(out, ")"); + } + break; + case NODE_TYPEOF: + if (node->size_of.target_type) { + fprintf(out, "typeof(%s)", node->size_of.target_type); + } else { + fprintf(out, "typeof("); + codegen_expression(ctx, node->size_of.expr, out); + fprintf(out, ")"); + } + break; + + case NODE_REFLECTION: { + Type *t = node->reflection.target_type; + if (node->reflection.kind == 0) { // @type_name + char *s = type_to_string(t); + fprintf(out, "\"%s\"", s); + free(s); + } else { // @fields + if (t->kind != TYPE_STRUCT || !t->name) { + fprintf(out, "((void*)0)"); break; - case NODE_TERNARY: - fprintf(out, "(("); - codegen_expression(ctx, node->ternary.cond, out); - fprintf(out, ") ? ("); - codegen_expression(ctx, node->ternary.true_expr, out); - fprintf(out, ") : ("); - codegen_expression(ctx, node->ternary.false_expr, out); - fprintf(out, "))"); + } + char *sname = t->name; + // Find definition + ASTNode *def = find_struct_def(ctx, sname); + if (!def) { + fprintf(out, "((void*)0)"); break; - case NODE_AWAIT: - { - char *ret_type = "void*"; - int free_ret = 0; - if (node->type_info) - { - char *t = type_to_string(node->type_info); - if (t) - { - ret_type = t; - free_ret = 1; - } - } - else if (node->resolved_type) - { - ret_type = node->resolved_type; - } + } + + fprintf( + out, + "({ static struct { char *name; char *type; unsigned long offset; } " + "_fields_%s[] = {", + sname); + ASTNode *f = def->strct.fields; + while (f) { + if (f->type == NODE_FIELD) { + fprintf(out, + "{ \"%s\", \"%s\", __builtin_offsetof(struct %s, %s) }, ", + f->field.name, f->field.type, sname, f->field.name); + } + f = f->next; + } + fprintf(out, "{ 0 } }; (void*)_fields_%s; })", sname); + } + break; + } + case NODE_EXPR_STRUCT_INIT: { + const char *struct_name = node->struct_init.struct_name; + if (strcmp(struct_name, "Self") == 0 && g_current_impl_type) { + struct_name = g_current_impl_type; + } + fprintf(out, "(struct %s){", struct_name); + ASTNode *f = node->struct_init.fields; + while (f) { + fprintf(out, ".%s = ", f->var_decl.name); + codegen_expression(ctx, f->var_decl.init_expr, out); + if (f->next) { + fprintf(out, ", "); + } + f = f->next; + } + fprintf(out, "}"); + break; + } + case NODE_EXPR_ARRAY_LITERAL: + fprintf(out, "{"); + ASTNode *elem = node->array_literal.elements; + int first = 1; + while (elem) { + if (!first) { + fprintf(out, ", "); + } + codegen_expression(ctx, elem, out); + elem = elem->next; + first = 0; + } + fprintf(out, "}"); + break; + case NODE_TERNARY: + fprintf(out, "(("); + codegen_expression(ctx, node->ternary.cond, out); + fprintf(out, ") ? ("); + codegen_expression(ctx, node->ternary.true_expr, out); + fprintf(out, ") : ("); + codegen_expression(ctx, node->ternary.false_expr, out); + fprintf(out, "))"); + break; + case NODE_AWAIT: { + char *ret_type = "void*"; + int free_ret = 0; + if (node->type_info) { + char *t = type_to_string(node->type_info); + if (t) { + ret_type = t; + free_ret = 1; + } + } else if (node->resolved_type) { + ret_type = node->resolved_type; + } - 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; - } + 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; + } + } - 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; - } - } + 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, "})"); - } - else - { - if (returns_struct) - { - 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); - } - break; + 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, "})"); + } else { + if (returns_struct) { + 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); + } + } } - default: - break; + if (free_ret) { + free(ret_type); } + break; + } + default: + break; + } } -void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) -{ - if (!node) - { - return; +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; } - 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]); - } + 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; + } - 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"); + defer_count = 0; + fprintf(out, "\n"); - break; + // 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%s%s\")", SEGMENT_NAME_PREFIX, + node->func.section, SEGMENT_NAME_SUFFIX); } - - 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%s%s\")", SEGMENT_NAME_PREFIX, node->func.section, SEGMENT_NAME_SUFFIX); - } #undef EMIT_ATTR - fprintf(out, ")) "); - } - } - - if (node->func.is_inline) - { - fprintf(out, "inline "); - } - fprintf(out, "%s %s(%s)\n", node->func.ret_type, node->func.name, node->func.args); - 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_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); - } + fprintf(out, ")) "); + } + } - // Else block - codegen_walker(ctx, node->destruct.else_block->block.statements, out); - fprintf(out, " }\n"); + if (node->func.is_inline) { + fprintf(out, "inline "); + } + fprintf(out, "%s %s(%s)\n", node->func.ret_type, node->func.name, + node->func.args); + 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; - // 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_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))) "); } - 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; + char *tname = NULL; + Type *tinfo = node->var_decl.type_info; + if (tinfo && tinfo->name) { + tname = tinfo->name; + } else if (node->var_decl.type_str && + strcmp(node->var_decl.type_str, "__auto_type") != 0) { + tname = node->var_decl.type_str; + } + + if (tname) { + ASTNode *def = find_struct_def(ctx, tname); + if (def && def->type_info && def->type_info->has_drop) { + fprintf(out, "__attribute__((cleanup(%s_Drop_glue))) ", tname); + } + } } - 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; - Type *tinfo = node->var_decl.type_info; - if (tinfo && tinfo->name) - { - tname = tinfo->name; - } - else if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0) - { - tname = node->var_decl.type_str; - } - - if (tname) - { - ASTNode *def = find_struct_def(ctx, tname); - if (def && def->type_info && def->type_info->has_drop) - { - fprintf(out, "__attribute__((cleanup(%s_Drop_glue))) ", tname); - } - } - } - if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0) - { - emit_var_decl_type(ctx, out, node->var_decl.type_str, node->var_decl.name); - add_symbol(ctx, node->var_decl.name, node->var_decl.type_str, node->var_decl.type_info); - if (node->var_decl.init_expr) - { - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - } - fprintf(out, ";\n"); - } - else - { - 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) - { - emit_var_decl_type(ctx, out, inferred, node->var_decl.name); - add_symbol(ctx, node->var_decl.name, inferred, NULL); - } - 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); - } - else - { - // Here we are cooked. - } - } - - 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); - } + if (node->var_decl.type_str && + strcmp(node->var_decl.type_str, "__auto_type") != 0) { + emit_var_decl_type(ctx, out, node->var_decl.type_str, + node->var_decl.name); + add_symbol(ctx, node->var_decl.name, node->var_decl.type_str, + node->var_decl.type_info); + if (node->var_decl.init_expr) { 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: - fprintf(out, "while ("); - codegen_expression(ctx, node->while_stmt.condition, out); - fprintf(out, ") "); - codegen_node_single(ctx, node->while_stmt.body, out); - break; - case NODE_FOR: - 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); - break; - case NODE_BREAK: - 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: - 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: - 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"); - break; - // Loop constructs: loop, repeat, for-in - case NODE_LOOP: - // loop { ... } => while (1) { ... } - fprintf(out, "while (1) "); - codegen_node_single(ctx, node->loop_stmt.body, out); - break; - case NODE_REPEAT: - 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); - break; - case NODE_FOR_RANGE: - 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, "__auto_type %s = ", node->for_range.var_name); - } - codegen_expression(ctx, node->for_range.start, out); - 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); - 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); + } + fprintf(out, ";\n"); + } else { + 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) { + emit_var_decl_type(ctx, out, inferred, node->var_decl.name); + add_symbol(ctx, node->var_decl.name, inferred, NULL); + } 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); + } else { + // Here we are cooked. + } + } + + 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: + fprintf(out, "while ("); + codegen_expression(ctx, node->while_stmt.condition, out); + fprintf(out, ") "); + codegen_node_single(ctx, node->while_stmt.body, out); + break; + case NODE_FOR: + 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); + break; + case NODE_BREAK: + 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: + 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: + 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"); + break; + // Loop constructs: loop, repeat, for-in + case NODE_LOOP: + // loop { ... } => while (1) { ... } + fprintf(out, "while (1) "); + codegen_node_single(ctx, node->loop_stmt.body, out); + break; + case NODE_REPEAT: + 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); + break; + case NODE_FOR_RANGE: + 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, "__auto_type %s = ", node->for_range.var_name); + } + codegen_expression(ctx, node->for_range.start, out); + 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); + 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__("); + } - 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\""); - 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_outputs > 0) { + fprintf(out, "\n : "); + for (int i = 0; i < node->asm_stmt.num_outputs; i++) { + if (i > 0) { + fprintf(out, ", "); } - 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]); - } + // 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]); } - else if (node->asm_stmt.num_outputs > 0) - { - fprintf(out, "\n : "); + } + } + + 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]); - } + 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; + fprintf(out, ");\n"); + break; + } + case NODE_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); } - case NODE_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; + if (lt) { + free(lt); } - 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; + 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 = type_to_string(node->type_info); + if (t) { + ret_type = t; + free_ret = 1; + } + } else if (node->resolved_type) { + ret_type = node->resolved_type; } - case NODE_AWAIT: - { - char *ret_type = "void*"; - int free_ret = 0; - if (node->type_info) - { - char *t = 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; - } + // 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 + } + } - if (strncmp(ret_type, "struct", 6) == 0) - { - returns_struct = 1; - } - } + 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; + 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); + } + } } - default: - codegen_expression(ctx, node, out); - fprintf(out, ";\n"); - break; + if (free_ret) { + free(ret_type); } + fprintf(out, ";\n"); // Statement terminator + 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; - } +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 4b66f99..4d13d65 100644 --- a/src/codegen/codegen.h +++ b/src/codegen/codegen.h @@ -16,9 +16,11 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out); // Utility functions (codegen_utils.c). char *infer_type(ParserContext *ctx, ASTNode *node); ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name); -char *get_field_type_str(ParserContext *ctx, const char *struct_name, const char *field_name); +char *get_field_type_str(ParserContext *ctx, const char *struct_name, + const char *field_name); char *extract_call_args(const char *args); -void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name); +void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, + const char *var_name); char *replace_string_type(const char *args); const char *parse_original_method_name(const char *mangled); void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out); diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c index 026824e..53c4eb2 100644 --- a/src/codegen/codegen_decl.c +++ b/src/codegen/codegen_decl.c @@ -8,912 +8,763 @@ #include <string.h> // Emit C preamble with standard includes and type definitions. -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); - } - else - { - // Standard hosted preamble. - fputs("#include <stdio.h>\n#include <stdlib.h>\n#include " - "<stddef.h>\n#include <string.h>\n", - out); - fputs("#include <stdarg.h>\n#include <stdint.h>\n#include <stdbool.h>\n", out); - fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions - fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out); - fputs("typedef size_t usize;\ntypedef char* string;\n", out); - if (ctx->has_async) - { - fputs("#include <pthread.h>\n", out); - fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out); - } - fputs("typedef struct { void *func; void *ctx; } z_closure_T;\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); - - // Memory Mapping. - fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free " - "free\n#define " - "z_print printf\n", - out); - fputs("void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", " - "msg); exit(1); }\n", - out); - - fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { " - "z_free(*pp); *pp " - "= NULL; } }\n", - out); - fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, " - "\"Assertion failed: \" " - "__VA_ARGS__); exit(1); }\n", - out); - fputs("string _z_readln_raw() { " - "size_t cap = 64; size_t len = 0; " - "char *line = z_malloc(cap); " - "if(!line) return NULL; " - "int c; " - "while((c = fgetc(stdin)) != EOF) { " - "if(c == '\\n') break; " - "if(len + 1 >= cap) { cap *= 2; char *n = z_realloc(line, cap); " - "if(!n) { z_free(line); return NULL; } line = n; } " - "line[len++] = c; } " - "if(len == 0 && c == EOF) { z_free(line); return NULL; } " - "line[len] = 0; return line; }\n", - out); - fputs("int _z_scan_helper(const char *fmt, ...) { char *l = " - "_z_readln_raw(); if(!l) return " - "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); " - "va_end(ap); " - "z_free(l); return r; }\n", - out); - - // REPL helpers: suppress/restore stdout. - fputs("int _z_orig_stdout = -1;\n", out); - fputs("void _z_suppress_stdout() {\n", out); - fputs(" fflush(stdout);\n", out); - fputs(" if (_z_orig_stdout == -1) _z_orig_stdout = dup(STDOUT_FILENO);\n", out); - fputs(" int nullfd = open(\"/dev/null\", O_WRONLY);\n", out); - fputs(" dup2(nullfd, STDOUT_FILENO);\n", out); - fputs(" close(nullfd);\n", out); - fputs("}\n", out); - fputs("void _z_restore_stdout() {\n", out); - fputs(" fflush(stdout);\n", out); - fputs(" if (_z_orig_stdout != -1) {\n", out); - fputs(" dup2(_z_orig_stdout, STDOUT_FILENO);\n", out); - fputs(" close(_z_orig_stdout);\n", out); - fputs(" _z_orig_stdout = -1;\n", out); - fputs(" }\n", out); - fputs("}\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); + } else { + // Standard hosted preamble. + fputs("#include <stdio.h>\n#include <stdlib.h>\n#include " + "<stddef.h>\n#include <string.h>\n", + out); + fputs("#include <stdarg.h>\n#include <stdint.h>\n#include <stdbool.h>\n", + out); + fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions + fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out); + fputs("typedef size_t usize;\ntypedef char* string;\n", out); + if (ctx->has_async) { + fputs("#include <pthread.h>\n", out); + fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out); } + fputs("typedef struct { void *func; void *ctx; } z_closure_T;\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); + + // Memory Mapping. + fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free " + "free\n#define " + "z_print printf\n", + out); + fputs("void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", " + "msg); exit(1); }\n", + out); + + fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { " + "z_free(*pp); *pp " + "= NULL; } }\n", + out); + fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, " + "\"Assertion failed: \" " + "__VA_ARGS__); exit(1); }\n", + out); + fputs("string _z_readln_raw() { " + "size_t cap = 64; size_t len = 0; " + "char *line = z_malloc(cap); " + "if(!line) return NULL; " + "int c; " + "while((c = fgetc(stdin)) != EOF) { " + "if(c == '\\n') break; " + "if(len + 1 >= cap) { cap *= 2; char *n = z_realloc(line, cap); " + "if(!n) { z_free(line); return NULL; } line = n; } " + "line[len++] = c; } " + "if(len == 0 && c == EOF) { z_free(line); return NULL; } " + "line[len] = 0; return line; }\n", + out); + fputs("int _z_scan_helper(const char *fmt, ...) { char *l = " + "_z_readln_raw(); if(!l) return " + "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); " + "va_end(ap); " + "z_free(l); return r; }\n", + out); + + // REPL helpers: suppress/restore stdout. + fputs("int _z_orig_stdout = -1;\n", out); + fputs("void _z_suppress_stdout() {\n", out); + fputs(" fflush(stdout);\n", out); + fputs( + " if (_z_orig_stdout == -1) _z_orig_stdout = dup(STDOUT_FILENO);\n", + out); + fputs(" int nullfd = open(\"/dev/null\", O_WRONLY);\n", out); + fputs(" dup2(nullfd, STDOUT_FILENO);\n", out); + fputs(" close(nullfd);\n", out); + fputs("}\n", out); + fputs("void _z_restore_stdout() {\n", out); + fputs(" fflush(stdout);\n", out); + fputs(" if (_z_orig_stdout != -1) {\n", out); + fputs(" dup2(_z_orig_stdout, STDOUT_FILENO);\n", out); + fputs(" close(_z_orig_stdout);\n", out); + fputs(" _z_orig_stdout = -1;\n", out); + fputs(" }\n", out); + fputs("}\n", out); + } } // Emit includes and type aliases. -void emit_includes_and_aliases(ASTNode *node, FILE *out) -{ - while (node) - { - if (node->type == NODE_INCLUDE) - { - if (node->include.is_system) - { - fprintf(out, "#include <%s>\n", node->include.path); - } - else - { - fprintf(out, "#include \"%s\"\n", node->include.path); - } - } - else if (node->type == NODE_TYPE_ALIAS) - { - fprintf(out, "typedef %s %s;\n", node->type_alias.original_type, - node->type_alias.alias); - } - node = node->next; +void emit_includes_and_aliases(ASTNode *node, FILE *out) { + while (node) { + if (node->type == NODE_INCLUDE) { + if (node->include.is_system) { + fprintf(out, "#include <%s>\n", node->include.path); + } else { + fprintf(out, "#include \"%s\"\n", node->include.path); + } + } else if (node->type == NODE_TYPE_ALIAS) { + fprintf(out, "typedef %s %s;\n", node->type_alias.original_type, + node->type_alias.alias); } + node = node->next; + } } // Emit enum constructor prototypes -void emit_enum_protos(ASTNode *node, FILE *out) -{ - while (node) - { - if (node->type == NODE_ENUM && !node->enm.is_template) - { - ASTNode *v = node->enm.variants; - while (v) - { - if (v->variant.payload) - { - char *tstr = type_to_string(v->variant.payload); - fprintf(out, "%s %s_%s(%s v);\n", node->enm.name, node->enm.name, - v->variant.name, tstr); - free(tstr); - } - else - { - fprintf(out, "%s %s_%s();\n", node->enm.name, node->enm.name, v->variant.name); - } - v = v->next; - } +void emit_enum_protos(ASTNode *node, FILE *out) { + while (node) { + if (node->type == NODE_ENUM && !node->enm.is_template) { + ASTNode *v = node->enm.variants; + while (v) { + if (v->variant.payload) { + char *tstr = type_to_string(v->variant.payload); + fprintf(out, "%s %s_%s(%s v);\n", node->enm.name, node->enm.name, + v->variant.name, tstr); + free(tstr); + } else { + fprintf(out, "%s %s_%s();\n", node->enm.name, node->enm.name, + v->variant.name); } - node = node->next; + v = v->next; + } } + node = node->next; + } } // Emit lambda definitions. -void emit_lambda_defs(ParserContext *ctx, FILE *out) -{ - LambdaRef *cur = ctx->global_lambdas; - while (cur) - { - ASTNode *node = cur->node; - int saved_defer = defer_count; - defer_count = 0; - - if (node->lambda.num_captures > 0) - { - fprintf(out, "struct Lambda_%d_Ctx {\n", node->lambda.lambda_id); - for (int i = 0; i < node->lambda.num_captures; i++) - { - fprintf(out, " %s %s;\n", node->lambda.captured_types[i], - node->lambda.captured_vars[i]); - } - fprintf(out, "};\n"); - } +void emit_lambda_defs(ParserContext *ctx, FILE *out) { + LambdaRef *cur = ctx->global_lambdas; + while (cur) { + ASTNode *node = cur->node; + int saved_defer = defer_count; + defer_count = 0; + + if (node->lambda.num_captures > 0) { + fprintf(out, "struct Lambda_%d_Ctx {\n", node->lambda.lambda_id); + for (int i = 0; i < node->lambda.num_captures; i++) { + fprintf(out, " %s %s;\n", node->lambda.captured_types[i], + node->lambda.captured_vars[i]); + } + fprintf(out, "};\n"); + } - fprintf(out, "%s _lambda_%d(void* _ctx", node->lambda.return_type, node->lambda.lambda_id); + fprintf(out, "%s _lambda_%d(void* _ctx", node->lambda.return_type, + node->lambda.lambda_id); - for (int i = 0; i < node->lambda.num_params; i++) - { - fprintf(out, ", %s %s", node->lambda.param_types[i], node->lambda.param_names[i]); - } - fprintf(out, ") {\n"); + for (int i = 0; i < node->lambda.num_params; i++) { + fprintf(out, ", %s %s", node->lambda.param_types[i], + node->lambda.param_names[i]); + } + fprintf(out, ") {\n"); - if (node->lambda.num_captures > 0) - { - fprintf(out, " struct Lambda_%d_Ctx* ctx = (struct Lambda_%d_Ctx*)_ctx;\n", - node->lambda.lambda_id, node->lambda.lambda_id); - } + if (node->lambda.num_captures > 0) { + fprintf(out, + " struct Lambda_%d_Ctx* ctx = (struct Lambda_%d_Ctx*)_ctx;\n", + node->lambda.lambda_id, node->lambda.lambda_id); + } - g_current_lambda = node; - if (node->lambda.body && node->lambda.body->type == NODE_BLOCK) - { - codegen_walker(ctx, node->lambda.body->block.statements, out); - } - g_current_lambda = NULL; + g_current_lambda = node; + if (node->lambda.body && node->lambda.body->type == NODE_BLOCK) { + codegen_walker(ctx, node->lambda.body->block.statements, out); + } + g_current_lambda = NULL; - for (int i = defer_count - 1; i >= 0; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } + for (int i = defer_count - 1; i >= 0; i--) { + codegen_node_single(ctx, defer_stack[i], out); + } - fprintf(out, "}\n\n"); + fprintf(out, "}\n\n"); - defer_count = saved_defer; - cur = cur->next; - } + defer_count = saved_defer; + cur = cur->next; + } } // Emit struct and enum definitions. -void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out) -{ - while (node) - { - if (node->type == NODE_STRUCT && node->strct.is_template) - { - node = node->next; - continue; +void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out) { + while (node) { + if (node->type == NODE_STRUCT && node->strct.is_template) { + node = node->next; + continue; + } + if (node->type == NODE_ENUM && node->enm.is_template) { + node = node->next; + continue; + } + if (node->type == NODE_STRUCT) { + if (node->strct.is_incomplete) { + // Forward declaration - no body needed (typedef handles it) + node = node->next; + continue; + } + + if (node->strct.is_union) { + fprintf(out, "union %s {", node->strct.name); + } else { + fprintf(out, "struct %s {", node->strct.name); + } + fprintf(out, "\n"); + codegen_walker(ctx, node->strct.fields, out); + fprintf(out, "}"); + + if (node->strct.is_packed && node->strct.align) { + fprintf(out, " __attribute__((packed, aligned(%d)))", + node->strct.align); + } else if (node->strct.is_packed) { + fprintf(out, " __attribute__((packed))"); + } else if (node->strct.align) { + fprintf(out, " __attribute__((aligned(%d)))", node->strct.align); + } + fprintf(out, ";\n\n"); + } else if (node->type == NODE_ENUM) { + fprintf(out, "typedef enum { "); + ASTNode *v = node->enm.variants; + while (v) { + fprintf(out, "%s_%s_Tag, ", node->enm.name, v->variant.name); + v = v->next; + } + fprintf(out, "} %s_Tag;\n", node->enm.name); + fprintf(out, "struct %s { %s_Tag tag; union { ", node->enm.name, + node->enm.name); + v = node->enm.variants; + while (v) { + if (v->variant.payload) { + char *tstr = type_to_string(v->variant.payload); + fprintf(out, "%s %s; ", tstr, v->variant.name); + free(tstr); } - if (node->type == NODE_ENUM && node->enm.is_template) - { - node = node->next; - continue; + v = v->next; + } + fprintf(out, "} data; };\n\n"); + v = node->enm.variants; + while (v) { + if (v->variant.payload) { + char *tstr = type_to_string(v->variant.payload); + fprintf(out, + "%s %s_%s(%s v) { return (%s){.tag=%s_%s_Tag, " + ".data.%s=v}; }\n", + node->enm.name, node->enm.name, v->variant.name, tstr, + node->enm.name, node->enm.name, v->variant.name, + v->variant.name); + free(tstr); + } else { + fprintf(out, "%s %s_%s() { return (%s){.tag=%s_%s_Tag}; }\n", + node->enm.name, node->enm.name, v->variant.name, + node->enm.name, node->enm.name, v->variant.name); } - if (node->type == NODE_STRUCT) - { - if (node->strct.is_incomplete) - { - // Forward declaration - no body needed (typedef handles it) - node = node->next; - continue; - } + v = v->next; + } + } + node = node->next; + } +} - if (node->strct.is_union) - { - fprintf(out, "union %s {", node->strct.name); - } - else - { - fprintf(out, "struct %s {", node->strct.name); - } - fprintf(out, "\n"); - codegen_walker(ctx, node->strct.fields, out); - fprintf(out, "}"); +// Emit trait definitions. +void emit_trait_defs(ASTNode *node, FILE *out) { + while (node) { + if (node->type == NODE_TRAIT) { + fprintf(out, "typedef struct %s_VTable {\n", node->trait.name); + ASTNode *m = node->trait.methods; + while (m) { + fprintf(out, " %s (*%s)(", m->func.ret_type, + parse_original_method_name(m->func.name)); + int has_self = (m->func.args && strstr(m->func.args, "self")); + if (!has_self) { + fprintf(out, "void* self"); + } - if (node->strct.is_packed && node->strct.align) - { - fprintf(out, " __attribute__((packed, aligned(%d)))", node->strct.align); - } - else if (node->strct.is_packed) - { - fprintf(out, " __attribute__((packed))"); - } - else if (node->strct.align) - { - fprintf(out, " __attribute__((aligned(%d)))", node->strct.align); - } - fprintf(out, ";\n\n"); + if (m->func.args) { + if (!has_self) { + fprintf(out, ", "); + } + fprintf(out, "%s", m->func.args); } - else if (node->type == NODE_ENUM) - { - fprintf(out, "typedef enum { "); - ASTNode *v = node->enm.variants; - while (v) - { - fprintf(out, "%s_%s_Tag, ", node->enm.name, v->variant.name); - v = v->next; - } - fprintf(out, "} %s_Tag;\n", node->enm.name); - fprintf(out, "struct %s { %s_Tag tag; union { ", node->enm.name, node->enm.name); - v = node->enm.variants; - while (v) - { - if (v->variant.payload) - { - char *tstr = type_to_string(v->variant.payload); - fprintf(out, "%s %s; ", tstr, v->variant.name); - free(tstr); - } - v = v->next; - } - fprintf(out, "} data; };\n\n"); - v = node->enm.variants; - while (v) - { - if (v->variant.payload) - { - char *tstr = type_to_string(v->variant.payload); - fprintf(out, - "%s %s_%s(%s v) { return (%s){.tag=%s_%s_Tag, " - ".data.%s=v}; }\n", - node->enm.name, node->enm.name, v->variant.name, tstr, node->enm.name, - node->enm.name, v->variant.name, v->variant.name); - free(tstr); - } - else - { - fprintf(out, "%s %s_%s() { return (%s){.tag=%s_%s_Tag}; }\n", node->enm.name, - node->enm.name, v->variant.name, node->enm.name, node->enm.name, - v->variant.name); - } - v = v->next; - } + fprintf(out, ");\n"); + m = m->next; + } + fprintf(out, "} %s_VTable;\n", node->trait.name); + fprintf(out, "typedef struct %s { void *self; %s_VTable *vtable; } %s;\n", + node->trait.name, node->trait.name, node->trait.name); + + m = node->trait.methods; + while (m) { + const char *orig = parse_original_method_name(m->func.name); + fprintf(out, "%s %s_%s(%s* self", m->func.ret_type, node->trait.name, + orig, node->trait.name); + + int has_self = (m->func.args && strstr(m->func.args, "self")); + if (m->func.args) { + if (has_self) { + char *comma = strchr(m->func.args, ','); + if (comma) { + fprintf(out, ", %s", comma + 1); + } + } else { + fprintf(out, ", %s", m->func.args); + } } - node = node->next; - } -} + fprintf(out, ") {\n"); -// Emit trait definitions. -void emit_trait_defs(ASTNode *node, FILE *out) -{ - while (node) - { - if (node->type == NODE_TRAIT) - { - fprintf(out, "typedef struct %s_VTable {\n", node->trait.name); - ASTNode *m = node->trait.methods; - while (m) - { - fprintf(out, " %s (*%s)(", m->func.ret_type, - parse_original_method_name(m->func.name)); - int has_self = (m->func.args && strstr(m->func.args, "self")); - if (!has_self) - { - fprintf(out, "void* self"); - } - - if (m->func.args) - { - if (!has_self) - { - fprintf(out, ", "); - } - fprintf(out, "%s", m->func.args); - } - fprintf(out, ");\n"); - m = m->next; + fprintf(out, " return self->vtable->%s(self->self", orig); + + if (m->func.args) { + char *call_args = extract_call_args(m->func.args); + if (has_self) { + char *comma = strchr(call_args, ','); + if (comma) { + fprintf(out, ", %s", comma + 1); } - fprintf(out, "} %s_VTable;\n", node->trait.name); - fprintf(out, "typedef struct %s { void *self; %s_VTable *vtable; } %s;\n", - node->trait.name, node->trait.name, node->trait.name); - - m = node->trait.methods; - while (m) - { - const char *orig = parse_original_method_name(m->func.name); - fprintf(out, "%s %s_%s(%s* self", m->func.ret_type, node->trait.name, orig, - node->trait.name); - - int has_self = (m->func.args && strstr(m->func.args, "self")); - if (m->func.args) - { - if (has_self) - { - char *comma = strchr(m->func.args, ','); - if (comma) - { - fprintf(out, ", %s", comma + 1); - } - } - else - { - fprintf(out, ", %s", m->func.args); - } - } - fprintf(out, ") {\n"); - - fprintf(out, " return self->vtable->%s(self->self", orig); - - if (m->func.args) - { - char *call_args = extract_call_args(m->func.args); - if (has_self) - { - char *comma = strchr(call_args, ','); - if (comma) - { - fprintf(out, ", %s", comma + 1); - } - } - else - { - if (strlen(call_args) > 0) - { - fprintf(out, ", %s", call_args); - } - } - free(call_args); - } - fprintf(out, ");\n}\n"); - - m = m->next; + } else { + if (strlen(call_args) > 0) { + fprintf(out, ", %s", call_args); } - fprintf(out, "\n"); + } + free(call_args); } - node = node->next; + fprintf(out, ");\n}\n"); + + m = m->next; + } + fprintf(out, "\n"); } + node = node->next; + } } // Emit global variables -void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out) -{ - while (node) - { - if (node->type == NODE_VAR_DECL || node->type == NODE_CONST) - { - if (node->type == NODE_CONST) - { - fprintf(out, "const "); - } - if (node->var_decl.type_str) - { - emit_var_decl_type(ctx, out, node->var_decl.type_str, node->var_decl.name); - } - else - { - 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) - { - emit_var_decl_type(ctx, out, inferred, node->var_decl.name); - } - else - { - emit_auto_type(ctx, node->var_decl.init_expr, node->token, out); - fprintf(out, " %s", node->var_decl.name); - } - } - if (node->var_decl.init_expr) - { - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - } - fprintf(out, ";\n"); +void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out) { + while (node) { + if (node->type == NODE_VAR_DECL || node->type == NODE_CONST) { + if (node->type == NODE_CONST) { + fprintf(out, "const "); + } + if (node->var_decl.type_str) { + emit_var_decl_type(ctx, out, node->var_decl.type_str, + node->var_decl.name); + } else { + char *inferred = NULL; + if (node->var_decl.init_expr) { + inferred = infer_type(ctx, node->var_decl.init_expr); } - node = node->next; + + if (inferred && strcmp(inferred, "__auto_type") != 0) { + emit_var_decl_type(ctx, out, inferred, node->var_decl.name); + } else { + emit_auto_type(ctx, node->var_decl.init_expr, node->token, out); + fprintf(out, " %s", node->var_decl.name); + } + } + if (node->var_decl.init_expr) { + fprintf(out, " = "); + codegen_expression(ctx, node->var_decl.init_expr, out); + } + fprintf(out, ";\n"); } + node = node->next; + } } // Emit function prototypes -void emit_protos(ASTNode *node, FILE *out) -{ - ASTNode *f = node; - while (f) - { - if (f->type == NODE_FUNCTION) - { - if (f->func.is_async) - { - fprintf(out, "Async %s(%s);\n", f->func.name, f->func.args); - // Also emit _impl_ prototype - if (f->func.ret_type) - { - fprintf(out, "%s _impl_%s(%s);\n", f->func.ret_type, f->func.name, - f->func.args); - } - else - { - fprintf(out, "void _impl_%s(%s);\n", f->func.name, f->func.args); - } - } - else - { - fprintf(out, "%s %s(%s);\n", f->func.ret_type, f->func.name, f->func.args); - } +void emit_protos(ASTNode *node, FILE *out) { + ASTNode *f = node; + while (f) { + if (f->type == NODE_FUNCTION) { + if (f->func.is_async) { + fprintf(out, "Async %s(%s);\n", f->func.name, f->func.args); + // Also emit _impl_ prototype + if (f->func.ret_type) { + fprintf(out, "%s _impl_%s(%s);\n", f->func.ret_type, f->func.name, + f->func.args); + } else { + fprintf(out, "void _impl_%s(%s);\n", f->func.name, f->func.args); } - else if (f->type == NODE_IMPL) - { - char *sname = f->impl.struct_name; - if (!sname) - { - f = f->next; - continue; - } - - char *mangled = replace_string_type(sname); - ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled); - int skip = 0; - if (def) - { - if (def->type == NODE_STRUCT && def->strct.is_template) - { - skip = 1; - } - else if (def->type == NODE_ENUM && def->enm.is_template) - { - skip = 1; - } - } - else - { - char *lt = strchr(sname, '<'); - if (lt) - { - 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) - { - skip = 1; - } - free(buf); - } - } - if (mangled) - { - free(mangled); - } - - if (skip) - { - f = f->next; - continue; - } - - ASTNode *m = f->impl.methods; - while (m) - { - char *fname = m->func.name; - char *proto = xmalloc(strlen(fname) + strlen(sname) + 2); - int slen = strlen(sname); - if (strncmp(fname, sname, slen) == 0 && fname[slen] == '_') - { - strcpy(proto, fname); - } - else - { - sprintf(proto, "%s_%s", sname, fname); - } - - if (m->func.is_async) - { - fprintf(out, "Async %s(%s);\n", proto, m->func.args); - } - else - { - fprintf(out, "%s %s(%s);\n", m->func.ret_type, proto, m->func.args); - } - - free(proto); - m = m->next; - } + } else { + fprintf(out, "%s %s(%s);\n", f->func.ret_type, f->func.name, + f->func.args); + } + } else if (f->type == NODE_IMPL) { + char *sname = f->impl.struct_name; + if (!sname) { + f = f->next; + continue; + } + + char *mangled = replace_string_type(sname); + ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled); + int skip = 0; + if (def) { + if (def->type == NODE_STRUCT && def->strct.is_template) { + skip = 1; + } else if (def->type == NODE_ENUM && def->enm.is_template) { + skip = 1; } - else if (f->type == NODE_IMPL_TRAIT) - { - char *sname = f->impl_trait.target_type; - if (!sname) - { - f = f->next; - continue; - } + } else { + char *lt = strchr(sname, '<'); + if (lt) { + 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) { + skip = 1; + } + free(buf); + } + } + if (mangled) { + free(mangled); + } - char *mangled = replace_string_type(sname); - ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled); - int skip = 0; - if (def) - { - if (def->strct.is_template) - { - skip = 1; - } - } - else - { - char *lt = strchr(sname, '<'); - if (lt) - { - 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) - { - skip = 1; - } - free(buf); - } - } - if (mangled) - { - free(mangled); - } + if (skip) { + f = f->next; + continue; + } + + ASTNode *m = f->impl.methods; + while (m) { + char *fname = m->func.name; + char *proto = xmalloc(strlen(fname) + strlen(sname) + 2); + int slen = strlen(sname); + if (strncmp(fname, sname, slen) == 0 && fname[slen] == '_') { + strcpy(proto, fname); + } else { + sprintf(proto, "%s_%s", sname, fname); + } - if (skip) - { - f = f->next; - continue; - } + if (m->func.is_async) { + fprintf(out, "Async %s(%s);\n", proto, m->func.args); + } else { + fprintf(out, "%s %s(%s);\n", m->func.ret_type, proto, m->func.args); + } - ASTNode *m = f->impl_trait.methods; - while (m) - { - if (m->func.is_async) - { - fprintf(out, "Async %s(%s);\n", m->func.name, m->func.args); - } - else - { - fprintf(out, "%s %s(%s);\n", m->func.ret_type, m->func.name, m->func.args); - } - m = m->next; - } - // RAII: Emit glue prototype - if (strcmp(f->impl_trait.trait_name, "Drop") == 0) - { - char *tname = f->impl_trait.target_type; - fprintf(out, "void %s_Drop_glue(%s *self);\n", tname, tname); - } + free(proto); + m = m->next; + } + } else if (f->type == NODE_IMPL_TRAIT) { + char *sname = f->impl_trait.target_type; + if (!sname) { + f = f->next; + continue; + } + + char *mangled = replace_string_type(sname); + ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled); + int skip = 0; + if (def) { + if (def->strct.is_template) { + skip = 1; } + } else { + char *lt = strchr(sname, '<'); + if (lt) { + 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) { + skip = 1; + } + free(buf); + } + } + if (mangled) { + free(mangled); + } + + if (skip) { f = f->next; + continue; + } + + ASTNode *m = f->impl_trait.methods; + while (m) { + if (m->func.is_async) { + fprintf(out, "Async %s(%s);\n", m->func.name, m->func.args); + } else { + fprintf(out, "%s %s(%s);\n", m->func.ret_type, m->func.name, + m->func.args); + } + m = m->next; + } + // RAII: Emit glue prototype + if (strcmp(f->impl_trait.trait_name, "Drop") == 0) { + char *tname = f->impl_trait.target_type; + fprintf(out, "void %s_Drop_glue(%s *self);\n", tname, tname); + } } + f = f->next; + } } // Emit VTable instances for trait implementations. -void emit_impl_vtables(ParserContext *ctx, FILE *out) -{ - StructRef *ref = ctx->parsed_impls_list; - struct - { - char *trait; - char *strct; - } emitted[1024]; - int count = 0; - - while (ref) - { - ASTNode *node = ref->node; - if (node && node->type == NODE_IMPL_TRAIT) - { - char *trait = node->impl_trait.trait_name; - char *strct = node->impl_trait.target_type; - - // Filter templates - char *mangled = replace_string_type(strct); - ASTNode *def = find_struct_def_codegen(ctx, mangled); - int skip = 0; - if (def) - { - if (def->type == NODE_STRUCT && def->strct.is_template) - { - skip = 1; - } - else if (def->type == NODE_ENUM && def->enm.is_template) - { - skip = 1; - } - } - else - { - char *lt = strchr(strct, '<'); - if (lt) - { - 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) - { - skip = 1; - } - free(buf); - } - } - if (mangled) - { - free(mangled); - } - if (skip) - { - ref = ref->next; - continue; - } - - // Check duplication - int dup = 0; - for (int i = 0; i < count; i++) - { - if (strcmp(emitted[i].trait, trait) == 0 && strcmp(emitted[i].strct, strct) == 0) - { - dup = 1; - break; - } - } - if (dup) - { - ref = ref->next; - continue; - } - - emitted[count].trait = trait; - emitted[count].strct = strct; - count++; - - fprintf(out, "%s_VTable %s_%s_VTable = {", trait, strct, trait); - - ASTNode *m = node->impl_trait.methods; - while (m) - { - const char *orig = parse_original_method_name(m->func.name); - fprintf(out, ".%s = (__typeof__(((%s_VTable*)0)->%s))%s_%s_%s", orig, trait, orig, - strct, trait, orig); - if (m->next) - { - fprintf(out, ", "); - } - m = m->next; - } - fprintf(out, "};\n"); +void emit_impl_vtables(ParserContext *ctx, FILE *out) { + StructRef *ref = ctx->parsed_impls_list; + struct { + char *trait; + char *strct; + } emitted[1024]; + int count = 0; + + while (ref) { + ASTNode *node = ref->node; + if (node && node->type == NODE_IMPL_TRAIT) { + char *trait = node->impl_trait.trait_name; + char *strct = node->impl_trait.target_type; + + // Filter templates + char *mangled = replace_string_type(strct); + ASTNode *def = find_struct_def_codegen(ctx, mangled); + int skip = 0; + if (def) { + if (def->type == NODE_STRUCT && def->strct.is_template) { + skip = 1; + } else if (def->type == NODE_ENUM && def->enm.is_template) { + skip = 1; + } + } else { + char *lt = strchr(strct, '<'); + if (lt) { + 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) { + skip = 1; + } + free(buf); + } + } + if (mangled) { + free(mangled); + } + if (skip) { + ref = ref->next; + continue; + } + + // Check duplication + int dup = 0; + for (int i = 0; i < count; i++) { + if (strcmp(emitted[i].trait, trait) == 0 && + strcmp(emitted[i].strct, strct) == 0) { + dup = 1; + break; } + } + if (dup) { ref = ref->next; + continue; + } + + emitted[count].trait = trait; + emitted[count].strct = strct; + count++; + + fprintf(out, "%s_VTable %s_%s_VTable = {", trait, strct, trait); + + ASTNode *m = node->impl_trait.methods; + while (m) { + const char *orig = parse_original_method_name(m->func.name); + fprintf(out, ".%s = (__typeof__(((%s_VTable*)0)->%s))%s_%s_%s", orig, + trait, orig, strct, trait, orig); + if (m->next) { + fprintf(out, ", "); + } + m = m->next; + } + fprintf(out, "};\n"); } + ref = ref->next; + } } // Emit test functions and runner -void emit_tests_and_runner(ParserContext *ctx, ASTNode *node, FILE *out) -{ - ASTNode *cur = node; - int test_count = 0; - while (cur) - { - if (cur->type == NODE_TEST) - { - fprintf(out, "static void _z_test_%d() {\n", test_count); - codegen_walker(ctx, cur->test_stmt.body, out); - fprintf(out, "}\n"); - test_count++; - } - cur = cur->next; +void emit_tests_and_runner(ParserContext *ctx, ASTNode *node, FILE *out) { + ASTNode *cur = node; + int test_count = 0; + while (cur) { + if (cur->type == NODE_TEST) { + fprintf(out, "static void _z_test_%d() {\n", test_count); + codegen_walker(ctx, cur->test_stmt.body, out); + fprintf(out, "}\n"); + test_count++; } - if (test_count > 0) - { - fprintf(out, "\nvoid _z_run_tests() {\n"); - for (int i = 0; i < test_count; i++) - { - fprintf(out, " _z_test_%d();\n", i); - } - fprintf(out, "}\n\n"); - } - else - { - fprintf(out, "void _z_run_tests() {}\n"); + cur = cur->next; + } + if (test_count > 0) { + fprintf(out, "\nvoid _z_run_tests() {\n"); + for (int i = 0; i < test_count; i++) { + fprintf(out, " _z_test_%d();\n", i); } + fprintf(out, "}\n\n"); + } else { + fprintf(out, "void _z_run_tests() {}\n"); + } } // Emit type definitions- -void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes) -{ - if (!g_config.is_freestanding) - { - fprintf(out, "typedef char* string;\n"); - } - - fprintf(out, "typedef struct { void **data; int len; int cap; } Vec;\n"); - fprintf(out, "#define Vec_new() (Vec){.data=0, .len=0, .cap=0}\n"); - fprintf(out, "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { " - "v->cap = v->cap?v->cap*2:8; " - "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } " - "v->data[v->len++] = item; }\n"); - fprintf(out, "#define Vec_push(v, i) _z_vec_push(&(v), (void*)(long)(i))\n"); - fprintf(out, "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = " - "count > 8 ? " - "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list " - "args; " - "va_start(args, count); for(int i=0; i<count; i++) { v.data[v.len++] = " - "va_arg(args, void*); } va_end(args); return v; }\n"); - - if (g_config.is_freestanding) - { - fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = " - "(index); if(_i < 0 " - "|| _i >= (limit)) { z_panic(\"index out of bounds\"); } _i; })\n"); +void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes) { + if (!g_config.is_freestanding) { + fprintf(out, "typedef char* string;\n"); + } + + fprintf(out, "typedef struct { void **data; int len; int cap; } Vec;\n"); + fprintf(out, "#define Vec_new() (Vec){.data=0, .len=0, .cap=0}\n"); + fprintf(out, "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { " + "v->cap = v->cap?v->cap*2:8; " + "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } " + "v->data[v->len++] = item; }\n"); + fprintf(out, "#define Vec_push(v, i) _z_vec_push(&(v), (void*)(long)(i))\n"); + fprintf( + out, + "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = " + "count > 8 ? " + "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list " + "args; " + "va_start(args, count); for(int i=0; i<count; i++) { v.data[v.len++] = " + "va_arg(args, void*); } va_end(args); return v; }\n"); + + if (g_config.is_freestanding) { + fprintf(out, + "#define _z_check_bounds(index, limit) ({ __auto_type _i = " + "(index); if(_i < 0 " + "|| _i >= (limit)) { z_panic(\"index out of bounds\"); } _i; })\n"); + } else { + fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = " + "(index); if(_i < 0 " + "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: " + "%%ld (limit " + "%%d)\\n\", (long)_i, (int)(limit)); exit(1); } _i; })\n"); + } + + SliceType *c = ctx->used_slices; + while (c) { + fprintf(out, + "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; " + "int len; int cap; };\n", + c->name, c->name, c->name, c->name); + c = c->next; + } + + TupleType *t = ctx->used_tuples; + while (t) { + fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ", + t->sig, t->sig, t->sig); + char *s = xstrdup(t->sig); + char *p = strtok(s, "_"); + int i = 0; + while (p) { + fprintf(out, "%s v%d; ", p, i++); + p = strtok(NULL, "_"); } - else - { - fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = " - "(index); if(_i < 0 " - "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: " - "%%ld (limit " - "%%d)\\n\", (long)_i, (int)(limit)); exit(1); } _i; })\n"); + free(s); + fprintf(out, "};\n"); + t = t->next; + } + fprintf(out, "\n"); + + // FIRST: Emit typedefs for ALL structs and enums in the current compilation + // unit (local definitions) + ASTNode *local = nodes; + while (local) { + if (local->type == NODE_STRUCT && !local->strct.is_template) { + const char *keyword = local->strct.is_union ? "union" : "struct"; + fprintf(out, "typedef %s %s %s;\n", keyword, local->strct.name, + local->strct.name); } - - SliceType *c = ctx->used_slices; - while (c) - { - fprintf(out, - "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; " - "int len; int cap; };\n", - c->name, c->name, c->name, c->name); - c = c->next; + if (local->type == NODE_ENUM && !local->enm.is_template) { + fprintf(out, "typedef struct %s %s;\n", local->enm.name, local->enm.name); } - - TupleType *t = ctx->used_tuples; - while (t) - { - fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ", t->sig, t->sig, - t->sig); - char *s = xstrdup(t->sig); - char *p = strtok(s, "_"); - int i = 0; - while (p) - { - fprintf(out, "%s v%d; ", p, i++); - p = strtok(NULL, "_"); - } - free(s); - fprintf(out, "};\n"); - t = t->next; + local = local->next; + } + + // THEN: Emit typedefs for instantiated generics + Instantiation *i = ctx->instantiations; + while (i) { + if (i->struct_node->type == NODE_RAW_STMT) { + fprintf(out, "%s\n", i->struct_node->raw_stmt.content); + } else { + fprintf(out, "typedef struct %s %s;\n", i->struct_node->strct.name, + i->struct_node->strct.name); + codegen_node(ctx, i->struct_node, out); } - fprintf(out, "\n"); - - // FIRST: Emit typedefs for ALL structs and enums in the current compilation - // unit (local definitions) - ASTNode *local = nodes; - while (local) - { - if (local->type == NODE_STRUCT && !local->strct.is_template) - { - const char *keyword = local->strct.is_union ? "union" : "struct"; - fprintf(out, "typedef %s %s %s;\n", keyword, local->strct.name, local->strct.name); - } - if (local->type == NODE_ENUM && !local->enm.is_template) - { - fprintf(out, "typedef struct %s %s;\n", local->enm.name, local->enm.name); - } - local = local->next; + i = i->next; + } + + StructRef *sr = ctx->parsed_structs_list; + while (sr) { + if (sr->node && sr->node->type == NODE_STRUCT && + !sr->node->strct.is_template) { + const char *keyword = sr->node->strct.is_union ? "union" : "struct"; + fprintf(out, "typedef %s %s %s;\n", keyword, sr->node->strct.name, + sr->node->strct.name); } - // THEN: Emit typedefs for instantiated generics - Instantiation *i = ctx->instantiations; - while (i) - { - if (i->struct_node->type == NODE_RAW_STMT) - { - fprintf(out, "%s\n", i->struct_node->raw_stmt.content); - } - else - { - fprintf(out, "typedef struct %s %s;\n", i->struct_node->strct.name, - i->struct_node->strct.name); - codegen_node(ctx, i->struct_node, out); - } - i = i->next; + if (sr->node && sr->node->type == NODE_ENUM && !sr->node->enm.is_template) { + fprintf(out, "typedef struct %s %s;\n", sr->node->enm.name, + sr->node->enm.name); } - - StructRef *sr = ctx->parsed_structs_list; - while (sr) - { - if (sr->node && sr->node->type == NODE_STRUCT && !sr->node->strct.is_template) - { - const char *keyword = sr->node->strct.is_union ? "union" : "struct"; - fprintf(out, "typedef %s %s %s;\n", keyword, sr->node->strct.name, - sr->node->strct.name); - } - - if (sr->node && sr->node->type == NODE_ENUM && !sr->node->enm.is_template) - { - fprintf(out, "typedef struct %s %s;\n", sr->node->enm.name, sr->node->enm.name); - } - sr = sr->next; + sr = sr->next; + } + + // Also check instantiated_structs list. + ASTNode *inst_s = ctx->instantiated_structs; + while (inst_s) { + if (inst_s->type == NODE_STRUCT && !inst_s->strct.is_template) { + const char *keyword = inst_s->strct.is_union ? "union" : "struct"; + fprintf(out, "typedef %s %s %s;\n", keyword, inst_s->strct.name, + inst_s->strct.name); } - // Also check instantiated_structs list. - ASTNode *inst_s = ctx->instantiated_structs; - while (inst_s) - { - if (inst_s->type == NODE_STRUCT && !inst_s->strct.is_template) - { - const char *keyword = inst_s->strct.is_union ? "union" : "struct"; - fprintf(out, "typedef %s %s %s;\n", keyword, inst_s->strct.name, inst_s->strct.name); - } - - if (inst_s->type == NODE_ENUM && !inst_s->enm.is_template) - { - fprintf(out, "typedef struct %s %s;\n", inst_s->enm.name, inst_s->enm.name); - } - inst_s = inst_s->next; + if (inst_s->type == NODE_ENUM && !inst_s->enm.is_template) { + fprintf(out, "typedef struct %s %s;\n", inst_s->enm.name, + inst_s->enm.name); } + inst_s = inst_s->next; + } } diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c index 3634af3..3b0e4dc 100644 --- a/src/codegen/codegen_main.c +++ b/src/codegen/codegen_main.c @@ -7,563 +7,457 @@ #include <string.h> // Helper: Check if a struct depends on another struct/enum by-value. -static int struct_depends_on(ASTNode *s1, const char *target_name) -{ - if (!s1) - { - return 0; - } - - // Only structs have dependencies that matter for ordering. - if (s1->type != NODE_STRUCT) - { - return 0; - } - - ASTNode *field = s1->strct.fields; - while (field) - { - if (field->type == NODE_FIELD && field->field.type) - { - char *type_str = field->field.type; - // Skip pointers - they don't create ordering dependency. - if (strchr(type_str, '*')) - { - field = field->next; - continue; - } +static int struct_depends_on(ASTNode *s1, const char *target_name) { + if (!s1) { + return 0; + } - // Check if this field's type matches target (struct or enum). - if (strcmp(type_str, target_name) == 0) - { - return 1; - } - } + // Only structs have dependencies that matter for ordering. + if (s1->type != NODE_STRUCT) { + return 0; + } + + ASTNode *field = s1->strct.fields; + while (field) { + if (field->type == NODE_FIELD && field->field.type) { + char *type_str = field->field.type; + // Skip pointers - they don't create ordering dependency. + if (strchr(type_str, '*')) { field = field->next; + continue; + } + + // Check if this field's type matches target (struct or enum). + if (strcmp(type_str, target_name) == 0) { + return 1; + } } - return 0; + field = field->next; + } + return 0; } // Topologically sort a list of struct/enum nodes. -static ASTNode *topo_sort_structs(ASTNode *head) -{ - if (!head) - { - return NULL; +static ASTNode *topo_sort_structs(ASTNode *head) { + if (!head) { + return NULL; + } + + // Count all nodes (structs + enums). + int count = 0; + ASTNode *n = head; + while (n) { + if (n->type == NODE_STRUCT || n->type == NODE_ENUM) { + count++; + } + n = n->next; + } + if (count == 0) { + return head; + } + + // Build array of all nodes. + ASTNode **nodes = malloc(count * sizeof(ASTNode *)); + int *emitted = calloc(count, sizeof(int)); + n = head; + int idx = 0; + while (n) { + if (n->type == NODE_STRUCT || n->type == NODE_ENUM) { + nodes[idx++] = n; } + n = n->next; + } + + // Build order array (indices in emission order). + int *order = malloc(count * sizeof(int)); + int order_idx = 0; + + int changed = 1; + int max_iterations = count * count; + int iterations = 0; + + while (changed && iterations < max_iterations) { + changed = 0; + iterations++; + + for (int i = 0; i < count; i++) { + if (emitted[i]) { + continue; + } + + // Enums have no dependencies, emit first. + if (nodes[i]->type == NODE_ENUM) { + order[order_idx++] = i; + emitted[i] = 1; + changed = 1; + continue; + } + + // For structs, check if all dependencies are emitted. + int can_emit = 1; + for (int j = 0; j < count; j++) { + if (i == j || emitted[j]) { + continue; + } - // Count all nodes (structs + enums). - int count = 0; - ASTNode *n = head; - while (n) - { - if (n->type == NODE_STRUCT || n->type == NODE_ENUM) - { - count++; + // Get the name of the potential dependency. + const char *dep_name = NULL; + if (nodes[j]->type == NODE_STRUCT) { + dep_name = nodes[j]->strct.name; + } else if (nodes[j]->type == NODE_ENUM) { + dep_name = nodes[j]->enm.name; } - n = n->next; - } - if (count == 0) - { - return head; - } - // Build array of all nodes. - ASTNode **nodes = malloc(count * sizeof(ASTNode *)); - int *emitted = calloc(count, sizeof(int)); - n = head; - int idx = 0; - while (n) - { - if (n->type == NODE_STRUCT || n->type == NODE_ENUM) - { - nodes[idx++] = n; + if (dep_name && struct_depends_on(nodes[i], dep_name)) { + can_emit = 0; + break; } - n = n->next; - } + } - // Build order array (indices in emission order). - int *order = malloc(count * sizeof(int)); - int order_idx = 0; + if (can_emit) { + order[order_idx++] = i; + emitted[i] = 1; + changed = 1; + } + } + } - int changed = 1; - int max_iterations = count * count; - int iterations = 0; + // Add any remaining nodes (cycles). + for (int i = 0; i < count; i++) { + if (!emitted[i]) { + order[order_idx++] = i; + } + } + + // Now build the linked list in the correct order. + ASTNode *result = NULL; + ASTNode *result_tail = NULL; + + for (int i = 0; i < order_idx; i++) { + ASTNode *node = nodes[order[i]]; + if (!result) { + result = node; + result_tail = node; + } else { + result_tail->next = node; + result_tail = node; + } + } + if (result_tail) { + result_tail->next = NULL; + } + + free(nodes); + free(emitted); + free(order); + return result; +} - while (changed && iterations < max_iterations) - { - changed = 0; - iterations++; +// Main entry point for code generation. +void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out) { + if (node->type == NODE_ROOT) { + ASTNode *kids = node->root.children; + // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple + // times). + while (kids && kids->type == NODE_ROOT) { + kids = kids->root.children; + } - for (int i = 0; i < count; i++) - { - if (emitted[i]) - { - continue; - } + global_user_structs = kids; - // Enums have no dependencies, emit first. - if (nodes[i]->type == NODE_ENUM) - { - order[order_idx++] = i; - emitted[i] = 1; - changed = 1; - continue; - } + if (!ctx->skip_preamble) { + emit_preamble(ctx, out); + } + emit_includes_and_aliases(kids, out); + + // Emit Hoisted Code (from plugins) + if (ctx->hoist_out) { + long pos = ftell(ctx->hoist_out); + rewind(ctx->hoist_out); + char buf[4096]; + size_t n; + while ((n = fread(buf, 1, sizeof(buf), ctx->hoist_out)) > 0) { + fwrite(buf, 1, n, out); + } + fseek(ctx->hoist_out, pos, SEEK_SET); + } - // For structs, check if all dependencies are emitted. - int can_emit = 1; - for (int j = 0; j < count; j++) - { - if (i == j || emitted[j]) - { - continue; - } - - // Get the name of the potential dependency. - const char *dep_name = NULL; - if (nodes[j]->type == NODE_STRUCT) - { - dep_name = nodes[j]->strct.name; - } - else if (nodes[j]->type == NODE_ENUM) - { - dep_name = nodes[j]->enm.name; - } - - if (dep_name && struct_depends_on(nodes[i], dep_name)) - { - can_emit = 0; - break; - } - } + ASTNode *merged = NULL; + ASTNode *merged_tail = NULL; + + ASTNode *s = ctx->instantiated_structs; + while (s) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *s; + copy->next = NULL; + if (!merged) { + merged = copy; + merged_tail = copy; + } else { + merged_tail->next = copy; + merged_tail = copy; + } + s = s->next; + } - if (can_emit) - { - order[order_idx++] = i; - emitted[i] = 1; - changed = 1; - } + StructRef *sr = ctx->parsed_structs_list; + while (sr) { + if (sr->node) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *sr->node; + copy->next = NULL; + if (!merged) { + merged = copy; + merged_tail = copy; + } else { + merged_tail->next = copy; + merged_tail = copy; } + } + sr = sr->next; } - // Add any remaining nodes (cycles). - for (int i = 0; i < count; i++) - { - if (!emitted[i]) - { - order[order_idx++] = i; + StructRef *er = ctx->parsed_enums_list; + while (er) { + if (er->node) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *er->node; + copy->next = NULL; + if (!merged) { + merged = copy; + merged_tail = copy; + } else { + merged_tail->next = copy; + merged_tail = copy; } + } + er = er->next; } - // Now build the linked list in the correct order. - ASTNode *result = NULL; - ASTNode *result_tail = NULL; - - for (int i = 0; i < order_idx; i++) - { - ASTNode *node = nodes[order[i]]; - if (!result) - { - result = node; - result_tail = node; + ASTNode *k = kids; + while (k) { + if (k->type == NODE_STRUCT || k->type == NODE_ENUM) { + int found = 0; + ASTNode *chk = merged; + while (chk) { + if (chk->type == k->type) { + const char *n1 = + (k->type == NODE_STRUCT) ? k->strct.name : k->enm.name; + const char *n2 = + (chk->type == NODE_STRUCT) ? chk->strct.name : chk->enm.name; + if (n1 && n2 && strcmp(n1, n2) == 0) { + found = 1; + break; + } + } + chk = chk->next; } - else - { - result_tail->next = node; - result_tail = node; + + if (!found) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *k; + copy->next = NULL; + if (!merged) { + merged = copy; + merged_tail = copy; + } else { + merged_tail->next = copy; + merged_tail = copy; + } } - } - if (result_tail) - { - result_tail->next = NULL; + } + k = k->next; } - free(nodes); - free(emitted); - free(order); - return result; -} + // Topologically sort. + ASTNode *sorted = topo_sort_structs(merged); -// Main entry point for code generation. -void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out) -{ - if (node->type == NODE_ROOT) - { - ASTNode *kids = node->root.children; - // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple - // times). - while (kids && kids->type == NODE_ROOT) - { - kids = kids->root.children; - } + print_type_defs(ctx, out, sorted); + emit_enum_protos(sorted, out); - global_user_structs = kids; + if (sorted) { + emit_struct_defs(ctx, sorted, out); + } + emit_trait_defs(kids, out); + + ASTNode *raw_iter = kids; + while (raw_iter) { + if (raw_iter->type == NODE_RAW_STMT) { + fprintf(out, "%s\n", raw_iter->raw_stmt.content); + } + raw_iter = raw_iter->next; + } - if (!ctx->skip_preamble) - { - emit_preamble(ctx, out); - } - emit_includes_and_aliases(kids, out); - - // Emit Hoisted Code (from plugins) - if (ctx->hoist_out) - { - long pos = ftell(ctx->hoist_out); - rewind(ctx->hoist_out); - char buf[4096]; - size_t n; - while ((n = fread(buf, 1, sizeof(buf), ctx->hoist_out)) > 0) - { - fwrite(buf, 1, n, out); - } - fseek(ctx->hoist_out, pos, SEEK_SET); - } + ASTNode *merged_globals = NULL; // Head - ASTNode *merged = NULL; - ASTNode *merged_tail = NULL; - - ASTNode *s = ctx->instantiated_structs; - while (s) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *s; - copy->next = NULL; - if (!merged) - { - merged = copy; - merged_tail = copy; - } - else - { - merged_tail->next = copy; - merged_tail = copy; - } - s = s->next; - } + if (ctx->parsed_globals_list) { + StructRef *s = ctx->parsed_globals_list; + while (s) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *s->node; + copy->next = merged_globals; + merged_globals = copy; - StructRef *sr = ctx->parsed_structs_list; - while (sr) - { - if (sr->node) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *sr->node; - copy->next = NULL; - if (!merged) - { - merged = copy; - merged_tail = copy; - } - else - { - merged_tail->next = copy; - merged_tail = copy; - } - } - sr = sr->next; - } + s = s->next; + } + } - StructRef *er = ctx->parsed_enums_list; - while (er) - { - if (er->node) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *er->node; - copy->next = NULL; - if (!merged) - { - merged = copy; - merged_tail = copy; - } - else - { - merged_tail->next = copy; - merged_tail = copy; - } - } - er = er->next; + emit_globals(ctx, merged_globals, out); + + ASTNode *merged_funcs = NULL; + ASTNode *merged_funcs_tail = NULL; + + if (ctx->instantiated_funcs) { + ASTNode *s = ctx->instantiated_funcs; + while (s) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *s; + copy->next = NULL; + if (!merged_funcs) { + merged_funcs = copy; + merged_funcs_tail = copy; + } else { + merged_funcs_tail->next = copy; + merged_funcs_tail = copy; } + s = s->next; + } + } - ASTNode *k = kids; - while (k) - { - if (k->type == NODE_STRUCT || k->type == NODE_ENUM) - { - int found = 0; - ASTNode *chk = merged; - while (chk) - { - if (chk->type == k->type) - { - const char *n1 = (k->type == NODE_STRUCT) ? k->strct.name : k->enm.name; - const char *n2 = - (chk->type == NODE_STRUCT) ? chk->strct.name : chk->enm.name; - if (n1 && n2 && strcmp(n1, n2) == 0) - { - found = 1; - break; - } - } - chk = chk->next; - } - - if (!found) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *k; - copy->next = NULL; - if (!merged) - { - merged = copy; - merged_tail = copy; - } - else - { - merged_tail->next = copy; - merged_tail = copy; - } - } - } - k = k->next; + if (ctx->parsed_funcs_list) { + StructRef *s = ctx->parsed_funcs_list; + while (s) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *s->node; + copy->next = NULL; + if (!merged_funcs) { + merged_funcs = copy; + merged_funcs_tail = copy; + } else { + merged_funcs_tail->next = copy; + merged_funcs_tail = copy; } + s = s->next; + } + } - // Topologically sort. - ASTNode *sorted = topo_sort_structs(merged); + if (ctx->parsed_impls_list) { + StructRef *s = ctx->parsed_impls_list; + while (s) { + ASTNode *copy = xmalloc(sizeof(ASTNode)); + *copy = *s->node; + copy->next = NULL; + if (!merged_funcs) { + merged_funcs = copy; + merged_funcs_tail = copy; + } else { + merged_funcs_tail->next = copy; + merged_funcs_tail = copy; + } + s = s->next; + } + } - print_type_defs(ctx, out, sorted); - emit_enum_protos(sorted, out); + emit_protos(merged_funcs, out); - if (sorted) - { - emit_struct_defs(ctx, sorted, out); - } - emit_trait_defs(kids, out); - - ASTNode *raw_iter = kids; - while (raw_iter) - { - if (raw_iter->type == NODE_RAW_STMT) - { - fprintf(out, "%s\n", raw_iter->raw_stmt.content); - } - raw_iter = raw_iter->next; - } + emit_impl_vtables(ctx, out); - ASTNode *merged_globals = NULL; // Head + emit_lambda_defs(ctx, out); - if (ctx->parsed_globals_list) - { - StructRef *s = ctx->parsed_globals_list; - while (s) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *s->node; - copy->next = merged_globals; - merged_globals = copy; + emit_tests_and_runner(ctx, kids, out); - s = s->next; - } + ASTNode *iter = merged_funcs; + while (iter) { + if (iter->type == NODE_IMPL) { + char *sname = iter->impl.struct_name; + if (!sname) { + iter = iter->next; + continue; } - emit_globals(ctx, merged_globals, out); - - ASTNode *merged_funcs = NULL; - ASTNode *merged_funcs_tail = NULL; - - if (ctx->instantiated_funcs) - { - ASTNode *s = ctx->instantiated_funcs; - while (s) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *s; - copy->next = NULL; - if (!merged_funcs) - { - merged_funcs = copy; - merged_funcs_tail = copy; - } - else - { - merged_funcs_tail->next = copy; - merged_funcs_tail = copy; - } - s = s->next; + char *mangled = replace_string_type(sname); + ASTNode *def = find_struct_def_codegen(ctx, mangled); + int skip = 0; + if (def) { + if (def->type == NODE_STRUCT && def->strct.is_template) { + skip = 1; + } else if (def->type == NODE_ENUM && def->enm.is_template) { + skip = 1; + } + } else { + char *lt = strchr(sname, '<'); + if (lt) { + 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) { + skip = 1; } + free(buf); + } } - - if (ctx->parsed_funcs_list) - { - StructRef *s = ctx->parsed_funcs_list; - while (s) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *s->node; - copy->next = NULL; - if (!merged_funcs) - { - merged_funcs = copy; - merged_funcs_tail = copy; - } - else - { - merged_funcs_tail->next = copy; - merged_funcs_tail = copy; - } - s = s->next; - } + if (mangled) { + free(mangled); } - - if (ctx->parsed_impls_list) - { - StructRef *s = ctx->parsed_impls_list; - while (s) - { - ASTNode *copy = xmalloc(sizeof(ASTNode)); - *copy = *s->node; - copy->next = NULL; - if (!merged_funcs) - { - merged_funcs = copy; - merged_funcs_tail = copy; - } - else - { - merged_funcs_tail->next = copy; - merged_funcs_tail = copy; - } - s = s->next; - } + if (skip) { + iter = iter->next; + continue; } - - emit_protos(merged_funcs, out); - - emit_impl_vtables(ctx, out); - - emit_lambda_defs(ctx, out); - - emit_tests_and_runner(ctx, kids, out); - - ASTNode *iter = merged_funcs; - while (iter) - { - if (iter->type == NODE_IMPL) - { - char *sname = iter->impl.struct_name; - if (!sname) - { - iter = iter->next; - continue; - } - - char *mangled = replace_string_type(sname); - ASTNode *def = find_struct_def_codegen(ctx, mangled); - int skip = 0; - if (def) - { - if (def->type == NODE_STRUCT && def->strct.is_template) - { - skip = 1; - } - else if (def->type == NODE_ENUM && def->enm.is_template) - { - skip = 1; - } - } - else - { - char *lt = strchr(sname, '<'); - if (lt) - { - 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) - { - skip = 1; - } - free(buf); - } - } - if (mangled) - { - free(mangled); - } - if (skip) - { - iter = iter->next; - continue; - } - } - if (iter->type == NODE_IMPL_TRAIT) - { - char *sname = iter->impl_trait.target_type; - if (!sname) - { - iter = iter->next; - continue; - } - - char *mangled = replace_string_type(sname); - ASTNode *def = find_struct_def_codegen(ctx, mangled); - int skip = 0; - if (def) - { - if (def->strct.is_template) - { - skip = 1; - } - } - else - { - char *lt = strchr(sname, '<'); - if (lt) - { - 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) - { - skip = 1; - } - free(buf); - } - } - if (mangled) - { - free(mangled); - } - if (skip) - { - iter = iter->next; - continue; - } - } - codegen_node_single(ctx, iter, out); - iter = iter->next; + } + if (iter->type == NODE_IMPL_TRAIT) { + char *sname = iter->impl_trait.target_type; + if (!sname) { + iter = iter->next; + continue; } - int has_user_main = 0; - ASTNode *chk = merged_funcs; - while (chk) - { - if (chk->type == NODE_FUNCTION && strcmp(chk->func.name, "main") == 0) - { - has_user_main = 1; - break; + char *mangled = replace_string_type(sname); + ASTNode *def = find_struct_def_codegen(ctx, mangled); + int skip = 0; + if (def) { + if (def->strct.is_template) { + skip = 1; + } + } else { + char *lt = strchr(sname, '<'); + if (lt) { + 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) { + skip = 1; } - chk = chk->next; + free(buf); + } } - - if (!has_user_main) - { - fprintf(out, "\nint main() { _z_run_tests(); return 0; }\n"); + if (mangled) { + free(mangled); + } + if (skip) { + iter = iter->next; + continue; } + } + codegen_node_single(ctx, iter, out); + iter = iter->next; + } + + int has_user_main = 0; + ASTNode *chk = merged_funcs; + while (chk) { + if (chk->type == NODE_FUNCTION && strcmp(chk->func.name, "main") == 0) { + has_user_main = 1; + break; + } + chk = chk->next; + } + + if (!has_user_main) { + fprintf(out, "\nint main() { _z_run_tests(); return 0; }\n"); } + } } diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c index 2feb757..c10685b 100644 --- a/src/codegen/codegen_utils.c +++ b/src/codegen/codegen_utils.c @@ -17,505 +17,417 @@ int defer_count = 0; ASTNode *g_current_lambda = NULL; // 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) -{ - (void)ctx; - - char *bracket = strchr(type_str, '['); - - if (bracket) - { - int base_len = bracket - type_str; - fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket); - } - else - { - fprintf(out, "%s %s", type_str, var_name); - } +void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, + const char *var_name) { + (void)ctx; + + char *bracket = strchr(type_str, '['); + + if (bracket) { + int base_len = bracket - type_str; + fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket); + } else { + fprintf(out, "%s %s", type_str, var_name); + } } // Find struct definition -ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name) -{ - if (!name) - { - return NULL; - } - ASTNode *s = global_user_structs; - while (s) - { - if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete) - { - return s; - } - s = s->next; +ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name) { + if (!name) { + return NULL; + } + ASTNode *s = global_user_structs; + while (s) { + if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && + !s->strct.is_incomplete) { + return s; } - - // Check parsed structs list (imports)- - StructRef *sr = ctx->parsed_structs_list; - while (sr) - { - if (sr->node && sr->node->type == NODE_STRUCT && strcmp(sr->node->strct.name, name) == 0 && - !sr->node->strct.is_incomplete) - { - return sr->node; - } - sr = sr->next; + s = s->next; + } + + // Check parsed structs list (imports)- + StructRef *sr = ctx->parsed_structs_list; + while (sr) { + if (sr->node && sr->node->type == NODE_STRUCT && + strcmp(sr->node->strct.name, name) == 0 && + !sr->node->strct.is_incomplete) { + return sr->node; } - s = ctx->instantiated_structs; - while (s) - { - if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete) - { - return s; - } - s = s->next; + sr = sr->next; + } + s = ctx->instantiated_structs; + while (s) { + if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && + !s->strct.is_incomplete) { + return s; } - return NULL; + s = s->next; + } + return NULL; } // Get field type from struct. -char *get_field_type_str(ParserContext *ctx, const char *struct_name, const char *field_name) -{ - char clean_name[256]; - strncpy(clean_name, struct_name, sizeof(clean_name) - 1); - clean_name[sizeof(clean_name) - 1] = 0; - - char *ptr = strchr(clean_name, '<'); - if (ptr) - { - *ptr = 0; - } - - ASTNode *def = find_struct_def_codegen(ctx, clean_name); - if (!def) - { - return NULL; - } +char *get_field_type_str(ParserContext *ctx, const char *struct_name, + const char *field_name) { + char clean_name[256]; + strncpy(clean_name, struct_name, sizeof(clean_name) - 1); + clean_name[sizeof(clean_name) - 1] = 0; + + char *ptr = strchr(clean_name, '<'); + if (ptr) { + *ptr = 0; + } + + ASTNode *def = find_struct_def_codegen(ctx, clean_name); + if (!def) { + return NULL; + } - ASTNode *f = def->strct.fields; - while (f) - { - if (strcmp(f->field.name, field_name) == 0) - { - return f->field.type; - } - f = f->next; + ASTNode *f = def->strct.fields; + while (f) { + if (strcmp(f->field.name, field_name) == 0) { + return f->field.type; } - return NULL; + f = f->next; + } + return NULL; } // Type inference. -char *infer_type(ParserContext *ctx, ASTNode *node) -{ - if (!node) - { - return NULL; +char *infer_type(ParserContext *ctx, ASTNode *node) { + if (!node) { + return NULL; + } + if (node->resolved_type && strcmp(node->resolved_type, "unknown") != 0) { + return node->resolved_type; + } + + if (node->type == NODE_EXPR_LITERAL) { + if (node->type_info) { + return type_to_string(node->type_info); } - if (node->resolved_type && strcmp(node->resolved_type, "unknown") != 0) - { - return node->resolved_type; + return NULL; + } + + if (node->type == NODE_EXPR_VAR) { + Symbol *sym = find_symbol_entry(ctx, node->var_ref.name); + if (sym) { + if (sym->type_name) { + return sym->type_name; + } + if (sym->type_info) { + return type_to_string(sym->type_info); + } } + } - if (node->type == NODE_EXPR_LITERAL) - { - if (node->type_info) - { - return type_to_string(node->type_info); + if (node->type == NODE_EXPR_CALL) { + if (node->call.callee->type == NODE_EXPR_VAR) { + FuncSig *sig = find_func(ctx, node->call.callee->var_ref.name); + if (sig) { + if (sig->is_async) { + return "Async"; } - return NULL; - } - - if (node->type == NODE_EXPR_VAR) - { - Symbol *sym = find_symbol_entry(ctx, node->var_ref.name); - if (sym) - { - if (sym->type_name) - { - return sym->type_name; - } - if (sym->type_info) - { - return type_to_string(sym->type_info); - } + if (sig->ret_type) { + return type_to_string(sig->ret_type); } - } + } - if (node->type == NODE_EXPR_CALL) - { - if (node->call.callee->type == NODE_EXPR_VAR) - { - FuncSig *sig = find_func(ctx, node->call.callee->var_ref.name); - if (sig) - { - if (sig->is_async) - { - return "Async"; - } - if (sig->ret_type) - { - return type_to_string(sig->ret_type); - } - } - - // Fallback for known stdlib memory functions. - if (strcmp(node->call.callee->var_ref.name, "malloc") == 0 || - strcmp(node->call.callee->var_ref.name, "calloc") == 0 || - strcmp(node->call.callee->var_ref.name, "realloc") == 0) - { - return "void*"; - } - ASTNode *sdef = find_struct_def_codegen(ctx, node->call.callee->var_ref.name); - if (sdef) - { - return node->call.callee->var_ref.name; - } - } - // Method call: target.method() - look up Type_method signature. - if (node->call.callee->type == NODE_EXPR_MEMBER) - { - char *target_type = infer_type(ctx, node->call.callee->member.target); - if (target_type) - { - char clean_type[256]; - strcpy(clean_type, target_type); - char *ptr = strchr(clean_type, '*'); - if (ptr) - { - *ptr = 0; - } - - char *base = clean_type; - if (strncmp(base, "struct ", 7) == 0) - { - base += 7; - } - - char func_name[512]; - sprintf(func_name, "%s_%s", base, node->call.callee->member.field); - - FuncSig *sig = find_func(ctx, func_name); - if (sig && sig->ret_type) - { - return type_to_string(sig->ret_type); - } - } + // Fallback for known stdlib memory functions. + if (strcmp(node->call.callee->var_ref.name, "malloc") == 0 || + strcmp(node->call.callee->var_ref.name, "calloc") == 0 || + strcmp(node->call.callee->var_ref.name, "realloc") == 0) { + return "void*"; + } + ASTNode *sdef = + find_struct_def_codegen(ctx, node->call.callee->var_ref.name); + if (sdef) { + return node->call.callee->var_ref.name; + } + } + // Method call: target.method() - look up Type_method signature. + if (node->call.callee->type == NODE_EXPR_MEMBER) { + char *target_type = infer_type(ctx, node->call.callee->member.target); + if (target_type) { + char clean_type[256]; + strcpy(clean_type, target_type); + char *ptr = strchr(clean_type, '*'); + if (ptr) { + *ptr = 0; } - if (node->call.callee->type == NODE_EXPR_VAR) - { - Symbol *sym = find_symbol_entry(ctx, node->call.callee->var_ref.name); - if (sym && sym->type_info && sym->type_info->kind == TYPE_FUNCTION && - sym->type_info->inner) - { - return type_to_string(sym->type_info->inner); - } + char *base = clean_type; + if (strncmp(base, "struct ", 7) == 0) { + base += 7; } - } - if (node->type == NODE_TRY) - { - char *inner_type = infer_type(ctx, node->try_stmt.expr); - if (inner_type) - { - // Extract T from Result<T> or Option<T> - char *start = strchr(inner_type, '<'); - if (start) - { - start++; // Skip < - char *end = strrchr(inner_type, '>'); - if (end && end > start) - { - int len = end - start; - char *extracted = xmalloc(len + 1); - strncpy(extracted, start, len); - extracted[len] = 0; - return extracted; - } - } - } - } + char func_name[512]; + sprintf(func_name, "%s_%s", base, node->call.callee->member.field); - if (node->type == NODE_EXPR_MEMBER) - { - char *parent_type = infer_type(ctx, node->member.target); - if (!parent_type) - { - return NULL; + FuncSig *sig = find_func(ctx, func_name); + if (sig && sig->ret_type) { + return type_to_string(sig->ret_type); } + } + } - char clean_name[256]; - strcpy(clean_name, parent_type); - char *ptr = strchr(clean_name, '*'); - if (ptr) - { - *ptr = 0; - } + if (node->call.callee->type == NODE_EXPR_VAR) { + Symbol *sym = find_symbol_entry(ctx, node->call.callee->var_ref.name); + if (sym && sym->type_info && sym->type_info->kind == TYPE_FUNCTION && + sym->type_info->inner) { + return type_to_string(sym->type_info->inner); + } + } + } + + if (node->type == NODE_TRY) { + char *inner_type = infer_type(ctx, node->try_stmt.expr); + if (inner_type) { + // Extract T from Result<T> or Option<T> + char *start = strchr(inner_type, '<'); + if (start) { + start++; // Skip < + char *end = strrchr(inner_type, '>'); + if (end && end > start) { + int len = end - start; + char *extracted = xmalloc(len + 1); + strncpy(extracted, start, len); + extracted[len] = 0; + return extracted; + } + } + } + } - return get_field_type_str(ctx, clean_name, node->member.field); + if (node->type == NODE_EXPR_MEMBER) { + char *parent_type = infer_type(ctx, node->member.target); + if (!parent_type) { + return NULL; } - if (node->type == NODE_EXPR_BINARY) - { - if (strcmp(node->binary.op, "??") == 0) - { - return infer_type(ctx, node->binary.left); - } + char clean_name[256]; + strcpy(clean_name, parent_type); + char *ptr = strchr(clean_name, '*'); + if (ptr) { + *ptr = 0; + } - const char *op = node->binary.op; - char *left_type = infer_type(ctx, node->binary.left); - char *right_type = infer_type(ctx, node->binary.right); + return get_field_type_str(ctx, clean_name, node->member.field); + } - int is_logical = (strcmp(op, "&&") == 0 || strcmp(op, "||") == 0 || strcmp(op, "==") == 0 || - strcmp(op, "!=") == 0 || strcmp(op, "<") == 0 || strcmp(op, ">") == 0 || - strcmp(op, "<=") == 0 || strcmp(op, ">=") == 0); + if (node->type == NODE_EXPR_BINARY) { + if (strcmp(node->binary.op, "??") == 0) { + return infer_type(ctx, node->binary.left); + } - if (is_logical) - { - return xstrdup("int"); - } + const char *op = node->binary.op; + char *left_type = infer_type(ctx, node->binary.left); + char *right_type = infer_type(ctx, node->binary.right); - if (left_type && strcmp(left_type, "usize") == 0) - { - return "usize"; - } - if (right_type && strcmp(right_type, "usize") == 0) - { - return "usize"; - } - if (left_type && strcmp(left_type, "double") == 0) - { - return "double"; - } + int is_logical = (strcmp(op, "&&") == 0 || strcmp(op, "||") == 0 || + strcmp(op, "==") == 0 || strcmp(op, "!=") == 0 || + strcmp(op, "<") == 0 || strcmp(op, ">") == 0 || + strcmp(op, "<=") == 0 || strcmp(op, ">=") == 0); - return left_type ? left_type : right_type; + if (is_logical) { + return xstrdup("int"); } - if (node->type == NODE_MATCH) - { - ASTNode *case_node = node->match_stmt.cases; - while (case_node) - { - char *type = infer_type(ctx, case_node->match_case.body); - if (type && strcmp(type, "void") != 0 && strcmp(type, "unknown") != 0) - { - return type; - } - case_node = case_node->next; - } - return NULL; + if (left_type && strcmp(left_type, "usize") == 0) { + return "usize"; } - - if (node->type == NODE_EXPR_INDEX) - { - char *array_type = infer_type(ctx, node->index.array); - if (array_type) - { - // If T*, returns T. If T[], returns T. - char *ptr = strrchr(array_type, '*'); - if (ptr) - { - int len = ptr - array_type; - char *buf = xmalloc(len + 1); - strncpy(buf, array_type, len); - buf[len] = 0; - return buf; - } - } - return "int"; + if (right_type && strcmp(right_type, "usize") == 0) { + return "usize"; + } + if (left_type && strcmp(left_type, "double") == 0) { + return "double"; } - if (node->type == NODE_EXPR_UNARY) - { - if (strcmp(node->unary.op, "&") == 0) - { - char *inner = infer_type(ctx, node->unary.operand); - if (inner) - { - char *buf = xmalloc(strlen(inner) + 2); - sprintf(buf, "%s*", inner); - return buf; - } - } - if (strcmp(node->unary.op, "*") == 0) - { - char *inner = infer_type(ctx, node->unary.operand); - if (inner) - { - char *ptr = strchr(inner, '*'); - if (ptr) - { - // Return base type (naive) - int len = ptr - inner; - char *dup = xmalloc(len + 1); - strncpy(dup, inner, len); - dup[len] = 0; - return dup; - } - } - } - return infer_type(ctx, node->unary.operand); + return left_type ? left_type : right_type; + } + + if (node->type == NODE_MATCH) { + ASTNode *case_node = node->match_stmt.cases; + while (case_node) { + char *type = infer_type(ctx, case_node->match_case.body); + if (type && strcmp(type, "void") != 0 && strcmp(type, "unknown") != 0) { + return type; + } + case_node = case_node->next; + } + return NULL; + } + + if (node->type == NODE_EXPR_INDEX) { + char *array_type = infer_type(ctx, node->index.array); + if (array_type) { + // If T*, returns T. If T[], returns T. + char *ptr = strrchr(array_type, '*'); + if (ptr) { + int len = ptr - array_type; + char *buf = xmalloc(len + 1); + strncpy(buf, array_type, len); + buf[len] = 0; + return buf; + } + } + return "int"; + } + + if (node->type == NODE_EXPR_UNARY) { + if (strcmp(node->unary.op, "&") == 0) { + char *inner = infer_type(ctx, node->unary.operand); + if (inner) { + char *buf = xmalloc(strlen(inner) + 2); + sprintf(buf, "%s*", inner); + return buf; + } + } + if (strcmp(node->unary.op, "*") == 0) { + char *inner = infer_type(ctx, node->unary.operand); + if (inner) { + char *ptr = strchr(inner, '*'); + if (ptr) { + // Return base type (naive) + int len = ptr - inner; + char *dup = xmalloc(len + 1); + strncpy(dup, inner, len); + dup[len] = 0; + return dup; + } + } + } + return infer_type(ctx, node->unary.operand); + } + + if (node->type == NODE_AWAIT) { + // Infer underlying type T from await Async<T> + // If it's a direct call await foo(), we know T from foo's signature. + if (node->unary.operand->type == NODE_EXPR_CALL && + node->unary.operand->call.callee->type == NODE_EXPR_VAR) { + FuncSig *sig = + find_func(ctx, node->unary.operand->call.callee->var_ref.name); + if (sig && sig->ret_type) { + return type_to_string(sig->ret_type); + } } - if (node->type == NODE_AWAIT) - { - // Infer underlying type T from await Async<T> - // If it's a direct call await foo(), we know T from foo's signature. - if (node->unary.operand->type == NODE_EXPR_CALL && - node->unary.operand->call.callee->type == NODE_EXPR_VAR) - { - FuncSig *sig = find_func(ctx, node->unary.operand->call.callee->var_ref.name); - if (sig && sig->ret_type) - { - return type_to_string(sig->ret_type); - } - } + return "void*"; + } - return "void*"; - } + if (node->type == NODE_EXPR_CAST) { + return node->cast.target_type; + } - if (node->type == NODE_EXPR_CAST) - { - return node->cast.target_type; - } + if (node->type == NODE_EXPR_STRUCT_INIT) { + return node->struct_init.struct_name; + } - if (node->type == NODE_EXPR_STRUCT_INIT) - { - return node->struct_init.struct_name; + if (node->type == NODE_EXPR_LITERAL) { + if (node->literal.type_kind == TOK_STRING) { + return "string"; } - - if (node->type == NODE_EXPR_LITERAL) - { - if (node->literal.type_kind == TOK_STRING) - { - return "string"; - } - if (node->literal.type_kind == TOK_CHAR) - { - return "char"; - } - if (node->literal.type_kind == 1) - { - return "double"; - } - return "int"; + if (node->literal.type_kind == TOK_CHAR) { + return "char"; + } + if (node->literal.type_kind == 1) { + return "double"; } + return "int"; + } - return NULL; + return NULL; } // Extract variable names from argument string. -char *extract_call_args(const char *args) -{ - if (!args || strlen(args) == 0) - { - return xstrdup(""); +char *extract_call_args(const char *args) { + if (!args || strlen(args) == 0) { + return xstrdup(""); + } + char *out = xmalloc(strlen(args) + 1); + out[0] = 0; + + char *dup = xstrdup(args); + char *p = strtok(dup, ","); + while (p) { + while (*p == ' ') { + p++; } - char *out = xmalloc(strlen(args) + 1); - out[0] = 0; - - char *dup = xstrdup(args); - char *p = strtok(dup, ","); - while (p) - { - while (*p == ' ') - { - p++; - } - char *last_space = strrchr(p, ' '); - char *ptr_star = strrchr(p, '*'); - - char *name = p; - if (last_space) - { - name = last_space + 1; - } - if (ptr_star && ptr_star > last_space) - { - name = ptr_star + 1; - } + char *last_space = strrchr(p, ' '); + char *ptr_star = strrchr(p, '*'); - if (strlen(out) > 0) - { - strcat(out, ", "); - } - strcat(out, name); + char *name = p; + if (last_space) { + name = last_space + 1; + } + if (ptr_star && ptr_star > last_space) { + name = ptr_star + 1; + } - p = strtok(NULL, ","); + if (strlen(out) > 0) { + strcat(out, ", "); } - free(dup); - return out; + strcat(out, name); + + p = strtok(NULL, ","); + } + free(dup); + return out; } // Parse original method name from mangled name. -const char *parse_original_method_name(const char *mangled) -{ - const char *last = strrchr(mangled, '_'); - return last ? last + 1 : mangled; +const char *parse_original_method_name(const char *mangled) { + const char *last = strrchr(mangled, '_'); + return last ? last + 1 : mangled; } // Replace string type in arguments. -char *replace_string_type(const char *args) -{ - if (!args) - { - return NULL; - } - char *res = xmalloc(strlen(args) * 2 + 1); - res[0] = 0; - const char *p = args; - while (*p) - { - const char *match = strstr(p, "string "); - if (match) - { - if (match > args && (isalnum(*(match - 1)) || *(match - 1) == '_')) - { - strncat(res, p, match - p + 6); - p = match + 6; - } - else - { - strncat(res, p, match - p); - strcat(res, "const char* "); - p = match + 7; - } - } - else - { - strcat(res, p); - break; - } +char *replace_string_type(const char *args) { + if (!args) { + return NULL; + } + char *res = xmalloc(strlen(args) * 2 + 1); + res[0] = 0; + const char *p = args; + while (*p) { + const char *match = strstr(p, "string "); + if (match) { + if (match > args && (isalnum(*(match - 1)) || *(match - 1) == '_')) { + strncat(res, p, match - p + 6); + p = match + 6; + } else { + strncat(res, p, match - p); + strcat(res, "const char* "); + p = match + 7; + } + } else { + strcat(res, p); + break; } - return res; + } + return res; } // Helper to emit auto type or fallback. -void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out) -{ - char *inferred = NULL; - if (init_expr) - { - inferred = infer_type(ctx, init_expr); - } - - if (inferred && strcmp(inferred, "__auto_type") != 0 && strcmp(inferred, "unknown") != 0) - { - fprintf(out, "%s", inferred); - } - else - { - if (strstr(g_config.cc, "tcc")) - { - zpanic_with_suggestion(t, - "Type inference failed for variable initialization and TCC does " - "not support __auto_type", - "Please specify the type explicitly: 'var x: Type = ...'"); - } - else - { - fprintf(out, "__auto_type"); - } +void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, + FILE *out) { + char *inferred = NULL; + if (init_expr) { + inferred = infer_type(ctx, init_expr); + } + + if (inferred && strcmp(inferred, "__auto_type") != 0 && + strcmp(inferred, "unknown") != 0) { + fprintf(out, "%s", inferred); + } else { + if (strstr(g_config.cc, "tcc")) { + zpanic_with_suggestion( + t, + "Type inference failed for variable initialization and TCC does " + "not support __auto_type", + "Please specify the type explicitly: 'var x: Type = ...'"); + } else { + fprintf(out, "__auto_type"); } + } } |
