summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast/ast.h8
-rw-r--r--src/codegen/codegen.c34
-rw-r--r--src/parser/parser_stmt.c12
-rw-r--r--src/parser/parser_utils.c114
-rw-r--r--tests/features/test_mixin_methods.zc33
5 files changed, 194 insertions, 7 deletions
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 3269e55..a528129 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -380,9 +380,11 @@ struct ASTNode
int generic_param_count; // Number of generic parameters
char *parent;
int is_union;
- int is_packed; // @packed attribute.
- int align; // @align(N) attribute, 0 = default.
- int is_incomplete; // Forward declaration (prototype)
+ int is_packed; // @packed attribute.
+ int align; // @align(N) attribute, 0 = default.
+ int is_incomplete; // Forward declaration (prototype)
+ char **used_structs; // Names of structs used/mixed-in
+ int used_struct_count;
} strct;
struct
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index f019a4b..25ae5b3 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -560,8 +560,38 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, "%s__%s(", base, method);
- if (!strchr(type, '*'))
+ // Mixin Lookup Logic
+ char *call_base = base;
+ int need_cast = 0;
+ char mixin_func_name[128];
+ sprintf(mixin_func_name, "%s__%s", base, method);
+
+ 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)
+ {
+ 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;
+ }
+ }
+ }
+ }
+
+ fprintf(out, "%s__%s(", call_base, method);
+ if (need_cast)
+ {
+ fprintf(out, "(%s*)%s", call_base, strchr(type, '*') ? "" : "&");
+ }
+ else if (!strchr(type, '*'))
{
fprintf(out, "&");
}
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index c9b144d..ca8cd8f 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -3268,6 +3268,10 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
lexer_next(l); // eat {
ASTNode *h = 0, *tl = 0;
+ // Temp storage for used structs
+ char **temp_used_structs = NULL;
+ int temp_used_count = 0;
+
while (1)
{
skip_comments(l);
@@ -3308,6 +3312,12 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
if (def && def->type == NODE_STRUCT)
{
+ if (!temp_used_structs)
+ {
+ temp_used_structs = xmalloc(sizeof(char *) * 8);
+ }
+ temp_used_structs[temp_used_count++] = xstrdup(use_name);
+
ASTNode *f = def->strct.fields;
while (f)
{
@@ -3410,6 +3420,8 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
node->strct.generic_params = gps;
node->strct.generic_param_count = gp_count;
node->strct.is_union = is_union;
+ node->strct.used_structs = temp_used_structs;
+ node->strct.used_struct_count = temp_used_count;
if (gp_count > 0)
{
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index d2214eb..87cf24e 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -2298,7 +2298,63 @@ char *rewrite_expr_methods(ParserContext *ctx, char *raw)
}
}
- dest += sprintf(dest, "%s__%s(%s%s", ptr_check, method, is_ptr ? "" : "&", acc);
+ // Mixin Lookup Logic
+ char target_func[128];
+ sprintf(target_func, "%s__%s", ptr_check, method);
+
+ char *final_cast = NULL;
+ char *final_method = xstrdup(method);
+ char *final_struct = xstrdup(ptr_check);
+
+ // Check if method exists on primary struct
+ if (!find_func(ctx, target_func))
+ {
+ // Not found, check mixins
+ ASTNode *def = find_struct_def(ctx, ptr_check);
+ if (def && def->type == NODE_STRUCT && def->strct.used_structs)
+ {
+ for (int k = 0; k < def->strct.used_struct_count; k++)
+ {
+ char mixin_func[128];
+ sprintf(mixin_func, "%s__%s", def->strct.used_structs[k], method);
+ if (find_func(ctx, mixin_func))
+ {
+ // Found in mixin!
+ free(final_struct);
+ final_struct = xstrdup(def->strct.used_structs[k]);
+
+ // Create cast string: (Mixin*) or (Mixin*)&
+ char cast_buf[128];
+ if (is_ptr)
+ {
+ sprintf(cast_buf, "(%s*)", final_struct);
+ }
+ else
+ {
+ sprintf(cast_buf, "(%s*)&", final_struct);
+ }
+ final_cast = xstrdup(cast_buf);
+ break;
+ }
+ }
+ }
+ }
+
+ if (final_cast)
+ {
+ // Mixin call: Foo__method((Foo*)&obj
+ dest +=
+ sprintf(dest, "%s__%s(%s%s", final_struct, final_method, final_cast, acc);
+ free(final_cast);
+ }
+ else
+ {
+ // Standard call
+ dest += sprintf(dest, "%s__%s(%s%s", final_struct, final_method,
+ is_ptr ? "" : "&", acc);
+ }
+ free(final_struct);
+ free(final_method);
int has_args = 0;
while (*src && paren_depth > 0)
@@ -2348,7 +2404,61 @@ char *rewrite_expr_methods(ParserContext *ctx, char *raw)
*p = 0;
}
}
- dest += sprintf(dest, "%s__%s(%s%s)", ptr_check, method, is_ptr ? "" : "&", acc);
+ // Mixin Lookup Logic (No Parens)
+ char target_func[128];
+ sprintf(target_func, "%s__%s", ptr_check, method);
+
+ char *final_cast = NULL;
+ char *final_method = xstrdup(method);
+ char *final_struct = xstrdup(ptr_check);
+
+ // Check if method exists on primary struct
+ if (!find_func(ctx, target_func))
+ {
+ // Not found, check mixins
+ ASTNode *def = find_struct_def(ctx, ptr_check);
+ if (def && def->type == NODE_STRUCT && def->strct.used_structs)
+ {
+ for (int k = 0; k < def->strct.used_struct_count; k++)
+ {
+ char mixin_func[128];
+ sprintf(mixin_func, "%s__%s", def->strct.used_structs[k], method);
+ if (find_func(ctx, mixin_func))
+ {
+ // Found in mixin!
+ free(final_struct);
+ final_struct = xstrdup(def->strct.used_structs[k]);
+
+ // Create cast string: (Mixin*) or (Mixin*)&
+ char cast_buf[128];
+ if (is_ptr)
+ {
+ sprintf(cast_buf, "(%s*)", final_struct);
+ }
+ else
+ {
+ sprintf(cast_buf, "(%s*)&", final_struct);
+ }
+ final_cast = xstrdup(cast_buf);
+ break;
+ }
+ }
+ }
+ }
+
+ if (final_cast)
+ {
+ dest +=
+ sprintf(dest, "%s__%s(%s%s)", final_struct, final_method, final_cast, acc);
+ free(final_cast);
+ }
+ else
+ {
+ dest += sprintf(dest, "%s__%s(%s%s)", final_struct, final_method,
+ is_ptr ? "" : "&", acc);
+ }
+ free(final_struct);
+ free(final_method);
continue;
}
}
diff --git a/tests/features/test_mixin_methods.zc b/tests/features/test_mixin_methods.zc
new file mode 100644
index 0000000..0932429
--- /dev/null
+++ b/tests/features/test_mixin_methods.zc
@@ -0,0 +1,33 @@
+
+struct Foo {
+ i: i32;
+}
+
+impl Foo {
+ fn get_i(self) -> i32 {
+ return self.i;
+ }
+
+ fn set_i(self, val: i32) {
+ self.i = val;
+ }
+}
+
+struct Bar {
+ use Foo;
+ f: f32;
+}
+
+test "test_mixin_methods" {
+ var b: Bar;
+ b.i = 42;
+ b.f = 3.14;
+
+ var val = b.get_i();
+ assert(val == 42, "Mixin method get_i() should return 42");
+
+ b.set_i(100);
+ assert(b.i == 100, "Mixin method set_i() should update i to 100");
+
+ "Mixin method dispatch OK";
+}