diff options
Diffstat (limited to 'src/parser')
| -rw-r--r-- | src/parser/parser.h | 5 | ||||
| -rw-r--r-- | src/parser/parser_core.c | 4 | ||||
| -rw-r--r-- | src/parser/parser_expr.c | 375 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 101 | ||||
| -rw-r--r-- | src/parser/parser_type.c | 15 | ||||
| -rw-r--r-- | src/parser/parser_utils.c | 147 |
6 files changed, 359 insertions, 288 deletions
diff --git a/src/parser/parser.h b/src/parser/parser.h index b3213c9..4aeb2c8 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -114,6 +114,8 @@ typedef struct VarMutability typedef struct Instantiation { char *name; + char *template_name; + char *concrete_arg; ASTNode *struct_node; struct Instantiation *next; } Instantiation; @@ -286,7 +288,8 @@ void add_symbol_with_token(ParserContext *ctx, const char *n, const char *t, Typ Type *find_symbol_type_info(ParserContext *ctx, const char *n); char *find_symbol_type(ParserContext *ctx, const char *n); Symbol *find_symbol_entry(ParserContext *ctx, const char *n); -Symbol *find_symbol_in_all(ParserContext *ctx, const char *n); // LSP flat lookup +Symbol *find_symbol_in_all(ParserContext *ctx, + const char *n); // LSP flat lookup char *find_similar_symbol(ParserContext *ctx, const char *name); // Function registry diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c index 1b40cf4..1a47275 100644 --- a/src/parser/parser_core.c +++ b/src/parser/parser_core.c @@ -1,9 +1,9 @@ +#include "parser.h" +#include "zprep.h" #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "parser.h" -#include "zprep.h" static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char **traits, int count); diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index e12c837..469d623 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -1,10 +1,10 @@ +#include "../zen/zen_facts.h" +#include "parser.h" +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "parser.h" -#include "../zen/zen_facts.h" Type *get_field_type(ParserContext *ctx, Type *struct_type, const char *field_name); @@ -1411,7 +1411,8 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) Type *st = type_new(TYPE_STRUCT); st->name = xstrdup(struct_name); node->type_info = st; - return node; // Struct init cannot be called/indexed usually, return early + return node; // Struct init cannot be called/indexed usually, return + // early } } @@ -1456,7 +1457,6 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) else { // readln(vars...) -> _z_scan_helper("fmt", &vars...) - // 1. Build Format String char fmt[256]; fmt[0] = 0; for (int i = 0; i < ac; i++) @@ -1505,14 +1505,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) } } - // 2. Build Call Node node = ast_create(NODE_EXPR_CALL); ASTNode *callee = ast_create(NODE_EXPR_VAR); callee->var_ref.name = xstrdup("_z_scan_helper"); node->call.callee = callee; node->type_info = type_new(TYPE_INT); // Returns count - // 3. Build Args List: "fmt" then &arg1, &arg2... ASTNode *fmt_node = ast_create(NODE_EXPR_LITERAL); fmt_node->literal.type_kind = 2; // string fmt_node->literal.string_val = xstrdup(fmt); @@ -1532,218 +1530,216 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) node->call.args = head; } free(acc); - } - else - if (sig && lexer_peek(l).type == TOK_LPAREN) - { - lexer_next(l); - ASTNode *head = NULL, *tail = NULL; - int args_provided = 0; - char **arg_names = NULL; - int has_named = 0; + else if (sig && lexer_peek(l).type == TOK_LPAREN) + { + lexer_next(l); + ASTNode *head = NULL, *tail = NULL; + int args_provided = 0; + char **arg_names = NULL; + int has_named = 0; - if (lexer_peek(l).type != TOK_RPAREN) + if (lexer_peek(l).type != TOK_RPAREN) + { + while (1) { - while (1) - { - char *arg_name = NULL; + char *arg_name = NULL; - Token t1 = lexer_peek(l); - if (t1.type == TOK_IDENT) + Token t1 = lexer_peek(l); + if (t1.type == TOK_IDENT) + { + Token t2 = lexer_peek2(l); + if (t2.type == TOK_COLON) { - Token t2 = lexer_peek2(l); - if (t2.type == TOK_COLON) - { - arg_name = token_strdup(t1); - has_named = 1; - lexer_next(l); - lexer_next(l); - } + arg_name = token_strdup(t1); + has_named = 1; + lexer_next(l); + lexer_next(l); } + } - ASTNode *arg = parse_expression(ctx, l); - if (!head) - { - head = arg; - } - else - { - tail->next = arg; - } - tail = arg; - args_provided++; + ASTNode *arg = parse_expression(ctx, l); + if (!head) + { + head = arg; + } + else + { + tail->next = arg; + } + tail = arg; + args_provided++; - arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); - arg_names[args_provided - 1] = arg_name; + arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); + arg_names[args_provided - 1] = arg_name; - arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); - arg_names[args_provided - 1] = arg_name; + arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); + arg_names[args_provided - 1] = arg_name; - if (lexer_peek(l).type == TOK_COMMA) - { - lexer_next(l); - } - else - { - break; - } + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); } - } - if (lexer_next(l).type != TOK_RPAREN) - { - zpanic("Expected )"); - } - for (int i = args_provided; i < sig->total_args; i++) - { - if (sig->defaults[i]) + else { - ASTNode *def = ast_create(NODE_RAW_STMT); - def->raw_stmt.content = xstrdup(sig->defaults[i]); - if (!head) - { - head = def; - } - else - { - tail->next = def; - } - tail = def; + break; } } - node = ast_create(NODE_EXPR_CALL); - node->token = t; // Set source token - ASTNode *callee = ast_create(NODE_EXPR_VAR); - callee->var_ref.name = acc; - node->call.callee = callee; - node->call.args = head; - node->call.arg_names = has_named ? arg_names : NULL; - node->call.arg_count = args_provided; - if (sig) - { - node->definition_token = sig->decl_token; - } - if (sig->is_async) - { - Type *async_type = type_new(TYPE_STRUCT); - async_type->name = xstrdup("Async"); - node->type_info = async_type; - node->resolved_type = xstrdup("Async"); - } - else if (sig->ret_type) - { - node->type_info = sig->ret_type; - node->resolved_type = type_to_string(sig->ret_type); - } - else + } + if (lexer_next(l).type != TOK_RPAREN) + { + zpanic("Expected )"); + } + for (int i = args_provided; i < sig->total_args; i++) + { + if (sig->defaults[i]) { - node->resolved_type = xstrdup("void"); + ASTNode *def = ast_create(NODE_RAW_STMT); + def->raw_stmt.content = xstrdup(sig->defaults[i]); + if (!head) + { + head = def; + } + else + { + tail->next = def; + } + tail = def; } } - else if (!sig && !find_symbol_entry(ctx, acc) && lexer_peek(l).type == TOK_LPAREN) + node = ast_create(NODE_EXPR_CALL); + node->token = t; // Set source token + ASTNode *callee = ast_create(NODE_EXPR_VAR); + callee->var_ref.name = acc; + node->call.callee = callee; + node->call.args = head; + node->call.arg_names = has_named ? arg_names : NULL; + node->call.arg_count = args_provided; + if (sig) { - lexer_next(l); // eat ( - ASTNode *head = NULL, *tail = NULL; - char **arg_names = NULL; - int args_provided = 0; - int has_named = 0; + node->definition_token = sig->decl_token; + } + if (sig->is_async) + { + Type *async_type = type_new(TYPE_STRUCT); + async_type->name = xstrdup("Async"); + node->type_info = async_type; + node->resolved_type = xstrdup("Async"); + } + else if (sig->ret_type) + { + node->type_info = sig->ret_type; + node->resolved_type = type_to_string(sig->ret_type); + } + else + { + node->resolved_type = xstrdup("void"); + } + } + else if (!sig && !find_symbol_entry(ctx, acc) && lexer_peek(l).type == TOK_LPAREN) + { + lexer_next(l); // eat ( + ASTNode *head = NULL, *tail = NULL; + char **arg_names = NULL; + int args_provided = 0; + int has_named = 0; - if (lexer_peek(l).type != TOK_RPAREN) + if (lexer_peek(l).type != TOK_RPAREN) + { + while (1) { - while (1) - { - char *arg_name = NULL; + char *arg_name = NULL; - // Check for named argument: name: value - Token t1 = lexer_peek(l); - if (t1.type == TOK_IDENT) + // Check for named argument: name: value + Token t1 = lexer_peek(l); + if (t1.type == TOK_IDENT) + { + Token t2 = lexer_peek2(l); + if (t2.type == TOK_COLON) { - Token t2 = lexer_peek2(l); - if (t2.type == TOK_COLON) - { - arg_name = token_strdup(t1); - has_named = 1; - lexer_next(l); - lexer_next(l); - } + arg_name = token_strdup(t1); + has_named = 1; + lexer_next(l); + lexer_next(l); } + } - ASTNode *arg = parse_expression(ctx, l); - if (!head) - { - head = arg; - } - else - { - tail->next = arg; - } - tail = arg; - args_provided++; + ASTNode *arg = parse_expression(ctx, l); + if (!head) + { + head = arg; + } + else + { + tail->next = arg; + } + tail = arg; + args_provided++; - arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); - arg_names[args_provided - 1] = arg_name; + arg_names = xrealloc(arg_names, args_provided * sizeof(char *)); + arg_names[args_provided - 1] = arg_name; - if (lexer_peek(l).type == TOK_COMMA) - { - lexer_next(l); - } - else - { - break; - } + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + } + else + { + break; } } - if (lexer_next(l).type != TOK_RPAREN) - { - zpanic("Expected )"); - } - - node = ast_create(NODE_EXPR_CALL); - node->token = t; - ASTNode *callee = ast_create(NODE_EXPR_VAR); - callee->var_ref.name = acc; - node->call.callee = callee; - node->call.args = head; - node->call.arg_names = has_named ? arg_names : NULL; - node->call.arg_count = args_provided; - // Unknown return type - let codegen infer it - node->resolved_type = xstrdup("unknown"); - // Fall through to Postfix } - else + if (lexer_next(l).type != TOK_RPAREN) { - node = ast_create(NODE_EXPR_VAR); - node->token = t; // Set source token - node->var_ref.name = acc; - node->type_info = find_symbol_type_info(ctx, acc); + zpanic("Expected )"); + } - Symbol *sym = find_symbol_entry(ctx, acc); - if (sym) - { - sym->is_used = 1; - node->definition_token = sym->decl_token; - } + node = ast_create(NODE_EXPR_CALL); + node->token = t; + ASTNode *callee = ast_create(NODE_EXPR_VAR); + callee->var_ref.name = acc; + node->call.callee = callee; + node->call.args = head; + node->call.arg_names = has_named ? arg_names : NULL; + node->call.arg_count = args_provided; + // Unknown return type - let codegen infer it + node->resolved_type = xstrdup("unknown"); + // Fall through to Postfix + } + else + { + node = ast_create(NODE_EXPR_VAR); + node->token = t; // Set source token + node->var_ref.name = acc; + node->type_info = find_symbol_type_info(ctx, acc); - char *type_str = find_symbol_type(ctx, acc); + Symbol *sym = find_symbol_entry(ctx, acc); + if (sym) + { + sym->is_used = 1; + node->definition_token = sym->decl_token; + } + + char *type_str = find_symbol_type(ctx, acc); - if (type_str) + if (type_str) + { + node->resolved_type = type_str; + node->var_ref.suggestion = NULL; + } + else + { + node->resolved_type = xstrdup("unknown"); + if (should_suppress_undef_warning(ctx, acc)) { - node->resolved_type = type_str; node->var_ref.suggestion = NULL; } else { - node->resolved_type = xstrdup("unknown"); - if (should_suppress_undef_warning(ctx, acc)) - { - node->var_ref.suggestion = NULL; - } - else - { - node->var_ref.suggestion = find_similar_symbol(ctx, acc); - } + node->var_ref.suggestion = find_similar_symbol(ctx, acc); } } + } } else if (t.type == TOK_LPAREN) @@ -2421,7 +2417,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) lhs = ast_create(NODE_AWAIT); lhs->unary.operand = operand; // Type inference: await Async<T> yields T - // If operand is a call to an async function, look up its ret_type (not Async) + // If operand is a call to an async function, look up its ret_type (not + // Async) if (operand->type == NODE_EXPR_CALL && operand->call.callee->type == NODE_EXPR_VAR) { FuncSig *sig = find_func(ctx, operand->call.callee->var_ref.name); @@ -2924,8 +2921,9 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) // Clean up string for registration (e.g. "int" from "int*") char *inner_str = type_to_string(inner); - // Strip * if it somehow managed to keep one, though parse_type_formal - // should handle it For now assume type_to_string gives base type + // Strip * if it somehow managed to keep one, though + // parse_type_formal should handle it For now assume type_to_string + // gives base type register_slice(ctx, inner_str); } } @@ -3050,7 +3048,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) FuncSig *sig = find_func(ctx, mangled); if (sig) { - // It is a method! Create a Function Type Info to carry the return type + // It is a method! Create a Function Type Info to carry the return + // type Type *ft = type_new(TYPE_FUNCTION); ft->name = xstrdup(mangled); ft->inner = sig->ret_type; // Return type @@ -3164,7 +3163,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) } } } - + if (strcmp(bin->binary.op, "=") == 0 || strcmp(bin->binary.op, "+=") == 0 || strcmp(bin->binary.op, "-=") == 0 || strcmp(bin->binary.op, "*=") == 0 || strcmp(bin->binary.op, "/=") == 0) @@ -3183,13 +3182,14 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (!is_var_mutable(ctx, lhs->var_ref.name)) { zpanic_at(op, - "Cannot assign to immutable variable '%s' (use 'var mut' to make it " + "Cannot assign to immutable variable '%s' (use 'var mut' " + "to make it " "mutable)", lhs->var_ref.name); } } } - + int is_compound = 0; size_t op_len = strlen(bin->binary.op); @@ -3318,7 +3318,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) set_callee->var_ref.name = set_name; set_call->call.callee = set_callee; - // Clone argument list (Shallow copy of arg nodes to preserve chain for get) + // Clone argument list (Shallow copy of arg nodes to preserve chain + // for get) ASTNode *lhs_args = lhs->call.args; ASTNode *new_head = NULL; ASTNode *new_tail = NULL; diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 619caaf..30c9e90 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -1,13 +1,13 @@ -// parser_stmt.c - Statement and Declaration parsing + +#include "parser.h" +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> #include <unistd.h> -#include "parser.h" -#include "../plugins/plugin_manager.h" #include "../ast/ast.h" +#include "../plugins/plugin_manager.h" #include "../zen/zen_facts.h" #include "zprep_plugin.h" @@ -83,7 +83,8 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async) curr_func_ret = ret; // Auto-prefix function name if in module context - // Don't prefix generic templates or functions inside impl blocks (already mangled) + // Don't prefix generic templates or functions inside impl blocks (already + // mangled) if (ctx->current_module_prefix && !gen_param && !ctx->current_impl_struct) { char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2); @@ -111,8 +112,8 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async) } // Check for unused parameters - // The current scope contains arguments (since parse_block creates a new child scope for body) - // Only check if we parsed a body (not a prototype) function + // The current scope contains arguments (since parse_block creates a new child + // scope for body) Only check if we parsed a body (not a prototype) function if (body && ctx->current_scope) { Symbol *sym = ctx->current_scope->symbols; @@ -1168,8 +1169,9 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l) type_obj->name = xstrdup(type); } - // fprintf(stderr, "DEBUG PVarDecl: Var '%s' inferred type '%s' (init->type_info - // present: %d)\n", name, type, init && init->type_info ? 1 : 0); + // fprintf(stderr, "DEBUG PVarDecl: Var '%s' inferred type '%s' + // (init->type_info present: %d)\n", name, type, init && init->type_info ? + // 1 : 0); } } @@ -1372,7 +1374,8 @@ ASTNode *parse_return(ParserContext *ctx, Lexer *l) int handled = 0; // 1. Check for Tuple Literal Return: return (a, b); - // Condition: Function returns Tuple_..., starts with '(', and contains ',' at top level + // Condition: Function returns Tuple_..., starts with '(', and contains ',' at + // top level if (curr_func_ret && strncmp(curr_func_ret, "Tuple_", 6) == 0 && lexer_peek(l).type == TOK_LPAREN) { @@ -1409,7 +1412,8 @@ ASTNode *parse_return(ParserContext *ctx, Lexer *l) } } - // If we find a comma at depth 1 (inside the first parens), it's a tuple literal! + // If we find a comma at depth 1 (inside the first parens), it's a tuple + // literal! if (depth == 1 && t.type == TOK_COMMA) { is_tuple_lit = 1; @@ -1772,7 +1776,8 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, clean_expr++; // Skip leading spaces } - // Mark the variable as used (fixes "Unused variable" warnings for f-string interpolation) + // Mark the variable as used (fixes "Unused variable" warnings for f-string + // interpolation) Symbol *sym = find_symbol_entry(ctx, clean_expr); if (sym) { @@ -1806,7 +1811,8 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, } // ============================================================ - // Rewrite the expression to handle pointer access (header_ptr.magic -> header_ptr->magic) + // Rewrite the expression to handle pointer access (header_ptr.magic -> + // header_ptr->magic) char *wrapped_expr = xmalloc(strlen(expr) + 5); sprintf(wrapped_expr, "#{%s}", expr); char *rw_expr = rewrite_expr_methods(ctx, wrapped_expr); @@ -2672,9 +2678,9 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l) // Parse method signature: fn name(args...) -> ret; // Re-use parse_function but stop at semicolon? - // Actually trait methods might have default impls later, but for now just signatures. - // Let's parse full function but body might be empty/null? - // Or simpler: just parse signature manually. + // Actually trait methods might have default impls later, but for now just + // signatures. Let's parse full function but body might be empty/null? Or + // simpler: just parse signature manually. Token ft = lexer_next(l); if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0) @@ -2995,8 +3001,8 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) free(f->func.args); f->func.args = na; - // FIX: Register the MANGLED name so calls like String_from(...) find the return - // type + // FIX: Register the MANGLED name so calls like String_from(...) find + // the return type 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); @@ -3077,6 +3083,25 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union) 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 != NULL); + n->strct.generic_param = gp; + n->strct.is_union = is_union; + n->strct.fields = NULL; + n->strct.is_incomplete = 1; + + if (!gp) + { + add_to_struct_list(ctx, n); + } + return n; + } + lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; @@ -3139,10 +3164,11 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union) } 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); + // 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; @@ -3528,7 +3554,9 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l) Token t = lexer_next(l); if (t.type != TOK_STRING) { - zpanic("Expected string (filename) after 'from' in selective import, got type %d", t.type); + zpanic("Expected string (filename) after 'from' in selective import, got " + "type %d", + t.type); } int ln = t.len - 2; // Remove quotes char *fn = xmalloc(ln + 1); @@ -3648,9 +3676,10 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l) // C Header: Emit include and return (don't parse) if (strlen(fn) > 2 && strcmp(fn + strlen(fn) - 2, ".h") == 0) { - // We can iterate over registered modules to check if we missed setting is_c_header? - // But we handled 'as' above. If no 'as', we need to check if we should register it? - // Usually 'import "foo.h" as f' is required for namespacing. + // We can iterate over registered modules to check if we missed setting + // is_c_header? But we handled 'as' above. If no 'as', we need to check if + // we should register it? Usually 'import "foo.h" as f' is required for + // namespacing. // Emit #include // TODO: Where to emit? parser doesn't emit code usually. @@ -3726,7 +3755,8 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l) } if (module_base_name) - { // This was only used for selective import registration, not for ctx->current_module_prefix + { // This was only used for selective import + // registration, not for ctx->current_module_prefix free(module_base_name); } @@ -3776,12 +3806,13 @@ ASTNode *parse_comptime(ParserContext *ctx, Lexer *l) // Stdout capture wrapper // We assume the user writes C code that fits in main(), or includes headers. - // For simplicity V1: We provide standard headers and wrap content in main if it doesn't look - // like definitions? Actually failure mode: User defines functions. Better: User provides body - // of main() or definitions. Heuristic: If we wrap in main, we can't define functions inside - // main (standard C). Proposal: User code runs AS IS. User must provide main(). Wait, user - // example: printf("..."); If I just paste printf("..."), it needs a main. Let's wrap in main() - // by default. + // For simplicity V1: We provide standard headers and wrap content in main if + // it doesn't look like definitions? Actually failure mode: User defines + // functions. Better: User provides body of main() or definitions. Heuristic: + // If we wrap in main, we can't define functions inside main (standard C). + // Proposal: User code runs AS IS. User must provide main(). Wait, user + // example: printf("..."); If I just paste printf("..."), it needs a main. + // Let's wrap in main() by default. fprintf(f, "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n"); fprintf(f, "int main() {\n%s\nreturn 0;\n}\n", code); fclose(f); @@ -3832,8 +3863,8 @@ ASTNode *parse_comptime(ParserContext *ctx, Lexer *l) // 6. Parse Output (Recursively) Lexer new_l; lexer_init(&new_l, output_src); - // Note: Recursive call. We leak output_src intentionally so AST tokens remain valid. - // In a long running process we would manage this in an Arena. + // Note: Recursive call. We leak output_src intentionally so AST tokens remain + // valid. In a long running process we would manage this in an Arena. return parse_program_nodes(ctx, &new_l); } diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c index a5f8d86..04a7de9 100644 --- a/src/parser/parser_type.c +++ b/src/parser/parser_type.c @@ -1,10 +1,10 @@ +#include "../ast/ast.h" +#include "parser.h" +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "parser.h" -#include "../ast/ast.h" Type *parse_type_base(ParserContext *ctx, Lexer *l) { @@ -252,7 +252,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) if (si) { // This is a selectively imported symbol - // Resolve to the actual struct name which was prefixed during module parsing + // Resolve to the actual struct name which was prefixed during module + // parsing free(name); name = xmalloc(strlen(si->source_module) + strlen(si->symbol) + 2); sprintf(name, "%s_%s", si->source_module, si->symbol); @@ -262,7 +263,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) // If we're IN a module and no selective import matched, apply module prefix if (ctx->current_module_prefix && !is_known_generic(ctx, name)) { - // Auto-prefix struct name if in module context (unless it's a known primitive/generic) + // Auto-prefix struct name if in module context (unless it's a known + // primitive/generic) char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2); sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name); free(name); @@ -278,7 +280,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) lexer_next(l); // eat < Type *arg = parse_type_formal(ctx, l); - // Handle nested generics like Vec<Vec<int>> where >> is tokenized as one op + // Handle nested generics like Vec<Vec<int>> where >> is tokenized as one + // op Token next_tok = lexer_peek(l); if (next_tok.type == TOK_RANGLE) { diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index 88823de..fcaab7f 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -1,10 +1,13 @@ +#include "../codegen/codegen.h" +#include "parser.h" +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "parser.h" -#include "../codegen/codegen.h" + +void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it, + const char *mangled_struct_name, const char *arg); Token expect(Lexer *l, TokenType type, const char *msg) { @@ -376,6 +379,18 @@ void register_impl_template(ParserContext *ctx, const char *sname, const char *p 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) @@ -917,7 +932,8 @@ char *replace_type_str(const char *src, const char *param, const char *concrete, 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*) + // 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); @@ -1145,7 +1161,8 @@ Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os, return n; } -// Helper to replace generic params in mangled names (e.g. Option_V_None -> Option_int_None) +// 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) @@ -1165,8 +1182,8 @@ char *replace_mangled_part(const char *src, const char *param, const char *concr // Check if param matches here if (strncmp(curr, param, plen) == 0) { - // Check boundaries: Must be delimited by quoted boundaries, OR underscores, OR string - // ends + // Check boundaries: Must be delimited by quoted boundaries, OR + // underscores, OR string ends int valid = 1; // Check Prev: Start of string OR Underscore @@ -1631,7 +1648,8 @@ ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char * if (n->field.type && strchr(n->field.type, '_')) { - // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry", "int") + // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry", + // "int") char *underscore = strrchr(n->field.type, '_'); if (underscore && underscore > n->field.type) { @@ -1676,6 +1694,67 @@ ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char * 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 + } + + 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); + 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) { // Ignore generic placeholders @@ -1719,6 +1798,8 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg) 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; @@ -1780,55 +1861,7 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg) { if (strcmp(it->struct_name, tpl) == 0) { - 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, tpl, m); - it->impl_node->next = backup_next; // Restore - - new_impl->impl.struct_name = xstrdup(m); - ASTNode *meth = new_impl->impl.methods; - while (meth) - { - char *suffix = strchr(meth->func.name, '_'); - if (suffix) - { - char *new_name = xmalloc(strlen(m) + strlen(suffix) + 1); - sprintf(new_name, "%s%s", m, 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); - } - - 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); - break; - } - gt = gt->next; - } - } - free(ret_copy); - } - - meth = meth->next; - } - add_instantiated_func(ctx, new_impl); + instantiate_methods(ctx, it, m, arg); } it = it->next; } |
