summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-21 22:50:20 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-21 22:50:31 +0000
commit260f01af1d3c19827d175740e30da57a288a6e86 (patch)
treee81e36c0297c22eefa6988c0306ea87211d78314 /src/parser
parenta552bd6b8175fe833e8a77dfb051bf3481df6851 (diff)
Fix for #74
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser_expr.c123
-rw-r--r--src/parser/parser_stmt.c56
-rw-r--r--src/parser/parser_type.c34
-rw-r--r--src/parser/parser_utils.c560
4 files changed, 585 insertions, 188 deletions
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index 2d0e10b..ff931f5 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -1542,15 +1542,46 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
Lexer lookahead = *l;
lexer_next(&lookahead);
- parse_type(ctx, &lookahead);
- if (lexer_peek(&lookahead).type == TOK_RANGLE)
+
+ int valid_generic = 0;
+ 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;
+ }
+
+ if (valid_generic)
{
- lexer_next(l);
- Type *formal_type = parse_type_formal(ctx, l);
- char *concrete_type = type_to_string(formal_type); // mangled for naming
- char *unmangled_type =
- type_to_c_string(formal_type); // C-compatible for substitution
- lexer_next(l);
+ lexer_next(l); // eat <
+
+ char **concrete_types = xmalloc(sizeof(char *) * 8);
+ char **unmangled_types = xmalloc(sizeof(char *) * 8);
+ int arg_count = 0;
+
+ while (1)
+ {
+ Type *formal_type = parse_type_formal(ctx, l);
+ concrete_types[arg_count] = type_to_string(formal_type);
+ unmangled_types[arg_count] = type_to_c_string(formal_type);
+ arg_count++;
+
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+ break;
+ }
+ lexer_next(l); // eat >
int is_struct = 0;
GenericTemplate *st = ctx->templates;
@@ -1570,21 +1601,67 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
if (is_struct)
{
- instantiate_generic(ctx, acc, concrete_type, unmangled_type, t);
-
- char *clean_type = sanitize_mangled_name(concrete_type);
-
- char *m = xmalloc(strlen(acc) + strlen(clean_type) + 2);
- sprintf(m, "%s_%s", acc, clean_type);
- free(clean_type);
+ char mangled[256];
+ strcpy(mangled, acc);
+ int is_generic_dep = 0;
+ for (int i = 0; i < arg_count; ++i)
+ {
+ for (int k = 0; k < ctx->known_generics_count; ++k)
+ {
+ if (strcmp(concrete_types[i], ctx->known_generics[k]) == 0)
+ {
+ is_generic_dep = 1;
+ break;
+ }
+ }
+ char *clean = sanitize_mangled_name(concrete_types[i]);
+ strcat(mangled, "_");
+ strcat(mangled, clean);
+ free(clean);
+ }
- free(acc);
- acc = m;
+ if (arg_count == 1)
+ {
+ // Single-arg: only instantiate if not generic dependent
+ if (!is_generic_dep)
+ {
+ instantiate_generic(ctx, acc, concrete_types[0], unmangled_types[0],
+ t);
+ }
+ free(acc);
+ acc = xstrdup(mangled);
+ }
+ else
+ {
+ // Multi-arg struct instantiation
+ if (!is_generic_dep)
+ {
+ instantiate_generic_multi(ctx, acc, concrete_types, arg_count, t);
+ }
+ free(acc);
+ acc = xstrdup(mangled);
+ }
}
else
{
+ // Function Template
+ // Join types with comma
+ char full_concrete[1024] = {0};
+ char full_unmangled[1024] = {0};
+
+ for (int i = 0; i < arg_count; ++i)
+ {
+ if (i > 0)
+ {
+ strcat(full_concrete, ",");
+ strcat(full_unmangled, ",");
+ }
+ strcat(full_concrete, concrete_types[i]);
+ strcat(full_unmangled, unmangled_types[i]);
+ }
+
char *m =
- instantiate_function_template(ctx, acc, concrete_type, unmangled_type);
+ instantiate_function_template(ctx, acc, full_concrete, full_unmangled);
if (m)
{
free(acc);
@@ -1595,6 +1672,16 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
zpanic_at(t, "Unknown generic %s", acc);
}
}
+
+ // Cleanup
+ for (int i = 0; i < arg_count; ++i)
+ {
+ free(concrete_types[i]);
+ free(unmangled_types[i]);
+ }
+ free(concrete_types);
+ free(unmangled_types);
+
changed = 1;
}
}
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 6e55d08..67045ea 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -51,13 +51,59 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
char *gen_param = NULL;
if (lexer_peek(l).type == TOK_LANGLE)
{
- lexer_next(l);
- Token gt = lexer_next(l);
- gen_param = token_strdup(gt);
+ lexer_next(l); // eat <
+
+ char buf[1024];
+ buf[0] = 0;
+
+ while (1)
+ {
+ Token gt = lexer_next(l);
+ if (gt.type != TOK_IDENT)
+ {
+ zpanic_at(gt, "Expected generic parameter name");
+ }
+ char *s = token_strdup(gt);
+
+ if (strlen(buf) + strlen(s) + 2 >= sizeof(buf))
+ {
+ zpanic_at(gt, "Too many generic parameters");
+ }
+
+ if (buf[0])
+ {
+ strcat(buf, ",");
+ }
+ strcat(buf, s);
+ free(s);
+
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ continue;
+ }
+ break;
+ }
+
if (lexer_next(l).type != TOK_RANGLE)
{
zpanic_at(lexer_peek(l), "Expected >");
}
+ gen_param = xstrdup(buf);
+ }
+
+ // Register generic parameters so type parsing recognizes them
+ int saved_generic_count = ctx->known_generics_count;
+ if (gen_param)
+ {
+ char *tmp = xstrdup(gen_param);
+ char *tok = strtok(tmp, ",");
+ while (tok)
+ {
+ register_generic(ctx, tok);
+ tok = strtok(NULL, ",");
+ }
+ free(tmp);
}
enter_scope(ctx);
@@ -138,6 +184,10 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
}
exit_scope(ctx);
+
+ // Restore generic count to unregister function-scoped generics
+ ctx->known_generics_count = saved_generic_count;
+
curr_func_ret = NULL;
ASTNode *node = ast_create(NODE_FUNCTION);
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index 3d5bff8..4e44c00 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -443,7 +443,23 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
// Call multi-arg instantiation
- instantiate_generic_multi(ctx, name, args, arg_count, t);
+ int is_generic_dep = 0;
+ for (int i = 0; i < arg_count; ++i)
+ {
+ for (int k = 0; k < ctx->known_generics_count; ++k)
+ {
+ if (strcmp(args[i], ctx->known_generics[k]) == 0)
+ {
+ is_generic_dep = 1;
+ break;
+ }
+ }
+ }
+
+ if (!is_generic_dep)
+ {
+ instantiate_generic_multi(ctx, name, args, arg_count, t);
+ }
// Build mangled name
char mangled[256];
@@ -481,7 +497,21 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
char *unmangled_arg = type_to_c_string(first_arg);
- instantiate_generic(ctx, name, first_arg_str, unmangled_arg, t);
+
+ int is_single_dep = 0;
+ for (int k = 0; k < ctx->known_generics_count; ++k)
+ {
+ if (strcmp(first_arg_str, ctx->known_generics[k]) == 0)
+ {
+ is_single_dep = 1;
+ break;
+ }
+ }
+
+ if (!is_single_dep)
+ {
+ instantiate_generic(ctx, name, first_arg_str, unmangled_arg, t);
+ }
free(unmangled_arg);
char *clean_arg = sanitize_mangled_name(first_arg_str);
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index afd6f33..f1345ba 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -858,6 +858,57 @@ char *replace_in_string(const char *src, const char *old_w, const char *new_w)
return src ? xstrdup(src) : NULL;
}
+ // Check for multiple parameters (comma separated)
+ if (strchr(old_w, ','))
+ {
+ char *running_src = xstrdup(src);
+
+ char *p_ptr = (char *)old_w;
+ char *c_ptr = (char *)new_w;
+
+ while (*p_ptr && *c_ptr)
+ {
+ char *p_end = strchr(p_ptr, ',');
+ int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+
+ char *c_end = strchr(c_ptr, ',');
+ int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
+
+ char *curr_p = xmalloc(p_len + 1);
+ strncpy(curr_p, p_ptr, p_len);
+ curr_p[p_len] = 0;
+
+ char *curr_c = xmalloc(c_len + 1);
+ strncpy(curr_c, c_ptr, c_len);
+ curr_c[c_len] = 0;
+
+ char *next_src = replace_in_string(running_src, curr_p, curr_c);
+ free(running_src);
+ running_src = next_src;
+
+ free(curr_p);
+ free(curr_c);
+
+ if (p_end)
+ {
+ p_ptr = p_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ if (c_end)
+ {
+ c_ptr = c_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return running_src;
+ }
+
char *result;
int i, cnt = 0;
int newWlen = strlen(new_w);
@@ -940,8 +991,50 @@ char *replace_type_str(const char *src, const char *param, const char *concrete,
return NULL;
}
- if (strcmp(src, param) == 0)
+ // Handle multi-param match
+ if (param && concrete && strchr(param, ','))
+ {
+ char *p_ptr = (char *)param;
+ char *c_ptr = (char *)concrete;
+
+ while (*p_ptr && *c_ptr)
+ {
+ char *p_end = strchr(p_ptr, ',');
+ int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+
+ char *c_end = strchr(c_ptr, ',');
+ int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
+
+ if (strlen(src) == p_len && strncmp(src, p_ptr, p_len) == 0)
+ {
+ char *ret = xmalloc(c_len + 1);
+ strncpy(ret, c_ptr, c_len);
+ ret[c_len] = 0;
+ return ret;
+ }
+
+ if (p_end)
+ {
+ p_ptr = p_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ if (c_end)
+ {
+ c_ptr = c_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if (param && strcmp(src, param) == 0)
{
+
return xstrdup(concrete);
}
@@ -964,21 +1057,46 @@ char *replace_type_str(const char *src, const char *param, const char *concrete,
if (param && concrete && src)
{
- char suffix[256];
- sprintf(suffix, "_%s", param);
+ // Construct mangled suffix from param ("F,S" -> "_F_S")
+ char p_suffix[1024];
+ p_suffix[0] = 0;
+
+ char *p_temp = xstrdup(param);
+ char *tok = strtok(p_temp, ",");
+ while (tok)
+ {
+ strcat(p_suffix, "_");
+ strcat(p_suffix, tok);
+ tok = strtok(NULL, ",");
+ }
+ free(p_temp);
+
size_t slen = strlen(src);
- size_t plen = strlen(suffix);
- if (slen > plen && strcmp(src + slen - plen, suffix) == 0)
+ size_t plen = strlen(p_suffix);
+
+ if (slen >= plen && strcmp(src + slen - plen, p_suffix) == 0)
{
- // Ends with _T -> Replace suffix with _int (sanitize for pointers like
- // JsonValue*)
- char *clean_concrete = sanitize_mangled_name(concrete);
- char *ret = xmalloc(slen - plen + strlen(clean_concrete) + 2);
+ // Construct replacement suffix from concrete ("int,float" -> "_int_float")
+ char c_suffix[1024];
+ c_suffix[0] = 0;
+
+ char *c_temp = xstrdup(concrete);
+ tok = strtok(c_temp, ",");
+ while (tok)
+ {
+ strcat(c_suffix, "_");
+ char *clean = sanitize_mangled_name(tok);
+ strcat(c_suffix, clean);
+ free(clean);
+ tok = strtok(NULL, ",");
+ }
+ free(c_temp);
+
+ // Perform replacement
+ char *ret = xmalloc(slen - plen + strlen(c_suffix) + 1);
strncpy(ret, src, slen - plen);
ret[slen - plen] = 0;
- strcat(ret, "_");
- strcat(ret, clean_concrete);
- free(clean_concrete);
+ strcat(ret, c_suffix);
return ret;
}
}
@@ -1025,6 +1143,111 @@ char *replace_type_str(const char *src, const char *param, const char *concrete,
ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char *os,
const char *ns);
+// Helper to create type from string (primitives or struct)
+Type *type_from_string_helper(const char *c)
+{
+ if (strcmp(c, "int") == 0)
+ {
+ return type_new(TYPE_INT);
+ }
+ if (strcmp(c, "float") == 0)
+ {
+ return type_new(TYPE_FLOAT);
+ }
+ if (strcmp(c, "void") == 0)
+ {
+ return type_new(TYPE_VOID);
+ }
+ if (strcmp(c, "string") == 0)
+ {
+ return type_new(TYPE_STRING);
+ }
+ if (strcmp(c, "bool") == 0)
+ {
+ return type_new(TYPE_BOOL);
+ }
+ if (strcmp(c, "char") == 0)
+ {
+ return type_new(TYPE_CHAR);
+ }
+ if (strcmp(c, "I8") == 0 || strcmp(c, "i8") == 0)
+ {
+ return type_new(TYPE_I8);
+ }
+ if (strcmp(c, "U8") == 0 || strcmp(c, "u8") == 0)
+ {
+ return type_new(TYPE_U8);
+ }
+ if (strcmp(c, "I16") == 0 || strcmp(c, "i16") == 0)
+ {
+ return type_new(TYPE_I16);
+ }
+ if (strcmp(c, "U16") == 0 || strcmp(c, "u16") == 0)
+ {
+ return type_new(TYPE_U16);
+ }
+ if (strcmp(c, "I32") == 0 || strcmp(c, "i32") == 0 || strcmp(c, "int32_t") == 0)
+ {
+ return type_new(TYPE_I32);
+ }
+ if (strcmp(c, "U32") == 0 || strcmp(c, "u32") == 0 || strcmp(c, "uint32_t") == 0)
+ {
+ return type_new(TYPE_U32);
+ }
+ if (strcmp(c, "I64") == 0 || strcmp(c, "i64") == 0 || strcmp(c, "int64_t") == 0)
+ {
+ return type_new(TYPE_I64);
+ }
+ if (strcmp(c, "U64") == 0 || strcmp(c, "u64") == 0 || strcmp(c, "uint64_t") == 0)
+ {
+ return type_new(TYPE_U64);
+ }
+ if (strcmp(c, "float") == 0 || strcmp(c, "f32") == 0)
+ {
+ return type_new(TYPE_F32);
+ }
+ if (strcmp(c, "double") == 0 || strcmp(c, "f64") == 0)
+ {
+ return type_new(TYPE_F64);
+ }
+ if (strcmp(c, "I128") == 0 || strcmp(c, "i128") == 0)
+ {
+ return type_new(TYPE_I128);
+ }
+ if (strcmp(c, "U128") == 0 || strcmp(c, "u128") == 0)
+ {
+ return type_new(TYPE_U128);
+ }
+ if (strcmp(c, "rune") == 0)
+ {
+ return type_new(TYPE_RUNE);
+ }
+ if (strcmp(c, "uint") == 0)
+ {
+ return type_new(TYPE_UINT);
+ }
+ if (strcmp(c, "double") == 0)
+ {
+ return type_new(TYPE_F64);
+ }
+ if (strcmp(c, "byte") == 0)
+ {
+ return type_new(TYPE_BYTE);
+ }
+ if (strcmp(c, "usize") == 0)
+ {
+ return type_new(TYPE_USIZE);
+ }
+ if (strcmp(c, "isize") == 0)
+ {
+ return type_new(TYPE_ISIZE);
+ }
+
+ Type *n = type_new(TYPE_STRUCT);
+ n->name = sanitize_mangled_name(c);
+ return n;
+}
+
Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os, const char *ns)
{
if (!t)
@@ -1032,155 +1255,54 @@ Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os,
return NULL;
}
- if ((t->kind == TYPE_STRUCT || t->kind == TYPE_GENERIC) && t->name && strcmp(t->name, p) == 0)
+ // Exact Match Logic (with multi-param splitting)
+ if ((t->kind == TYPE_STRUCT || t->kind == TYPE_GENERIC) && t->name)
{
- if (strcmp(c, "int") == 0)
- {
- return type_new(TYPE_INT);
- }
- if (strcmp(c, "float") == 0)
- {
- return type_new(TYPE_FLOAT);
- }
- if (strcmp(c, "void") == 0)
- {
- return type_new(TYPE_VOID);
- }
- if (strcmp(c, "string") == 0)
- {
- return type_new(TYPE_STRING);
- }
- if (strcmp(c, "bool") == 0)
- {
- return type_new(TYPE_BOOL);
- }
- if (strcmp(c, "char") == 0)
- {
- return type_new(TYPE_CHAR);
- }
- if (strcmp(c, "I8") == 0)
- {
- return type_new(TYPE_I8);
- }
- if (strcmp(c, "U8") == 0)
- {
- return type_new(TYPE_U8);
- }
- if (strcmp(c, "I16") == 0)
- {
- return type_new(TYPE_I16);
- }
- if (strcmp(c, "U16") == 0)
- {
- return type_new(TYPE_U16);
- }
- if (strcmp(c, "I32") == 0)
- {
- return type_new(TYPE_I32);
- }
- if (strcmp(c, "U32") == 0)
- {
- return type_new(TYPE_U32);
- }
- if (strcmp(c, "I64") == 0)
- {
- return type_new(TYPE_I64);
- }
- if (strcmp(c, "U64") == 0)
- {
- return type_new(TYPE_U64);
- }
- if (strcmp(c, "F32") == 0)
- {
- return type_new(TYPE_F32);
- }
- if (strcmp(c, "f32") == 0)
+ if (p && c && strchr(p, ','))
{
- return type_new(TYPE_F32);
- }
- if (strcmp(c, "F64") == 0)
- {
- return type_new(TYPE_F64);
- }
- if (strcmp(c, "f64") == 0)
- {
- return type_new(TYPE_F64);
- }
+ char *p_ptr = (char *)p;
+ char *c_ptr = (char *)c;
+ while (*p_ptr && *c_ptr)
+ {
+ char *p_end = strchr(p_ptr, ',');
+ int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+ char *c_end = strchr(c_ptr, ',');
+ int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
- if (strcmp(c, "usize") == 0)
- {
- return type_new(TYPE_USIZE);
- }
- if (strcmp(c, "isize") == 0)
- {
- return type_new(TYPE_ISIZE);
- }
- if (strcmp(c, "byte") == 0)
- {
- return type_new(TYPE_BYTE);
- }
- if (strcmp(c, "I128") == 0)
- {
- return type_new(TYPE_I128);
- }
- if (strcmp(c, "U128") == 0)
- {
- return type_new(TYPE_U128);
- }
- if (strcmp(c, "i8") == 0)
- {
- return type_new(TYPE_I8);
- }
- if (strcmp(c, "u8") == 0)
- {
- return type_new(TYPE_U8);
- }
- if (strcmp(c, "i16") == 0)
- {
- return type_new(TYPE_I16);
- }
- if (strcmp(c, "u16") == 0)
- {
- return type_new(TYPE_U16);
- }
- if (strcmp(c, "i32") == 0)
- {
- return type_new(TYPE_I32);
- }
- if (strcmp(c, "u32") == 0)
- {
- return type_new(TYPE_U32);
- }
- if (strcmp(c, "i64") == 0)
- {
- return type_new(TYPE_I64);
- }
- if (strcmp(c, "u64") == 0)
- {
- return type_new(TYPE_U64);
- }
- if (strcmp(c, "i128") == 0)
- {
- return type_new(TYPE_I128);
- }
- if (strcmp(c, "u128") == 0)
- {
- return type_new(TYPE_U128);
- }
+ if (strlen(t->name) == p_len && strncmp(t->name, p_ptr, p_len) == 0)
+ {
+ char *c_part = xmalloc(c_len + 1);
+ strncpy(c_part, c_ptr, c_len);
+ c_part[c_len] = 0;
- if (strcmp(c, "rune") == 0)
- {
- return type_new(TYPE_RUNE);
+ Type *res = type_from_string_helper(c_part);
+ free(c_part);
+ return res;
+ }
+ if (p_end)
+ {
+ p_ptr = p_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ if (c_end)
+ {
+ c_ptr = c_end + 1;
+ }
+ else
+ {
+ break;
+ }
+ }
}
- if (strcmp(c, "uint") == 0)
+ else if (strcmp(t->name, p) == 0)
{
- return type_new(TYPE_UINT);
- }
- Type *n = type_new(TYPE_STRUCT);
- n->name = sanitize_mangled_name(c);
- return n;
+ return type_from_string_helper(c);
+ }
}
Type *n = xmalloc(sizeof(Type));
@@ -1195,26 +1317,46 @@ Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os,
n->arg_count = 0;
n->args = NULL;
}
-
else if (p && c)
{
- char suffix[256];
- sprintf(suffix, "_%s", p); // e.g. "_T"
+ // Suffix Match Logic (with multi-param splitting)
+ char p_suffix[1024];
+ p_suffix[0] = 0;
+
+ char *p_temp = xstrdup(p);
+ char *tok = strtok(p_temp, ",");
+ while (tok)
+ {
+ strcat(p_suffix, "_");
+ strcat(p_suffix, tok);
+ tok = strtok(NULL, ",");
+ }
+ free(p_temp);
+
size_t nlen = strlen(t->name);
- size_t slen = strlen(suffix);
+ size_t slen = strlen(p_suffix);
- if (nlen > slen && strcmp(t->name + nlen - slen, suffix) == 0)
+ if (nlen >= slen && strcmp(t->name + nlen - slen, p_suffix) == 0)
{
- // It ends in _T. Replace with _int (c), sanitizing for pointers
- char *clean_c = sanitize_mangled_name(c);
- char *new_name = xmalloc(nlen - slen + strlen(clean_c) + 2);
+ char c_suffix[1024];
+ c_suffix[0] = 0;
+ char *c_temp = xstrdup(c);
+ tok = strtok(c_temp, ",");
+ while (tok)
+ {
+ strcat(c_suffix, "_");
+ char *clean = sanitize_mangled_name(tok);
+ strcat(c_suffix, clean);
+ free(clean);
+ tok = strtok(NULL, ",");
+ }
+ free(c_temp);
+
+ char *new_name = xmalloc(nlen - slen + strlen(c_suffix) + 1);
strncpy(new_name, t->name, nlen - slen);
new_name[nlen - slen] = 0;
- strcat(new_name, "_");
- strcat(new_name, clean_c);
- free(clean_c);
+ strcat(new_name, c_suffix);
n->name = new_name;
- // Ensure it's concrete to prevent double mangling later
n->kind = TYPE_STRUCT;
n->arg_count = 0;
n->args = NULL;
@@ -1622,6 +1764,92 @@ char *instantiate_function_template(ParserContext *ctx, const char *name, const
}
const char *subst_arg = unmangled_type ? unmangled_type : concrete_type;
+
+ // Scan the original return type for generic struct patterns like "Triple_X_Y_Z"
+ // and instantiate them with the concrete types
+ if (tpl->func_node && tpl->func_node->func.ret_type)
+ {
+ const char *ret = tpl->func_node->func.ret_type;
+
+ // Build the param suffix (e.g., for "X,Y,Z" -> "_X_Y_Z")
+ char param_suffix[256];
+ param_suffix[0] = 0;
+ char *tmp = xstrdup(tpl->generic_param);
+ char *tokp = strtok(tmp, ",");
+ while (tokp)
+ {
+ strcat(param_suffix, "_");
+ strcat(param_suffix, tokp);
+ tokp = strtok(NULL, ",");
+ }
+ free(tmp);
+
+ // Check if ret_type ends with param_suffix (e.g., "Triple_X_Y_Z" ends with "_X_Y_Z")
+ size_t ret_len = strlen(ret);
+ size_t suffix_len = strlen(param_suffix);
+ if (ret_len > suffix_len && strcmp(ret + ret_len - suffix_len, param_suffix) == 0)
+ {
+ // Extract base struct name (e.g., "Triple" from "Triple_X_Y_Z")
+ size_t base_len = ret_len - suffix_len;
+ char *struct_base = xmalloc(base_len + 1);
+ strncpy(struct_base, ret, base_len);
+ struct_base[base_len] = 0;
+
+ // Check if it's a known generic template
+ GenericTemplate *gt = ctx->templates;
+ while (gt && strcmp(gt->name, struct_base) != 0)
+ {
+ gt = gt->next;
+ }
+ if (gt)
+ {
+ // Parse the concrete types from unmangled_type or concrete_type
+ const char *types_src = unmangled_type ? unmangled_type : concrete_type;
+
+ // Count params in template
+ int template_param_count = 1;
+ for (const char *p = tpl->generic_param; *p; p++)
+ {
+ if (*p == ',')
+ {
+ template_param_count++;
+ }
+ }
+
+ // Split concrete types
+ char **args = xmalloc(sizeof(char *) * template_param_count);
+ int arg_count = 0;
+ char *types_copy = xstrdup(types_src);
+ char *tok = strtok(types_copy, ",");
+ while (tok && arg_count < template_param_count)
+ {
+ args[arg_count++] = xstrdup(tok);
+ tok = strtok(NULL, ",");
+ }
+ free(types_copy);
+
+ // Now instantiate the struct with these args
+ Token dummy_tok = {0};
+ if (arg_count == 1)
+ {
+ instantiate_generic(ctx, struct_base, args[0], args[0], dummy_tok);
+ }
+ else if (arg_count > 1)
+ {
+ instantiate_generic_multi(ctx, struct_base, args, arg_count, dummy_tok);
+ }
+
+ // Cleanup
+ for (int i = 0; i < arg_count; i++)
+ {
+ free(args[i]);
+ }
+ free(args);
+ }
+ free(struct_base);
+ }
+ }
+
ASTNode *new_fn = copy_ast_replacing(tpl->func_node, tpl->generic_param, subst_arg, NULL, NULL);
if (!new_fn || new_fn->type != NODE_FUNCTION)
{
@@ -2157,12 +2385,14 @@ void instantiate_generic_multi(ParserContext *ctx, const char *tpl, char **args,
if (param_count > 0 && arg_count > 0)
{
// First substitution
+
i->strct.fields = copy_fields_replacing(
ctx, fields, t->struct_node->strct.generic_params[0], args[0]);
// Subsequent substitutions (for params B, C, etc.)
for (int j = 1; j < param_count && j < arg_count; j++)
{
+
ASTNode *tmp = copy_fields_replacing(
ctx, i->strct.fields, t->struct_node->strct.generic_params[j], args[j]);
// This leaks prev fields, but that's acceptable for now, still, TODO.