#include "parser.h" #include #include #include #include #include #include "../ast/ast.h" #include "../plugins/plugin_manager.h" #include "../zen/zen_facts.h" #include "zprep_plugin.h" #include "../codegen/codegen.h" // Trait Parsing ASTNode *parse_trait(ParserContext *ctx, Lexer *l) { lexer_next(l); // eat trait Token n = lexer_next(l); if (n.type != TOK_IDENT) { zpanic_at(n, "Expected trait name"); } char *name = xmalloc(n.len + 1); strncpy(name, n.start, n.len); name[n.len] = 0; // Generics char **generic_params = NULL; int generic_count = 0; if (lexer_peek(l).type == TOK_LANGLE) { lexer_next(l); // eat < generic_params = xmalloc(sizeof(char *) * 8); // simplified while (1) { Token p = lexer_next(l); if (p.type != TOK_IDENT) { zpanic_at(p, "Expected generic parameter name"); } generic_params[generic_count] = xmalloc(p.len + 1); strncpy(generic_params[generic_count], p.start, p.len); generic_params[generic_count][p.len] = 0; generic_count++; Token sep = lexer_peek(l); if (sep.type == TOK_COMMA) { lexer_next(l); continue; } else if (sep.type == TOK_RANGLE) { lexer_next(l); break; } else { zpanic_at(sep, "Expected , or > in generic params"); } } } if (generic_count > 0) { for (int i = 0; i < generic_count; i++) { register_generic(ctx, generic_params[i]); } } lexer_next(l); // eat { ASTNode *methods = NULL, *tail = NULL; while (1) { skip_comments(l); if (lexer_peek(l).type == TOK_RBRACE) { lexer_next(l); break; } // Parse method signature: fn name(args...) -> ret; Token ft = lexer_next(l); if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0) { zpanic_at(ft, "Expected fn in trait"); } Token mn = lexer_next(l); char *mname = xmalloc(mn.len + 1); strncpy(mname, mn.start, mn.len); mname[mn.len] = 0; char **defaults = NULL; int arg_count = 0; Type **arg_types = NULL; char **param_names = NULL; int is_varargs = 0; char *args = parse_and_convert_args(ctx, l, &defaults, &arg_count, &arg_types, ¶m_names, &is_varargs); char *ret = xstrdup("void"); if (lexer_peek(l).type == TOK_ARROW) { lexer_next(l); char *rt = parse_type(ctx, l); free(ret); ret = rt; } if (lexer_peek(l).type == TOK_SEMICOLON) { lexer_next(l); ASTNode *m = ast_create(NODE_FUNCTION); m->func.param_names = param_names; m->func.name = mname; m->func.args = args; m->func.ret_type = ret; m->func.body = NULL; if (!methods) { methods = m; } else { tail->next = m; } tail = m; } else { // Default implementation? Not supported yet. zpanic_at(lexer_peek(l), "Trait methods must end with ; for now"); } } ASTNode *n_node = ast_create(NODE_TRAIT); n_node->trait.name = name; n_node->trait.methods = methods; n_node->trait.generic_params = generic_params; n_node->trait.generic_param_count = generic_count; register_trait(name); return n_node; } ASTNode *parse_impl(ParserContext *ctx, Lexer *l) { lexer_next(l); // eat impl Token t1 = lexer_next(l); char *name1 = token_strdup(t1); char *gen_param = NULL; // Check for on the struct name if (lexer_peek(l).type == TOK_LANGLE) { lexer_next(l); // eat < Token gt = lexer_next(l); gen_param = token_strdup(gt); if (lexer_next(l).type != TOK_RANGLE) { zpanic_at(lexer_peek(l), "Expected >"); } } // Check for "for" (Trait impl) Token pk = lexer_peek(l); if (pk.type == TOK_FOR || (pk.type == TOK_IDENT && strncmp(pk.start, "for", 3) == 0 && pk.len == 3)) { if (pk.type != TOK_FOR) { lexer_next(l); } else { lexer_next(l); // eat for } Token t2 = lexer_next(l); char *name2 = token_strdup(t2); register_impl(ctx, name1, name2); // RAII: Check for "Drop" trait implementation if (strcmp(name1, "Drop") == 0) { Symbol *s = find_symbol_entry(ctx, name2); if (s && s->type_info) { s->type_info->traits.has_drop = 1; } else { // Try finding struct definition ASTNode *def = find_struct_def(ctx, name2); if (def && def->type_info) { def->type_info->traits.has_drop = 1; } } } // Iterator: Check for "Iterable" trait implementation else if (strcmp(name1, "Iterable") == 0) { Symbol *s = find_symbol_entry(ctx, name2); if (s && s->type_info) { s->type_info->traits.has_iterable = 1; } else { // Try finding struct definition ASTNode *def = find_struct_def(ctx, name2); if (def && def->type_info) { def->type_info->traits.has_iterable = 1; } } } ctx->current_impl_struct = name2; // Set context to prevent duplicate emission and prefixing lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; while (1) { skip_comments(l); if (lexer_peek(l).type == TOK_RBRACE) { lexer_next(l); break; } if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 0); // Mangle: Type_Trait_Method char *mangled = xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 4); sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; char *na = patch_self_args(f->func.args, name2); free(f->func.args); f->func.args = na; // Register function for lookup register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, f->func.is_async, f->token); if (!h) { h = f; } else { tl->next = f; } tl = f; } else if (lexer_peek(l).type == TOK_ASYNC) { lexer_next(l); // eat async if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 1); f->func.is_async = 1; // Mangle: Type_Trait_Method char *mangled = xmalloc(strlen(name2) + strlen(name1) + strlen(f->func.name) + 5); sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; char *na = patch_self_args(f->func.args, name2); free(f->func.args); f->func.args = na; // Register function for lookup register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, f->func.is_async, f->token); if (!h) { h = f; } else { tl->next = f; } tl = f; } else { zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'"); } } else { lexer_next(l); } } ctx->current_impl_struct = NULL; // Restore context ASTNode *n = ast_create(NODE_IMPL_TRAIT); n->impl_trait.trait_name = name1; n->impl_trait.target_type = name2; n->impl_trait.methods = h; add_to_impl_list(ctx, n); // If target struct is generic, register this impl as a template ASTNode *def = find_struct_def(ctx, name2); if (def && ((def->type == NODE_STRUCT && def->strct.is_template) || (def->type == NODE_ENUM && def->enm.is_template))) { const char *gp = "T"; if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0) { gp = def->strct.generic_params[0]; } // TODO: Enum generic params support if needed register_impl_template(ctx, name2, gp, n); } return n; } else { // Regular impl Struct (impl Box or impl Box) // Auto-prefix struct name if in module context if (ctx->current_module_prefix && !gen_param) { char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name1) + 2); sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name1); free(name1); name1 = prefixed_name; } ctx->current_impl_struct = name1; // For patch_self_args inside parse_function if (gen_param) { // GENERIC IMPL TEMPLATE: impl Box if (lexer_next(l).type != TOK_LBRACE) { zpanic_at(lexer_peek(l), "Expected {"); } char *full_struct_name = xmalloc(strlen(name1) + strlen(gen_param) + 3); sprintf(full_struct_name, "%s<%s>", name1, gen_param); ASTNode *h = 0, *tl = 0; ctx->current_impl_methods = NULL; while (1) { ctx->current_impl_methods = h; skip_comments(l); if (lexer_peek(l).type == TOK_RBRACE) { lexer_next(l); break; } if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 0); // Standard Mangle for template: Box_method char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3); sprintf(mangled, "%s__%s", name1, f->func.name); free(f->func.name); f->func.name = mangled; // Update args string char *na = patch_self_args(f->func.args, full_struct_name); free(f->func.args); f->func.args = na; // Manual Type construction for self: Foo* if (f->func.arg_count > 0 && f->func.param_names && strcmp(f->func.param_names[0], "self") == 0) { Type *t_struct = type_new(TYPE_STRUCT); t_struct->name = xstrdup(name1); t_struct->arg_count = 1; t_struct->args = xmalloc(sizeof(Type *)); t_struct->args[0] = type_new(TYPE_GENERIC); t_struct->args[0]->name = xstrdup(gen_param); Type *t_ptr = type_new(TYPE_POINTER); t_ptr->inner = t_struct; f->func.arg_types[0] = t_ptr; } if (!h) { h = f; } else { tl->next = f; } tl = f; } else if (lexer_peek(l).type == TOK_ASYNC) { lexer_next(l); // eat async if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 1); f->func.is_async = 1; char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3); sprintf(mangled, "%s__%s", name1, f->func.name); free(f->func.name); f->func.name = mangled; char *na = patch_self_args(f->func.args, full_struct_name); free(f->func.args); f->func.args = na; if (f->func.arg_count > 0 && f->func.param_names && strcmp(f->func.param_names[0], "self") == 0) { Type *t_struct = type_new(TYPE_STRUCT); t_struct->name = xstrdup(name1); t_struct->arg_count = 1; t_struct->args = xmalloc(sizeof(Type *)); t_struct->args[0] = type_new(TYPE_GENERIC); t_struct->args[0]->name = xstrdup(gen_param); Type *t_ptr = type_new(TYPE_POINTER); t_ptr->inner = t_struct; f->func.arg_types[0] = t_ptr; } if (!h) { h = f; } else { tl->next = f; } tl = f; } else { zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'"); } } else { lexer_next(l); } } free(full_struct_name); // Register Template ASTNode *n = ast_create(NODE_IMPL); n->impl.struct_name = name1; n->impl.methods = h; register_impl_template(ctx, name1, gen_param, n); ctx->current_impl_struct = NULL; return NULL; // Do not emit generic template } else { // REGULAR IMPL lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; while (1) { skip_comments(l); if (lexer_peek(l).type == TOK_RBRACE) { lexer_next(l); break; } if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 0); // Standard Mangle: Struct_method char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3); sprintf(mangled, "%s__%s", name1, f->func.name); free(f->func.name); f->func.name = mangled; char *na = patch_self_args(f->func.args, name1); free(f->func.args); f->func.args = na; register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 0, f->token); if (!h) { h = f; } else { tl->next = f; } tl = f; } else if (lexer_peek(l).type == TOK_ASYNC) { lexer_next(l); if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0) { ASTNode *f = parse_function(ctx, l, 1); f->func.is_async = 1; char *mangled = xmalloc(strlen(name1) + strlen(f->func.name) + 3); sprintf(mangled, "%s__%s", name1, f->func.name); free(f->func.name); f->func.name = mangled; char *na = patch_self_args(f->func.args, name1); free(f->func.args); f->func.args = na; register_func(ctx, mangled, f->func.arg_count, f->func.defaults, f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 1, f->token); if (!h) { h = f; } else { tl->next = f; } tl = f; } else { zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'"); } } else { lexer_next(l); } } ctx->current_impl_struct = NULL; ASTNode *n = ast_create(NODE_IMPL); n->impl.struct_name = name1; n->impl.methods = h; add_to_impl_list(ctx, n); return n; } } } ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union) { lexer_next(l); // eat struct or union Token n = lexer_next(l); char *name = token_strdup(n); // Generic Params or char **gps = NULL; int gp_count = 0; if (lexer_peek(l).type == TOK_LANGLE) { lexer_next(l); // eat < while (1) { Token g = lexer_next(l); gps = realloc(gps, sizeof(char *) * (gp_count + 1)); gps[gp_count++] = token_strdup(g); Token next = lexer_peek(l); if (next.type == TOK_COMMA) { lexer_next(l); // eat , } else if (next.type == TOK_RANGLE) { lexer_next(l); // eat > break; } else { zpanic_at(next, "Expected ',' or '>' in generic parameter list"); } } register_generic(ctx, name); } // Check for prototype (forward declaration) if (lexer_peek(l).type == TOK_SEMICOLON) { lexer_next(l); ASTNode *n = ast_create(NODE_STRUCT); n->strct.name = name; n->strct.is_template = (gp_count > 0); n->strct.generic_params = gps; n->strct.generic_param_count = gp_count; n->strct.is_union = is_union; n->strct.fields = NULL; n->strct.is_incomplete = 1; return n; } lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; // Temp storage for used structs char **temp_used_structs = NULL; int temp_used_count = 0; while (1) { skip_comments(l); Token t = lexer_peek(l); // printf("DEBUG: parse_struct loop seeing '%.*s'\n", t.len, t.start); if (t.type == TOK_RBRACE) { lexer_next(l); break; } if (t.type == TOK_SEMICOLON || t.type == TOK_COMMA) { lexer_next(l); continue; } // Handle 'use' (Struct Embedding) if (t.type == TOK_USE) { lexer_next(l); // eat use // Check for named use: use name: Type; Token t1 = lexer_peek(l); Token t2 = lexer_peek2(l); if (t1.type == TOK_IDENT && t2.type == TOK_COLON) { // Named use -> Composition (Add field, don't flatten) Token field_name = lexer_next(l); lexer_next(l); // eat : char *field_type_str = parse_type(ctx, l); expect(l, TOK_SEMICOLON, "Expected ;"); ASTNode *nf = ast_create(NODE_FIELD); nf->field.name = token_strdup(field_name); nf->field.type = field_type_str; if (!h) { h = nf; } else { tl->next = nf; } tl = nf; continue; } // Normal use -> Mixin (Flatten) // Parse the type (e.g. Header) Type *use_type = parse_type_formal(ctx, l); char *use_name = type_to_string(use_type); expect(l, TOK_SEMICOLON, "Expected ; after use"); // Find the definition and COPY fields ASTNode *def = find_struct_def(ctx, use_name); if (!def && is_known_generic(ctx, use_type->name)) { // Try to force instantiation if not found? // For now, rely on parse_type having triggered instantiation. char *mangled = type_to_string(use_type); // This works if type_to_string returns mangled name def = find_struct_def(ctx, mangled); free(mangled); } if (def && def->type == NODE_STRUCT) { if (!temp_used_structs) { temp_used_structs = xmalloc(sizeof(char *) * 8); } temp_used_structs[temp_used_count++] = xstrdup(use_name); ASTNode *f = def->strct.fields; while (f) { ASTNode *nf = ast_create(NODE_FIELD); nf->field.name = xstrdup(f->field.name); nf->field.type = xstrdup(f->field.type); if (!h) { h = nf; } else { tl->next = nf; } tl = nf; f = f->next; } } else { // If definition not found (e.g. user struct defined later), we can't // embed fields yet. Compiler limitation: 'use' requires struct to be // defined before. Fallback: Emit a placeholder field so compilation // doesn't crash, but layout will be wrong. printf("Warning: Could not // find struct '%s' for embedding.\n", use_name); } free(use_name); continue; } // --------------------------------------- if (t.type == TOK_IDENT) { Token f_name = lexer_next(l); expect(l, TOK_COLON, "Expected :"); char *f_type = parse_type(ctx, l); ASTNode *f = ast_create(NODE_FIELD); f->field.name = token_strdup(f_name); f->field.type = f_type; f->field.bit_width = 0; // Optional bit width: name: type : 3 if (lexer_peek(l).type == TOK_COLON) { lexer_next(l); // eat : Token width_tok = lexer_next(l); if (width_tok.type != TOK_INT) { zpanic_at(width_tok, "Expected bit width integer"); } f->field.bit_width = atoi(token_strdup(width_tok)); } if (!h) { h = f; } else { tl->next = f; } tl = f; if (lexer_peek(l).type == TOK_SEMICOLON || lexer_peek(l).type == TOK_COMMA) { lexer_next(l); } } else { lexer_next(l); } } ASTNode *node = ast_create(NODE_STRUCT); add_to_struct_list(ctx, node); // Auto-prefix struct name if in module context if (ctx->current_module_prefix && gp_count == 0) { // Don't prefix generic templates char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2); sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name); free(name); name = prefixed_name; } node->strct.name = name; // Initialize Type Info so we can track traits (like Drop) node->type_info = type_new(TYPE_STRUCT); node->type_info->name = xstrdup(name); if (gp_count > 0) { node->type_info->kind = TYPE_GENERIC; // TODO: track generic params } node->strct.fields = h; node->strct.generic_params = gps; node->strct.generic_param_count = gp_count; node->strct.is_union = is_union; node->strct.used_structs = temp_used_structs; node->strct.used_struct_count = temp_used_count; if (gp_count > 0) { node->strct.is_template = 1; register_template(ctx, name, node); } // Register definition for 'use' lookups and LSP if (gp_count == 0) { register_struct_def(ctx, name, node); } return node; } Type *parse_type_obj(ParserContext *ctx, Lexer *l) { // Parse the base type (int, U32, MyStruct, etc.) Type *t = parse_type_base(ctx, l); // Handle Pointers while (lexer_peek(l).type == TOK_OP && lexer_peek(l).start[0] == '*') { lexer_next(l); // eat * // Wrap the current type in a Pointer type Type *ptr = type_new(TYPE_POINTER); ptr->inner = t; t = ptr; } return t; } ASTNode *parse_enum(ParserContext *ctx, Lexer *l) { lexer_next(l); Token n = lexer_next(l); // 1. Check for Generic char *gp = NULL; if (lexer_peek(l).type == TOK_LANGLE) { lexer_next(l); // eat < Token g = lexer_next(l); gp = token_strdup(g); lexer_next(l); // eat > register_generic(ctx, n.start ? token_strdup(n) : "anon"); } lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; int v = 0; char *ename = token_strdup(n); // Store enum name while (1) { skip_comments(l); Token t = lexer_peek(l); if (t.type == TOK_RBRACE) { lexer_next(l); break; } if (t.type == TOK_COMMA) { lexer_next(l); continue; } if (t.type == TOK_IDENT) { Token vt = lexer_next(l); char *vname = token_strdup(vt); // 2. Parse Payload Type (Ok(int)) Type *payload = NULL; if (lexer_peek(l).type == TOK_LPAREN) { lexer_next(l); payload = parse_type_obj(ctx, l); if (lexer_next(l).type != TOK_RPAREN) { zpanic_at(lexer_peek(l), "Expected )"); } } ASTNode *va = ast_create(NODE_ENUM_VARIANT); va->variant.name = vname; va->variant.tag_id = v++; // Use tag_id instead of value va->variant.payload = payload; // Store Type* // Register Variant (Mangled name to avoid collisions: Result_Ok) char mangled[256]; sprintf(mangled, "%s_%s", ename, vname); register_enum_variant(ctx, ename, mangled, va->variant.tag_id); // Handle explicit assignment: Ok = 5 if (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '=') { lexer_next(l); va->variant.tag_id = atoi(lexer_next(l).start); v = va->variant.tag_id + 1; } if (!h) { h = va; } else { tl->next = va; } tl = va; } else { lexer_next(l); } } // Auto-prefix enum name if in module context if (ctx->current_module_prefix && !gp) { // Don't prefix generic templates char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(ename) + 2); sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, ename); free(ename); ename = prefixed_name; } ASTNode *node = ast_create(NODE_ENUM); node->enm.name = ename; node->enm.variants = h; node->enm.generic_param = gp; // 3. Store generic param if (gp) { node->enm.is_template = 1; register_template(ctx, node->enm.name, node); } add_to_enum_list(ctx, node); // Register globally return node; }