diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-17 15:33:18 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-17 15:33:18 +0000 |
| commit | b885629239d04d2860a8853799a3d335d8bec154 (patch) | |
| tree | 98ee21d5e7ef791948456da4f23e6b5bb496de7f /src | |
| parent | e0cf5aca2a17fae1f89860d5106aa901dde32782 (diff) | |
Add support for mixin method dispatch.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast/ast.h | 8 | ||||
| -rw-r--r-- | src/codegen/codegen.c | 34 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 12 | ||||
| -rw-r--r-- | src/parser/parser_utils.c | 114 |
4 files changed, 161 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; } } |
