summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-24 01:39:38 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-24 01:39:52 +0000
commit3df7cada4c3d050a01980afffdbfc0fc60be0fb5 (patch)
treeaa1dd603039d284f58b62c89bb662fd74c19deda
parent769d8ff1a1fd898e1a8c8b299f7e7fa444f32528 (diff)
Fix for #106
-rw-r--r--src/parser/parser_expr.c40
-rw-r--r--src/parser/parser_type.c3
-rw-r--r--src/parser/parser_utils.c60
-rw-r--r--tests/generics/test_sizeof_template.zc40
4 files changed, 102 insertions, 41 deletions
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index c848072..1556ee7 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -3623,44 +3623,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
else if (is_token(t, "sizeof"))
{
- lexer_next(l);
- if (lexer_peek(l).type == TOK_LPAREN)
- {
- const char *start = l->src + l->pos;
- int depth = 0;
- while (1)
- {
- Token tk = lexer_peek(l);
- if (tk.type == TOK_EOF)
- {
- zpanic_at(tk, "Unterminated sizeof");
- }
- if (tk.type == TOK_LPAREN)
- {
- depth++;
- }
- if (tk.type == TOK_RPAREN)
- {
- depth--;
- if (depth == 0)
- {
- lexer_next(l);
- break;
- }
- }
- lexer_next(l);
- }
- int len = (l->src + l->pos) - start;
- char *content = xmalloc(len + 8);
- sprintf(content, "sizeof%.*s", len, start);
- lhs = ast_create(NODE_RAW_STMT);
- lhs->raw_stmt.content = content;
- lhs->type_info = type_new(TYPE_INT);
- }
- else
- {
- zpanic_at(lexer_peek(l), "sizeof must be followed by (");
- }
+ lexer_next(l); // consume sizeof
+ lhs = parse_sizeof_expr(ctx, l);
}
else
{
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index 39a4dc7..5774571 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -483,7 +483,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
ty->is_explicit_struct = explicit_struct;
// Handle Generics <T> or <K, V>
- if (lexer_peek(l).type == TOK_LANGLE)
+ if (lexer_peek(l).type == TOK_LANGLE ||
+ (lexer_peek(l).type == TOK_OP && strncmp(lexer_peek(l).start, "<", 1) == 0))
{
lexer_next(l); // eat <
Type *first_arg = parse_type_formal(ctx, l);
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 0b47d2a..05ea74a 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1713,6 +1713,48 @@ ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char
replace_type_str(n->impl_trait.target_type, p, c, os, ns);
new_node->impl_trait.methods = copy_ast_replacing(n->impl_trait.methods, p, c, os, ns);
break;
+ case NODE_EXPR_SIZEOF:
+ if (n->size_of.target_type)
+ {
+ char *replaced = replace_type_str(n->size_of.target_type, p, c, os, ns);
+ if (replaced && strchr(replaced, '<'))
+ {
+ char *src = replaced;
+ char *mangled = xmalloc(strlen(src) * 2 + 1);
+ char *dst = mangled;
+ while (*src)
+ {
+ if (*src == '<' || *src == ',')
+ {
+ *dst++ = '_';
+ while (*(src + 1) == ' ')
+ {
+ src++; // skip space
+ }
+ }
+ else if (*src == '>')
+ {
+ // skip
+ }
+ else if (*src == '*')
+ {
+ strcpy(dst, "Ptr");
+ dst += 3;
+ }
+ else if (!isspace(*src))
+ {
+ *dst++ = *src;
+ }
+ src++;
+ }
+ *dst = 0;
+ free(replaced);
+ replaced = mangled;
+ }
+ new_node->size_of.target_type = replaced;
+ }
+ new_node->size_of.expr = copy_ast_replacing(n->size_of.expr, p, c, os, ns);
+ break;
default:
break;
}
@@ -2408,8 +2450,13 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg,
i->type_info->traits = t->struct_node->type_info->traits;
i->type_info->is_restrict = t->struct_node->type_info->is_restrict;
}
-
- // Use first generic param for substitution (single-param backward compat)
+ i->strct.is_packed = t->struct_node->strct.is_packed;
+ i->strct.is_union = t->struct_node->strct.is_union;
+ i->strct.align = t->struct_node->strct.align;
+ if (t->struct_node->strct.parent)
+ {
+ i->strct.parent = xstrdup(t->struct_node->strct.parent);
+ }
const char *gp = (t->struct_node->strct.generic_param_count > 0)
? t->struct_node->strct.generic_params[0]
: "T";
@@ -2535,6 +2582,15 @@ void instantiate_generic_multi(ParserContext *ctx, const char *tpl, char **args,
i->strct.name = xstrdup(m);
i->strct.is_template = 0;
+ // Copy struct attributes
+ i->strct.is_packed = t->struct_node->strct.is_packed;
+ i->strct.is_union = t->struct_node->strct.is_union;
+ i->strct.align = t->struct_node->strct.align;
+ if (t->struct_node->strct.parent)
+ {
+ i->strct.parent = xstrdup(t->struct_node->strct.parent);
+ }
+
// Copy fields with sequential substitutions for each param
ASTNode *fields = t->struct_node->strct.fields;
int param_count = t->struct_node->strct.generic_param_count;
diff --git a/tests/generics/test_sizeof_template.zc b/tests/generics/test_sizeof_template.zc
new file mode 100644
index 0000000..8390512
--- /dev/null
+++ b/tests/generics/test_sizeof_template.zc
@@ -0,0 +1,40 @@
+struct Struct<T> {
+ val: T;
+}
+
+fn hello<T>() {
+ var s = sizeof(Struct<T>);
+ println "size: {s}";
+}
+
+test "sizeof template" {
+ var _first: Struct<i32>;
+ hello<i32>();
+ var _second: Struct<f64>;
+ hello<f64>();
+}
+
+struct Mixed<T> {
+ val: T;
+ flag: u8;
+}
+
+test "sizeof mixed" {
+ var s1 = sizeof(Mixed<i32>);
+ println "i32 mixed: {s1}";
+ var s2 = sizeof(Mixed<f64>);
+ println "f64 mixed: {s2}";
+}
+
+@packed
+struct PackedMixed<T> {
+ val: T;
+ flag: u8;
+}
+
+test "sizeof packed mixed" {
+ var s1 = sizeof(PackedMixed<i32>);
+ println "i32 packed mixed: {s1}";
+ var s2 = sizeof(PackedMixed<f64>);
+ println "f64 packed mixed: {s2}";
+} \ No newline at end of file