summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast/ast.h5
-rw-r--r--src/codegen/codegen_decl.c10
-rw-r--r--src/codegen/codegen_stmt.c2
-rw-r--r--src/parser/parser_decl.c8
-rw-r--r--src/parser/parser_expr.c135
-rw-r--r--src/parser/parser_struct.c52
-rw-r--r--src/parser/parser_utils.c1
-rw-r--r--std/fs.zc8
-rw-r--r--tests/generics/test_generics_fn.zc14
9 files changed, 214 insertions, 21 deletions
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 523c1fb..6ef5d7a 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -160,8 +160,9 @@ struct ASTNode
struct
{
char *name;
- char *args; // Legacy string args.
- char *ret_type; // Legacy string return type.
+ char *generic_params; // <T, U>
+ char *args; // Legacy string args.
+ char *ret_type; // Legacy string return type.
ASTNode *body;
Type **arg_types;
char **defaults;
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 109aa9a..18d81f5 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -732,6 +732,11 @@ void emit_protos(ASTNode *node, FILE *out)
ASTNode *m = f->impl.methods;
while (m)
{
+ if (m->func.generic_params)
+ {
+ m = m->next;
+ continue;
+ }
char *fname = m->func.name;
char *proto = xmalloc(strlen(fname) + strlen(sname) + 2);
int slen = strlen(sname);
@@ -810,6 +815,11 @@ void emit_protos(ASTNode *node, FILE *out)
ASTNode *m = f->impl_trait.methods;
while (m)
{
+ if (m->func.generic_params)
+ {
+ m = m->next;
+ continue;
+ }
if (m->func.is_async)
{
fprintf(out, "Async %s(%s);\n", m->func.name, m->func.args);
diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c
index 983130c..54c6a14 100644
--- a/src/codegen/codegen_stmt.c
+++ b/src/codegen/codegen_stmt.c
@@ -551,7 +551,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, ";\n");
break;
case NODE_FUNCTION:
- if (!node->func.body)
+ if (!node->func.body || node->func.generic_params)
{
break;
}
diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c
index 0cd2990..5cac0b4 100644
--- a/src/parser/parser_decl.c
+++ b/src/parser/parser_decl.c
@@ -187,8 +187,12 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
if (gen_param)
{
- register_func_template(ctx, name, gen_param, node);
- return NULL;
+ node->func.generic_params = xstrdup(gen_param);
+ if (!ctx->current_impl_struct)
+ {
+ register_func_template(ctx, name, gen_param, node);
+ return NULL;
+ }
}
if (!ctx->current_impl_struct)
{
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index 59e3a04..248deb8 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -4397,6 +4397,141 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
node->resolved_type = xstrdup("unknown");
}
+ // Handle Generic Method Call: object.method<T>
+ if (lexer_peek(l).type == TOK_LANGLE)
+ {
+ Lexer lookahead = *l;
+ lexer_next(&lookahead);
+
+ int valid_generic = 0;
+ int saved = ctx->is_speculative;
+ ctx->is_speculative = 1;
+
+ // Speculatively check if it's a valid generic list
+ while (1)
+ {
+ parse_type(ctx, &lookahead);
+ if (lexer_peek(&lookahead).type == TOK_COMMA)
+ {
+ lexer_next(&lookahead);
+ continue;
+ }
+ if (lexer_peek(&lookahead).type == TOK_RANGLE)
+ {
+ valid_generic = 1;
+ }
+ break;
+ }
+ ctx->is_speculative = saved;
+
+ if (valid_generic)
+ {
+ lexer_next(l); // consume <
+
+ char **concrete = xmalloc(sizeof(char *) * 8);
+ char **unmangled = xmalloc(sizeof(char *) * 8);
+ int argc = 0;
+ while (1)
+ {
+ Type *t = parse_type_formal(ctx, l);
+ concrete[argc] = type_to_string(t);
+ unmangled[argc] = type_to_c_string(t);
+ argc++;
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (lexer_next(l).type != TOK_RANGLE)
+ {
+ zpanic_at(lexer_peek(l), "Expected >");
+ }
+
+ // Locate the generic template
+ char *mn = NULL; // method name
+ char full_name[1024];
+
+ // If logic above found a sig, we have a mangled name in node->type_info->name
+ // But for templates, find_func might have failed.
+ // Construct potential template name: Struct__method
+ char *struct_name = NULL;
+ if (lhs->type_info)
+ {
+ if (lhs->type_info->kind == TYPE_STRUCT)
+ {
+ struct_name = lhs->type_info->name;
+ }
+ else if (lhs->type_info->kind == TYPE_POINTER && lhs->type_info->inner &&
+ lhs->type_info->inner->kind == TYPE_STRUCT)
+ {
+ struct_name = lhs->type_info->inner->name;
+ }
+ }
+
+ if (struct_name)
+ {
+ sprintf(full_name, "%s__%s", struct_name, node->member.field);
+
+ // Join types
+ char all_concrete[1024] = {0};
+ char all_unmangled[1024] = {0};
+ for (int i = 0; i < argc; i++)
+ {
+ if (i > 0)
+ {
+ strcat(all_concrete, ",");
+ strcat(all_unmangled, ",");
+ }
+ strcat(all_concrete, concrete[i]);
+ strcat(all_unmangled, unmangled[i]);
+ free(concrete[i]);
+ free(unmangled[i]);
+ }
+ free(concrete);
+ free(unmangled);
+
+ mn = instantiate_function_template(ctx, full_name, all_concrete,
+ all_unmangled);
+ if (mn)
+ {
+ // Ensure member field reflects the instantiated name (suffix only)
+ // The instantiate returns Struct__method_int. We need method_int part?
+ // Actually member access codegen expects .field to be unmangled or
+ // checks lookup. But here we are resolving a specific method instance.
+
+ // AST doesn't support generic member node well, typical approach:
+ // Replace member node with a special "MEMBER_GENERIC" or hack the field
+ // name. Hack: Update field name to include mangle suffix? But codegen
+ // does "Struct__Field". If full_name is Struct__method, mn is
+ // Struct__method_int. Codegen does: struct_name + "__" + field. So if
+ // we set field to "method_int", codegen does Struct__method_int.
+
+ char *p = strstr(mn, "__");
+ if (p)
+ {
+ free(node->member.field);
+ node->member.field = xstrdup(p + 2);
+ }
+
+ // Update Type Info
+ Type *ft = type_new(TYPE_FUNCTION);
+ ft->name = xstrdup(mn);
+ // Look up return type from instantiated func
+ FuncSig *isig = find_func(ctx, mn);
+ if (isig)
+ {
+ ft->inner = isig->ret_type;
+ }
+ node->type_info = ft;
+ }
+ }
+ }
+ }
+
lhs = node;
continue;
}
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
index 01d1156..19bfd47 100644
--- a/src/parser/parser_struct.c
+++ b/src/parser/parser_struct.c
@@ -252,9 +252,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
f->func.args = na;
// Register function for lookup
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types,
- f->func.ret_type_info, f->func.is_varargs, f->func.is_async,
- f->token);
+ if (f->func.generic_params)
+ {
+ register_func_template(ctx, mangled, f->func.generic_params, f);
+ }
+ else
+ {
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
+ f->func.is_async, f->token);
+ }
if (!h)
{
@@ -284,9 +291,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
f->func.args = na;
// Register function for lookup
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
- f->func.is_async, f->token);
+ if (f->func.generic_params)
+ {
+ register_func_template(ctx, mangled, f->func.generic_params, f);
+ }
+ else
+ {
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
+ f->func.is_async, f->token);
+ }
if (!h)
{
@@ -505,9 +519,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
free(f->func.args);
f->func.args = na;
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 0,
- f->token);
+ if (f->func.generic_params)
+ {
+ register_func_template(ctx, mangled, f->func.generic_params, f);
+ }
+ else
+ {
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
+ 0, f->token);
+ }
if (!h)
{
@@ -534,9 +555,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
char *na = patch_self_args(f->func.args, name1);
free(f->func.args);
f->func.args = na;
- register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
- f->func.arg_types, f->func.ret_type_info, f->func.is_varargs,
- 1, f->token);
+ if (f->func.generic_params)
+ {
+ register_func_template(ctx, mangled, f->func.generic_params, f);
+ }
+ else
+ {
+ register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
+ f->func.arg_types, f->func.ret_type_info,
+ f->func.is_varargs, 1, f->token);
+ }
if (!h)
{
h = f;
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index b322881..a11324d 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1980,6 +1980,7 @@ char *instantiate_function_template(ParserContext *ctx, const char *name, const
}
free(new_fn->func.name);
new_fn->func.name = xstrdup(mangled);
+ new_fn->func.generic_params = NULL;
register_func(ctx, mangled, new_fn->func.arg_count, new_fn->func.defaults,
new_fn->func.arg_types, new_fn->func.ret_type_info, new_fn->func.is_varargs, 0,
diff --git a/std/fs.zc b/std/fs.zc
index e16c8ff..0b9c158 100644
--- a/std/fs.zc
+++ b/std/fs.zc
@@ -33,12 +33,12 @@ raw {
return fwrite(ptr, size, nmemb, (FILE*)stream);
}
- int _z_fs_fseek(void* stream, long offset, int whence) {
- return fseek((FILE*)stream, offset, whence);
+ int _z_fs_fseek(void* stream, int64_t offset, int whence) {
+ return fseek((FILE*)stream, (long)offset, whence);
}
- long _z_fs_ftell(void* stream) {
- return ftell((FILE*)stream);
+ int64_t _z_fs_ftell(void* stream) {
+ return (int64_t)ftell((FILE*)stream);
}
int _z_fs_access(char* pathname, int mode) {
diff --git a/tests/generics/test_generics_fn.zc b/tests/generics/test_generics_fn.zc
index ac1cbb5..03f751a 100644
--- a/tests/generics/test_generics_fn.zc
+++ b/tests/generics/test_generics_fn.zc
@@ -23,3 +23,17 @@ test "Generics" {
var b = Box<int> { val: 100 };
assert(b.get() == 100, "Generic impl failed");
}
+
+struct Container { }
+
+impl Container {
+ fn check_size<T>(self, value: T) -> int {
+ return sizeof(value);
+ }
+}
+
+test "Generic Method in Regular Impl" {
+ var c = Container{};
+ assert(c.check_size<int>(10) == sizeof(int), "Generic method int size");
+ assert(c.check_size<double>(3.14) == sizeof(double), "Generic method double size");
+}