diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-16 10:22:05 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-16 10:28:25 +0000 |
| commit | 489c393d47ac42dee939e741b732958b082539a7 (patch) | |
| tree | 9f5619374f605bd276d78ccc5e793a6433ffa6fc /src/parser/parser_utils.c | |
| parent | 46b0cfd792a2187d8984f55b9cf59493ec078239 (diff) | |
Fixed bug related to 'defer' and added some examples.
Diffstat (limited to 'src/parser/parser_utils.c')
| -rw-r--r-- | src/parser/parser_utils.c | 4562 |
1 files changed, 2495 insertions, 2067 deletions
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index d616056..e013a40 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -10,2237 +10,2665 @@ void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it, const char *mangled_struct_name, const char *arg); -Token expect(Lexer *l, TokenType type, const char *msg) { - Token t = lexer_next(l); - if (t.type != type) { - zpanic_at(t, "Expected %s, but got '%.*s'", msg, t.len, t.start); - return (Token){type, t.start, 0, t.line, t.col}; - } - return t; +Token expect(Lexer *l, TokenType type, const char *msg) +{ + Token t = lexer_next(l); + if (t.type != type) + { + zpanic_at(t, "Expected %s, but got '%.*s'", msg, t.len, t.start); + return (Token){type, t.start, 0, t.line, t.col}; + } + return t; } -int is_token(Token t, const char *s) { - int len = strlen(s); - return (t.len == len && strncmp(t.start, s, len) == 0); +int is_token(Token t, const char *s) +{ + int len = strlen(s); + return (t.len == len && strncmp(t.start, s, len) == 0); } -char *token_strdup(Token t) { - char *s = xmalloc(t.len + 1); - strncpy(s, t.start, t.len); - s[t.len] = 0; - return s; +char *token_strdup(Token t) +{ + char *s = xmalloc(t.len + 1); + strncpy(s, t.start, t.len); + s[t.len] = 0; + return s; } -void skip_comments(Lexer *l) { - while (lexer_peek(l).type == TOK_COMMENT) { - lexer_next(l); - } +void skip_comments(Lexer *l) +{ + while (lexer_peek(l).type == TOK_COMMENT) + { + lexer_next(l); + } } // C reserved words that conflict with C when used as identifiers. // TODO: We gotta work on these. static const char *C_RESERVED_WORDS[] = { // C types that could be used as names - "double", "float", "signed", "unsigned", "short", "long", "auto", - "register", + "double", "float", "signed", "unsigned", "short", "long", "auto", "register", // C keywords - "switch", "case", "default", "do", "goto", "typedef", "static", "extern", - "volatile", "inline", "restrict", "sizeof", "const", + "switch", "case", "default", "do", "goto", "typedef", "static", "extern", "volatile", "inline", + "restrict", "sizeof", "const", // C11+ keywords - "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", - "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", NULL}; + "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn", + "_Static_assert", "_Thread_local", NULL}; -int is_c_reserved_word(const char *name) { - for (int i = 0; C_RESERVED_WORDS[i] != NULL; i++) { - if (strcmp(name, C_RESERVED_WORDS[i]) == 0) { - return 1; +int is_c_reserved_word(const char *name) +{ + for (int i = 0; C_RESERVED_WORDS[i] != NULL; i++) + { + if (strcmp(name, C_RESERVED_WORDS[i]) == 0) + { + return 1; + } } - } - return 0; + return 0; } -void warn_c_reserved_word(Token t, const char *name) { - zwarn_at(t, "Identifier '%s' conflicts with C reserved word", name); - fprintf(stderr, COLOR_CYAN - " = note: " COLOR_RESET - "This will cause compilation errors in the generated C code\n"); +void warn_c_reserved_word(Token t, const char *name) +{ + zwarn_at(t, "Identifier '%s' conflicts with C reserved word", name); + fprintf(stderr, COLOR_CYAN " = note: " COLOR_RESET + "This will cause compilation errors in the generated C code\n"); } -char *consume_until_semicolon(Lexer *l) { - const char *s = l->src + l->pos; - int d = 0; - while (1) { - Token t = lexer_peek(l); - if (t.type == TOK_EOF) { - break; - } - if (t.type == TOK_LBRACE || t.type == TOK_LPAREN || - t.type == TOK_LBRACKET) { - d++; - } - if (t.type == TOK_RBRACE || t.type == TOK_RPAREN || - t.type == TOK_RBRACKET) { - d--; - } - - if (d == 0 && t.type == TOK_SEMICOLON) { - int len = t.start - s; - char *r = xmalloc(len + 1); - strncpy(r, s, len); - r[len] = 0; - lexer_next(l); - return r; - } - lexer_next(l); - } - return xstrdup(""); -} - -void enter_scope(ParserContext *ctx) { - Scope *s = xmalloc(sizeof(Scope)); - s->symbols = 0; - s->parent = ctx->current_scope; - ctx->current_scope = s; -} - -void exit_scope(ParserContext *ctx) { - if (!ctx->current_scope) { - return; - } - - // Check for unused variables - Symbol *sym = ctx->current_scope->symbols; - while (sym) { - if (!sym->is_used && strcmp(sym->name, "self") != 0 && - sym->name[0] != '_') { - // Could emit warning here - } - sym = sym->next; - } - - ctx->current_scope = ctx->current_scope->parent; -} - -void add_symbol(ParserContext *ctx, const char *n, const char *t, - Type *type_info) { - add_symbol_with_token(ctx, n, t, type_info, (Token){0}); -} - -void add_symbol_with_token(ParserContext *ctx, const char *n, const char *t, - Type *type_info, Token tok) { - if (!ctx->current_scope) { - enter_scope(ctx); - } - - if (n[0] != '_' && ctx->current_scope->parent && strcmp(n, "it") != 0 && - strcmp(n, "self") != 0) { - Scope *p = ctx->current_scope->parent; - while (p) { - Symbol *sh = p->symbols; - while (sh) { - if (strcmp(sh->name, n) == 0) { - warn_shadowing(tok, n); - break; - } - sh = sh->next; - } - if (sh) { - break; // found it - } - p = p->parent; - } - } - Symbol *s = xmalloc(sizeof(Symbol)); - s->name = xstrdup(n); - s->type_name = t ? xstrdup(t) : NULL; - s->type_info = type_info; - s->is_mutable = 1; - s->is_used = 0; - s->decl_token = tok; - s->is_const_value = 0; - s->next = ctx->current_scope->symbols; - ctx->current_scope->symbols = s; - - // LSP: Also add to flat list (for persistent access after scope exit) - Symbol *lsp_copy = xmalloc(sizeof(Symbol)); - *lsp_copy = *s; - lsp_copy->next = ctx->all_symbols; - ctx->all_symbols = lsp_copy; -} - -Type *find_symbol_type_info(ParserContext *ctx, const char *n) { - if (!ctx->current_scope) { - return NULL; - } - Scope *s = ctx->current_scope; - while (s) { - Symbol *sym = s->symbols; - while (sym) { - if (strcmp(sym->name, n) == 0) { - return sym->type_info; - } - sym = sym->next; - } - s = s->parent; - } - return NULL; -} - -char *find_symbol_type(ParserContext *ctx, const char *n) { - if (!ctx->current_scope) { - return NULL; - } - Scope *s = ctx->current_scope; - while (s) { - Symbol *sym = s->symbols; - while (sym) { - if (strcmp(sym->name, n) == 0) { - return sym->type_name; - } - sym = sym->next; - } - s = s->parent; - } - return NULL; -} - -Symbol *find_symbol_entry(ParserContext *ctx, const char *n) { - if (!ctx->current_scope) { - return NULL; - } - Scope *s = ctx->current_scope; - while (s) { - Symbol *sym = s->symbols; - while (sym) { - if (strcmp(sym->name, n) == 0) { - return sym; - } - sym = sym->next; +char *consume_until_semicolon(Lexer *l) +{ + const char *s = l->src + l->pos; + int d = 0; + while (1) + { + Token t = lexer_peek(l); + if (t.type == TOK_EOF) + { + break; + } + if (t.type == TOK_LBRACE || t.type == TOK_LPAREN || t.type == TOK_LBRACKET) + { + d++; + } + if (t.type == TOK_RBRACE || t.type == TOK_RPAREN || t.type == TOK_RBRACKET) + { + d--; + } + + if (d == 0 && t.type == TOK_SEMICOLON) + { + int len = t.start - s; + char *r = xmalloc(len + 1); + strncpy(r, s, len); + r[len] = 0; + lexer_next(l); + return r; + } + lexer_next(l); } - s = s->parent; - } - return NULL; + return xstrdup(""); } -// LSP: Search flat symbol list (works after scopes are destroyed). -Symbol *find_symbol_in_all(ParserContext *ctx, const char *n) { - Symbol *sym = ctx->all_symbols; - while (sym) { - if (strcmp(sym->name, n) == 0) { - return sym; - } - sym = sym->next; - } - return NULL; -} - -void init_builtins() { - static int init = 0; - if (init) { - return; - } - init = 1; -} - -void register_func(ParserContext *ctx, const char *name, int count, - char **defaults, Type **arg_types, Type *ret_type, - int is_varargs, int is_async, Token decl_token) { - FuncSig *f = xmalloc(sizeof(FuncSig)); - f->name = xstrdup(name); - f->decl_token = decl_token; - f->total_args = count; - f->defaults = defaults; - f->arg_types = arg_types; - f->ret_type = ret_type; - f->is_varargs = is_varargs; - f->is_async = is_async; - f->must_use = 0; // Default: can discard result - f->next = ctx->func_registry; - ctx->func_registry = f; -} - -void register_func_template(ParserContext *ctx, const char *name, - const char *param, ASTNode *node) { - GenericFuncTemplate *t = xmalloc(sizeof(GenericFuncTemplate)); - t->name = xstrdup(name); - t->generic_param = xstrdup(param); - t->func_node = node; - t->next = ctx->func_templates; - ctx->func_templates = t; -} - -void register_deprecated_func(ParserContext *ctx, const char *name, - const char *reason) { - DeprecatedFunc *d = xmalloc(sizeof(DeprecatedFunc)); - d->name = xstrdup(name); - d->reason = reason ? xstrdup(reason) : NULL; - d->next = ctx->deprecated_funcs; - ctx->deprecated_funcs = d; -} - -DeprecatedFunc *find_deprecated_func(ParserContext *ctx, const char *name) { - DeprecatedFunc *d = ctx->deprecated_funcs; - while (d) { - if (strcmp(d->name, name) == 0) { - return d; - } - d = d->next; - } - return NULL; -} - -GenericFuncTemplate *find_func_template(ParserContext *ctx, const char *name) { - GenericFuncTemplate *t = ctx->func_templates; - while (t) { - if (strcmp(t->name, name) == 0) { - return t; - } - t = t->next; - } - return NULL; -} - -void register_generic(ParserContext *ctx, char *name) { - for (int i = 0; i < ctx->known_generics_count; i++) { - if (strcmp(ctx->known_generics[i], name) == 0) { - return; - } - } - ctx->known_generics[ctx->known_generics_count++] = strdup(name); -} - -int is_known_generic(ParserContext *ctx, char *name) { - for (int i = 0; i < ctx->known_generics_count; i++) { - if (strcmp(ctx->known_generics[i], name) == 0) { - return 1; - } - } - return 0; -} - -void register_impl_template(ParserContext *ctx, const char *sname, - const char *param, ASTNode *node) { - GenericImplTemplate *t = xmalloc(sizeof(GenericImplTemplate)); - t->struct_name = xstrdup(sname); - t->generic_param = xstrdup(param); - t->impl_node = node; - t->next = ctx->impl_templates; - ctx->impl_templates = t; - - // Late binding: Check if any existing instantiations match this new impl - // template - Instantiation *inst = ctx->instantiations; - while (inst) { - if (inst->template_name && strcmp(inst->template_name, sname) == 0) { - instantiate_methods(ctx, t, inst->name, inst->concrete_arg); - } - inst = inst->next; - } -} - -void add_to_struct_list(ParserContext *ctx, ASTNode *node) { - StructRef *r = xmalloc(sizeof(StructRef)); - r->node = node; - r->next = ctx->parsed_structs_list; - ctx->parsed_structs_list = r; -} - -void add_to_enum_list(ParserContext *ctx, ASTNode *node) { - StructRef *r = xmalloc(sizeof(StructRef)); - r->node = node; - r->next = ctx->parsed_enums_list; - ctx->parsed_enums_list = r; -} - -void add_to_func_list(ParserContext *ctx, ASTNode *node) { - StructRef *r = xmalloc(sizeof(StructRef)); - r->node = node; - r->next = ctx->parsed_funcs_list; - ctx->parsed_funcs_list = r; -} - -void add_to_impl_list(ParserContext *ctx, ASTNode *node) { - StructRef *r = xmalloc(sizeof(StructRef)); - r->node = node; - r->next = ctx->parsed_impls_list; - ctx->parsed_impls_list = r; -} - -void add_to_global_list(ParserContext *ctx, ASTNode *node) { - StructRef *r = xmalloc(sizeof(StructRef)); - r->node = node; - r->next = ctx->parsed_globals_list; - ctx->parsed_globals_list = r; +void enter_scope(ParserContext *ctx) +{ + Scope *s = xmalloc(sizeof(Scope)); + s->symbols = 0; + s->parent = ctx->current_scope; + ctx->current_scope = s; } -void register_builtins(ParserContext *ctx) { - Type *t = type_new(TYPE_BOOL); - t->is_const = 1; - add_symbol(ctx, "true", "bool", t); - - t = type_new(TYPE_BOOL); - t->is_const = 1; - add_symbol(ctx, "false", "bool", t); - - // Register 'free' - Type *void_t = type_new(TYPE_VOID); - add_symbol(ctx, "free", "void", void_t); +void exit_scope(ParserContext *ctx) +{ + if (!ctx->current_scope) + { + return; + } - // Register common libc functions to avoid warnings - add_symbol(ctx, "strdup", "string", type_new(TYPE_STRING)); - add_symbol(ctx, "malloc", "void*", type_new_ptr(void_t)); - add_symbol(ctx, "realloc", "void*", type_new_ptr(void_t)); - add_symbol(ctx, "calloc", "void*", type_new_ptr(void_t)); - add_symbol(ctx, "puts", "int", type_new(TYPE_INT)); - add_symbol(ctx, "printf", "int", type_new(TYPE_INT)); - add_symbol(ctx, "strcmp", "int", type_new(TYPE_INT)); - add_symbol(ctx, "strlen", "int", type_new(TYPE_INT)); - add_symbol(ctx, "strcpy", "string", type_new(TYPE_STRING)); - add_symbol(ctx, "strcat", "string", type_new(TYPE_STRING)); - add_symbol(ctx, "exit", "void", void_t); + // Check for unused variables + Symbol *sym = ctx->current_scope->symbols; + while (sym) + { + if (!sym->is_used && strcmp(sym->name, "self") != 0 && sym->name[0] != '_') + { + // Could emit warning here + } + sym = sym->next; + } - // File I/O - add_symbol(ctx, "fopen", "void*", type_new_ptr(void_t)); - add_symbol(ctx, "fclose", "int", type_new(TYPE_INT)); - add_symbol(ctx, "fread", "usize", type_new(TYPE_USIZE)); - add_symbol(ctx, "fwrite", "usize", type_new(TYPE_USIZE)); - add_symbol(ctx, "fseek", "int", type_new(TYPE_INT)); - add_symbol(ctx, "ftell", "long", type_new(TYPE_I64)); - add_symbol(ctx, "rewind", "void", void_t); - add_symbol(ctx, "fprintf", "int", type_new(TYPE_INT)); - add_symbol(ctx, "sprintf", "int", type_new(TYPE_INT)); - add_symbol(ctx, "feof", "int", type_new(TYPE_INT)); - add_symbol(ctx, "ferror", "int", type_new(TYPE_INT)); - add_symbol(ctx, "usleep", "int", type_new(TYPE_INT)); + ctx->current_scope = ctx->current_scope->parent; } -void add_instantiated_func(ParserContext *ctx, ASTNode *fn) { - fn->next = ctx->instantiated_funcs; - ctx->instantiated_funcs = fn; -} - -void register_enum_variant(ParserContext *ctx, const char *ename, - const char *vname, int tag) { - EnumVariantReg *r = xmalloc(sizeof(EnumVariantReg)); - r->enum_name = xstrdup(ename); - r->variant_name = xstrdup(vname); - r->tag_id = tag; - r->next = ctx->enum_variants; - ctx->enum_variants = r; +void add_symbol(ParserContext *ctx, const char *n, const char *t, Type *type_info) +{ + add_symbol_with_token(ctx, n, t, type_info, (Token){0}); } -EnumVariantReg *find_enum_variant(ParserContext *ctx, const char *vname) { - EnumVariantReg *r = ctx->enum_variants; - while (r) { - if (strcmp(r->variant_name, vname) == 0) { - return r; +void add_symbol_with_token(ParserContext *ctx, const char *n, const char *t, Type *type_info, + Token tok) +{ + if (!ctx->current_scope) + { + enter_scope(ctx); } - r = r->next; - } - return NULL; -} - -void register_lambda(ParserContext *ctx, ASTNode *node) { - LambdaRef *ref = xmalloc(sizeof(LambdaRef)); - ref->node = node; - ref->next = ctx->global_lambdas; - ctx->global_lambdas = ref; -} -void register_var_mutability(ParserContext *ctx, const char *name, - int is_mutable) { - VarMutability *v = xmalloc(sizeof(VarMutability)); - v->name = xstrdup(name); - v->is_mutable = is_mutable; - v->next = ctx->var_mutability_table; - ctx->var_mutability_table = v; + if (n[0] != '_' && ctx->current_scope->parent && strcmp(n, "it") != 0 && strcmp(n, "self") != 0) + { + Scope *p = ctx->current_scope->parent; + while (p) + { + Symbol *sh = p->symbols; + while (sh) + { + if (strcmp(sh->name, n) == 0) + { + warn_shadowing(tok, n); + break; + } + sh = sh->next; + } + if (sh) + { + break; // found it + } + p = p->parent; + } + } + Symbol *s = xmalloc(sizeof(Symbol)); + s->name = xstrdup(n); + s->type_name = t ? xstrdup(t) : NULL; + s->type_info = type_info; + s->is_mutable = 1; + s->is_used = 0; + s->decl_token = tok; + s->is_const_value = 0; + s->next = ctx->current_scope->symbols; + ctx->current_scope->symbols = s; + + // LSP: Also add to flat list (for persistent access after scope exit) + Symbol *lsp_copy = xmalloc(sizeof(Symbol)); + *lsp_copy = *s; + lsp_copy->next = ctx->all_symbols; + ctx->all_symbols = lsp_copy; +} + +Type *find_symbol_type_info(ParserContext *ctx, const char *n) +{ + if (!ctx->current_scope) + { + return NULL; + } + Scope *s = ctx->current_scope; + while (s) + { + Symbol *sym = s->symbols; + while (sym) + { + if (strcmp(sym->name, n) == 0) + { + return sym->type_info; + } + sym = sym->next; + } + s = s->parent; + } + return NULL; } -int is_var_mutable(ParserContext *ctx, const char *name) { - for (VarMutability *v = ctx->var_mutability_table; v; v = v->next) { - if (strcmp(v->name, name) == 0) { - return v->is_mutable; - } - } - return 1; +char *find_symbol_type(ParserContext *ctx, const char *n) +{ + if (!ctx->current_scope) + { + return NULL; + } + Scope *s = ctx->current_scope; + while (s) + { + Symbol *sym = s->symbols; + while (sym) + { + if (strcmp(sym->name, n) == 0) + { + return sym->type_name; + } + sym = sym->next; + } + s = s->parent; + } + return NULL; } -void register_extern_symbol(ParserContext *ctx, const char *name) { - // Check for duplicates - for (int i = 0; i < ctx->extern_symbol_count; i++) { - if (strcmp(ctx->extern_symbols[i], name) == 0) { - return; +Symbol *find_symbol_entry(ParserContext *ctx, const char *n) +{ + if (!ctx->current_scope) + { + return NULL; } - } - - // Grow array if needed - if (ctx->extern_symbol_count == 0) { - ctx->extern_symbols = xmalloc(sizeof(char *) * 64); - } else if (ctx->extern_symbol_count % 64 == 0) { - ctx->extern_symbols = xrealloc( - ctx->extern_symbols, sizeof(char *) * (ctx->extern_symbol_count + 64)); - } - - ctx->extern_symbols[ctx->extern_symbol_count++] = xstrdup(name); -} - -int is_extern_symbol(ParserContext *ctx, const char *name) { - for (int i = 0; i < ctx->extern_symbol_count; i++) { - if (strcmp(ctx->extern_symbols[i], name) == 0) { - return 1; - } - } - return 0; + Scope *s = ctx->current_scope; + while (s) + { + Symbol *sym = s->symbols; + while (sym) + { + if (strcmp(sym->name, n) == 0) + { + return sym; + } + sym = sym->next; + } + s = s->parent; + } + return NULL; } -// Unified check: should we suppress "undefined variable" warning for this name? -int should_suppress_undef_warning(ParserContext *ctx, const char *name) { - if (strcmp(name, "struct") == 0 || strcmp(name, "tv") == 0) { - return 1; - } - - if (is_extern_symbol(ctx, name)) { - return 1; - } - - int is_all_caps = 1; - for (const char *p = name; *p; p++) { - if (islower((unsigned char)*p)) { - is_all_caps = 0; - break; +// LSP: Search flat symbol list (works after scopes are destroyed). +Symbol *find_symbol_in_all(ParserContext *ctx, const char *n) +{ + Symbol *sym = ctx->all_symbols; + while (sym) + { + if (strcmp(sym->name, n) == 0) + { + return sym; + } + sym = sym->next; } - } - if (is_all_caps && name[0] != '\0') { - return 1; - } - - if (ctx->has_external_includes) { - return 1; - } - - return 0; -} - -void register_slice(ParserContext *ctx, const char *type) { - SliceType *c = ctx->used_slices; - while (c) { - if (strcmp(c->name, type) == 0) { - return; - } - c = c->next; - } - SliceType *n = xmalloc(sizeof(SliceType)); - n->name = xstrdup(type); - n->next = ctx->used_slices; - ctx->used_slices = n; - - // Register Struct Def for Reflection - char slice_name[256]; - sprintf(slice_name, "Slice_%s", type); - - ASTNode *len_f = ast_create(NODE_FIELD); - len_f->field.name = xstrdup("len"); - len_f->field.type = xstrdup("int"); - ASTNode *cap_f = ast_create(NODE_FIELD); - cap_f->field.name = xstrdup("cap"); - cap_f->field.type = xstrdup("int"); - ASTNode *data_f = ast_create(NODE_FIELD); - data_f->field.name = xstrdup("data"); - char ptr_type[256]; - sprintf(ptr_type, "%s*", type); - data_f->field.type = xstrdup(ptr_type); - - data_f->next = len_f; - len_f->next = cap_f; - - ASTNode *def = ast_create(NODE_STRUCT); - def->strct.name = xstrdup(slice_name); - def->strct.fields = data_f; - - register_struct_def(ctx, slice_name, def); + return NULL; } -void register_tuple(ParserContext *ctx, const char *sig) { - TupleType *c = ctx->used_tuples; - while (c) { - if (strcmp(c->sig, sig) == 0) { - return; - } - c = c->next; - } - TupleType *n = xmalloc(sizeof(TupleType)); - n->sig = xstrdup(sig); - n->next = ctx->used_tuples; - ctx->used_tuples = n; - - char struct_name[1024]; - sprintf(struct_name, "Tuple_%s", sig); - - ASTNode *s_def = ast_create(NODE_STRUCT); - s_def->strct.name = xstrdup(struct_name); - - char *s_sig = xstrdup(sig); - char *tok = strtok(s_sig, "_"); - ASTNode *head = NULL, *tail = NULL; - int i = 0; - while (tok) { - ASTNode *f = ast_create(NODE_FIELD); - char fname[32]; - sprintf(fname, "v%d", i++); - f->field.name = xstrdup(fname); - f->field.type = xstrdup(tok); - - if (!head) { - head = f; - } else { - tail->next = f; - } - tail = f; - - tok = strtok(NULL, "_"); - } - free(s_sig); - s_def->strct.fields = head; - - register_struct_def(ctx, struct_name, s_def); -} - -void register_struct_def(ParserContext *ctx, const char *name, ASTNode *node) { - StructDef *d = xmalloc(sizeof(StructDef)); - d->name = xstrdup(name); - d->node = node; - d->next = ctx->struct_defs; - ctx->struct_defs = d; -} - -ASTNode *find_struct_def(ParserContext *ctx, const char *name) { - Instantiation *i = ctx->instantiations; - while (i) { - if (strcmp(i->name, name) == 0) { - return i->struct_node; - } - i = i->next; - } - - ASTNode *s = ctx->instantiated_structs; - while (s) { - if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0) { - return s; - } - s = s->next; - } - - StructRef *r = ctx->parsed_structs_list; - while (r) { - if (strcmp(r->node->strct.name, name) == 0) { - return r->node; - } - r = r->next; - } - - // Check manually registered definitions (e.g. Slices) - StructDef *d = ctx->struct_defs; - while (d) { - if (strcmp(d->name, name) == 0) { - return d->node; +void init_builtins() +{ + static int init = 0; + if (init) + { + return; + } + init = 1; +} + +void register_func(ParserContext *ctx, const char *name, int count, char **defaults, + Type **arg_types, Type *ret_type, int is_varargs, int is_async, Token decl_token) +{ + FuncSig *f = xmalloc(sizeof(FuncSig)); + f->name = xstrdup(name); + f->decl_token = decl_token; + f->total_args = count; + f->defaults = defaults; + f->arg_types = arg_types; + f->ret_type = ret_type; + f->is_varargs = is_varargs; + f->is_async = is_async; + f->must_use = 0; // Default: can discard result + f->next = ctx->func_registry; + ctx->func_registry = f; +} + +void register_func_template(ParserContext *ctx, const char *name, const char *param, ASTNode *node) +{ + GenericFuncTemplate *t = xmalloc(sizeof(GenericFuncTemplate)); + t->name = xstrdup(name); + t->generic_param = xstrdup(param); + t->func_node = node; + t->next = ctx->func_templates; + ctx->func_templates = t; +} + +void register_deprecated_func(ParserContext *ctx, const char *name, const char *reason) +{ + DeprecatedFunc *d = xmalloc(sizeof(DeprecatedFunc)); + d->name = xstrdup(name); + d->reason = reason ? xstrdup(reason) : NULL; + d->next = ctx->deprecated_funcs; + ctx->deprecated_funcs = d; +} + +DeprecatedFunc *find_deprecated_func(ParserContext *ctx, const char *name) +{ + DeprecatedFunc *d = ctx->deprecated_funcs; + while (d) + { + if (strcmp(d->name, name) == 0) + { + return d; + } + d = d->next; } - d = d->next; - } + return NULL; +} - // Check enums list (for @derive(Eq) and field type lookups) - StructRef *e = ctx->parsed_enums_list; - while (e) { - if (e->node->type == NODE_ENUM && strcmp(e->node->enm.name, name) == 0) { - return e->node; +GenericFuncTemplate *find_func_template(ParserContext *ctx, const char *name) +{ + GenericFuncTemplate *t = ctx->func_templates; + while (t) + { + if (strcmp(t->name, name) == 0) + { + return t; + } + t = t->next; } - e = e->next; - } - - return NULL; + return NULL; } -Module *find_module(ParserContext *ctx, const char *alias) { - Module *m = ctx->modules; - while (m) { - if (strcmp(m->alias, alias) == 0) { - return m; +void register_generic(ParserContext *ctx, char *name) +{ + for (int i = 0; i < ctx->known_generics_count; i++) + { + if (strcmp(ctx->known_generics[i], name) == 0) + { + return; + } } - m = m->next; - } - return NULL; + ctx->known_generics[ctx->known_generics_count++] = strdup(name); } -void register_module(ParserContext *ctx, const char *alias, const char *path) { - Module *m = xmalloc(sizeof(Module)); - m->alias = xstrdup(alias); - m->path = xstrdup(path); - m->base_name = extract_module_name(path); - m->next = ctx->modules; - ctx->modules = m; +int is_known_generic(ParserContext *ctx, char *name) +{ + for (int i = 0; i < ctx->known_generics_count; i++) + { + if (strcmp(ctx->known_generics[i], name) == 0) + { + return 1; + } + } + return 0; } -void register_selective_import(ParserContext *ctx, const char *symbol, - const char *alias, const char *source_module) { - SelectiveImport *si = xmalloc(sizeof(SelectiveImport)); - si->symbol = xstrdup(symbol); - si->alias = alias ? xstrdup(alias) : NULL; - si->source_module = xstrdup(source_module); - si->next = ctx->selective_imports; - ctx->selective_imports = si; -} +void register_impl_template(ParserContext *ctx, const char *sname, const char *param, ASTNode *node) +{ + GenericImplTemplate *t = xmalloc(sizeof(GenericImplTemplate)); + t->struct_name = xstrdup(sname); + t->generic_param = xstrdup(param); + t->impl_node = node; + t->next = ctx->impl_templates; + ctx->impl_templates = t; -SelectiveImport *find_selective_import(ParserContext *ctx, const char *name) { - SelectiveImport *si = ctx->selective_imports; - while (si) { - if (si->alias && strcmp(si->alias, name) == 0) { - return si; - } - if (!si->alias && strcmp(si->symbol, name) == 0) { - return si; + // Late binding: Check if any existing instantiations match this new impl + // template + Instantiation *inst = ctx->instantiations; + while (inst) + { + if (inst->template_name && strcmp(inst->template_name, sname) == 0) + { + instantiate_methods(ctx, t, inst->name, inst->concrete_arg); + } + inst = inst->next; + } +} + +void add_to_struct_list(ParserContext *ctx, ASTNode *node) +{ + StructRef *r = xmalloc(sizeof(StructRef)); + r->node = node; + r->next = ctx->parsed_structs_list; + ctx->parsed_structs_list = r; +} + +void add_to_enum_list(ParserContext *ctx, ASTNode *node) +{ + StructRef *r = xmalloc(sizeof(StructRef)); + r->node = node; + r->next = ctx->parsed_enums_list; + ctx->parsed_enums_list = r; +} + +void add_to_func_list(ParserContext *ctx, ASTNode *node) +{ + StructRef *r = xmalloc(sizeof(StructRef)); + r->node = node; + r->next = ctx->parsed_funcs_list; + ctx->parsed_funcs_list = r; +} + +void add_to_impl_list(ParserContext *ctx, ASTNode *node) +{ + StructRef *r = xmalloc(sizeof(StructRef)); + r->node = node; + r->next = ctx->parsed_impls_list; + ctx->parsed_impls_list = r; +} + +void add_to_global_list(ParserContext *ctx, ASTNode *node) +{ + StructRef *r = xmalloc(sizeof(StructRef)); + r->node = node; + r->next = ctx->parsed_globals_list; + ctx->parsed_globals_list = r; +} + +void register_builtins(ParserContext *ctx) +{ + Type *t = type_new(TYPE_BOOL); + t->is_const = 1; + add_symbol(ctx, "true", "bool", t); + + t = type_new(TYPE_BOOL); + t->is_const = 1; + add_symbol(ctx, "false", "bool", t); + + // Register 'free' + Type *void_t = type_new(TYPE_VOID); + add_symbol(ctx, "free", "void", void_t); + + // Register common libc functions to avoid warnings + add_symbol(ctx, "strdup", "string", type_new(TYPE_STRING)); + add_symbol(ctx, "malloc", "void*", type_new_ptr(void_t)); + add_symbol(ctx, "realloc", "void*", type_new_ptr(void_t)); + add_symbol(ctx, "calloc", "void*", type_new_ptr(void_t)); + add_symbol(ctx, "puts", "int", type_new(TYPE_INT)); + add_symbol(ctx, "printf", "int", type_new(TYPE_INT)); + add_symbol(ctx, "strcmp", "int", type_new(TYPE_INT)); + add_symbol(ctx, "strlen", "int", type_new(TYPE_INT)); + add_symbol(ctx, "strcpy", "string", type_new(TYPE_STRING)); + add_symbol(ctx, "strcat", "string", type_new(TYPE_STRING)); + add_symbol(ctx, "exit", "void", void_t); + + // File I/O + add_symbol(ctx, "fopen", "void*", type_new_ptr(void_t)); + add_symbol(ctx, "fclose", "int", type_new(TYPE_INT)); + add_symbol(ctx, "fread", "usize", type_new(TYPE_USIZE)); + add_symbol(ctx, "fwrite", "usize", type_new(TYPE_USIZE)); + add_symbol(ctx, "fseek", "int", type_new(TYPE_INT)); + add_symbol(ctx, "ftell", "long", type_new(TYPE_I64)); + add_symbol(ctx, "rewind", "void", void_t); + add_symbol(ctx, "fprintf", "int", type_new(TYPE_INT)); + add_symbol(ctx, "sprintf", "int", type_new(TYPE_INT)); + add_symbol(ctx, "feof", "int", type_new(TYPE_INT)); + add_symbol(ctx, "ferror", "int", type_new(TYPE_INT)); + add_symbol(ctx, "usleep", "int", type_new(TYPE_INT)); +} + +void add_instantiated_func(ParserContext *ctx, ASTNode *fn) +{ + fn->next = ctx->instantiated_funcs; + ctx->instantiated_funcs = fn; +} + +void register_enum_variant(ParserContext *ctx, const char *ename, const char *vname, int tag) +{ + EnumVariantReg *r = xmalloc(sizeof(EnumVariantReg)); + r->enum_name = xstrdup(ename); + r->variant_name = xstrdup(vname); + r->tag_id = tag; + r->next = ctx->enum_variants; + ctx->enum_variants = r; +} + +EnumVariantReg *find_enum_variant(ParserContext *ctx, const char *vname) +{ + EnumVariantReg *r = ctx->enum_variants; + while (r) + { + if (strcmp(r->variant_name, vname) == 0) + { + return r; + } + r = r->next; } - si = si->next; - } - return NULL; + return NULL; } -char *extract_module_name(const char *path) { - const char *slash = strrchr(path, '/'); - const char *base = slash ? slash + 1 : path; - const char *dot = strrchr(base, '.'); - int len = dot ? (int)(dot - base) : (int)strlen(base); - char *name = xmalloc(len + 1); - strncpy(name, base, len); - name[len] = 0; - return name; +void register_lambda(ParserContext *ctx, ASTNode *node) +{ + LambdaRef *ref = xmalloc(sizeof(LambdaRef)); + ref->node = node; + ref->next = ctx->global_lambdas; + ctx->global_lambdas = ref; } -int is_ident_char(char c) { return isalnum(c) || c == '_'; } - -ASTNode *copy_fields(ASTNode *fields) { - if (!fields) { - return NULL; - } - ASTNode *n = ast_create(NODE_FIELD); - n->field.name = xstrdup(fields->field.name); - n->field.type = xstrdup(fields->field.type); - n->next = copy_fields(fields->next); - return n; -} -char *replace_in_string(const char *src, const char *old_w, const char *new_w) { - if (!src || !old_w || !new_w) { - return src ? xstrdup(src) : NULL; - } - - char *result; - int i, cnt = 0; - int newWlen = strlen(new_w); - int oldWlen = strlen(old_w); - - for (i = 0; src[i] != '\0'; i++) { - if (strstr(&src[i], old_w) == &src[i]) { - // Check boundaries to ensure we match whole words only - int valid = 1; - - // Check preceding character - if (i > 0 && is_ident_char(src[i - 1])) { - valid = 0; - } - - // Check following character - if (valid && is_ident_char(src[i + oldWlen])) { - valid = 0; - } - - if (valid) { - cnt++; - i += oldWlen - 1; - } - } - } - - // Allocate result buffer - result = (char *)xmalloc(i + cnt * (newWlen - oldWlen) + 1); - - i = 0; - while (*src) { - if (strstr(src, old_w) == src) { - int valid = 1; - - // Check boundary relative to the *new* result buffer built so far - if (i > 0 && is_ident_char(result[i - 1])) { - valid = 0; - } - - // Check boundary relative to the *original* source string - if (valid && is_ident_char(src[oldWlen])) { - valid = 0; - } - - if (valid) { - strcpy(&result[i], new_w); - i += newWlen; - src += oldWlen; - } else { - result[i++] = *src++; - } - } else { - result[i++] = *src++; - } - } - result[i] = '\0'; - return result; +void register_var_mutability(ParserContext *ctx, const char *name, int is_mutable) +{ + VarMutability *v = xmalloc(sizeof(VarMutability)); + v->name = xstrdup(name); + v->is_mutable = is_mutable; + v->next = ctx->var_mutability_table; + ctx->var_mutability_table = v; } -char *replace_type_str(const char *src, const char *param, const char *concrete, - const char *old_struct, const char *new_struct) { - if (!src) { - return NULL; - } - - if (strcmp(src, param) == 0) { - return xstrdup(concrete); - } - - if (old_struct && new_struct && strcmp(src, old_struct) == 0) { - return xstrdup(new_struct); - } - - if (old_struct && new_struct && param) { - char *mangled = xmalloc(strlen(old_struct) + strlen(param) + 2); - sprintf(mangled, "%s_%s", old_struct, param); - if (strcmp(src, mangled) == 0) { - free(mangled); - return xstrdup(new_struct); - } - free(mangled); - } - - if (param && concrete && src) { - char suffix[256]; - sprintf(suffix, "_%s", param); - size_t slen = strlen(src); - size_t plen = strlen(suffix); - if (slen > plen && strcmp(src + slen - plen, 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); - strncpy(ret, src, slen - plen); - ret[slen - plen] = 0; - strcat(ret, "_"); - strcat(ret, clean_concrete); - free(clean_concrete); - return ret; - } - } - - size_t len = strlen(src); - if (len > 1 && src[len - 1] == '*') { - char *base = xmalloc(len); - strncpy(base, src, len - 1); - base[len - 1] = 0; - - char *new_base = - replace_type_str(base, param, concrete, old_struct, new_struct); - free(base); - - if (strcmp(new_base, base) != 0) { - char *ret = xmalloc(strlen(new_base) + 2); - sprintf(ret, "%s*", new_base); - free(new_base); - return ret; - } - free(new_base); - } - - if (strncmp(src, "Slice_", 6) == 0) { - char *base = xstrdup(src + 6); - char *new_base = - replace_type_str(base, param, concrete, old_struct, new_struct); - free(base); - - if (strcmp(new_base, base) != 0) { - char *ret = xmalloc(strlen(new_base) + 7); - sprintf(ret, "Slice_%s", new_base); - free(new_base); - return ret; - } - free(new_base); - } - - return xstrdup(src); -} - -ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, - const char *os, const char *ns); - -Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os, - const char *ns) { - if (!t) { - return NULL; - } - - if ((t->kind == TYPE_STRUCT || t->kind == TYPE_GENERIC) && t->name && - strcmp(t->name, p) == 0) { - if (strcmp(c, "int") == 0) { - return type_new(TYPE_INT); +int is_var_mutable(ParserContext *ctx, const char *name) +{ + for (VarMutability *v = ctx->var_mutability_table; v; v = v->next) + { + if (strcmp(v->name, name) == 0) + { + return v->is_mutable; + } } - if (strcmp(c, "float") == 0) { - return type_new(TYPE_FLOAT); + return 1; +} + +void register_extern_symbol(ParserContext *ctx, const char *name) +{ + // Check for duplicates + for (int i = 0; i < ctx->extern_symbol_count; i++) + { + if (strcmp(ctx->extern_symbols[i], name) == 0) + { + return; + } } - if (strcmp(c, "void") == 0) { - return type_new(TYPE_VOID); + + // Grow array if needed + if (ctx->extern_symbol_count == 0) + { + ctx->extern_symbols = xmalloc(sizeof(char *) * 64); } - if (strcmp(c, "string") == 0) { - return type_new(TYPE_STRING); + else if (ctx->extern_symbol_count % 64 == 0) + { + ctx->extern_symbols = + xrealloc(ctx->extern_symbols, sizeof(char *) * (ctx->extern_symbol_count + 64)); } - if (strcmp(c, "bool") == 0) { - return type_new(TYPE_BOOL); + + ctx->extern_symbols[ctx->extern_symbol_count++] = xstrdup(name); +} + +int is_extern_symbol(ParserContext *ctx, const char *name) +{ + for (int i = 0; i < ctx->extern_symbol_count; i++) + { + if (strcmp(ctx->extern_symbols[i], name) == 0) + { + return 1; + } } - if (strcmp(c, "char") == 0) { - return type_new(TYPE_CHAR); + return 0; +} + +// Unified check: should we suppress "undefined variable" warning for this name? +int should_suppress_undef_warning(ParserContext *ctx, const char *name) +{ + if (strcmp(name, "struct") == 0 || strcmp(name, "tv") == 0) + { + return 1; } - if (strcmp(c, "I8") == 0) { - return type_new(TYPE_I8); + if (is_extern_symbol(ctx, name)) + { + return 1; } - if (strcmp(c, "U8") == 0) { - return type_new(TYPE_U8); + + int is_all_caps = 1; + for (const char *p = name; *p; p++) + { + if (islower((unsigned char)*p)) + { + is_all_caps = 0; + break; + } } - if (strcmp(c, "I16") == 0) { - return type_new(TYPE_I16); + if (is_all_caps && name[0] != '\0') + { + return 1; } - if (strcmp(c, "U16") == 0) { - return type_new(TYPE_U16); + + if (ctx->has_external_includes) + { + return 1; } - if (strcmp(c, "I32") == 0) { - return type_new(TYPE_I32); + + return 0; +} + +void register_slice(ParserContext *ctx, const char *type) +{ + SliceType *c = ctx->used_slices; + while (c) + { + if (strcmp(c->name, type) == 0) + { + return; + } + c = c->next; + } + SliceType *n = xmalloc(sizeof(SliceType)); + n->name = xstrdup(type); + n->next = ctx->used_slices; + ctx->used_slices = n; + + // Register Struct Def for Reflection + char slice_name[256]; + sprintf(slice_name, "Slice_%s", type); + + ASTNode *len_f = ast_create(NODE_FIELD); + len_f->field.name = xstrdup("len"); + len_f->field.type = xstrdup("int"); + ASTNode *cap_f = ast_create(NODE_FIELD); + cap_f->field.name = xstrdup("cap"); + cap_f->field.type = xstrdup("int"); + ASTNode *data_f = ast_create(NODE_FIELD); + data_f->field.name = xstrdup("data"); + char ptr_type[256]; + sprintf(ptr_type, "%s*", type); + data_f->field.type = xstrdup(ptr_type); + + data_f->next = len_f; + len_f->next = cap_f; + + ASTNode *def = ast_create(NODE_STRUCT); + def->strct.name = xstrdup(slice_name); + def->strct.fields = data_f; + + register_struct_def(ctx, slice_name, def); +} + +void register_tuple(ParserContext *ctx, const char *sig) +{ + TupleType *c = ctx->used_tuples; + while (c) + { + if (strcmp(c->sig, sig) == 0) + { + return; + } + c = c->next; } - if (strcmp(c, "U32") == 0) { - return type_new(TYPE_U32); + TupleType *n = xmalloc(sizeof(TupleType)); + n->sig = xstrdup(sig); + n->next = ctx->used_tuples; + ctx->used_tuples = n; + + char struct_name[1024]; + sprintf(struct_name, "Tuple_%s", sig); + + ASTNode *s_def = ast_create(NODE_STRUCT); + s_def->strct.name = xstrdup(struct_name); + + char *s_sig = xstrdup(sig); + char *tok = strtok(s_sig, "_"); + ASTNode *head = NULL, *tail = NULL; + int i = 0; + while (tok) + { + ASTNode *f = ast_create(NODE_FIELD); + char fname[32]; + sprintf(fname, "v%d", i++); + f->field.name = xstrdup(fname); + f->field.type = xstrdup(tok); + + if (!head) + { + head = f; + } + else + { + tail->next = f; + } + tail = f; + + tok = strtok(NULL, "_"); } - if (strcmp(c, "I64") == 0) { - return type_new(TYPE_I64); + free(s_sig); + s_def->strct.fields = head; + + register_struct_def(ctx, struct_name, s_def); +} + +void register_struct_def(ParserContext *ctx, const char *name, ASTNode *node) +{ + StructDef *d = xmalloc(sizeof(StructDef)); + d->name = xstrdup(name); + d->node = node; + d->next = ctx->struct_defs; + ctx->struct_defs = d; +} + +ASTNode *find_struct_def(ParserContext *ctx, const char *name) +{ + Instantiation *i = ctx->instantiations; + while (i) + { + if (strcmp(i->name, name) == 0) + { + return i->struct_node; + } + i = i->next; } - if (strcmp(c, "U64") == 0) { - return type_new(TYPE_U64); + + ASTNode *s = ctx->instantiated_structs; + while (s) + { + if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0) + { + return s; + } + s = s->next; } - if (strcmp(c, "F32") == 0) { - return type_new(TYPE_F32); + + StructRef *r = ctx->parsed_structs_list; + while (r) + { + if (strcmp(r->node->strct.name, name) == 0) + { + return r->node; + } + r = r->next; } - if (strcmp(c, "f32") == 0) { - return type_new(TYPE_F32); + + // Check manually registered definitions (e.g. Slices) + StructDef *d = ctx->struct_defs; + while (d) + { + if (strcmp(d->name, name) == 0) + { + return d->node; + } + d = d->next; } - if (strcmp(c, "F64") == 0) { - return type_new(TYPE_F64); + + // Check enums list (for @derive(Eq) and field type lookups) + StructRef *e = ctx->parsed_enums_list; + while (e) + { + if (e->node->type == NODE_ENUM && strcmp(e->node->enm.name, name) == 0) + { + return e->node; + } + e = e->next; } - if (strcmp(c, "f64") == 0) { - return type_new(TYPE_F64); + + return NULL; +} + +Module *find_module(ParserContext *ctx, const char *alias) +{ + Module *m = ctx->modules; + while (m) + { + if (strcmp(m->alias, alias) == 0) + { + return m; + } + m = m->next; } + return NULL; +} + +void register_module(ParserContext *ctx, const char *alias, const char *path) +{ + Module *m = xmalloc(sizeof(Module)); + m->alias = xstrdup(alias); + m->path = xstrdup(path); + m->base_name = extract_module_name(path); + m->next = ctx->modules; + ctx->modules = m; +} - if (strcmp(c, "usize") == 0) { - return type_new(TYPE_USIZE); +void register_selective_import(ParserContext *ctx, const char *symbol, const char *alias, + const char *source_module) +{ + SelectiveImport *si = xmalloc(sizeof(SelectiveImport)); + si->symbol = xstrdup(symbol); + si->alias = alias ? xstrdup(alias) : NULL; + si->source_module = xstrdup(source_module); + si->next = ctx->selective_imports; + ctx->selective_imports = si; +} + +SelectiveImport *find_selective_import(ParserContext *ctx, const char *name) +{ + SelectiveImport *si = ctx->selective_imports; + while (si) + { + if (si->alias && strcmp(si->alias, name) == 0) + { + return si; + } + if (!si->alias && strcmp(si->symbol, name) == 0) + { + return si; + } + si = si->next; } - if (strcmp(c, "isize") == 0) { - return type_new(TYPE_ISIZE); + return NULL; +} + +char *extract_module_name(const char *path) +{ + const char *slash = strrchr(path, '/'); + const char *base = slash ? slash + 1 : path; + const char *dot = strrchr(base, '.'); + int len = dot ? (int)(dot - base) : (int)strlen(base); + char *name = xmalloc(len + 1); + strncpy(name, base, len); + name[len] = 0; + return name; +} + +int is_ident_char(char c) +{ + return isalnum(c) || c == '_'; +} + +ASTNode *copy_fields(ASTNode *fields) +{ + if (!fields) + { + return NULL; } - if (strcmp(c, "byte") == 0) { - return type_new(TYPE_BYTE); + ASTNode *n = ast_create(NODE_FIELD); + n->field.name = xstrdup(fields->field.name); + n->field.type = xstrdup(fields->field.type); + n->next = copy_fields(fields->next); + return n; +} +char *replace_in_string(const char *src, const char *old_w, const char *new_w) +{ + if (!src || !old_w || !new_w) + { + return src ? xstrdup(src) : NULL; } - if (strcmp(c, "I128") == 0) { - return type_new(TYPE_I128); + + char *result; + int i, cnt = 0; + int newWlen = strlen(new_w); + int oldWlen = strlen(old_w); + + for (i = 0; src[i] != '\0'; i++) + { + if (strstr(&src[i], old_w) == &src[i]) + { + // Check boundaries to ensure we match whole words only + int valid = 1; + + // Check preceding character + if (i > 0 && is_ident_char(src[i - 1])) + { + valid = 0; + } + + // Check following character + if (valid && is_ident_char(src[i + oldWlen])) + { + valid = 0; + } + + if (valid) + { + cnt++; + i += oldWlen - 1; + } + } } - if (strcmp(c, "U128") == 0) { - return type_new(TYPE_U128); + + // Allocate result buffer + result = (char *)xmalloc(i + cnt * (newWlen - oldWlen) + 1); + + i = 0; + while (*src) + { + if (strstr(src, old_w) == src) + { + int valid = 1; + + // Check boundary relative to the *new* result buffer built so far + if (i > 0 && is_ident_char(result[i - 1])) + { + valid = 0; + } + + // Check boundary relative to the *original* source string + if (valid && is_ident_char(src[oldWlen])) + { + valid = 0; + } + + if (valid) + { + strcpy(&result[i], new_w); + i += newWlen; + src += oldWlen; + } + else + { + result[i++] = *src++; + } + } + else + { + result[i++] = *src++; + } } - if (strcmp(c, "i8") == 0) { - return type_new(TYPE_I8); + result[i] = '\0'; + return result; +} + +char *replace_type_str(const char *src, const char *param, const char *concrete, + const char *old_struct, const char *new_struct) +{ + if (!src) + { + return NULL; } - if (strcmp(c, "u8") == 0) { - return type_new(TYPE_U8); + + if (strcmp(src, param) == 0) + { + return xstrdup(concrete); } - if (strcmp(c, "i16") == 0) { - return type_new(TYPE_I16); + + if (old_struct && new_struct && strcmp(src, old_struct) == 0) + { + return xstrdup(new_struct); } - if (strcmp(c, "u16") == 0) { - return type_new(TYPE_U16); + + if (old_struct && new_struct && param) + { + char *mangled = xmalloc(strlen(old_struct) + strlen(param) + 2); + sprintf(mangled, "%s_%s", old_struct, param); + if (strcmp(src, mangled) == 0) + { + free(mangled); + return xstrdup(new_struct); + } + free(mangled); } - if (strcmp(c, "i32") == 0) { - return type_new(TYPE_I32); + + if (param && concrete && src) + { + char suffix[256]; + sprintf(suffix, "_%s", param); + size_t slen = strlen(src); + size_t plen = strlen(suffix); + if (slen > plen && strcmp(src + slen - plen, 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); + strncpy(ret, src, slen - plen); + ret[slen - plen] = 0; + strcat(ret, "_"); + strcat(ret, clean_concrete); + free(clean_concrete); + return ret; + } } - if (strcmp(c, "u32") == 0) { - return type_new(TYPE_U32); + + size_t len = strlen(src); + if (len > 1 && src[len - 1] == '*') + { + char *base = xmalloc(len); + strncpy(base, src, len - 1); + base[len - 1] = 0; + + char *new_base = replace_type_str(base, param, concrete, old_struct, new_struct); + free(base); + + if (strcmp(new_base, base) != 0) + { + char *ret = xmalloc(strlen(new_base) + 2); + sprintf(ret, "%s*", new_base); + free(new_base); + return ret; + } + free(new_base); } - if (strcmp(c, "i64") == 0) { - return type_new(TYPE_I64); + + if (strncmp(src, "Slice_", 6) == 0) + { + char *base = xstrdup(src + 6); + char *new_base = replace_type_str(base, param, concrete, old_struct, new_struct); + free(base); + + if (strcmp(new_base, base) != 0) + { + char *ret = xmalloc(strlen(new_base) + 7); + sprintf(ret, "Slice_%s", new_base); + free(new_base); + return ret; + } + free(new_base); } - if (strcmp(c, "u64") == 0) { - return type_new(TYPE_U64); + + return xstrdup(src); +} + +ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char *os, + const char *ns); + +Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os, const char *ns) +{ + if (!t) + { + return NULL; } - if (strcmp(c, "i128") == 0) { - return type_new(TYPE_I128); + + if ((t->kind == TYPE_STRUCT || t->kind == TYPE_GENERIC) && t->name && strcmp(t->name, p) == 0) + { + 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) + { + 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); + } + + 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 (strcmp(c, "rune") == 0) + { + return type_new(TYPE_RUNE); + } + if (strcmp(c, "uint") == 0) + { + return type_new(TYPE_UINT); + } + + Type *n = type_new(TYPE_STRUCT); + n->name = sanitize_mangled_name(c); + return n; } - if (strcmp(c, "u128") == 0) { - return type_new(TYPE_U128); + + Type *n = xmalloc(sizeof(Type)); + *n = *t; + + if (t->name) + { + if (os && ns && strcmp(t->name, os) == 0) + { + n->name = xstrdup(ns); + n->kind = TYPE_STRUCT; + n->arg_count = 0; + n->args = NULL; + } + + else if (p && c) + { + char suffix[256]; + sprintf(suffix, "_%s", p); // e.g. "_T" + size_t nlen = strlen(t->name); + size_t slen = strlen(suffix); + + if (nlen > slen && strcmp(t->name + nlen - slen, 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); + strncpy(new_name, t->name, nlen - slen); + new_name[nlen - slen] = 0; + strcat(new_name, "_"); + strcat(new_name, clean_c); + free(clean_c); + n->name = new_name; + // Ensure it's concrete to prevent double mangling later + n->kind = TYPE_STRUCT; + n->arg_count = 0; + n->args = NULL; + } + else + { + n->name = xstrdup(t->name); + } + } + else + { + n->name = xstrdup(t->name); + } } - if (strcmp(c, "rune") == 0) { - return type_new(TYPE_RUNE); + if (t->kind == TYPE_POINTER || t->kind == TYPE_ARRAY) + { + n->inner = replace_type_formal(t->inner, p, c, os, ns); } - if (strcmp(c, "uint") == 0) { - return type_new(TYPE_UINT); + + if (n->arg_count > 0 && t->args) + { + n->args = xmalloc(sizeof(Type *) * t->arg_count); + for (int i = 0; i < t->arg_count; i++) + { + n->args[i] = replace_type_formal(t->args[i], p, c, os, ns); + } } - Type *n = type_new(TYPE_STRUCT); - n->name = sanitize_mangled_name(c); return n; - } - - Type *n = xmalloc(sizeof(Type)); - *n = *t; - - if (t->name) { - if (os && ns && strcmp(t->name, os) == 0) { - n->name = xstrdup(ns); - n->kind = TYPE_STRUCT; - n->arg_count = 0; - n->args = NULL; - } - - else if (p && c) { - char suffix[256]; - sprintf(suffix, "_%s", p); // e.g. "_T" - size_t nlen = strlen(t->name); - size_t slen = strlen(suffix); - - if (nlen > slen && strcmp(t->name + nlen - slen, 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); - strncpy(new_name, t->name, nlen - slen); - new_name[nlen - slen] = 0; - strcat(new_name, "_"); - strcat(new_name, clean_c); - free(clean_c); - n->name = new_name; - // Ensure it's concrete to prevent double mangling later - n->kind = TYPE_STRUCT; - n->arg_count = 0; - n->args = NULL; - } else { - n->name = xstrdup(t->name); - } - } else { - n->name = xstrdup(t->name); - } - } - - if (t->kind == TYPE_POINTER || t->kind == TYPE_ARRAY) { - n->inner = replace_type_formal(t->inner, p, c, os, ns); - } - - if (n->arg_count > 0 && t->args) { - n->args = xmalloc(sizeof(Type *) * t->arg_count); - for (int i = 0; i < t->arg_count; i++) { - n->args[i] = replace_type_formal(t->args[i], p, c, os, ns); - } - } - - return n; } // Helper to replace generic params in mangled names (e.g. Option_V_None -> // Option_int_None) -char *replace_mangled_part(const char *src, const char *param, - const char *concrete) { - if (!src || !param || !concrete) { - return src ? xstrdup(src) : NULL; - } - - char *result = xmalloc(4096); // Basic buffer for simplicity - result[0] = 0; - - const char *curr = src; - char *out = result; - int plen = strlen(param); - - while (*curr) { - // Check if param matches here - if (strncmp(curr, param, plen) == 0) { - // Check boundaries: Must be delimited by quoted boundaries, OR - // underscores, OR string ends - int valid = 1; - - // Check Prev: Start of string OR Underscore - if (curr > src) { - if (*(curr - 1) != '_' && is_ident_char(*(curr - 1))) { - valid = 0; - } - } - - // Check Next: End of string OR Underscore - if (valid && curr[plen] != 0 && curr[plen] != '_' && - is_ident_char(curr[plen])) { - valid = 0; - } - - if (valid) { - strcpy(out, concrete); - out += strlen(concrete); - curr += plen; - continue; - } - } - *out++ = *curr++; - } - *out = 0; - return xstrdup(result); -} - -ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, - const char *os, const char *ns) { - if (!n) { - return NULL; - } +char *replace_mangled_part(const char *src, const char *param, const char *concrete) +{ + if (!src || !param || !concrete) + { + return src ? xstrdup(src) : NULL; + } - ASTNode *new_node = xmalloc(sizeof(ASTNode)); - *new_node = *n; + char *result = xmalloc(4096); // Basic buffer for simplicity + result[0] = 0; - if (n->resolved_type) { - new_node->resolved_type = replace_type_str(n->resolved_type, p, c, os, ns); - } - new_node->type_info = replace_type_formal(n->type_info, p, c, os, ns); + const char *curr = src; + char *out = result; + int plen = strlen(param); - new_node->next = copy_ast_replacing(n->next, p, c, os, ns); + while (*curr) + { + // Check if param matches here + if (strncmp(curr, param, plen) == 0) + { + // Check boundaries: Must be delimited by quoted boundaries, OR + // underscores, OR string ends + int valid = 1; + + // Check Prev: Start of string OR Underscore + if (curr > src) + { + if (*(curr - 1) != '_' && is_ident_char(*(curr - 1))) + { + valid = 0; + } + } - switch (n->type) { - case NODE_FUNCTION: - new_node->func.name = xstrdup(n->func.name); - new_node->func.ret_type = replace_type_str(n->func.ret_type, p, c, os, ns); + // Check Next: End of string OR Underscore + if (valid && curr[plen] != 0 && curr[plen] != '_' && is_ident_char(curr[plen])) + { + valid = 0; + } - char *tmp_args = replace_in_string(n->func.args, p, c); - if (os && ns) { - char *tmp2 = replace_in_string(tmp_args, os, ns); - free(tmp_args); - tmp_args = tmp2; + if (valid) + { + strcpy(out, concrete); + out += strlen(concrete); + curr += plen; + continue; + } + } + *out++ = *curr++; } - if (p && c) { - char *clean_c = sanitize_mangled_name(c); - char *tmp3 = replace_mangled_part(tmp_args, p, clean_c); - free(clean_c); - free(tmp_args); - tmp_args = tmp3; + *out = 0; + return xstrdup(result); +} + +ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char *os, + const char *ns) +{ + if (!n) + { + return NULL; } - new_node->func.args = tmp_args; - new_node->func.ret_type_info = - replace_type_formal(n->func.ret_type_info, p, c, os, ns); - if (n->func.arg_types) { - new_node->func.arg_types = xmalloc(sizeof(Type *) * n->func.arg_count); - for (int i = 0; i < n->func.arg_count; i++) { - new_node->func.arg_types[i] = - replace_type_formal(n->func.arg_types[i], p, c, os, ns); - } + ASTNode *new_node = xmalloc(sizeof(ASTNode)); + *new_node = *n; + + if (n->resolved_type) + { + new_node->resolved_type = replace_type_str(n->resolved_type, p, c, os, ns); } + new_node->type_info = replace_type_formal(n->type_info, p, c, os, ns); - new_node->func.body = copy_ast_replacing(n->func.body, p, c, os, ns); - break; - case NODE_BLOCK: - new_node->block.statements = - copy_ast_replacing(n->block.statements, p, c, os, ns); - break; - case NODE_RAW_STMT: { - char *s1 = replace_in_string(n->raw_stmt.content, p, c); - if (os && ns) { - char *s2 = replace_in_string(s1, os, ns); - free(s1); - s1 = s2; - } - - if (p && c) { - char *clean_c = sanitize_mangled_name(c); - char *s3 = replace_mangled_part(s1, p, clean_c); - free(clean_c); - free(s1); - s1 = s3; - } - - new_node->raw_stmt.content = s1; - } break; - case NODE_VAR_DECL: - new_node->var_decl.name = xstrdup(n->var_decl.name); - new_node->var_decl.type_str = - replace_type_str(n->var_decl.type_str, p, c, os, ns); - new_node->var_decl.init_expr = - copy_ast_replacing(n->var_decl.init_expr, p, c, os, ns); - break; - case NODE_RETURN: - new_node->ret.value = copy_ast_replacing(n->ret.value, p, c, os, ns); - break; - case NODE_EXPR_BINARY: - new_node->binary.left = copy_ast_replacing(n->binary.left, p, c, os, ns); - new_node->binary.right = copy_ast_replacing(n->binary.right, p, c, os, ns); - new_node->binary.op = xstrdup(n->binary.op); - break; - case NODE_EXPR_UNARY: - new_node->unary.op = xstrdup(n->unary.op); - new_node->unary.operand = - copy_ast_replacing(n->unary.operand, p, c, os, ns); - break; - case NODE_EXPR_CALL: - new_node->call.callee = copy_ast_replacing(n->call.callee, p, c, os, ns); - new_node->call.args = copy_ast_replacing(n->call.args, p, c, os, ns); - new_node->call.arg_names = - n->call.arg_names; // Share pointer (shallow copy) - new_node->call.arg_count = n->call.arg_count; - break; - case NODE_EXPR_VAR: { - char *n1 = xstrdup(n->var_ref.name); - if (p && c) { - char *clean_c = sanitize_mangled_name(c); - char *n2 = replace_mangled_part(n1, p, clean_c); - free(clean_c); - free(n1); - n1 = n2; - } - new_node->var_ref.name = n1; - } break; - case NODE_FIELD: - new_node->field.name = xstrdup(n->field.name); - new_node->field.type = replace_type_str(n->field.type, p, c, os, ns); - break; - case NODE_EXPR_LITERAL: - if (n->literal.type_kind == 2) { - new_node->literal.string_val = xstrdup(n->literal.string_val); + new_node->next = copy_ast_replacing(n->next, p, c, os, ns); + + switch (n->type) + { + case NODE_FUNCTION: + new_node->func.name = xstrdup(n->func.name); + new_node->func.ret_type = replace_type_str(n->func.ret_type, p, c, os, ns); + + char *tmp_args = replace_in_string(n->func.args, p, c); + if (os && ns) + { + char *tmp2 = replace_in_string(tmp_args, os, ns); + free(tmp_args); + tmp_args = tmp2; + } + if (p && c) + { + char *clean_c = sanitize_mangled_name(c); + char *tmp3 = replace_mangled_part(tmp_args, p, clean_c); + free(clean_c); + free(tmp_args); + tmp_args = tmp3; + } + new_node->func.args = tmp_args; + + new_node->func.ret_type_info = replace_type_formal(n->func.ret_type_info, p, c, os, ns); + if (n->func.arg_types) + { + new_node->func.arg_types = xmalloc(sizeof(Type *) * n->func.arg_count); + for (int i = 0; i < n->func.arg_count; i++) + { + new_node->func.arg_types[i] = + replace_type_formal(n->func.arg_types[i], p, c, os, ns); + } + } + + new_node->func.body = copy_ast_replacing(n->func.body, p, c, os, ns); + break; + case NODE_BLOCK: + new_node->block.statements = copy_ast_replacing(n->block.statements, p, c, os, ns); + break; + case NODE_RAW_STMT: + { + char *s1 = replace_in_string(n->raw_stmt.content, p, c); + if (os && ns) + { + char *s2 = replace_in_string(s1, os, ns); + free(s1); + s1 = s2; + } + + if (p && c) + { + char *clean_c = sanitize_mangled_name(c); + char *s3 = replace_mangled_part(s1, p, clean_c); + free(clean_c); + free(s1); + s1 = s3; + } + + new_node->raw_stmt.content = s1; } break; - case NODE_EXPR_MEMBER: - new_node->member.target = - copy_ast_replacing(n->member.target, p, c, os, ns); - new_node->member.field = xstrdup(n->member.field); - break; - case NODE_EXPR_INDEX: - new_node->index.array = copy_ast_replacing(n->index.array, p, c, os, ns); - new_node->index.index = copy_ast_replacing(n->index.index, p, c, os, ns); - break; - case NODE_EXPR_CAST: - new_node->cast.target_type = - replace_type_str(n->cast.target_type, p, c, os, ns); - new_node->cast.expr = copy_ast_replacing(n->cast.expr, p, c, os, ns); - break; - case NODE_EXPR_STRUCT_INIT: - new_node->struct_init.struct_name = - replace_type_str(n->struct_init.struct_name, p, c, os, ns); - ASTNode *h = NULL, *t = NULL, *curr = n->struct_init.fields; - while (curr) { - ASTNode *cp = copy_ast_replacing(curr, p, c, os, ns); - cp->next = NULL; - if (!h) { - h = cp; - } else { - t->next = cp; - } - t = cp; - curr = curr->next; - } - new_node->struct_init.fields = h; - break; - case NODE_IF: - new_node->if_stmt.condition = - copy_ast_replacing(n->if_stmt.condition, p, c, os, ns); - new_node->if_stmt.then_body = - copy_ast_replacing(n->if_stmt.then_body, p, c, os, ns); - new_node->if_stmt.else_body = - copy_ast_replacing(n->if_stmt.else_body, p, c, os, ns); - break; - case NODE_WHILE: - new_node->while_stmt.condition = - copy_ast_replacing(n->while_stmt.condition, p, c, os, ns); - new_node->while_stmt.body = - copy_ast_replacing(n->while_stmt.body, p, c, os, ns); - break; - case NODE_FOR: - new_node->for_stmt.init = - copy_ast_replacing(n->for_stmt.init, p, c, os, ns); - new_node->for_stmt.condition = - copy_ast_replacing(n->for_stmt.condition, p, c, os, ns); - new_node->for_stmt.step = - copy_ast_replacing(n->for_stmt.step, p, c, os, ns); - new_node->for_stmt.body = - copy_ast_replacing(n->for_stmt.body, p, c, os, ns); - break; - - case NODE_MATCH_CASE: - if (n->match_case.pattern) { - char *s1 = replace_in_string(n->match_case.pattern, p, c); - if (os && ns) { - char *s2 = replace_in_string(s1, os, ns); - free(s1); - s1 = s2; - char *colons = strstr(s1, "::"); - if (colons) { - colons[0] = '_'; - memmove(colons + 1, colons + 2, strlen(colons + 2) + 1); - } - } - new_node->match_case.pattern = s1; - } - new_node->match_case.body = - copy_ast_replacing(n->match_case.body, p, c, os, ns); - if (n->match_case.guard) { - new_node->match_case.guard = - copy_ast_replacing(n->match_case.guard, p, c, os, ns); + case NODE_VAR_DECL: + new_node->var_decl.name = xstrdup(n->var_decl.name); + new_node->var_decl.type_str = replace_type_str(n->var_decl.type_str, p, c, os, ns); + new_node->var_decl.init_expr = copy_ast_replacing(n->var_decl.init_expr, p, c, os, ns); + break; + case NODE_RETURN: + new_node->ret.value = copy_ast_replacing(n->ret.value, p, c, os, ns); + break; + case NODE_EXPR_BINARY: + new_node->binary.left = copy_ast_replacing(n->binary.left, p, c, os, ns); + new_node->binary.right = copy_ast_replacing(n->binary.right, p, c, os, ns); + new_node->binary.op = xstrdup(n->binary.op); + break; + case NODE_EXPR_UNARY: + new_node->unary.op = xstrdup(n->unary.op); + new_node->unary.operand = copy_ast_replacing(n->unary.operand, p, c, os, ns); + break; + case NODE_EXPR_CALL: + new_node->call.callee = copy_ast_replacing(n->call.callee, p, c, os, ns); + new_node->call.args = copy_ast_replacing(n->call.args, p, c, os, ns); + new_node->call.arg_names = n->call.arg_names; // Share pointer (shallow copy) + new_node->call.arg_count = n->call.arg_count; + break; + case NODE_EXPR_VAR: + { + char *n1 = xstrdup(n->var_ref.name); + if (p && c) + { + char *clean_c = sanitize_mangled_name(c); + char *n2 = replace_mangled_part(n1, p, clean_c); + free(clean_c); + free(n1); + n1 = n2; + } + new_node->var_ref.name = n1; } break; + case NODE_FIELD: + new_node->field.name = xstrdup(n->field.name); + new_node->field.type = replace_type_str(n->field.type, p, c, os, ns); + break; + case NODE_EXPR_LITERAL: + if (n->literal.type_kind == 2) + { + new_node->literal.string_val = xstrdup(n->literal.string_val); + } + break; + case NODE_EXPR_MEMBER: + new_node->member.target = copy_ast_replacing(n->member.target, p, c, os, ns); + new_node->member.field = xstrdup(n->member.field); + break; + case NODE_EXPR_INDEX: + new_node->index.array = copy_ast_replacing(n->index.array, p, c, os, ns); + new_node->index.index = copy_ast_replacing(n->index.index, p, c, os, ns); + break; + case NODE_EXPR_CAST: + new_node->cast.target_type = replace_type_str(n->cast.target_type, p, c, os, ns); + new_node->cast.expr = copy_ast_replacing(n->cast.expr, p, c, os, ns); + break; + case NODE_EXPR_STRUCT_INIT: + new_node->struct_init.struct_name = + replace_type_str(n->struct_init.struct_name, p, c, os, ns); + ASTNode *h = NULL, *t = NULL, *curr = n->struct_init.fields; + while (curr) + { + ASTNode *cp = copy_ast_replacing(curr, p, c, os, ns); + cp->next = NULL; + if (!h) + { + h = cp; + } + else + { + t->next = cp; + } + t = cp; + curr = curr->next; + } + new_node->struct_init.fields = h; + break; + case NODE_IF: + new_node->if_stmt.condition = copy_ast_replacing(n->if_stmt.condition, p, c, os, ns); + new_node->if_stmt.then_body = copy_ast_replacing(n->if_stmt.then_body, p, c, os, ns); + new_node->if_stmt.else_body = copy_ast_replacing(n->if_stmt.else_body, p, c, os, ns); + break; + case NODE_WHILE: + new_node->while_stmt.condition = copy_ast_replacing(n->while_stmt.condition, p, c, os, ns); + new_node->while_stmt.body = copy_ast_replacing(n->while_stmt.body, p, c, os, ns); + break; + case NODE_FOR: + new_node->for_stmt.init = copy_ast_replacing(n->for_stmt.init, p, c, os, ns); + new_node->for_stmt.condition = copy_ast_replacing(n->for_stmt.condition, p, c, os, ns); + new_node->for_stmt.step = copy_ast_replacing(n->for_stmt.step, p, c, os, ns); + new_node->for_stmt.body = copy_ast_replacing(n->for_stmt.body, p, c, os, ns); + break; - case NODE_IMPL: - new_node->impl.struct_name = - replace_type_str(n->impl.struct_name, p, c, os, ns); - new_node->impl.methods = copy_ast_replacing(n->impl.methods, p, c, os, ns); - break; - default: - break; - } - return new_node; + case NODE_MATCH_CASE: + if (n->match_case.pattern) + { + char *s1 = replace_in_string(n->match_case.pattern, p, c); + if (os && ns) + { + char *s2 = replace_in_string(s1, os, ns); + free(s1); + s1 = s2; + char *colons = strstr(s1, "::"); + if (colons) + { + colons[0] = '_'; + memmove(colons + 1, colons + 2, strlen(colons + 2) + 1); + } + } + new_node->match_case.pattern = s1; + } + new_node->match_case.body = copy_ast_replacing(n->match_case.body, p, c, os, ns); + if (n->match_case.guard) + { + new_node->match_case.guard = copy_ast_replacing(n->match_case.guard, p, c, os, ns); + } + break; + + case NODE_IMPL: + new_node->impl.struct_name = replace_type_str(n->impl.struct_name, p, c, os, ns); + new_node->impl.methods = copy_ast_replacing(n->impl.methods, p, c, os, ns); + break; + default: + break; + } + return new_node; } // Helper to sanitize type names for mangling (e.g. "int*" -> "intPtr") -char *sanitize_mangled_name(const char *s) { - char *buf = xmalloc(strlen(s) * 4 + 1); - char *p = buf; - while (*s) { - if (*s == '*') { - strcpy(p, "Ptr"); - p += 3; - } else if (*s == ' ') { - *p++ = '_'; - } else if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || - (*s >= '0' && *s <= '9') || *s == '_') { - *p++ = *s; - } else { - *p++ = '_'; - } - s++; - } - *p = 0; - return buf; -} - -FuncSig *find_func(ParserContext *ctx, const char *name) { - FuncSig *c = ctx->func_registry; - while (c) { - if (strcmp(c->name, name) == 0) { - return c; - } - c = c->next; - } - return NULL; -} - -char *instantiate_function_template(ParserContext *ctx, const char *name, - const char *concrete_type) { - GenericFuncTemplate *tpl = find_func_template(ctx, name); - if (!tpl) { +char *sanitize_mangled_name(const char *s) +{ + char *buf = xmalloc(strlen(s) * 4 + 1); + char *p = buf; + while (*s) + { + if (*s == '*') + { + strcpy(p, "Ptr"); + p += 3; + } + else if (*s == ' ') + { + *p++ = '_'; + } + else if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || + *s == '_') + { + *p++ = *s; + } + else + { + *p++ = '_'; + } + s++; + } + *p = 0; + return buf; +} + +FuncSig *find_func(ParserContext *ctx, const char *name) +{ + FuncSig *c = ctx->func_registry; + while (c) + { + if (strcmp(c->name, name) == 0) + { + return c; + } + c = c->next; + } return NULL; - } +} + +char *instantiate_function_template(ParserContext *ctx, const char *name, const char *concrete_type) +{ + GenericFuncTemplate *tpl = find_func_template(ctx, name); + if (!tpl) + { + return NULL; + } + + char *clean_type = sanitize_mangled_name(concrete_type); + char *mangled = xmalloc(strlen(name) + strlen(clean_type) + 2); + sprintf(mangled, "%s_%s", name, clean_type); + free(clean_type); + + if (find_func(ctx, mangled)) + { + return mangled; + } - char *clean_type = sanitize_mangled_name(concrete_type); - char *mangled = xmalloc(strlen(name) + strlen(clean_type) + 2); - sprintf(mangled, "%s_%s", name, clean_type); - free(clean_type); + ASTNode *new_fn = + copy_ast_replacing(tpl->func_node, tpl->generic_param, concrete_type, NULL, NULL); + if (!new_fn || new_fn->type != NODE_FUNCTION) + { + return NULL; + } + free(new_fn->func.name); + new_fn->func.name = xstrdup(mangled); + + 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, + new_fn->token); - if (find_func(ctx, mangled)) { + add_instantiated_func(ctx, new_fn); return mangled; - } +} - ASTNode *new_fn = copy_ast_replacing(tpl->func_node, tpl->generic_param, - concrete_type, NULL, NULL); - if (!new_fn || new_fn->type != NODE_FUNCTION) { - return NULL; - } - free(new_fn->func.name); - new_fn->func.name = xstrdup(mangled); +char *process_fstring(ParserContext *ctx, const char *content, char ***used_syms, int *count) +{ + (void)ctx; // suppress unused parameter warning + char *gen = xmalloc(4096); + + strcpy(gen, "({ static char _b[1024]; _b[0]=0; char _t[128]; "); + + char *s = xstrdup(content); + char *cur = s; + + while (*cur) + { + char *brace = cur; + while (*brace && *brace != '{') + { + brace++; + } + + if (brace > cur) + { + char tmp = *brace; + *brace = 0; + strcat(gen, "strcat(_b, \""); + strcat(gen, cur); + strcat(gen, "\"); "); + *brace = tmp; + } + + if (*brace == 0) + { + break; + } + + char *p = brace + 1; + char *colon = NULL; + int depth = 1; + + while (*p && depth > 0) + { + if (*p == '{') + { + depth++; + } + if (*p == '}') + { + depth--; + } + if (depth == 1 && *p == ':' && !colon) + { + colon = p; + } + if (depth == 0) + { + break; + } + p++; + } + + *p = 0; + char *expr = brace + 1; + char *fmt = NULL; + if (colon) + { + *colon = 0; + fmt = colon + 1; + } + + // Analyze usage in expression + { + Lexer lex; + lexer_init(&lex, expr); + Token t; + while ((t = lexer_next(&lex)).type != TOK_EOF) + { + if (t.type == TOK_IDENT) + { + char *name = token_strdup(t); + Symbol *sym = find_symbol_entry(ctx, name); + if (sym) + { + sym->is_used = 1; + } + + if (used_syms && count) + { + *used_syms = xrealloc(*used_syms, sizeof(char *) * (*count + 1)); + (*used_syms)[*count] = name; + (*count)++; + } + else + { + free(name); + } + } + } + } - 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, new_fn->token); + if (fmt) + { + strcat(gen, "sprintf(_t, \"%"); + strcat(gen, fmt); + strcat(gen, "\", "); + strcat(gen, expr); + strcat(gen, "); strcat(_b, _t); "); + } + else + { + strcat(gen, "sprintf(_t, _z_str("); + strcat(gen, expr); + strcat(gen, "), "); + strcat(gen, expr); + strcat(gen, "); strcat(_b, _t); "); + } - add_instantiated_func(ctx, new_fn); - return mangled; + cur = p + 1; + } + + strcat(gen, "_b; })"); + free(s); + return gen; } -char *process_fstring(ParserContext *ctx, const char *content, - char ***used_syms, int *count) { - (void)ctx; // suppress unused parameter warning - char *gen = xmalloc(4096); +void register_impl(ParserContext *ctx, const char *trait, const char *strct) +{ + ImplReg *r = xmalloc(sizeof(ImplReg)); + r->trait = xstrdup(trait); + r->strct = xstrdup(strct); + r->next = ctx->registered_impls; + ctx->registered_impls = r; +} - strcpy(gen, "({ static char _b[1024]; _b[0]=0; char _t[128]; "); +int check_impl(ParserContext *ctx, const char *trait, const char *strct) +{ + ImplReg *r = ctx->registered_impls; + while (r) + { + if (strcmp(r->trait, trait) == 0 && strcmp(r->strct, strct) == 0) + { + return 1; + } + r = r->next; + } + return 0; +} - char *s = xstrdup(content); - char *cur = s; +void register_template(ParserContext *ctx, const char *name, ASTNode *node) +{ + GenericTemplate *t = xmalloc(sizeof(GenericTemplate)); + t->name = xstrdup(name); + t->struct_node = node; + t->next = ctx->templates; + ctx->templates = t; +} - while (*cur) { - char *brace = cur; - while (*brace && *brace != '{') { - brace++; +ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char *param, + const char *concrete) +{ + if (!fields) + { + return NULL; } + ASTNode *n = ast_create(NODE_FIELD); + n->field.name = xstrdup(fields->field.name); + + // Replace strings + n->field.type = replace_type_str(fields->field.type, param, concrete, NULL, NULL); - if (brace > cur) { - char tmp = *brace; - *brace = 0; - strcat(gen, "strcat(_b, \""); - strcat(gen, cur); - strcat(gen, "\"); "); - *brace = tmp; + // Replace formal types (Deep Copy) + n->type_info = replace_type_formal(fields->type_info, param, concrete, NULL, NULL); + + if (n->field.type && strchr(n->field.type, '_')) + { + // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry", + // "int") + char *underscore = strrchr(n->field.type, '_'); + if (underscore && underscore > n->field.type) + { + // Remove trailing '*' if present + char *type_copy = xstrdup(n->field.type); + char *star = strchr(type_copy, '*'); + if (star) + { + *star = '\0'; + } + + underscore = strrchr(type_copy, '_'); + if (underscore) + { + *underscore = '\0'; + char *template_name = type_copy; + char *concrete_arg = underscore + 1; + + // Check if this is actually a known generic template + GenericTemplate *gt = ctx->templates; + int found = 0; + while (gt) + { + if (strcmp(gt->name, template_name) == 0) + { + found = 1; + break; + } + gt = gt->next; + } + + if (found) + { + instantiate_generic(ctx, template_name, concrete_arg, fields->token); + } + } + free(type_copy); + } } - if (*brace == 0) { - break; + n->next = copy_fields_replacing(ctx, fields->next, param, concrete); + return n; +} + +void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it, + const char *mangled_struct_name, const char *arg) +{ + if (check_impl(ctx, "Methods", mangled_struct_name)) + { + return; // Simple dedupe check } - char *p = brace + 1; - char *colon = NULL; - int depth = 1; + ASTNode *backup_next = it->impl_node->next; + it->impl_node->next = NULL; // Break link to isolate node + ASTNode *new_impl = copy_ast_replacing(it->impl_node, it->generic_param, arg, it->struct_name, + mangled_struct_name); + it->impl_node->next = backup_next; // Restore - while (*p && depth > 0) { - if (*p == '{') { - depth++; - } - if (*p == '}') { - depth--; - } - if (depth == 1 && *p == ':' && !colon) { - colon = p; - } - if (depth == 0) { - break; - } - p++; + new_impl->impl.struct_name = xstrdup(mangled_struct_name); + ASTNode *meth = new_impl->impl.methods; + while (meth) + { + char *suffix = meth->func.name + strlen(it->struct_name); + if (suffix && *suffix) + { + char *new_name = xmalloc(strlen(mangled_struct_name) + strlen(suffix) + 1); + sprintf(new_name, "%s%s", mangled_struct_name, suffix); + free(meth->func.name); + meth->func.name = new_name; + register_func(ctx, new_name, meth->func.arg_count, meth->func.defaults, + meth->func.arg_types, meth->func.ret_type_info, meth->func.is_varargs, 0, + meth->token); + } + + // Handle generic return types in methods (e.g., Option<T> -> Option_int) + if (meth->func.ret_type && strchr(meth->func.ret_type, '_')) + { + char *ret_copy = xstrdup(meth->func.ret_type); + char *underscore = strrchr(ret_copy, '_'); + if (underscore && underscore > ret_copy) + { + *underscore = '\0'; + char *template_name = ret_copy; + + // Check if this looks like a generic (e.g., "Option_V" or "Result_V") + GenericTemplate *gt = ctx->templates; + while (gt) + { + if (strcmp(gt->name, template_name) == 0) + { + // Found matching template, instantiate it + instantiate_generic(ctx, template_name, arg, meth->token); + break; + } + gt = gt->next; + } + } + free(ret_copy); + } + + meth = meth->next; } + add_instantiated_func(ctx, new_impl); +} - *p = 0; - char *expr = brace + 1; - char *fmt = NULL; - if (colon) { - *colon = 0; - fmt = colon + 1; - } - - // Analyze usage in expression - { - Lexer lex; - lexer_init(&lex, expr); - Token t; - while ((t = lexer_next(&lex)).type != TOK_EOF) { - if (t.type == TOK_IDENT) { - char *name = token_strdup(t); - Symbol *sym = find_symbol_entry(ctx, name); - if (sym) { - sym->is_used = 1; - } - - if (used_syms && count) { - *used_syms = xrealloc(*used_syms, sizeof(char *) * (*count + 1)); - (*used_syms)[*count] = name; - (*count)++; - } else { - free(name); - } - } - } - } - - if (fmt) { - strcat(gen, "sprintf(_t, \"%"); - strcat(gen, fmt); - strcat(gen, "\", "); - strcat(gen, expr); - strcat(gen, "); strcat(_b, _t); "); - } else { - strcat(gen, "sprintf(_t, _z_str("); - strcat(gen, expr); - strcat(gen, "), "); - strcat(gen, expr); - strcat(gen, "); strcat(_b, _t); "); - } - - cur = p + 1; - } - - strcat(gen, "_b; })"); - free(s); - return gen; -} - -void register_impl(ParserContext *ctx, const char *trait, const char *strct) { - ImplReg *r = xmalloc(sizeof(ImplReg)); - r->trait = xstrdup(trait); - r->strct = xstrdup(strct); - r->next = ctx->registered_impls; - ctx->registered_impls = r; -} - -int check_impl(ParserContext *ctx, const char *trait, const char *strct) { - ImplReg *r = ctx->registered_impls; - while (r) { - if (strcmp(r->trait, trait) == 0 && strcmp(r->strct, strct) == 0) { - return 1; - } - r = r->next; - } - return 0; -} - -void register_template(ParserContext *ctx, const char *name, ASTNode *node) { - GenericTemplate *t = xmalloc(sizeof(GenericTemplate)); - t->name = xstrdup(name); - t->struct_node = node; - t->next = ctx->templates; - ctx->templates = t; -} - -ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, - const char *param, const char *concrete) { - if (!fields) { - return NULL; - } - ASTNode *n = ast_create(NODE_FIELD); - n->field.name = xstrdup(fields->field.name); - - // Replace strings - n->field.type = - replace_type_str(fields->field.type, param, concrete, NULL, NULL); - - // Replace formal types (Deep Copy) - n->type_info = - replace_type_formal(fields->type_info, param, concrete, NULL, NULL); - - if (n->field.type && strchr(n->field.type, '_')) { - // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry", - // "int") - char *underscore = strrchr(n->field.type, '_'); - if (underscore && underscore > n->field.type) { - // Remove trailing '*' if present - char *type_copy = xstrdup(n->field.type); - char *star = strchr(type_copy, '*'); - if (star) { - *star = '\0'; - } - - underscore = strrchr(type_copy, '_'); - if (underscore) { - *underscore = '\0'; - char *template_name = type_copy; - char *concrete_arg = underscore + 1; - - // Check if this is actually a known generic template - GenericTemplate *gt = ctx->templates; - int found = 0; - while (gt) { - if (strcmp(gt->name, template_name) == 0) { - found = 1; +void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg, Token token) +{ + // Ignore generic placeholders + if (strlen(arg) == 1 && isupper(arg[0])) + { + return; + } + if (strcmp(arg, "T") == 0) + { + return; + } + + char *clean_arg = sanitize_mangled_name(arg); + char m[256]; + sprintf(m, "%s_%s", tpl, clean_arg); + free(clean_arg); + + Instantiation *c = ctx->instantiations; + while (c) + { + if (strcmp(c->name, m) == 0) + { + return; // Already instantiated, DO NOTHING. + } + c = c->next; + } + + GenericTemplate *t = ctx->templates; + while (t) + { + if (strcmp(t->name, tpl) == 0) + { break; - } - gt = gt->next; } + t = t->next; + } + if (!t) + { + zpanic_at(token, "Unknown generic: %s", tpl); + } + + Instantiation *ni = xmalloc(sizeof(Instantiation)); + ni->name = xstrdup(m); + ni->template_name = xstrdup(tpl); + ni->concrete_arg = xstrdup(arg); + ni->struct_node = NULL; // Placeholder to break cycles + ni->next = ctx->instantiations; + ctx->instantiations = ni; - if (found) { - instantiate_generic(ctx, template_name, concrete_arg, fields->token); + ASTNode *struct_node_copy = NULL; + + if (t->struct_node->type == NODE_STRUCT) + { + ASTNode *i = ast_create(NODE_STRUCT); + i->strct.name = xstrdup(m); + i->strct.is_template = 0; + i->strct.fields = copy_fields_replacing(ctx, t->struct_node->strct.fields, + t->struct_node->strct.generic_param, arg); + struct_node_copy = i; + register_struct_def(ctx, m, i); + } + else if (t->struct_node->type == NODE_ENUM) + { + ASTNode *i = ast_create(NODE_ENUM); + i->enm.name = xstrdup(m); + i->enm.is_template = 0; + ASTNode *h = 0, *tl = 0; + ASTNode *v = t->struct_node->enm.variants; + while (v) + { + ASTNode *nv = ast_create(NODE_ENUM_VARIANT); + nv->variant.name = xstrdup(v->variant.name); + nv->variant.tag_id = v->variant.tag_id; + nv->variant.payload = replace_type_formal( + v->variant.payload, t->struct_node->enm.generic_param, arg, NULL, NULL); + char mangled_var[512]; + sprintf(mangled_var, "%s_%s", m, nv->variant.name); + register_enum_variant(ctx, m, mangled_var, nv->variant.tag_id); + if (!h) + { + h = nv; + } + else + { + tl->next = nv; + } + tl = nv; + v = v->next; } - } - free(type_copy); + i->enm.variants = h; + struct_node_copy = i; + } + + ni->struct_node = struct_node_copy; + + if (struct_node_copy) + { + struct_node_copy->next = ctx->instantiated_structs; + ctx->instantiated_structs = struct_node_copy; } - } - n->next = copy_fields_replacing(ctx, fields->next, param, concrete); - return n; + GenericImplTemplate *it = ctx->impl_templates; + while (it) + { + if (strcmp(it->struct_name, tpl) == 0) + { + instantiate_methods(ctx, it, m, arg); + } + it = it->next; + } } -void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it, - const char *mangled_struct_name, const char *arg) { - if (check_impl(ctx, "Methods", mangled_struct_name)) { - return; // Simple dedupe check - } - - ASTNode *backup_next = it->impl_node->next; - it->impl_node->next = NULL; // Break link to isolate node - ASTNode *new_impl = copy_ast_replacing(it->impl_node, it->generic_param, arg, - it->struct_name, mangled_struct_name); - it->impl_node->next = backup_next; // Restore - - new_impl->impl.struct_name = xstrdup(mangled_struct_name); - ASTNode *meth = new_impl->impl.methods; - while (meth) { - char *suffix = strchr(meth->func.name, '_'); - if (suffix) { - char *new_name = - xmalloc(strlen(mangled_struct_name) + strlen(suffix) + 1); - sprintf(new_name, "%s%s", mangled_struct_name, suffix); - free(meth->func.name); - meth->func.name = new_name; - register_func(ctx, new_name, meth->func.arg_count, meth->func.defaults, - meth->func.arg_types, meth->func.ret_type_info, - meth->func.is_varargs, 0, meth->token); - } - - // Handle generic return types in methods (e.g., Option<T> -> Option_int) - if (meth->func.ret_type && strchr(meth->func.ret_type, '_')) { - char *ret_copy = xstrdup(meth->func.ret_type); - char *underscore = strrchr(ret_copy, '_'); - if (underscore && underscore > ret_copy) { - *underscore = '\0'; - char *template_name = ret_copy; - - // Check if this looks like a generic (e.g., "Option_V" or "Result_V") - GenericTemplate *gt = ctx->templates; - while (gt) { - if (strcmp(gt->name, template_name) == 0) { - // Found matching template, instantiate it - instantiate_generic(ctx, template_name, arg, meth->token); - break; - } - gt = gt->next; - } - } - free(ret_copy); - } - - meth = meth->next; - } - add_instantiated_func(ctx, new_impl); -} - -void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg, - Token token) { - // Ignore generic placeholders - if (strlen(arg) == 1 && isupper(arg[0])) { - return; - } - if (strcmp(arg, "T") == 0) { - return; - } - - char *clean_arg = sanitize_mangled_name(arg); - char m[256]; - sprintf(m, "%s_%s", tpl, clean_arg); - free(clean_arg); - - Instantiation *c = ctx->instantiations; - while (c) { - if (strcmp(c->name, m) == 0) { - return; // Already instantiated, DO NOTHING. - } - c = c->next; - } - - GenericTemplate *t = ctx->templates; - while (t) { - if (strcmp(t->name, tpl) == 0) { - break; - } - t = t->next; - } - if (!t) { - zpanic_at(token, "Unknown generic: %s", tpl); - } - - Instantiation *ni = xmalloc(sizeof(Instantiation)); - ni->name = xstrdup(m); - ni->template_name = xstrdup(tpl); - ni->concrete_arg = xstrdup(arg); - ni->struct_node = NULL; // Placeholder to break cycles - ni->next = ctx->instantiations; - ctx->instantiations = ni; - - ASTNode *struct_node_copy = NULL; - - if (t->struct_node->type == NODE_STRUCT) { - ASTNode *i = ast_create(NODE_STRUCT); - i->strct.name = xstrdup(m); - i->strct.is_template = 0; - i->strct.fields = - copy_fields_replacing(ctx, t->struct_node->strct.fields, - t->struct_node->strct.generic_param, arg); - struct_node_copy = i; - register_struct_def(ctx, m, i); - } else if (t->struct_node->type == NODE_ENUM) { - ASTNode *i = ast_create(NODE_ENUM); - i->enm.name = xstrdup(m); - i->enm.is_template = 0; - ASTNode *h = 0, *tl = 0; - ASTNode *v = t->struct_node->enm.variants; - while (v) { - ASTNode *nv = ast_create(NODE_ENUM_VARIANT); - nv->variant.name = xstrdup(v->variant.name); - nv->variant.tag_id = v->variant.tag_id; - nv->variant.payload = replace_type_formal( - v->variant.payload, t->struct_node->enm.generic_param, arg, NULL, - NULL); - char mangled_var[512]; - sprintf(mangled_var, "%s_%s", m, nv->variant.name); - register_enum_variant(ctx, m, mangled_var, nv->variant.tag_id); - if (!h) { - h = nv; - } else { - tl->next = nv; - } - tl = nv; - v = v->next; - } - i->enm.variants = h; - struct_node_copy = i; - } - - ni->struct_node = struct_node_copy; - - if (struct_node_copy) { - struct_node_copy->next = ctx->instantiated_structs; - ctx->instantiated_structs = struct_node_copy; - } - - GenericImplTemplate *it = ctx->impl_templates; - while (it) { - if (strcmp(it->struct_name, tpl) == 0) { - instantiate_methods(ctx, it, m, arg); - } - it = it->next; - } -} - -int is_file_imported(ParserContext *ctx, const char *p) { - ImportedFile *c = ctx->imported_files; - while (c) { - if (strcmp(c->path, p) == 0) { - return 1; - } - c = c->next; - } - return 0; -} - -void mark_file_imported(ParserContext *ctx, const char *p) { - ImportedFile *f = xmalloc(sizeof(ImportedFile)); - f->path = xstrdup(p); - f->next = ctx->imported_files; - ctx->imported_files = f; -} - -char *parse_condition_raw(ParserContext *ctx, Lexer *l) { - (void)ctx; // suppress unused parameter warning - Token t = lexer_peek(l); - if (t.type == TOK_LPAREN) { - Token op = lexer_next(l); - const char *s = op.start; - int d = 1; - while (d > 0) { - t = lexer_next(l); - if (t.type == TOK_EOF) { - zpanic_at(t, "Unterminated condition"); - } - if (t.type == TOK_LPAREN) { - d++; - } - if (t.type == TOK_RPAREN) { - d--; - } - } - const char *cs = s + 1; - int len = t.start - cs; - char *c = xmalloc(len + 1); - strncpy(c, cs, len); - c[len] = 0; - return c; - } else { - const char *start = l->src + l->pos; - while (1) { - t = lexer_peek(l); - if (t.type == TOK_LBRACE || t.type == TOK_EOF) { - break; - } - lexer_next(l); +int is_file_imported(ParserContext *ctx, const char *p) +{ + ImportedFile *c = ctx->imported_files; + while (c) + { + if (strcmp(c->path, p) == 0) + { + return 1; + } + c = c->next; } - int len = (l->src + l->pos) - start; - if (len == 0) { - zpanic_at(lexer_peek(l), "Empty condition or missing body"); + return 0; +} + +void mark_file_imported(ParserContext *ctx, const char *p) +{ + ImportedFile *f = xmalloc(sizeof(ImportedFile)); + f->path = xstrdup(p); + f->next = ctx->imported_files; + ctx->imported_files = f; +} + +char *parse_condition_raw(ParserContext *ctx, Lexer *l) +{ + (void)ctx; // suppress unused parameter warning + Token t = lexer_peek(l); + if (t.type == TOK_LPAREN) + { + Token op = lexer_next(l); + const char *s = op.start; + int d = 1; + while (d > 0) + { + t = lexer_next(l); + if (t.type == TOK_EOF) + { + zpanic_at(t, "Unterminated condition"); + } + if (t.type == TOK_LPAREN) + { + d++; + } + if (t.type == TOK_RPAREN) + { + d--; + } + } + const char *cs = s + 1; + int len = t.start - cs; + char *c = xmalloc(len + 1); + strncpy(c, cs, len); + c[len] = 0; + return c; + } + else + { + const char *start = l->src + l->pos; + while (1) + { + t = lexer_peek(l); + if (t.type == TOK_LBRACE || t.type == TOK_EOF) + { + break; + } + lexer_next(l); + } + int len = (l->src + l->pos) - start; + if (len == 0) + { + zpanic_at(lexer_peek(l), "Empty condition or missing body"); + } + char *c = xmalloc(len + 1); + strncpy(c, start, len); + c[len] = 0; + return c; } - char *c = xmalloc(len + 1); - strncpy(c, start, len); - c[len] = 0; - return c; - } } -char *rewrite_expr_methods(ParserContext *ctx, char *raw) { - if (!raw) { - return NULL; - } - - int in_expr = 0; - char *result = xmalloc(strlen(raw) * 4 + 100); - char *dest = result; - char *src = raw; - - while (*src) { - if (strncmp(src, "#{", 2) == 0) { - in_expr = 1; - src += 2; - *dest++ = '('; - continue; - } - - if (in_expr && *src == '}') { - in_expr = 0; - *dest++ = ')'; - src++; - continue; - } - - if (in_expr && *src == '.') { - char acc[64]; - int i = 0; - char *back = src - 1; - while (back >= raw && (isalnum(*back) || *back == '_')) { - back--; - } - back++; - while (back < src && i < 63) { - acc[i++] = *back++; - } - acc[i] = 0; - - char *vtype = find_symbol_type(ctx, acc); - if (!vtype) { - *dest++ = *src++; - continue; - } - - char method[64]; - i = 0; - src++; - while (isalnum(*src) || *src == '_') { - method[i++] = *src++; - } - method[i] = 0; - - // Check for field access - char *base_t = xstrdup(vtype); - char *pc = strchr(base_t, '*'); - int is_ptr_type = (pc != NULL); - if (pc) { - *pc = 0; - } - - ASTNode *def = find_struct_def(ctx, base_t); - int is_field = 0; - if (def && (def->type == NODE_STRUCT)) { - ASTNode *f = def->strct.fields; - while (f) { - if (strcmp(f->field.name, method) == 0) { - is_field = 1; - break; - } - f = f->next; - } - } - free(base_t); - - if (is_field) { - dest -= strlen(acc); - if (is_ptr_type) { - dest += sprintf(dest, "(%s)->%s", acc, method); - } else { - dest += sprintf(dest, "(%s).%s", acc, method); - } - continue; - } - - if (*src == '(') { - dest -= strlen(acc); - int paren_depth = 0; - src++; - paren_depth++; - - char ptr_check[64]; - strcpy(ptr_check, vtype); - int is_ptr = (strchr(ptr_check, '*') != NULL); - if (is_ptr) { - char *p = strchr(ptr_check, '*'); - if (p) { - *p = 0; - } - } - - dest += sprintf(dest, "%s_%s(%s%s", ptr_check, method, - is_ptr ? "" : "&", acc); - - int has_args = 0; - while (*src && paren_depth > 0) { - if (!isspace(*src)) { - has_args = 1; - } - if (*src == '(') { - paren_depth++; - } - if (*src == ')') { - paren_depth--; - } - if (paren_depth == 0) { - break; - } - *dest++ = *src++; - } - - if (has_args) { - *dest++ = ')'; - } else { - *dest++ = ')'; - } - - src++; - continue; - } else { - dest -= strlen(acc); - char ptr_check[64]; - strcpy(ptr_check, vtype); - int is_ptr = (strchr(ptr_check, '*') != NULL); - if (is_ptr) { - char *p = strchr(ptr_check, '*'); - if (p) { - *p = 0; - } - } - dest += sprintf(dest, "%s_%s(%s%s)", ptr_check, method, - is_ptr ? "" : "&", acc); - continue; - } - } - - if (!in_expr && strncmp(src, "::", 2) == 0) { - char acc[64]; - int i = 0; - char *back = src - 1; - while (back >= raw && (isalnum(*back) || *back == '_')) { - back--; - } - back++; - while (back < src && i < 63) { - acc[i++] = *back++; - } - acc[i] = 0; - - src += 2; - char field[64]; - i = 0; - while (isalnum(*src) || *src == '_') { - field[i++] = *src++; - } - field[i] = 0; - - dest -= strlen(acc); - - Module *mod = find_module(ctx, acc); - if (mod && mod->is_c_header) { - dest += sprintf(dest, "%s", field); - } else { - dest += sprintf(dest, "%s_%s", acc, field); - } - continue; - } - - if (in_expr && isalpha(*src)) { - char tok[128]; - int i = 0; - while ((isalnum(*src) || *src == '_') && i < 127) { - tok[i++] = *src++; - } - tok[i] = 0; - - while (*src == ' ' || *src == '\t') { - src++; - } - - if (strncmp(src, "::", 2) == 0) { - src += 2; - char func_name[128]; - snprintf(func_name, sizeof(func_name), "%s", tok); - char method[64]; - i = 0; - while (isalnum(*src) || *src == '_') { - method[i++] = *src++; - } - method[i] = 0; - - while (*src == ' ' || *src == '\t') { - src++; - } - - if (*src == '(') { - src++; - - char mangled[256]; - snprintf(mangled, sizeof(mangled), "%s_%s", func_name, method); - - if (*src == ')') { - dest += sprintf(dest, "%s()", mangled); +char *rewrite_expr_methods(ParserContext *ctx, char *raw) +{ + if (!raw) + { + return NULL; + } + + int in_expr = 0; + char *result = xmalloc(strlen(raw) * 4 + 100); + char *dest = result; + char *src = raw; + + while (*src) + { + if (strncmp(src, "#{", 2) == 0) + { + in_expr = 1; + src += 2; + *dest++ = '('; + continue; + } + + if (in_expr && *src == '}') + { + in_expr = 0; + *dest++ = ')'; src++; - } else { - FuncSig *sig = find_func(ctx, func_name); - if (sig) { - dest += sprintf(dest, "%s(&(%s){0}", mangled, func_name); - while (*src && *src != ')') { + continue; + } + + if (in_expr && *src == '.') + { + char acc[64]; + int i = 0; + char *back = src - 1; + while (back >= raw && (isalnum(*back) || *back == '_')) + { + back--; + } + back++; + while (back < src && i < 63) + { + acc[i++] = *back++; + } + acc[i] = 0; + + char *vtype = find_symbol_type(ctx, acc); + if (!vtype) + { *dest++ = *src++; - } - *dest++ = ')'; - if (*src == ')') { + continue; + } + + char method[64]; + i = 0; + src++; + while (isalnum(*src) || *src == '_') + { + method[i++] = *src++; + } + method[i] = 0; + + // Check for field access + char *base_t = xstrdup(vtype); + char *pc = strchr(base_t, '*'); + int is_ptr_type = (pc != NULL); + if (pc) + { + *pc = 0; + } + + ASTNode *def = find_struct_def(ctx, base_t); + int is_field = 0; + if (def && (def->type == NODE_STRUCT)) + { + ASTNode *f = def->strct.fields; + while (f) + { + if (strcmp(f->field.name, method) == 0) + { + is_field = 1; + break; + } + f = f->next; + } + } + free(base_t); + + if (is_field) + { + dest -= strlen(acc); + if (is_ptr_type) + { + dest += sprintf(dest, "(%s)->%s", acc, method); + } + else + { + dest += sprintf(dest, "(%s).%s", acc, method); + } + continue; + } + + if (*src == '(') + { + dest -= strlen(acc); + int paren_depth = 0; src++; - } - } else { - dest += sprintf(dest, "%s(", mangled); - while (*src && *src != ')') { - *dest++ = *src++; - } - *dest++ = ')'; - if (*src == ')') { + paren_depth++; + + char ptr_check[64]; + strcpy(ptr_check, vtype); + int is_ptr = (strchr(ptr_check, '*') != NULL); + if (is_ptr) + { + char *p = strchr(ptr_check, '*'); + if (p) + { + *p = 0; + } + } + + dest += sprintf(dest, "%s__%s(%s%s", ptr_check, method, is_ptr ? "" : "&", acc); + + int has_args = 0; + while (*src && paren_depth > 0) + { + if (!isspace(*src)) + { + has_args = 1; + } + if (*src == '(') + { + paren_depth++; + } + if (*src == ')') + { + paren_depth--; + } + if (paren_depth == 0) + { + break; + } + *dest++ = *src++; + } + + if (has_args) + { + *dest++ = ')'; + } + else + { + *dest++ = ')'; + } + src++; - } + continue; } - } - continue; - } - } - - strcpy(dest, tok); - dest += strlen(tok); - continue; - } - - *dest++ = *src++; - } - - *dest = 0; - return result; -} - -char *consume_and_rewrite(ParserContext *ctx, Lexer *l) { - char *r = consume_until_semicolon(l); - char *rw = rewrite_expr_methods(ctx, r); - free(r); - return rw; -} - -char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out, - int *count_out, Type ***types_out, - char ***names_out, int *is_varargs_out) { - Token t = lexer_next(l); - if (t.type != TOK_LPAREN) { - zpanic_at(t, "Expected '(' in function args"); - } - - char *buf = xmalloc(1024); - buf[0] = 0; - int count = 0; - char **defaults = xmalloc(sizeof(char *) * 16); - Type **types = xmalloc(sizeof(Type *) * 16); - char **names = xmalloc(sizeof(char *) * 16); - - for (int i = 0; i < 16; i++) { - defaults[i] = NULL; - types[i] = NULL; - names[i] = NULL; - } - - if (lexer_peek(l).type != TOK_RPAREN) { - while (1) { - Token t = lexer_next(l); - // Handle 'self' - if (t.type == TOK_IDENT && strncmp(t.start, "self", 4) == 0 && - t.len == 4) { - names[count] = xstrdup("self"); - if (ctx->current_impl_struct) { - Type *st = NULL; - // Check for primitives to avoid creating struct int* - if (strcmp(ctx->current_impl_struct, "int") == 0) { - st = type_new(TYPE_INT); - } else if (strcmp(ctx->current_impl_struct, "float") == 0) { - st = type_new(TYPE_F32); - } else if (strcmp(ctx->current_impl_struct, "char") == 0) { - st = type_new(TYPE_CHAR); - } else if (strcmp(ctx->current_impl_struct, "bool") == 0) { - st = type_new(TYPE_BOOL); - } else if (strcmp(ctx->current_impl_struct, "string") == 0) { - st = type_new(TYPE_STRING); - } - // Add other primitives as needed - else { - st = type_new(TYPE_STRUCT); - st->name = xstrdup(ctx->current_impl_struct); - } - Type *pt = type_new_ptr(st); - - char buf_type[256]; - sprintf(buf_type, "%s*", ctx->current_impl_struct); - // Register 'self' with actual type in symbol table - add_symbol(ctx, "self", buf_type, pt); - - types[count] = pt; - - strcat(buf, "void* self"); - } else { - strcat(buf, "void* self"); - types[count] = type_new_ptr(type_new(TYPE_VOID)); - add_symbol(ctx, "self", "void*", types[count]); - } - count++; - } else { - if (t.type != TOK_IDENT) { - zpanic_at(lexer_peek(l), "Expected arg name"); - } - char *name = token_strdup(t); - names[count] = name; // Store name - if (lexer_next(l).type != TOK_COLON) { - zpanic_at(lexer_peek(l), "Expected ':'"); - } - - Type *arg_type = parse_type_formal(ctx, l); - char *type_str = type_to_string(arg_type); - - add_symbol(ctx, name, type_str, arg_type); - types[count] = arg_type; - - if (strlen(buf) > 0) { - strcat(buf, ", "); - } - - char *fn_ptr = strstr(type_str, "(*)"); - if (arg_type->kind == TYPE_FUNCTION) { - strcat(buf, "z_closure_T "); - strcat(buf, name); - } else if (fn_ptr) { - // Inject name into function pointer: int (*)(int) -> int (*name)(int) - int prefix_len = fn_ptr - type_str; - strncat(buf, type_str, prefix_len); - strcat(buf, " (*"); - strcat(buf, name); - strcat(buf, ")"); - strcat(buf, fn_ptr + 3); // Skip "(*)" - } else { - strcat(buf, type_str); - strcat(buf, " "); - strcat(buf, name); - } - - count++; - - if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "=")) { - lexer_next(l); - Token val = lexer_next(l); - defaults[count - 1] = token_strdup(val); - } - } - if (lexer_peek(l).type == TOK_COMMA) { - lexer_next(l); - // Check if next is ... - if (lexer_peek(l).type == TOK_ELLIPSIS) { - lexer_next(l); - if (is_varargs_out) { - *is_varargs_out = 1; - } - if (strlen(buf) > 0) { - strcat(buf, ", "); - } - strcat(buf, "..."); - break; // Must be last - } - } else { - break; - } + else + { + dest -= strlen(acc); + char ptr_check[64]; + strcpy(ptr_check, vtype); + int is_ptr = (strchr(ptr_check, '*') != NULL); + if (is_ptr) + { + char *p = strchr(ptr_check, '*'); + if (p) + { + *p = 0; + } + } + dest += sprintf(dest, "%s__%s(%s%s)", ptr_check, method, is_ptr ? "" : "&", acc); + continue; + } + } + + if (!in_expr && strncmp(src, "::", 2) == 0) + { + char acc[64]; + int i = 0; + char *back = src - 1; + while (back >= raw && (isalnum(*back) || *back == '_')) + { + back--; + } + back++; + while (back < src && i < 63) + { + acc[i++] = *back++; + } + acc[i] = 0; + + src += 2; + char field[64]; + i = 0; + while (isalnum(*src) || *src == '_') + { + field[i++] = *src++; + } + field[i] = 0; + + dest -= strlen(acc); + + Module *mod = find_module(ctx, acc); + if (mod && mod->is_c_header) + { + dest += sprintf(dest, "%s", field); + } + else + { + ASTNode *sdef = find_struct_def(ctx, acc); + if (sdef && sdef->type == NODE_ENUM) + { + // For Enums, check if it's a variant + int is_variant = 0; + ASTNode *v = sdef->enm.variants; + while (v) + { + if (strcmp(v->variant.name, field) == 0) + { + is_variant = 1; + break; + } + v = v->next; + } + if (is_variant) + { + dest += sprintf(dest, "%s_%s", acc, field); + } + else + { + // Static method on Enum + dest += sprintf(dest, "%s__%s", acc, field); + } + } + else if (sdef || !mod) + { + // Struct static method, or Type static method + dest += sprintf(dest, "%s__%s", acc, field); + } + else + { + // Module function + dest += sprintf(dest, "%s_%s", acc, field); + } + } + continue; + } + + if (in_expr && isalpha(*src)) + { + char tok[128]; + int i = 0; + while ((isalnum(*src) || *src == '_') && i < 127) + { + tok[i++] = *src++; + } + tok[i] = 0; + + while (*src == ' ' || *src == '\t') + { + src++; + } + + if (strncmp(src, "::", 2) == 0) + { + src += 2; + char func_name[128]; + snprintf(func_name, sizeof(func_name), "%s", tok); + char method[64]; + i = 0; + while (isalnum(*src) || *src == '_') + { + method[i++] = *src++; + } + method[i] = 0; + + while (*src == ' ' || *src == '\t') + { + src++; + } + + if (*src == '(') + { + src++; + + char mangled[256]; + snprintf(mangled, sizeof(mangled), "%s_%s", func_name, method); + + if (*src == ')') + { + dest += sprintf(dest, "%s()", mangled); + src++; + } + else + { + FuncSig *sig = find_func(ctx, func_name); + if (sig) + { + dest += sprintf(dest, "%s(&(%s){0}", mangled, func_name); + while (*src && *src != ')') + { + *dest++ = *src++; + } + *dest++ = ')'; + if (*src == ')') + { + src++; + } + } + else + { + dest += sprintf(dest, "%s(", mangled); + while (*src && *src != ')') + { + *dest++ = *src++; + } + *dest++ = ')'; + if (*src == ')') + { + src++; + } + } + } + continue; + } + } + + strcpy(dest, tok); + dest += strlen(tok); + continue; + } + + *dest++ = *src++; + } + + *dest = 0; + return result; +} + +char *consume_and_rewrite(ParserContext *ctx, Lexer *l) +{ + char *r = consume_until_semicolon(l); + char *rw = rewrite_expr_methods(ctx, r); + free(r); + return rw; +} + +char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out, int *count_out, + Type ***types_out, char ***names_out, int *is_varargs_out) +{ + Token t = lexer_next(l); + if (t.type != TOK_LPAREN) + { + zpanic_at(t, "Expected '(' in function args"); + } + + char *buf = xmalloc(1024); + buf[0] = 0; + int count = 0; + char **defaults = xmalloc(sizeof(char *) * 16); + Type **types = xmalloc(sizeof(Type *) * 16); + char **names = xmalloc(sizeof(char *) * 16); + + for (int i = 0; i < 16; i++) + { + defaults[i] = NULL; + types[i] = NULL; + names[i] = NULL; + } + + if (lexer_peek(l).type != TOK_RPAREN) + { + while (1) + { + Token t = lexer_next(l); + // Handle 'self' + if (t.type == TOK_IDENT && strncmp(t.start, "self", 4) == 0 && t.len == 4) + { + names[count] = xstrdup("self"); + if (ctx->current_impl_struct) + { + Type *st = NULL; + // Check for primitives to avoid creating struct int* + if (strcmp(ctx->current_impl_struct, "int") == 0) + { + st = type_new(TYPE_INT); + } + else if (strcmp(ctx->current_impl_struct, "float") == 0) + { + st = type_new(TYPE_F32); + } + else if (strcmp(ctx->current_impl_struct, "char") == 0) + { + st = type_new(TYPE_CHAR); + } + else if (strcmp(ctx->current_impl_struct, "bool") == 0) + { + st = type_new(TYPE_BOOL); + } + else if (strcmp(ctx->current_impl_struct, "string") == 0) + { + st = type_new(TYPE_STRING); + } + // Add other primitives as needed + else + { + st = type_new(TYPE_STRUCT); + st->name = xstrdup(ctx->current_impl_struct); + } + Type *pt = type_new_ptr(st); + + char buf_type[256]; + sprintf(buf_type, "%s*", ctx->current_impl_struct); + // Register 'self' with actual type in symbol table + add_symbol(ctx, "self", buf_type, pt); + + types[count] = pt; + + strcat(buf, "void* self"); + } + else + { + strcat(buf, "void* self"); + types[count] = type_new_ptr(type_new(TYPE_VOID)); + add_symbol(ctx, "self", "void*", types[count]); + } + count++; + } + else + { + if (t.type != TOK_IDENT) + { + zpanic_at(lexer_peek(l), "Expected arg name"); + } + char *name = token_strdup(t); + names[count] = name; // Store name + if (lexer_next(l).type != TOK_COLON) + { + zpanic_at(lexer_peek(l), "Expected ':'"); + } + + Type *arg_type = parse_type_formal(ctx, l); + char *type_str = type_to_string(arg_type); + + add_symbol(ctx, name, type_str, arg_type); + types[count] = arg_type; + + if (strlen(buf) > 0) + { + strcat(buf, ", "); + } + + char *fn_ptr = strstr(type_str, "(*)"); + if (arg_type->kind == TYPE_FUNCTION) + { + strcat(buf, "z_closure_T "); + strcat(buf, name); + } + else if (fn_ptr) + { + // Inject name into function pointer: int (*)(int) -> int (*name)(int) + int prefix_len = fn_ptr - type_str; + strncat(buf, type_str, prefix_len); + strcat(buf, " (*"); + strcat(buf, name); + strcat(buf, ")"); + strcat(buf, fn_ptr + 3); // Skip "(*)" + } + else + { + strcat(buf, type_str); + strcat(buf, " "); + strcat(buf, name); + } + + count++; + + if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "=")) + { + lexer_next(l); + Token val = lexer_next(l); + defaults[count - 1] = token_strdup(val); + } + } + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + // Check if next is ... + if (lexer_peek(l).type == TOK_ELLIPSIS) + { + lexer_next(l); + if (is_varargs_out) + { + *is_varargs_out = 1; + } + if (strlen(buf) > 0) + { + strcat(buf, ", "); + } + strcat(buf, "..."); + break; // Must be last + } + } + else + { + break; + } + } + } + if (lexer_next(l).type != TOK_RPAREN) + { + zpanic_at(lexer_peek(l), "Expected ')' after args"); } - } - if (lexer_next(l).type != TOK_RPAREN) { - zpanic_at(lexer_peek(l), "Expected ')' after args"); - } - *defaults_out = defaults; - *count_out = count; - *types_out = types; - *names_out = names; - return buf; + *defaults_out = defaults; + *count_out = count; + *types_out = types; + *names_out = names; + return buf; } // Helper to find similar symbol name in current scope -char *find_similar_symbol(ParserContext *ctx, const char *name) { - if (!ctx->current_scope) { - return NULL; - } - - const char *best_match = NULL; - int best_dist = 999; - - // Check local scopes - Scope *s = ctx->current_scope; - while (s) { - Symbol *sym = s->symbols; - while (sym) { - int dist = levenshtein(name, sym->name); - if (dist < best_dist && dist <= 3) { - best_dist = dist; - best_match = sym->name; - } - sym = sym->next; - } - s = s->parent; - } - - // Check builtins/globals if any (simplified) - return best_match ? xstrdup(best_match) : NULL; -} - -void register_plugin(ParserContext *ctx, const char *name, const char *alias) { - // Try to find existing (built-in) or already loaded plugin - ZPlugin *plugin = zptr_find_plugin(name); - - // If not found, try to load it dynamically - if (!plugin) { - plugin = zptr_load_plugin(name); - - if (!plugin) { - char path[1024]; - snprintf(path, sizeof(path), "%s.so", name); - plugin = zptr_load_plugin(path); - } - - if (!plugin && !strchr(name, '/')) { - char path[1024]; - snprintf(path, sizeof(path), "./%s.so", name); - plugin = zptr_load_plugin(path); - } - } - - if (!plugin) { - fprintf(stderr, - COLOR_RED "Error:" COLOR_RESET " Could not load plugin '%s'\n" - " Tried built-ins and dynamic loading (.so)\n", - name); - exit(1); - } - - ImportedPlugin *p = xmalloc(sizeof(ImportedPlugin)); - p->name = xstrdup(plugin->name); // Use the plugin's internal name - p->alias = alias ? xstrdup(alias) : NULL; - p->next = ctx->imported_plugins; - ctx->imported_plugins = p; -} - -const char *resolve_plugin(ParserContext *ctx, const char *name_or_alias) { - for (ImportedPlugin *p = ctx->imported_plugins; p; p = p->next) { - // Check if it matches the alias - if (p->alias && strcmp(p->alias, name_or_alias) == 0) { - return p->name; - } - // Check if it matches the name - if (strcmp(p->name, name_or_alias) == 0) { - return p->name; - } - } - return NULL; // Plugin not found +char *find_similar_symbol(ParserContext *ctx, const char *name) +{ + if (!ctx->current_scope) + { + return NULL; + } + + const char *best_match = NULL; + int best_dist = 999; + + // Check local scopes + Scope *s = ctx->current_scope; + while (s) + { + Symbol *sym = s->symbols; + while (sym) + { + int dist = levenshtein(name, sym->name); + if (dist < best_dist && dist <= 3) + { + best_dist = dist; + best_match = sym->name; + } + sym = sym->next; + } + s = s->parent; + } + + // Check builtins/globals if any (simplified) + return best_match ? xstrdup(best_match) : NULL; +} + +void register_plugin(ParserContext *ctx, const char *name, const char *alias) +{ + // Try to find existing (built-in) or already loaded plugin + ZPlugin *plugin = zptr_find_plugin(name); + + // If not found, try to load it dynamically + if (!plugin) + { + plugin = zptr_load_plugin(name); + + if (!plugin) + { + char path[1024]; + snprintf(path, sizeof(path), "%s.so", name); + plugin = zptr_load_plugin(path); + } + + if (!plugin && !strchr(name, '/')) + { + char path[1024]; + snprintf(path, sizeof(path), "./%s.so", name); + plugin = zptr_load_plugin(path); + } + } + + if (!plugin) + { + fprintf(stderr, + COLOR_RED "Error:" COLOR_RESET " Could not load plugin '%s'\n" + " Tried built-ins and dynamic loading (.so)\n", + name); + exit(1); + } + + ImportedPlugin *p = xmalloc(sizeof(ImportedPlugin)); + p->name = xstrdup(plugin->name); // Use the plugin's internal name + p->alias = alias ? xstrdup(alias) : NULL; + p->next = ctx->imported_plugins; + ctx->imported_plugins = p; +} + +const char *resolve_plugin(ParserContext *ctx, const char *name_or_alias) +{ + for (ImportedPlugin *p = ctx->imported_plugins; p; p = p->next) + { + // Check if it matches the alias + if (p->alias && strcmp(p->alias, name_or_alias) == 0) + { + return p->name; + } + // Check if it matches the name + if (strcmp(p->name, name_or_alias) == 0) + { + return p->name; + } + } + return NULL; // Plugin not found } |
