diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-22 22:40:43 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-22 22:40:43 +0000 |
| commit | ed4bbfd8cf4a72fdf4a5d6cba94d537cab340356 (patch) | |
| tree | 80f520cb36f25a210537b477007b0ac5a24e4b8e /src/codegen/codegen.c | |
| parent | 3d1840e8690bef6e58a208d9ca33857a59a2e852 (diff) | |
Removing some duplicates and dissecting codegen/parser.
Diffstat (limited to 'src/codegen/codegen.c')
| -rw-r--r-- | src/codegen/codegen.c | 1671 |
1 files changed, 2 insertions, 1669 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index a43c902..3a93f91 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -1,6 +1,7 @@ #include "codegen.h" #include "zprep.h" +#include "../constants.h" #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -10,534 +11,6 @@ #include "ast.h" #include "zprep_plugin.h" -// Helper: emit a single pattern condition (either a value, or a range) -static void emit_single_pattern_cond(const char *pat, int id, int is_ptr, FILE *out) -{ - // Check for range pattern: "start..end" or "start..=end" - char *range_incl = strstr(pat, "..="); - char *range_excl = strstr(pat, ".."); - - if (range_incl) - { - // Inclusive range: start..=end -> _m_id >= start && _m_id <= end - int start_len = (int)(range_incl - pat); - char *start = xmalloc(start_len + 1); - strncpy(start, pat, start_len); - start[start_len] = 0; - char *end = xstrdup(range_incl + 3); - if (is_ptr) - { - fprintf(out, "(*_m_%d >= %s && *_m_%d <= %s)", id, start, id, end); - } - else - { - fprintf(out, "(_m_%d >= %s && _m_%d <= %s)", id, start, id, end); - } - free(start); - free(end); - } - else if (range_excl) - { - // Exclusive range: start..end -> _m_id >= start && _m_id < end - int start_len = (int)(range_excl - pat); - char *start = xmalloc(start_len + 1); - strncpy(start, pat, start_len); - start[start_len] = 0; - char *end = xstrdup(range_excl + 2); - if (is_ptr) - { - fprintf(out, "(*_m_%d >= %s && *_m_%d < %s)", id, start, id, end); - } - else - { - fprintf(out, "(_m_%d >= %s && _m_%d < %s)", id, start, id, end); - } - free(start); - free(end); - } - else if (pat[0] == '"') - { - // String pattern - string comparison, _m is char* or similar - if (is_ptr) - { - fprintf(out, "strcmp(*_m_%d, %s) == 0", id, pat); - } - else - { - fprintf(out, "strcmp(_m_%d, %s) == 0", id, pat); - } - } - else if (pat[0] == '\'') - { - // Char literal pattern - if (is_ptr) - { - fprintf(out, "*_m_%d == %s", id, pat); - } - else - { - fprintf(out, "_m_%d == %s", id, pat); - } - } - else - { - // Numeric or simple pattern - if (is_ptr) - { - fprintf(out, "*_m_%d == %s", id, pat); - } - else - { - fprintf(out, "_m_%d == %s", id, pat); - } - } -} - -// Helper: emit condition for a pattern (may contain OR patterns with '|') -static void emit_pattern_condition(ParserContext *ctx, const char *pattern, int id, int is_ptr, - FILE *out) -{ - // Check if pattern contains '|' for OR patterns - if (strchr(pattern, '|')) - { - // Split by '|' and emit OR conditions - char *pattern_copy = xstrdup(pattern); - char *saveptr; - char *part = strtok_r(pattern_copy, "|", &saveptr); - int first = 1; - fprintf(out, "("); - while (part) - { - if (!first) - { - fprintf(out, " || "); - } - - // Check if part is an enum variant - EnumVariantReg *reg = find_enum_variant(ctx, part); - if (reg) - { - if (is_ptr) - { - fprintf(out, "_m_%d->tag == %d", id, reg->tag_id); - } - else - { - fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); - } - } - else - { - emit_single_pattern_cond(part, id, is_ptr, out); - } - first = 0; - part = strtok_r(NULL, "|", &saveptr); - } - fprintf(out, ")"); - free(pattern_copy); - } - else - { - // Single pattern (may be a range) - EnumVariantReg *reg = find_enum_variant(ctx, pattern); - if (reg) - { - if (is_ptr) - { - fprintf(out, "_m_%d->tag == %d", id, reg->tag_id); - } - else - { - fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); - } - } - else - { - emit_single_pattern_cond(pattern, id, is_ptr, out); - } - } -} - -// static function for internal use. -static char *g_current_func_ret_type = NULL; -static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result) -{ - int id = tmp_counter++; - int is_self = (node->match_stmt.expr->type == NODE_EXPR_VAR && - strcmp(node->match_stmt.expr->var_ref.name, "self") == 0); - - char *ret_type = infer_type(ctx, node); - int is_expr = (use_result && ret_type && strcmp(ret_type, "void") != 0); - - fprintf(out, "({ "); - - // Check if any case uses ref binding - only take address if needed - int has_ref_binding = 0; - ASTNode *ref_check = node->match_stmt.cases; - while (ref_check) - { - if (ref_check->match_case.is_ref) - { - has_ref_binding = 1; - break; - } - ref_check = ref_check->next; - } - - int is_lvalue_opt = (node->match_stmt.expr->type == NODE_EXPR_VAR || - node->match_stmt.expr->type == NODE_EXPR_MEMBER || - node->match_stmt.expr->type == NODE_EXPR_INDEX); - - if (is_self) - { - fprintf(out, "ZC_AUTO _m_%d = ", id); - codegen_expression(ctx, node->match_stmt.expr, out); - fprintf(out, "; "); - } - else if (has_ref_binding && is_lvalue_opt) - { - // Take address for ref bindings - fprintf(out, "ZC_AUTO _m_%d = &", id); - codegen_expression(ctx, node->match_stmt.expr, out); - fprintf(out, "; "); - } - else if (has_ref_binding) - { - // Non-lvalue with ref binding: create temporary - emit_auto_type(ctx, node->match_stmt.expr, node->token, out); - fprintf(out, " _temp_%d = ", id); - codegen_expression(ctx, node->match_stmt.expr, out); - fprintf(out, "; ZC_AUTO _m_%d = &_temp_%d; ", id, id); - } - else - { - // No ref bindings: store value directly (not pointer) - fprintf(out, "ZC_AUTO _m_%d = ", id); - codegen_expression(ctx, node->match_stmt.expr, out); - fprintf(out, "; "); - } - - if (is_expr) - { - fprintf(out, "%s _r_%d; ", ret_type, id); - } - - char *expr_type = infer_type(ctx, node->match_stmt.expr); - int is_option = (expr_type && strncmp(expr_type, "Option_", 7) == 0); - int is_result = (expr_type && strncmp(expr_type, "Result_", 7) == 0); - - char *enum_name = NULL; - ASTNode *chk = node->match_stmt.cases; - int has_wildcard = 0; - while (chk) - { - if (strcmp(chk->match_case.pattern, "_") == 0) - { - has_wildcard = 1; - } - else if (!enum_name) - { - EnumVariantReg *reg = find_enum_variant(ctx, chk->match_case.pattern); - if (reg) - { - enum_name = reg->enum_name; - } - } - chk = chk->next; - } - - if (enum_name && !has_wildcard) - { - // Iterate through all registered variants for this enum - EnumVariantReg *v = ctx->enum_variants; - while (v) - { - if (strcmp(v->enum_name, enum_name) == 0) - { - int covered = 0; - ASTNode *c2 = node->match_stmt.cases; - while (c2) - { - if (strcmp(c2->match_case.pattern, v->variant_name) == 0) - { - covered = 1; - break; - } - c2 = c2->next; - } - if (!covered) - { - zwarn_at(node->token, "Non-exhaustive match: Missing variant '%s'", - v->variant_name); - } - } - v = v->next; - } - } - - ASTNode *c = node->match_stmt.cases; - int first = 1; - while (c) - { - if (!first) - { - fprintf(out, " else "); - } - fprintf(out, "if ("); - if (strcmp(c->match_case.pattern, "_") == 0) - { - fprintf(out, "1"); - } - else if (is_option) - { - if (strcmp(c->match_case.pattern, "Some") == 0) - { - fprintf(out, "_m_%d->is_some", id); - } - else if (strcmp(c->match_case.pattern, "None") == 0) - { - fprintf(out, "!_m_%d->is_some", id); - } - else - { - fprintf(out, "1"); - } - } - else if (is_result) - { - if (strcmp(c->match_case.pattern, "Ok") == 0) - { - fprintf(out, "_m_%d->is_ok", id); - } - else if (strcmp(c->match_case.pattern, "Err") == 0) - { - fprintf(out, "!_m_%d->is_ok", id); - } - else - { - fprintf(out, "1"); - } - } - else - { - // Use helper for OR patterns, range patterns, and simple patterns - emit_pattern_condition(ctx, c->match_case.pattern, id, has_ref_binding, out); - } - fprintf(out, ") { "); - if (c->match_case.binding_name) - { - if (is_option) - { - if (strstr(g_config.cc, "tcc")) - { - if (c->match_case.is_ref) - { - fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); - } - } - else - { - if (c->match_case.is_ref) - { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, id); - } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, id); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id); - } - } - } - else if (is_result) // FIX: Changed 'if' to 'else if' to match original logic structure - // if needed, but original code had implicit fallthrough checks? No, - // checks match pattern. - { - if (strcmp(c->match_case.pattern, "Ok") == 0) - { - if (strstr(g_config.cc, "tcc")) - { - if (c->match_case.is_ref) - { - fprintf(out, "__typeof__(&_m_%d->val) %s = &_m_%d->val; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__typeof__(_m_%d->val) %s = _m_%d->val; ", id, - c->match_case.binding_name, id); - } - } - else - { - if (c->match_case.is_ref) - { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, - id); - } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, - id); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, - id); - } - } - } - else - { - if (strstr(g_config.cc, "tcc")) - { - if (c->match_case.is_ref) - { - fprintf(out, "__typeof__(&_m_%d->err) %s = &_m_%d->err; ", id, - c->match_case.binding_name, id); - } - else - { - fprintf(out, "__typeof__(_m_%d->err) %s = _m_%d->err; ", id, - c->match_case.binding_name, id); - } - } - else - { - if (c->match_case.is_ref) - { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->err; ", c->match_case.binding_name, - id); - } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->err; ", c->match_case.binding_name, - id); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name, - id); - } - } - } - } - else - { - char *f = strrchr(c->match_case.pattern, '_'); - if (f) - { - f++; - } - else - { - f = c->match_case.pattern; - } - // Generic struct destructuring (for example, MyStruct_Variant) - // Assuming data union or accessible field. - if (c->match_case.is_ref) - { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", c->match_case.binding_name, id, - f); - } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", c->match_case.binding_name, id, - f); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f); - } - } - } - - // Check if body is a string literal (should auto-print). - ASTNode *body = c->match_case.body; - int is_string_literal = (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2); - - if (is_expr) - { - fprintf(out, "_r_%d = ", id); - if (is_string_literal) - { - codegen_node_single(ctx, body, out); - } - else - { - if (body->type == NODE_BLOCK) - { - int saved = defer_count; - fprintf(out, "({ "); - ASTNode *stmt = body->block.statements; - while (stmt) - { - codegen_node_single(ctx, stmt, out); - stmt = stmt->next; - } - for (int i = defer_count - 1; i >= saved; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - defer_count = saved; - fprintf(out, " })"); - } - else - { - codegen_node_single(ctx, body, out); - } - } - fprintf(out, ";"); - } - else - { - if (is_string_literal) - { - fprintf(out, "({ printf(\"%%s\", "); - codegen_expression(ctx, body, out); - fprintf(out, "); printf(\"\\n\"); 0; })"); - } - else - { - codegen_node_single(ctx, body, out); - } - } - - fprintf(out, " }"); - first = 0; - c = c->next; - } - - if (is_expr) - { - fprintf(out, " _r_%d; })", id); - } - else - { - fprintf(out, " })"); - } -} - // Emit literal expression (int, float, string, char) static void codegen_literal_expr(ASTNode *node, FILE *out) { @@ -711,15 +184,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) } } - int is_basic = 0; - if (t1) - { - is_basic = (strcmp(t1, "int") == 0 || strcmp(t1, "bool") == 0 || - strcmp(t1, "char") == 0 || strcmp(t1, "void") == 0 || - strcmp(t1, "float") == 0 || strcmp(t1, "double") == 0 || - strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 || - strcmp(t1, "ssize_t") == 0 || strcmp(t1, "__auto_type") == 0); - } + int is_basic = IS_BASIC_TYPE(t1); ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL; if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic && @@ -1662,1135 +1127,3 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) break; } } - -void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) -{ - if (!node) - { - return; - } - switch (node->type) - { - case NODE_MATCH: - codegen_match_internal(ctx, node, out, 0); // 0 = statement context - fprintf(out, ";\n"); - break; - case NODE_FUNCTION: - if (!node->func.body) - { - break; - } - - if (node->func.is_async) - { - fprintf(out, "struct %s_Args {\n", node->func.name); - char *args_copy = xstrdup(node->func.args); - char *token = strtok(args_copy, ","); - int arg_count = 0; - char **arg_names = xmalloc(32 * sizeof(char *)); - - while (token) - { - while (*token == ' ') - { - token++; // trim leading - } - char *last_space = strrchr(token, ' '); - if (last_space) - { - *last_space = 0; - char *type = token; - char *name = last_space + 1; - fprintf(out, "%s %s;\n", type, name); - - arg_names[arg_count++] = xstrdup(name); - } - token = strtok(NULL, ","); - } - free(args_copy); - fprintf(out, "};\n"); - - fprintf(out, "void* _runner_%s(void* _args)\n", node->func.name); - fprintf(out, "{\n"); - fprintf(out, " struct %s_Args* args = (struct %s_Args*)_args;\n", node->func.name, - node->func.name); - - // Determine mechanism: struct/large-type? -> malloc; primitive -> cast - int returns_struct = 0; - char *rt = node->func.ret_type; - if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0) - { - if (strstr(rt, "*") == NULL && strcmp(rt, "string") != 0 && - strcmp(rt, "int") != 0 && strcmp(rt, "bool") != 0 && strcmp(rt, "char") != 0 && - strcmp(rt, "float") != 0 && strcmp(rt, "double") != 0 && - strcmp(rt, "long") != 0 && strcmp(rt, "usize") != 0 && - strcmp(rt, "isize") != 0 && strncmp(rt, "uint", 4) != 0 && - strncmp(rt, "int", 3) != 0) - { - returns_struct = 1; - } - } - - // Call Impl - if (returns_struct) - { - fprintf(out, " %s *res_ptr = malloc(sizeof(%s));\n", rt, rt); - fprintf(out, " *res_ptr = "); - } - else if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0) - { - fprintf(out, " %s res = ", rt); - } - else - { - fprintf(out, " "); - } - - fprintf(out, "_impl_%s(", node->func.name); - for (int i = 0; i < arg_count; i++) - { - fprintf(out, "%sargs->%s", i > 0 ? ", " : "", arg_names[i]); - } - fprintf(out, ");\n"); - fprintf(out, " free(args);\n"); - - if (returns_struct) - { - fprintf(out, " return (void*)res_ptr;\n"); - } - else if (strcmp(rt, "void") != 0) - { - fprintf(out, " return (void*)(long)res;\n"); - } - else - { - fprintf(out, " return NULL;\n"); - } - fprintf(out, "}\n"); - - fprintf(out, "%s _impl_%s(%s)\n", node->func.ret_type, node->func.name, - node->func.args); - fprintf(out, "{\n"); - defer_count = 0; - codegen_walker(ctx, node->func.body, out); - for (int i = defer_count - 1; i >= 0; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - fprintf(out, "}\n"); - - // 4. Define Public Wrapper (Spawns Thread) - fprintf(out, "Async %s(%s)\n", node->func.name, node->func.args); - fprintf(out, "{\n"); - fprintf(out, " struct %s_Args* args = malloc(sizeof(struct %s_Args));\n", - node->func.name, node->func.name); - for (int i = 0; i < arg_count; i++) - { - fprintf(out, " args->%s = %s;\n", arg_names[i], arg_names[i]); - } - - fprintf(out, " pthread_t th;\n"); - fprintf(out, " pthread_create(&th, NULL, _runner_%s, args);\n", node->func.name); - fprintf(out, " return (Async){.thread=th, .result=NULL};\n"); - fprintf(out, "}\n"); - - break; - } - - defer_count = 0; - fprintf(out, "\n"); - - // Emit GCC attributes before function - { - int has_attrs = node->func.constructor || node->func.destructor || - node->func.noinline || node->func.unused || node->func.weak || - node->func.cold || node->func.hot || node->func.noreturn || - node->func.pure || node->func.section; - if (has_attrs) - { - fprintf(out, "__attribute__(("); - int first = 1; -#define EMIT_ATTR(cond, name) \ - if (cond) \ - { \ - if (!first) \ - fprintf(out, ", "); \ - fprintf(out, name); \ - first = 0; \ - } - EMIT_ATTR(node->func.constructor, "constructor"); - EMIT_ATTR(node->func.destructor, "destructor"); - EMIT_ATTR(node->func.noinline, "noinline"); - EMIT_ATTR(node->func.unused, "unused"); - EMIT_ATTR(node->func.weak, "weak"); - EMIT_ATTR(node->func.cold, "cold"); - EMIT_ATTR(node->func.hot, "hot"); - EMIT_ATTR(node->func.noreturn, "noreturn"); - EMIT_ATTR(node->func.pure, "pure"); - if (node->func.section) - { - if (!first) - { - fprintf(out, ", "); - } - fprintf(out, "section(\"%s\")", node->func.section); - } -#undef EMIT_ATTR - fprintf(out, ")) "); - } - } - - if (node->func.is_inline) - { - fprintf(out, "inline "); - } - emit_func_signature(out, node, NULL); - fprintf(out, "\n"); - fprintf(out, "{\n"); - char *prev_ret = g_current_func_ret_type; - g_current_func_ret_type = node->func.ret_type; - codegen_walker(ctx, node->func.body, out); - for (int i = defer_count - 1; i >= 0; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - g_current_func_ret_type = prev_ret; - fprintf(out, "}\n"); - break; - - case NODE_ASSERT: - fprintf(out, "assert("); - codegen_expression(ctx, node->assert_stmt.condition, out); - if (node->assert_stmt.message) - { - fprintf(out, ", %s", node->assert_stmt.message); - } - else - { - fprintf(out, ", \"Assertion failed\""); - } - fprintf(out, ");\n"); - break; - - case NODE_DEFER: - if (defer_count < MAX_DEFER) - { - defer_stack[defer_count++] = node->defer_stmt.stmt; - } - break; - case NODE_IMPL: - g_current_impl_type = node->impl.struct_name; - codegen_walker(ctx, node->impl.methods, out); - g_current_impl_type = NULL; - break; - case NODE_IMPL_TRAIT: - g_current_impl_type = node->impl_trait.target_type; - codegen_walker(ctx, node->impl_trait.methods, out); - - if (strcmp(node->impl_trait.trait_name, "Drop") == 0) - { - char *tname = node->impl_trait.target_type; - fprintf(out, "\n// RAII Glue\n"); - fprintf(out, "void %s__Drop_glue(%s *self) {\n", tname, tname); - fprintf(out, " %s__Drop_drop(self);\n", tname); - fprintf(out, "}\n"); - } - g_current_impl_type = NULL; - break; - case NODE_DESTRUCT_VAR: - { - int id = tmp_counter++; - fprintf(out, " "); - emit_auto_type(ctx, node->destruct.init_expr, node->token, out); - fprintf(out, " _tmp_%d = ", id); - codegen_expression(ctx, node->destruct.init_expr, out); - fprintf(out, ";\n"); - - if (node->destruct.is_guard) - { - // var Some(val) = opt else ... - char *variant = node->destruct.guard_variant; - char *check = "val"; // field to access - - if (strcmp(variant, "Some") == 0) - { - fprintf(out, " if (!_tmp_%d.is_some) {\n", id); - } - else if (strcmp(variant, "Ok") == 0) - { - fprintf(out, " if (!_tmp_%d.is_ok) {\n", id); - } - else if (strcmp(variant, "Err") == 0) - { - fprintf(out, " if (_tmp_%d.is_ok) {\n", id); // Err if NOT ok - check = "err"; - } - else - { - // Generic guard? Assume .is_variant present? - fprintf(out, " if (!_tmp_%d.is_%s) {\n", id, variant); - } - - // Else block - codegen_walker(ctx, node->destruct.else_block->block.statements, out); - fprintf(out, " }\n"); - - // Bind value - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, check, - node->destruct.names[0], id, check); - } - else - { - fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id, - check); - } - } - else - { - for (int i = 0; i < node->destruct.count; i++) - { - if (node->destruct.is_struct_destruct) - { - char *field = node->destruct.field_names ? node->destruct.field_names[i] - : node->destruct.names[i]; - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, field, - node->destruct.names[i], id, field); - } - else - { - fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i], - id, field); - } - } - else - { - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, " __typeof__(_tmp_%d.v%d) %s = _tmp_%d.v%d;\n", id, i, - node->destruct.names[i], id, i); - } - else - { - fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i], - id, i); - } - } - } - } - break; - } - case NODE_BLOCK: - { - int saved = defer_count; - fprintf(out, " {\n"); - codegen_walker(ctx, node->block.statements, out); - for (int i = defer_count - 1; i >= saved; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - defer_count = saved; - fprintf(out, " }\n"); - break; - } - case NODE_VAR_DECL: - fprintf(out, " "); - if (node->var_decl.is_static) - { - fprintf(out, "static "); - } - if (node->var_decl.is_autofree) - { - fprintf(out, "__attribute__((cleanup(_z_autofree_impl))) "); - } - { - char *tname = NULL; - if (node->type_info && - (!node->var_decl.init_expr || node->var_decl.init_expr->type != NODE_AWAIT)) - { - tname = codegen_type_to_string(node->type_info); - } - else if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0) - { - tname = node->var_decl.type_str; - } - - if (tname && strcmp(tname, "void*") != 0 && strcmp(tname, "unknown") != 0) - { - char *clean_type = tname; - if (strncmp(clean_type, "struct ", 7) == 0) - { - clean_type += 7; - } - - ASTNode *def = find_struct_def(ctx, clean_type); - if (def && def->type_info && def->type_info->traits.has_drop) - { - fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type); - } - - // Emit Variable with Type - emit_var_decl_type(ctx, out, tname, node->var_decl.name); - add_symbol(ctx, node->var_decl.name, tname, node->type_info); - - if (node->var_decl.init_expr) - { - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - } - fprintf(out, ";\n"); - - if (node->type_info) - { - free(tname); // Free if allocated by codegen_type_to_string - } - } - else - { - // Inference Fallback - char *inferred = NULL; - if (node->var_decl.init_expr) - { - inferred = infer_type(ctx, node->var_decl.init_expr); - } - - if (inferred && strcmp(inferred, "__auto_type") != 0) - { - char *clean_type = inferred; - if (strncmp(clean_type, "struct ", 7) == 0) - { - clean_type += 7; - } - - ASTNode *def = find_struct_def(ctx, clean_type); - if (def && def->type_info && def->type_info->traits.has_drop) - { - fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type); - } - - emit_var_decl_type(ctx, out, inferred, node->var_decl.name); - add_symbol(ctx, node->var_decl.name, inferred, NULL); - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - fprintf(out, ";\n"); - } - else - { - emit_auto_type(ctx, node->var_decl.init_expr, node->token, out); - fprintf(out, " %s", node->var_decl.name); - - if (inferred) - { - add_symbol(ctx, node->var_decl.name, inferred, NULL); - } - - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - fprintf(out, ";\n"); - } - } - } - break; - case NODE_CONST: - fprintf(out, " const "); - if (node->var_decl.type_str) - { - fprintf(out, "%s %s", node->var_decl.type_str, node->var_decl.name); - } - else - { - emit_auto_type(ctx, node->var_decl.init_expr, node->token, out); - fprintf(out, " %s", node->var_decl.name); - } - fprintf(out, " = "); - codegen_expression(ctx, node->var_decl.init_expr, out); - fprintf(out, ";\n"); - break; - case NODE_FIELD: - if (node->field.bit_width > 0) - { - fprintf(out, " %s %s : %d;\n", node->field.type, node->field.name, - node->field.bit_width); - } - else - { - fprintf(out, " "); - emit_var_decl_type(ctx, out, node->field.type, node->field.name); - fprintf(out, ";\n"); - } - break; - case NODE_IF: - fprintf(out, "if ("); - codegen_expression(ctx, node->if_stmt.condition, out); - fprintf(out, ") "); - codegen_node_single(ctx, node->if_stmt.then_body, out); - if (node->if_stmt.else_body) - { - fprintf(out, " else "); - codegen_node_single(ctx, node->if_stmt.else_body, out); - } - break; - case NODE_UNLESS: - fprintf(out, "if (!("); - codegen_expression(ctx, node->unless_stmt.condition, out); - fprintf(out, ")) "); - codegen_node_single(ctx, node->unless_stmt.body, out); - break; - case NODE_GUARD: - fprintf(out, "if (!("); - codegen_expression(ctx, node->guard_stmt.condition, out); - fprintf(out, ")) "); - codegen_node_single(ctx, node->guard_stmt.body, out); - break; - case NODE_WHILE: - { - loop_defer_boundary[loop_depth++] = defer_count; - fprintf(out, "while ("); - codegen_expression(ctx, node->while_stmt.condition, out); - fprintf(out, ") "); - codegen_node_single(ctx, node->while_stmt.body, out); - loop_depth--; - break; - } - case NODE_FOR: - { - loop_defer_boundary[loop_depth++] = defer_count; - fprintf(out, "for ("); - if (node->for_stmt.init) - { - if (node->for_stmt.init->type == NODE_VAR_DECL) - { - ASTNode *v = node->for_stmt.init; - if (v->var_decl.type_str && strcmp(v->var_decl.type_str, "__auto_type") != 0) - { - fprintf(out, "%s %s = (%s)(", v->var_decl.type_str, v->var_decl.name, - v->var_decl.type_str); - codegen_expression(ctx, v->var_decl.init_expr, out); - fprintf(out, ")"); - } - else - { - emit_auto_type(ctx, v->var_decl.init_expr, v->token, out); - fprintf(out, " %s = ", v->var_decl.name); - codegen_expression(ctx, v->var_decl.init_expr, out); - } - } - else - { - codegen_expression(ctx, node->for_stmt.init, out); - } - } - fprintf(out, "; "); - if (node->for_stmt.condition) - { - codegen_expression(ctx, node->for_stmt.condition, out); - } - fprintf(out, "; "); - if (node->for_stmt.step) - { - codegen_expression(ctx, node->for_stmt.step, out); - } - fprintf(out, ") "); - codegen_node_single(ctx, node->for_stmt.body, out); - loop_depth--; - break; - } - case NODE_BREAK: - // Run defers from current scope down to loop boundary before breaking - if (loop_depth > 0) - { - int boundary = loop_defer_boundary[loop_depth - 1]; - for (int i = defer_count - 1; i >= boundary; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - } - if (node->break_stmt.target_label) - { - fprintf(out, "goto __break_%s;\n", node->break_stmt.target_label); - } - else - { - fprintf(out, "break;\n"); - } - break; - case NODE_CONTINUE: - // Run defers from current scope down to loop boundary before continuing - if (loop_depth > 0) - { - int boundary = loop_defer_boundary[loop_depth - 1]; - for (int i = defer_count - 1; i >= boundary; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - } - if (node->continue_stmt.target_label) - { - fprintf(out, "goto __continue_%s;\n", node->continue_stmt.target_label); - } - else - { - fprintf(out, "continue;\n"); - } - break; - case NODE_GOTO: - if (node->goto_stmt.goto_expr) - { - // Computed goto: goto *expr; - fprintf(out, "goto *("); - codegen_expression(ctx, node->goto_stmt.goto_expr, out); - fprintf(out, ");\n"); - } - else - { - fprintf(out, "goto %s;\n", node->goto_stmt.label_name); - } - break; - case NODE_LABEL: - fprintf(out, "%s:;\n", node->label_stmt.label_name); - break; - case NODE_DO_WHILE: - { - loop_defer_boundary[loop_depth++] = defer_count; - fprintf(out, "do "); - codegen_node_single(ctx, node->do_while_stmt.body, out); - fprintf(out, " while ("); - codegen_expression(ctx, node->do_while_stmt.condition, out); - fprintf(out, ");\n"); - loop_depth--; - break; - } - // Loop constructs: loop, repeat, for-in - case NODE_LOOP: - { - // loop { ... } => while (1) { ... } - loop_defer_boundary[loop_depth++] = defer_count; - fprintf(out, "while (1) "); - codegen_node_single(ctx, node->loop_stmt.body, out); - loop_depth--; - break; - } - case NODE_REPEAT: - { - loop_defer_boundary[loop_depth++] = defer_count; - fprintf(out, "for (int _rpt_i = 0; _rpt_i < (%s); _rpt_i++) ", node->repeat_stmt.count); - codegen_node_single(ctx, node->repeat_stmt.body, out); - loop_depth--; - break; - } - case NODE_FOR_RANGE: - { - // Track loop entry for defer boundary - loop_defer_boundary[loop_depth++] = defer_count; - - fprintf(out, "for ("); - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, "__typeof__(("); - codegen_expression(ctx, node->for_range.start, out); - fprintf(out, ")) %s = ", node->for_range.var_name); - } - else - { - fprintf(out, "ZC_AUTO %s = ", node->for_range.var_name); - } - codegen_expression(ctx, node->for_range.start, out); - if (node->for_range.is_inclusive) - { - fprintf(out, "; %s <= ", node->for_range.var_name); - } - else - { - fprintf(out, "; %s < ", node->for_range.var_name); - } - codegen_expression(ctx, node->for_range.end, out); - fprintf(out, "; %s", node->for_range.var_name); - if (node->for_range.step) - { - fprintf(out, " += %s) ", node->for_range.step); - } - else - { - fprintf(out, "++) "); - } - codegen_node_single(ctx, node->for_range.body, out); - - loop_depth--; - break; - } - case NODE_ASM: - { - int is_extended = (node->asm_stmt.num_outputs > 0 || node->asm_stmt.num_inputs > 0 || - node->asm_stmt.num_clobbers > 0); - - if (node->asm_stmt.is_volatile) - { - fprintf(out, " __asm__ __volatile__("); - } - else - { - fprintf(out, " __asm__("); - } - - char *code = node->asm_stmt.code; - char *transformed = xmalloc(strlen(code) * 3); // Generous buffer - char *dst = transformed; - - for (char *p = code; *p; p++) - { - if (*p == '{') - { - // Find matching } - char *end = strchr(p + 1, '}'); - if (end) - { - // Extract variable name - int var_len = end - p - 1; - char var_name[64]; - strncpy(var_name, p + 1, var_len); - var_name[var_len] = 0; - - // Find variable index - int idx = -1; - - // Check outputs first - for (int i = 0; i < node->asm_stmt.num_outputs; i++) - { - if (strcmp(node->asm_stmt.outputs[i], var_name) == 0) - { - idx = i; - break; - } - } - - // Then check inputs - if (idx == -1) - { - for (int i = 0; i < node->asm_stmt.num_inputs; i++) - { - if (strcmp(node->asm_stmt.inputs[i], var_name) == 0) - { - idx = node->asm_stmt.num_outputs + i; - break; - } - } - } - - if (idx >= 0) - { - // Replace with %N - dst += sprintf(dst, "%%%d", idx); - } - else - { - // Variable not found - error or keep as-is? - dst += sprintf(dst, "{%s}", var_name); - } - - p = end; // Skip past } - } - else - { - *dst++ = *p; - } - } - else if (*p == '%') - { - if (is_extended) - { - *dst++ = '%'; - *dst++ = '%'; - } - else - { - *dst++ = '%'; - } - } - else - { - *dst++ = *p; - } - } - *dst = 0; - - fprintf(out, "\""); - for (char *p = transformed; *p; p++) - { - if (*p == '\n') - { - fprintf(out, "\\n\"\n \""); - } - else if (*p == '"') - { - fprintf(out, "\\\""); - } - else if (*p == '\\') - { - fprintf(out, "\\\\"); - } - else - { - fputc(*p, out); - } - } - fprintf(out, "\\n\""); - - if (node->asm_stmt.num_outputs > 0) - { - fprintf(out, "\n : "); - for (int i = 0; i < node->asm_stmt.num_outputs; i++) - { - if (i > 0) - { - fprintf(out, ", "); - } - - // Determine constraint - char *mode = node->asm_stmt.output_modes[i]; - if (strcmp(mode, "out") == 0) - { - fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]); - } - else if (strcmp(mode, "inout") == 0) - { - fprintf(out, "\"+r\"(%s)", node->asm_stmt.outputs[i]); - } - else - { - fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]); - } - } - } - - if (node->asm_stmt.num_inputs > 0) - { - fprintf(out, "\n : "); - for (int i = 0; i < node->asm_stmt.num_inputs; i++) - { - if (i > 0) - { - fprintf(out, ", "); - } - fprintf(out, "\"r\"(%s)", node->asm_stmt.inputs[i]); - } - } - else if (node->asm_stmt.num_outputs > 0) - { - fprintf(out, "\n : "); - } - - if (node->asm_stmt.num_clobbers > 0) - { - fprintf(out, "\n : "); - for (int i = 0; i < node->asm_stmt.num_clobbers; i++) - { - if (i > 0) - { - fprintf(out, ", "); - } - fprintf(out, "\"%s\"", node->asm_stmt.clobbers[i]); - } - } - - fprintf(out, ");\n"); - break; - } - case NODE_RETURN: - { - int has_defers = (defer_count > func_defer_boundary); - int handled = 0; - - if (node->ret.value && node->ret.value->type == NODE_EXPR_VAR) - { - char *tname = infer_type(ctx, node->ret.value); - if (tname) - { - char *clean = tname; - if (strncmp(clean, "struct ", 7) == 0) - { - clean += 7; - } - - ASTNode *def = find_struct_def(ctx, clean); - if (def && def->type_info && def->type_info->traits.has_drop) - { - fprintf(out, " return ({ "); - if (strstr(g_config.cc, "tcc")) - { - fprintf(out, "__typeof__("); - codegen_expression(ctx, node->ret.value, out); - fprintf(out, ")"); - } - else - { - fprintf(out, "__auto_type"); - } - fprintf(out, " _z_ret_mv = "); - codegen_expression(ctx, node->ret.value, out); - fprintf(out, "; memset(&"); - codegen_expression(ctx, node->ret.value, out); - fprintf(out, ", 0, sizeof(_z_ret_mv)); "); - // Run defers before returning - for (int i = defer_count - 1; i >= func_defer_boundary; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - fprintf(out, "_z_ret_mv; });\n"); - handled = 1; - } - free(tname); - } - } - - if (!handled) - { - if (has_defers && node->ret.value) - { - // Save return value, run defers, then return - fprintf(out, " { "); - emit_auto_type(ctx, node->ret.value, node->token, out); - fprintf(out, " _z_ret = "); - codegen_expression(ctx, node->ret.value, out); - fprintf(out, "; "); - for (int i = defer_count - 1; i >= func_defer_boundary; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - fprintf(out, "return _z_ret; }\n"); - } - else if (has_defers) - { - // No return value, just run defers - for (int i = defer_count - 1; i >= func_defer_boundary; i--) - { - codegen_node_single(ctx, defer_stack[i], out); - } - fprintf(out, " return;\n"); - } - else - { - // No defers, simple return - fprintf(out, " return "); - codegen_expression(ctx, node->ret.value, out); - fprintf(out, ";\n"); - } - } - break; - } - case NODE_EXPR_MEMBER: - { - codegen_expression(ctx, node->member.target, out); - char *lt = infer_type(ctx, node->member.target); - if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*"))) - { - fprintf(out, "->%s", node->member.field); - } - else - { - fprintf(out, ".%s", node->member.field); - } - if (lt) - { - free(lt); - } - break; - } - case NODE_REPL_PRINT: - { - fprintf(out, "{ "); - emit_auto_type(ctx, node->repl_print.expr, node->token, out); - fprintf(out, " _zval = ("); - codegen_expression(ctx, node->repl_print.expr, out); - fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, " - "\"\\n\"); }\n"); - break; - } - case NODE_AWAIT: - { - char *ret_type = "void*"; - int free_ret = 0; - if (node->type_info) - { - char *t = codegen_type_to_string(node->type_info); - if (t) - { - ret_type = t; - free_ret = 1; - } - } - else if (node->resolved_type) - { - ret_type = node->resolved_type; - } - - // Fallback: If type is still Async/void* (likely from Future type, not - // Result type), try to infer - if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0) - { - char *inf = infer_type(ctx, node); - if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0) - { - if (free_ret) - { - free(ret_type); - } - ret_type = inf; - free_ret = 0; // infer_type ownership ambiguous, avoid double free - } - } - - int needs_long_cast = 0; - int returns_struct = 0; - if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 && - strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0) - { - if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 && - strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 && - strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 && - strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 && - strncmp(ret_type, "uint", 4) != 0 && strncmp(ret_type, "int", 3) != 0) - { - returns_struct = 1; - } - else - { - needs_long_cast = 1; - } - - if (strncmp(ret_type, "struct", 6) == 0) - { - returns_struct = 1; - } - } - - fprintf(out, "({ Async _a = "); - codegen_expression(ctx, node->unary.operand, out); - fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); "); - if (strcmp(ret_type, "void") == 0) - { - fprintf(out, "})"); // result unused - } - else - { - if (returns_struct) - { - // Dereference and free - fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type, ret_type); - } - else - { - if (needs_long_cast) - { - fprintf(out, "(%s)(long)_r; })", ret_type); - } - else - { - fprintf(out, "(%s)_r; })", ret_type); - } - } - } - if (free_ret) - { - free(ret_type); - } - fprintf(out, ";\n"); // Statement terminator - break; - } - case NODE_EXPR_LITERAL: - // String literal statement should auto-print - if (node->literal.type_kind == 2 || node->literal.type_kind == TOK_STRING) - { - fprintf(out, " printf(\"%%s\\n\", "); - codegen_expression(ctx, node, out); - fprintf(out, ");\n"); - } - else - { - // Non-string literals as statements - just evaluate - codegen_expression(ctx, node, out); - fprintf(out, ";\n"); - } - break; - case NODE_CUDA_LAUNCH: - { - // Emit CUDA kernel launch: kernel<<<grid, block, shared, stream>>>(args); - ASTNode *call = node->cuda_launch.call; - - // Get kernel name from callee - if (call->call.callee->type == NODE_EXPR_VAR) - { - fprintf(out, " %s<<<", call->call.callee->var_ref.name); - } - else - { - fprintf(out, " "); - codegen_expression(ctx, call->call.callee, out); - fprintf(out, "<<<"); - } - - // Grid dimension - codegen_expression(ctx, node->cuda_launch.grid, out); - fprintf(out, ", "); - - // Block dimension - codegen_expression(ctx, node->cuda_launch.block, out); - - // Optional shared memory size - if (node->cuda_launch.shared_mem || node->cuda_launch.stream) - { - fprintf(out, ", "); - if (node->cuda_launch.shared_mem) - { - codegen_expression(ctx, node->cuda_launch.shared_mem, out); - } - else - { - fprintf(out, "0"); - } - } - - // Optional CUDA stream - if (node->cuda_launch.stream) - { - fprintf(out, ", "); - codegen_expression(ctx, node->cuda_launch.stream, out); - } - - fprintf(out, ">>>("); - - // Arguments - ASTNode *arg = call->call.args; - int first = 1; - while (arg) - { - if (!first) - { - fprintf(out, ", "); - } - codegen_expression(ctx, arg, out); - first = 0; - arg = arg->next; - } - - fprintf(out, ");\n"); - break; - } - default: - codegen_expression(ctx, node, out); - fprintf(out, ";\n"); - break; - } -} - -// Walks AST nodes and generates code. -void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out) -{ - while (node) - { - codegen_node_single(ctx, node, out); - node = node->next; - } -} |
