summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser.h5
-rw-r--r--src/parser/parser_core.c4
-rw-r--r--src/parser/parser_expr.c375
-rw-r--r--src/parser/parser_stmt.c101
-rw-r--r--src/parser/parser_type.c15
-rw-r--r--src/parser/parser_utils.c147
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;
}