diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/codegen.c | 166 | ||||
| -rw-r--r-- | src/codegen/codegen_decl.c | 111 | ||||
| -rw-r--r-- | src/codegen/codegen_main.c | 110 |
3 files changed, 332 insertions, 55 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 01c8204..b2f1ad1 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -246,38 +246,89 @@ static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, { if (strstr(g_config.cc, "tcc")) { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); + 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 { - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id); + if (c->match_case.is_ref) + { + fprintf(out, "ZC_AUTO %s = &_m_%d.val; ", c->match_case.binding_name, id); + } + else + { + fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id); + } } } - if (is_result) + 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")) { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); + 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 { - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id); + if (c->match_case.is_ref) + { + fprintf(out, "ZC_AUTO %s = &_m_%d.val; ", c->match_case.binding_name, + id); + } + else + { + fprintf(out, "ZC_AUTO %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); + 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 { - fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name, id); + if (c->match_case.is_ref) + { + fprintf(out, "ZC_AUTO %s = &_m_%d.err; ", c->match_case.binding_name, + id); + } + else + { + fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name, + id); + } } } } @@ -292,7 +343,18 @@ static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, { f = c->match_case.pattern; } - fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f); + // Generic struct destructuring (e.g. MyStruct_Variant) + // Assuming data union or accessible field. + // Original: _m_%d.data.%s + if (c->match_case.is_ref) + { + fprintf(out, "ZC_AUTO %s = &_m_%d.data.%s; ", c->match_case.binding_name, id, + f); + } + else + { + fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f); + } } } @@ -461,7 +523,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) } fprintf(out, "%s__eq(&", base); codegen_expression(ctx, node->binary.left, out); - fprintf(out, ", "); + fprintf(out, ", &"); codegen_expression(ctx, node->binary.right, out); fprintf(out, ")"); if (strcmp(node->binary.op, "!=") == 0) @@ -641,21 +703,57 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) char mixin_func_name[128]; sprintf(mixin_func_name, "%s__%s", base, method); + char *resolved_method_suffix = NULL; + if (!find_func(ctx, mixin_func_name)) { - // Method not found on primary struct, check mixins - ASTNode *def = find_struct_def(ctx, base); - if (def && def->type == NODE_STRUCT && def->strct.used_structs) + // Try resolving as a trait method: Struct__Trait_Method + StructRef *ref = ctx->parsed_impls_list; + while (ref) { - for (int k = 0; k < def->strct.used_struct_count; k++) + if (ref->node && ref->node->type == NODE_IMPL_TRAIT) { - char mixin_check[128]; - sprintf(mixin_check, "%s__%s", def->strct.used_structs[k], method); - if (find_func(ctx, mixin_check)) + if (strcmp(ref->node->impl_trait.target_type, base) == 0) { - call_base = def->strct.used_structs[k]; - need_cast = 1; - break; + char trait_mangled[256]; + sprintf(trait_mangled, "%s__%s_%s", base, + ref->node->impl_trait.trait_name, method); + if (find_func(ctx, trait_mangled)) + { + char *suffix = + xmalloc(strlen(ref->node->impl_trait.trait_name) + + strlen(method) + 2); + sprintf(suffix, "%s_%s", ref->node->impl_trait.trait_name, + method); + resolved_method_suffix = suffix; + break; + } + } + } + ref = ref->next; + } + + if (resolved_method_suffix) + { + method = resolved_method_suffix; + } + else + { + // Method not found on primary struct, check mixins + ASTNode *def = find_struct_def(ctx, base); + if (def && def->type == NODE_STRUCT && def->strct.used_structs) + { + for (int k = 0; k < def->strct.used_struct_count; k++) + { + char mixin_check[128]; + sprintf(mixin_check, "%s__%s", def->strct.used_structs[k], + method); + if (find_func(ctx, mixin_check)) + { + call_base = def->strct.used_structs[k]; + need_cast = 1; + break; + } } } } @@ -1685,7 +1783,6 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } { char *tname = NULL; - // Use type_info with codegen_type_to_string if available if (node->type_info) { tname = codegen_type_to_string(node->type_info); @@ -1697,11 +1794,16 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) if (tname) { - // Cleanup attribute - ASTNode *def = find_struct_def(ctx, tname); + 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))) ", tname); + fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type); } // Emit Variable with Type @@ -1731,6 +1833,18 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) 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, " = "); diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c index 8ada7d6..e7bd3f1 100644 --- a/src/codegen/codegen_decl.c +++ b/src/codegen/codegen_decl.c @@ -424,6 +424,28 @@ void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out) } } +// Helper to substitute 'Self' with replacement string +static char *substitute_proto_self(const char *type_str, const char *replacement) +{ + if (!type_str) + { + return NULL; + } + if (strcmp(type_str, "Self") == 0) + { + return xstrdup(replacement); + } + // Handle pointers (Self* -> replacement*) + if (strncmp(type_str, "Self", 4) == 0) + { + char *rest = (char *)type_str + 4; + char *buf = xmalloc(strlen(replacement) + strlen(rest) + 1); + sprintf(buf, "%s%s", replacement, rest); + return buf; + } + return xstrdup(type_str); +} + // Emit trait definitions. void emit_trait_defs(ASTNode *node, FILE *out) { @@ -440,8 +462,10 @@ void emit_trait_defs(ASTNode *node, FILE *out) ASTNode *m = node->trait.methods; while (m) { - fprintf(out, " %s (*%s)(", m->func.ret_type, - parse_original_method_name(m->func.name)); + char *ret_safe = substitute_proto_self(m->func.ret_type, "void*"); + fprintf(out, " %s (*%s)(", ret_safe, parse_original_method_name(m->func.name)); + free(ret_safe); + int has_self = (m->func.args && strstr(m->func.args, "self")); if (!has_self) { @@ -454,7 +478,32 @@ void emit_trait_defs(ASTNode *node, FILE *out) { fprintf(out, ", "); } - fprintf(out, "%s", m->func.args); + char *args_safe = xstrdup(m->func.args); + // TODO: better replace, but for now this works. + char *p = strstr(args_safe, "Self"); + while (p) + { + // Check word boundary + if ((p == args_safe || !isalnum(p[-1])) && !isalnum(p[4])) + { + int off = p - args_safe; + char *new_s = xmalloc(strlen(args_safe) + 10); + strncpy(new_s, args_safe, off); + new_s[off] = 0; + strcat(new_s, "void*"); + strcat(new_s, p + 4); + free(args_safe); + args_safe = new_s; + p = strstr(args_safe + off + 5, "Self"); + } + else + { + p = strstr(p + 1, "Self"); + } + } + + fprintf(out, "%s", args_safe); + free(args_safe); } fprintf(out, ");\n"); m = m->next; @@ -467,7 +516,9 @@ void emit_trait_defs(ASTNode *node, FILE *out) 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, + char *ret_sub = substitute_proto_self(m->func.ret_type, node->trait.name); + + fprintf(out, "%s %s__%s(%s* self", ret_sub, node->trait.name, orig, node->trait.name); int has_self = (m->func.args && strstr(m->func.args, "self")); @@ -478,17 +529,45 @@ void emit_trait_defs(ASTNode *node, FILE *out) char *comma = strchr(m->func.args, ','); if (comma) { - fprintf(out, ", %s", comma + 1); + // Substitute Self -> TraitName in wrapper args + char *args_sub = xstrdup(comma + 1); + char *p = strstr(args_sub, "Self"); + while (p) + { + int off = p - args_sub; + char *new_s = + xmalloc(strlen(args_sub) + strlen(node->trait.name) + 5); + strncpy(new_s, args_sub, off); + new_s[off] = 0; + strcat(new_s, node->trait.name); + strcat(new_s, p + 4); + free(args_sub); + args_sub = new_s; + p = strstr(args_sub + off + strlen(node->trait.name), "Self"); + } + + fprintf(out, ", %s", args_sub); + free(args_sub); } } else { - fprintf(out, ", %s", m->func.args); + fprintf(out, ", %s", m->func.args); // TODO: recursive subst } } fprintf(out, ") {\n"); - fprintf(out, " return self->vtable->%s(self->self", orig); + int ret_is_self = (strcmp(m->func.ret_type, "Self") == 0); + + if (ret_is_self) + { + // Special handling: return (Trait){.self = call(), .vtable = self->vtable} + fprintf(out, " void* ret = self->vtable->%s(self->self", orig); + } + else + { + fprintf(out, " return self->vtable->%s(self->self", orig); + } if (m->func.args) { @@ -510,7 +589,16 @@ void emit_trait_defs(ASTNode *node, FILE *out) } free(call_args); } - fprintf(out, ");\n}\n"); + fprintf(out, ");\n"); + + if (ret_is_self) + { + fprintf(out, " return (%s){.self = ret, .vtable = self->vtable};\n", + node->trait.name); + } + + fprintf(out, "}\n\n"); + free(ret_sub); m = m->next; } @@ -853,6 +941,13 @@ void emit_impl_vtables(ParserContext *ctx, FILE *out) emitted[count].strct = strct; count++; + if (0 == strcmp(trait, "Copy")) + { + // Marker trait, no runtime vtable needed + ref = ref->next; + continue; + } + fprintf(out, "%s_VTable %s_%s_VTable = {", trait, strct, trait); ASTNode *m = node->impl_trait.methods; diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c index 7382827..97abfc7 100644 --- a/src/codegen/codegen_main.c +++ b/src/codegen/codegen_main.c @@ -14,33 +14,101 @@ static int struct_depends_on(ASTNode *s1, const char *target_name) return 0; } - // Only structs have dependencies that matter for ordering. - if (s1->type != NODE_STRUCT) + // Check structs + 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; - ASTNode *field = s1->strct.fields; - while (field) + // Skip pointers - they don't create ordering dependency. + if (strchr(type_str, '*')) + { + field = field->next; + continue; + } + + // Clean type string (remove struct/enum prefixes) + const char *clean = type_str; + if (strncmp(clean, "struct ", 7) == 0) + { + clean += 7; + } + else if (strncmp(clean, "enum ", 5) == 0) + { + clean += 5; + } + else if (strncmp(clean, "union ", 6) == 0) + { + clean += 6; + } + + // Check for match + size_t len = strlen(target_name); + if (strncmp(clean, target_name, len) == 0) + { + char next = clean[len]; + if (next == 0 || next == '[' || isspace(next)) + { + return 1; + } + } + } + field = field->next; + } + } + // Check enums (ADTs) + else if (s1->type == NODE_ENUM) { - if (field->type == NODE_FIELD && field->field.type) + ASTNode *variant = s1->enm.variants; + while (variant) { - char *type_str = field->field.type; - // Skip pointers - they don't create ordering dependency. - if (strchr(type_str, '*')) + if (variant->type == NODE_ENUM_VARIANT && variant->variant.payload) { - field = field->next; - continue; - } + char *type_str = type_to_string(variant->variant.payload); + if (type_str) + { + if (strchr(type_str, '*')) + { + free(type_str); + variant = variant->next; + continue; + } - // Check if this field's type matches target (struct or enum). - if (strcmp(type_str, target_name) == 0) - { - return 1; + const char *clean = type_str; + if (strncmp(clean, "struct ", 7) == 0) + { + clean += 7; + } + else if (strncmp(clean, "enum ", 5) == 0) + { + clean += 5; + } + else if (strncmp(clean, "union ", 6) == 0) + { + clean += 6; + } + + size_t len = strlen(target_name); + if (strncmp(clean, target_name, len) == 0) + { + char next = clean[len]; + if (next == 0 || next == '[' || isspace(next)) + { + free(type_str); + return 1; + } + } + free(type_str); + } } + variant = variant->next; } - field = field->next; } + return 0; } @@ -102,8 +170,8 @@ static ASTNode *topo_sort_structs(ASTNode *head) continue; } - // Enums and traits have no dependencies, emit first. - if (nodes[i]->type == NODE_ENUM || nodes[i]->type == NODE_TRAIT) + // Traits have no dependencies, emit first. + if (nodes[i]->type == NODE_TRAIT) { order[order_idx++] = i; emitted[i] = 1; @@ -111,7 +179,7 @@ static ASTNode *topo_sort_structs(ASTNode *head) continue; } - // For structs, check if all dependencies are emitted. + // For structs/enums, check if all dependencies are emitted. int can_emit = 1; for (int j = 0; j < count; j++) { |
