diff options
Diffstat (limited to 'src/codegen/codegen_utils.c')
| -rw-r--r-- | src/codegen/codegen_utils.c | 178 |
1 files changed, 152 insertions, 26 deletions
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c index fe580bf..6283bce 100644 --- a/src/codegen/codegen_utils.c +++ b/src/codegen/codegen_utils.c @@ -40,19 +40,33 @@ char *strip_template_suffix(const char *name) return xstrdup(name); } -// Helper to emit variable declarations with array types. -void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name) +// Helper to emit C declaration (handle arrays, function pointers correctly) +void emit_c_decl(FILE *out, const char *type_str, const char *name) { - (void)ctx; - char *bracket = strchr(type_str, '['); char *generic = strchr(type_str, '<'); + char *fn_ptr = strstr(type_str, "(*"); - if (generic && (!bracket || generic < bracket)) + if (fn_ptr) + { + char *end_paren = strchr(fn_ptr, ')'); + if (end_paren) + { + int prefix_len = end_paren - type_str; + fprintf(out, "%.*s%s%s", prefix_len, type_str, name, end_paren); + } + else + { + // Fallback if malformed (shouldn't happen) + int prefix_len = fn_ptr - type_str + 2; + fprintf(out, "%.*s%s%s", prefix_len, type_str, name, fn_ptr + 2); + } + } + else if (generic && (!bracket || generic < bracket)) { // Strip generic part for C output int base_len = generic - type_str; - fprintf(out, "%.*s %s", base_len, type_str, var_name); + fprintf(out, "%.*s %s", base_len, type_str, name); if (bracket) { @@ -62,14 +76,21 @@ void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, con else if (bracket) { int base_len = bracket - type_str; - fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket); + fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket); } else { - fprintf(out, "%s %s", type_str, var_name); + fprintf(out, "%s %s", type_str, name); } } +// Helper to emit variable declarations with array types. +void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name) +{ + (void)ctx; + emit_c_decl(out, type_str, var_name); +} + // Find struct definition ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name) { @@ -455,15 +476,15 @@ char *infer_type(ParserContext *ctx, ASTNode *node) if (node->type == NODE_EXPR_LITERAL) { - if (node->literal.type_kind == TOK_STRING) + if (node->literal.type_kind == LITERAL_STRING) { - return "string"; + return xstrdup("string"); } - if (node->literal.type_kind == TOK_CHAR) + if (node->literal.type_kind == LITERAL_CHAR) { - return "char"; + return xstrdup("char"); } - if (node->literal.type_kind == 1) + if (node->literal.type_kind == LITERAL_FLOAT) { return "double"; } @@ -519,8 +540,22 @@ char *extract_call_args(const char *args) // 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 *sep = strstr(mangled, "__"); + if (!sep) + { + return mangled; + } + + // Let's iterate to find the last `__`. + const char *last_double = NULL; + const char *p = mangled; + while ((p = strstr(p, "__"))) + { + last_double = p; + p += 2; + } + + return last_double ? last_double + 2 : mangled; } // Replace string type in arguments. @@ -635,7 +670,20 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override) ret_str = xstrdup("void"); } - fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name); + char *ret_suffix = NULL; + char *fn_ptr = strstr(ret_str, "(*)"); + + if (fn_ptr) + { + int prefix_len = fn_ptr - ret_str + 2; // Include "(*" + fprintf(out, "%.*s%s(", prefix_len, ret_str, + name_override ? name_override : func->func.name); + ret_suffix = fn_ptr + 2; + } + else + { + fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name); + } free(ret_str); // Args @@ -669,16 +717,7 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override) } // check if array type - char *bracket = strchr(type_str, '['); - if (bracket) - { - int base_len = bracket - type_str; - fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket); - } - else - { - fprintf(out, "%s %s", type_str, name); - } + emit_c_decl(out, type_str, name); free(type_str); } if (func->func.is_varargs) @@ -691,4 +730,91 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override) } } fprintf(out, ")"); + + if (ret_suffix) + { + fprintf(out, "%s", ret_suffix); + } +} + +// Invalidate a moved-from variable by zeroing it out to prevent double-free +int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out) +{ + if (!node) + { + return 0; + } + + // Check if it's a valid l-value we can memset + if (node->type != NODE_EXPR_VAR && node->type != NODE_EXPR_MEMBER) + { + return 0; + } + + // Common logic to find type and check Drop + char *type_name = infer_type(ctx, node); + ASTNode *def = NULL; + if (type_name) + { + char *clean_type = type_name; + if (strncmp(clean_type, "struct ", 7) == 0) + { + clean_type += 7; + } + def = find_struct_def(ctx, clean_type); + } + + if (def && def->type_info && def->type_info->traits.has_drop) + { + if (node->type == NODE_EXPR_VAR) + { + fprintf(out, "__z_drop_flag_%s = 0; ", node->var_ref.name); + fprintf(out, "memset(&%s, 0, sizeof(%s))", node->var_ref.name, node->var_ref.name); + return 1; + } + else if (node->type == NODE_EXPR_MEMBER) + { + // For members: memset(&foo.bar, 0, sizeof(foo.bar)) + fprintf(out, "memset(&"); + codegen_expression(ctx, node, out); + fprintf(out, ", 0, sizeof("); + codegen_expression(ctx, node, out); + fprintf(out, "))"); + return 1; + } + } + return 0; +} + +// Emits expression, wrapping it in a move-invalidation block if it's a consuming variable usage +void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out) +{ + if (node && (node->type == NODE_EXPR_VAR || node->type == NODE_EXPR_MEMBER)) + { + // Re-use infer logic to see if we need invalidation + char *type_name = infer_type(ctx, node); + ASTNode *def = NULL; + if (type_name) + { + char *clean_type = type_name; + if (strncmp(clean_type, "struct ", 7) == 0) + { + clean_type += 7; + } + def = find_struct_def(ctx, clean_type); + } + + if (def && def->type_info && def->type_info->traits.has_drop) + { + fprintf(out, "({ __typeof__("); + codegen_expression(ctx, node, out); + fprintf(out, ") _mv = "); + codegen_expression(ctx, node, out); + fprintf(out, "; "); + emit_move_invalidation(ctx, node, out); + fprintf(out, "; _mv; })"); + return; + } + } + codegen_expression(ctx, node, out); } |
