summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-18 22:32:49 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-18 22:32:49 +0000
commit562e010dd47ec1e238017369ea481700d826b68d (patch)
treef39d428621c3f7f084540c85d4a9fee07aac148d
parente007eb629f422fb96fa8da81e2f79e7d0301c866 (diff)
Fix for #73
-rw-r--r--src/parser/parser_expr.c253
-rw-r--r--tests/features/test_alias.zc25
2 files changed, 206 insertions, 72 deletions
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index b9f022a..6d95f12 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -2382,7 +2382,6 @@ const char *get_operator_method(const char *op)
return "ge";
}
- // --- NEW: Bitwise ---
if (strcmp(op, "&") == 0)
{
return "bitand";
@@ -2407,6 +2406,104 @@ const char *get_operator_method(const char *op)
return NULL;
}
+char *resolve_struct_name_from_type(ParserContext *ctx, Type *t, int *is_ptr_out,
+ char **allocated_out)
+{
+ if (!t)
+ {
+ return NULL;
+ }
+ char *struct_name = NULL;
+ *allocated_out = NULL;
+ *is_ptr_out = 0;
+
+ const char *alias_target = NULL;
+ if (t->kind == TYPE_STRUCT)
+ {
+ alias_target = find_type_alias(ctx, t->name);
+ }
+
+ if (alias_target)
+ {
+ char *tpl = xstrdup(alias_target);
+ char *args_ptr = strchr(tpl, '<');
+ if (args_ptr)
+ {
+ *args_ptr = 0;
+ args_ptr++;
+ char *end = strrchr(args_ptr, '>');
+ if (end)
+ {
+ *end = 0;
+ }
+
+ const char *c_type = args_ptr;
+ if (strcmp(args_ptr, "f32") == 0)
+ {
+ c_type = "float";
+ }
+ else if (strcmp(args_ptr, "f64") == 0)
+ {
+ c_type = "double";
+ }
+ else if (strcmp(args_ptr, "i32") == 0)
+ {
+ c_type = "int";
+ }
+ else if (strcmp(args_ptr, "u32") == 0)
+ {
+ c_type = "uint";
+ }
+ else if (strcmp(args_ptr, "bool") == 0)
+ {
+ c_type = "bool";
+ }
+
+ char *clean = sanitize_mangled_name(c_type);
+ char *mangled = xmalloc(strlen(tpl) + strlen(clean) + 2);
+ sprintf(mangled, "%s_%s", tpl, clean);
+ struct_name = mangled;
+ *allocated_out = mangled;
+ free(clean);
+ *is_ptr_out = 0;
+ }
+ else if (strchr(alias_target, '*'))
+ {
+ *is_ptr_out = 1;
+ char *tmp = xstrdup(alias_target);
+ char *p = strchr(tmp, '*');
+ if (p)
+ {
+ *p = 0;
+ }
+ struct_name = xstrdup(tmp);
+ *allocated_out = struct_name;
+ free(tmp);
+ }
+ else
+ {
+ struct_name = xstrdup(alias_target);
+ *allocated_out = struct_name;
+ *is_ptr_out = 0;
+ }
+ free(tpl);
+ }
+ else
+ {
+ if (t->kind == TYPE_STRUCT)
+ {
+ struct_name = t->name;
+ *is_ptr_out = 0;
+ }
+ else if (t->kind == TYPE_POINTER && t->inner->kind == TYPE_STRUCT)
+ {
+ struct_name = t->inner->name;
+ *is_ptr_out = 1;
+ }
+ }
+ return struct_name;
+}
+
ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
{
Token t = lexer_peek(l);
@@ -2675,19 +2772,9 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
if (method && operand->type_info)
{
Type *ot = operand->type_info;
- char *struct_name = NULL;
int is_ptr = 0;
- // Unwrap pointer if needed (Struct* -> Struct) to find the method
- if (ot->kind == TYPE_STRUCT)
- {
- struct_name = ot->name;
- is_ptr = 0;
- }
- else if (ot->kind == TYPE_POINTER && ot->inner->kind == TYPE_STRUCT)
- {
- struct_name = ot->inner->name;
- is_ptr = 1;
- }
+ char *allocated_name = NULL;
+ char *struct_name = resolve_struct_name_from_type(ctx, ot, &is_ptr, &allocated_name);
if (struct_name)
{
@@ -2732,9 +2819,17 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
call->resolved_type = type_to_string(sig->ret_type);
lhs = call;
+ if (allocated_name)
+ {
+ free(allocated_name);
+ }
// Skip standard unary node creation
goto after_unary;
}
+ if (allocated_name)
+ {
+ free(allocated_name);
+ }
}
}
@@ -3529,22 +3624,10 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
if (inner_method)
{
Type *lt = lhs->type_info;
- char *struct_name = NULL;
int is_lhs_ptr = 0;
-
- if (lt)
- {
- if (lt->kind == TYPE_STRUCT)
- {
- struct_name = lt->name;
- is_lhs_ptr = 0;
- }
- else if (lt->kind == TYPE_POINTER && lt->inner->kind == TYPE_STRUCT)
- {
- struct_name = lt->inner->name;
- is_lhs_ptr = 1;
- }
- }
+ char *allocated_name = NULL;
+ char *struct_name =
+ resolve_struct_name_from_type(ctx, lt, &is_lhs_ptr, &allocated_name);
if (struct_name)
{
@@ -3587,6 +3670,10 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
op_node = call;
}
}
+ if (allocated_name)
+ {
+ free(allocated_name);
+ }
}
free(bin->binary.op);
@@ -3672,22 +3759,10 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
if (method)
{
Type *lt = lhs->type_info;
- char *struct_name = NULL;
int is_lhs_ptr = 0;
-
- if (lt)
- {
- if (lt->kind == TYPE_STRUCT)
- {
- struct_name = lt->name;
- is_lhs_ptr = 0;
- }
- else if (lt->kind == TYPE_POINTER && lt->inner->kind == TYPE_STRUCT)
- {
- struct_name = lt->inner->name;
- is_lhs_ptr = 1;
- }
- }
+ char *allocated_name = NULL;
+ char *struct_name =
+ resolve_struct_name_from_type(ctx, lt, &is_lhs_ptr, &allocated_name);
if (struct_name)
{
@@ -3749,8 +3824,16 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
call->resolved_type = type_to_string(sig->ret_type);
lhs = call;
+ if (allocated_name)
+ {
+ free(allocated_name);
+ }
continue; // Loop again with result as new lhs
}
+ if (allocated_name)
+ {
+ free(allocated_name);
+ }
}
}
@@ -3806,44 +3889,70 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
else
{
+ // Check aliases
+ char *al = NULL, *ar = NULL;
+ int pl = 0, pr = 0;
+ char *sl = resolve_struct_name_from_type(ctx, lhs->type_info, &pl, &al);
+ char *sr = resolve_struct_name_from_type(ctx, rhs->type_info, &pr, &ar);
+
+ int alias_match = 0;
+ if (sl && sr && strcmp(sl, sr) == 0 && pl == pr)
+ {
+ alias_match = 1;
+ bin->type_info = lhs->type_info;
+ }
+ if (al)
+ {
+ free(al);
+ }
+ if (ar)
+ {
+ free(ar);
+ }
+
char *t1 = type_to_string(lhs->type_info);
char *t2 = type_to_string(rhs->type_info);
// Allow pointer arithmetic: ptr + int, ptr - int, int + ptr
int is_ptr_arith = 0;
- if (strcmp(bin->binary.op, "+") == 0 || strcmp(bin->binary.op, "-") == 0)
- {
- int lhs_is_ptr = (lhs->type_info->kind == TYPE_POINTER ||
- lhs->type_info->kind == TYPE_STRING ||
- (t1 && strstr(t1, "*") != NULL));
- int rhs_is_ptr = (rhs->type_info->kind == TYPE_POINTER ||
- rhs->type_info->kind == TYPE_STRING ||
- (t2 && strstr(t2, "*") != NULL));
- int lhs_is_int =
- (lhs->type_info->kind == TYPE_INT || lhs->type_info->kind == TYPE_I32 ||
- lhs->type_info->kind == TYPE_I64 ||
- lhs->type_info->kind == TYPE_ISIZE ||
- lhs->type_info->kind == TYPE_USIZE ||
- (t1 && (strcmp(t1, "int") == 0 || strcmp(t1, "isize") == 0 ||
- strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 ||
- strcmp(t1, "ptrdiff_t") == 0)));
- int rhs_is_int =
- (rhs->type_info->kind == TYPE_INT || rhs->type_info->kind == TYPE_I32 ||
- rhs->type_info->kind == TYPE_I64 ||
- rhs->type_info->kind == TYPE_ISIZE ||
- rhs->type_info->kind == TYPE_USIZE ||
- (t2 && (strcmp(t2, "int") == 0 || strcmp(t2, "isize") == 0 ||
- strcmp(t2, "usize") == 0 || strcmp(t2, "size_t") == 0 ||
- strcmp(t2, "ptrdiff_t") == 0)));
-
- if ((lhs_is_ptr && rhs_is_int) || (lhs_is_int && rhs_is_ptr))
+ if (!alias_match)
+ {
+ if (strcmp(bin->binary.op, "+") == 0 || strcmp(bin->binary.op, "-") == 0)
{
- is_ptr_arith = 1;
- bin->type_info = lhs_is_ptr ? lhs->type_info : rhs->type_info;
+ int lhs_is_ptr = (lhs->type_info->kind == TYPE_POINTER ||
+ lhs->type_info->kind == TYPE_STRING ||
+ (t1 && strstr(t1, "*") != NULL));
+ int rhs_is_ptr = (rhs->type_info->kind == TYPE_POINTER ||
+ rhs->type_info->kind == TYPE_STRING ||
+ (t2 && strstr(t2, "*") != NULL));
+ int lhs_is_int =
+ (lhs->type_info->kind == TYPE_INT ||
+ lhs->type_info->kind == TYPE_I32 ||
+ lhs->type_info->kind == TYPE_I64 ||
+ lhs->type_info->kind == TYPE_ISIZE ||
+ lhs->type_info->kind == TYPE_USIZE ||
+ (t1 && (strcmp(t1, "int") == 0 || strcmp(t1, "isize") == 0 ||
+ strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 ||
+ strcmp(t1, "ptrdiff_t") == 0)));
+ int rhs_is_int =
+ (rhs->type_info->kind == TYPE_INT ||
+ rhs->type_info->kind == TYPE_I32 ||
+ rhs->type_info->kind == TYPE_I64 ||
+ rhs->type_info->kind == TYPE_ISIZE ||
+ rhs->type_info->kind == TYPE_USIZE ||
+ (t2 && (strcmp(t2, "int") == 0 || strcmp(t2, "isize") == 0 ||
+ strcmp(t2, "usize") == 0 || strcmp(t2, "size_t") == 0 ||
+ strcmp(t2, "ptrdiff_t") == 0)));
+
+ if ((lhs_is_ptr && rhs_is_int) || (lhs_is_int && rhs_is_ptr))
+ {
+ is_ptr_arith = 1;
+ bin->type_info = lhs_is_ptr ? lhs->type_info : rhs->type_info;
+ }
}
}
- if (!is_ptr_arith)
+ if (!is_ptr_arith && !alias_match)
{
char msg[256];
sprintf(msg, "Type mismatch in binary operation '%s'", bin->binary.op);
diff --git a/tests/features/test_alias.zc b/tests/features/test_alias.zc
index ec84947..7b0eaa4 100644
--- a/tests/features/test_alias.zc
+++ b/tests/features/test_alias.zc
@@ -23,6 +23,15 @@ struct Vec2<T> {
y: T;
}
+impl Vec2<T> {
+ fn neg(self) -> Vec2<T> {
+ return Vec2<T>{x: -self.x, y: -self.y};
+ }
+ fn add(self, rhs: Vec2<T>) -> Vec2<T> {
+ return Vec2<T>{x: self.x + rhs.x, y: self.y + rhs.y};
+ }
+}
+
alias Vec2f = Vec2<f32>;
alias Vec2i = Vec2<int>;
@@ -67,3 +76,19 @@ test "alias function pointer" {
// op = add;
// assert(op(1, 2) == 3, "Function alias");
}
+
+test "alias operator overloading" {
+ var v = Vec2f{x: 1.0, y: 1.0};
+ v = -v; // Should call __neg
+ assert(v.x == -1.0, "Unary operator generic alias failed");
+
+ v += v; // Should call __add (-1 + -1 = -2)
+ assert(v.x == -2.0, "Compound assignment generic alias failed");
+
+ // Control
+ var v2 = Vec2<f32>{x: 1.0, y: 1.0};
+ v2 = -v2;
+ v2 += v2;
+ assert(v2.x == -2.0, "Control generic operator overloading failed");
+}
+