summaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/codegen.c166
-rw-r--r--src/codegen/codegen_decl.c111
-rw-r--r--src/codegen/codegen_main.c110
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++)
{