stage1 修复类型体内部函数前向引用时 CALL 地址错误

This commit is contained in:
zzy
2026-07-12 22:16:17 +08:00
parent 1ceda90207
commit b67edc5cee
7 changed files with 273 additions and 44 deletions

View File

@@ -390,6 +390,15 @@ int spl_prog_add_func_simple(spl_prog_t *prog, const char *name, spl_val_t nargs
return (int)vec_size(prog->funcs) - 1; return (int)vec_size(prog->funcs) - 1;
} }
int spl_prog_update_func(spl_prog_t *prog, int func_idx, const char *name, spl_val_t nargs) {
if (!prog || func_idx < 0 || func_idx >= (int)vec_size(prog->funcs))
return spl_prog_add_func_simple(prog, name, nargs);
spl_func_t *func = &vec_at(prog->funcs, func_idx);
func->address = vec_size(prog->insns);
func->nargs = nargs;
return func_idx;
}
void spl_prog_end_func(spl_prog_t *prog, int func_idx) { void spl_prog_end_func(spl_prog_t *prog, int func_idx) {
if (!prog || func_idx < 0 || func_idx >= (int)vec_size(prog->funcs)) if (!prog || func_idx < 0 || func_idx >= (int)vec_size(prog->funcs))
return; return;

View File

@@ -210,6 +210,7 @@ spl_native_t *spl_prog_get_native(spl_prog_t *prog, const char *name);
/* High-level program construction helpers */ /* High-level program construction helpers */
spl_val_t spl_prog_emit(spl_prog_t *prog, uint16_t opcode, uint16_t type, spl_val_t imm); spl_val_t spl_prog_emit(spl_prog_t *prog, uint16_t opcode, uint16_t type, spl_val_t imm);
int spl_prog_add_func_simple(spl_prog_t *prog, const char *name, spl_val_t nargs); int spl_prog_add_func_simple(spl_prog_t *prog, const char *name, spl_val_t nargs);
int spl_prog_update_func(spl_prog_t *prog, int func_idx, const char *name, spl_val_t nargs);
void spl_prog_end_func(spl_prog_t *prog, int func_idx); void spl_prog_end_func(spl_prog_t *prog, int func_idx);
int spl_prog_add_str(spl_prog_t *prog, const char *str); int spl_prog_add_str(spl_prog_t *prog, const char *str);

View File

@@ -13,11 +13,13 @@ void spl_comp_init(spl_comp_t *ctx) {
vec_init(ctx->toks); vec_init(ctx->toks);
vec_init(ctx->scopes); vec_init(ctx->scopes);
vec_init(ctx->funcs); vec_init(ctx->funcs);
vec_init(ctx->ns_chain);
map_init(ctx->type_defs, MAP_HASH_STR, MAP_CMP_STR); map_init(ctx->type_defs, MAP_HASH_STR, MAP_CMP_STR);
map_init(ctx->const_values, MAP_HASH_STR, MAP_CMP_STR); map_init(ctx->const_values, MAP_HASH_STR, MAP_CMP_STR);
vec_init(ctx->call_fixups);
vec_init(ctx->call_fixup_funcs);
spl_prog_init(&ctx->prog); spl_prog_init(&ctx->prog);
ctx->error_msg[0] = '\0'; ctx->error_msg[0] = '\0';
ctx->current_type_name = NULL;
} }
void spl_comp_drop(spl_comp_t *ctx) { void spl_comp_drop(spl_comp_t *ctx) {
@@ -27,9 +29,12 @@ void spl_comp_drop(spl_comp_t *ctx) {
vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); } vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); }
vec_free(ctx->scopes); vec_free(ctx->scopes);
vec_free(ctx->funcs); vec_free(ctx->funcs);
vec_free(ctx->ns_chain);
/* Free type defs — complex, leak for now in bootstrap */ /* Free type defs — complex, leak for now in bootstrap */
map_free(ctx->type_defs); map_free(ctx->type_defs);
map_free(ctx->const_values); map_free(ctx->const_values);
vec_free(ctx->call_fixups);
vec_free(ctx->call_fixup_funcs);
spl_prog_drop(&ctx->prog); spl_prog_drop(&ctx->prog);
free(ctx->break_patches); free(ctx->break_patches);
} }
@@ -41,6 +46,8 @@ void spl_comp_reset(spl_comp_t *ctx) {
vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); } vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); }
vec_free(ctx->scopes); vec_free(ctx->scopes);
vec_init(ctx->scopes); vec_init(ctx->scopes);
vec_free(ctx->ns_chain);
vec_init(ctx->ns_chain);
ctx->scope_depth = 0; ctx->scope_depth = 0;
ctx->tok_idx = 0; ctx->tok_idx = 0;
ctx->has_error = 0; ctx->has_error = 0;
@@ -56,9 +63,12 @@ void spl_comp_reset(spl_comp_t *ctx) {
ctx->defer_count = 0; ctx->defer_count = 0;
ctx->next_gdata_idx = 0; ctx->next_gdata_idx = 0;
ctx->addr_of_mode = 0; ctx->addr_of_mode = 0;
ctx->current_type_name = NULL;
free(ctx->break_patches); free(ctx->break_patches);
ctx->break_patches = NULL; ctx->break_patches = NULL;
vec_free(ctx->call_fixups);
vec_init(ctx->call_fixups);
vec_free(ctx->call_fixup_funcs);
vec_init(ctx->call_fixup_funcs);
} }
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) { void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
@@ -164,6 +174,18 @@ void spl_pop_scope(spl_comp_t *ctx) {
} }
} }
/* ---- Namespace chain management ---- */
void spl_ns_push(spl_comp_t *ctx, spl_type_info_t *type) {
if (type)
vec_push(ctx->ns_chain, type);
}
void spl_ns_pop(spl_comp_t *ctx) {
if (vec_size(ctx->ns_chain) > 0)
ctx->ns_chain.size--;
}
/* ---- Variable management ---- */ /* ---- Variable management ---- */
int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const) { int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const) {
@@ -214,6 +236,20 @@ int spl_get_var_offset(spl_comp_t *ctx, const char *name) {
int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type, int nparams, int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type, int nparams,
int is_extern, int is_pub) { int is_extern, int is_pub) {
/* Check if already declared — allows pre-registration */
vec_for(ctx->funcs, i) {
spl_func_info_t *existing = &vec_at(ctx->funcs, i);
if (strcmp(existing->name, name) == 0) {
existing->ret_type = ret_type;
existing->nparams = nparams;
existing->is_extern = is_extern;
existing->is_pub = is_pub;
existing->func_idx =
spl_prog_update_func(&ctx->prog, existing->func_idx, name, nparams);
return (int)i;
}
}
spl_func_info_t fi; spl_func_info_t fi;
memset(&fi, 0, sizeof(fi)); memset(&fi, 0, sizeof(fi));
fi.name = strdup(name); fi.name = strdup(name);
@@ -233,9 +269,19 @@ int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_typ
} }
int spl_lookup_func(spl_comp_t *ctx, const char *name) { int spl_lookup_func(spl_comp_t *ctx, const char *name) {
vec_for(ctx->funcs, i) { /* 1. Walk ns_chain from innermost to outermost, check each type's methods */
if (strcmp(vec_at(ctx->funcs, i).name, name) == 0) for (usize i = vec_size(ctx->ns_chain); i > 0; i--) {
return (int)i; spl_type_info_t *type = vec_at(ctx->ns_chain, i - 1);
vec_for(type->methods, j) {
if (strcmp(vec_at(type->methods, j).name, name) == 0)
return vec_at(type->methods, j).func_idx;
}
}
/* 2. Fallback to flat func table (top-level functions and qualified names) */
vec_for(ctx->funcs, j) {
if (strcmp(vec_at(ctx->funcs, j).name, name) == 0)
return (int)j;
} }
return -1; return -1;
} }
@@ -340,6 +386,19 @@ void spl_comp_register(spl_prog_t *prog) {
(void)prog; (void)prog;
} }
/* ---- Patch call fixups ---- */
void spl_patch_call_fixups(spl_comp_t *ctx) {
for (usize i = 0; i < vec_size(ctx->call_fixups); i++) {
spl_val_t insn_idx = vec_at(ctx->call_fixups, i);
int pfi = vec_at(ctx->call_fixup_funcs, i);
if (pfi >= 0 && pfi < (int)vec_size(ctx->prog.funcs)) {
spl_val_t addr = vec_at(ctx->prog.funcs, pfi).address;
vec_at(ctx->prog.insns, insn_idx).imm = addr;
}
}
}
/* ---- Main compilation ---- */ /* ---- Main compilation ---- */
int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) { int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) {
@@ -358,5 +417,9 @@ int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) {
spl_parse_prog(ctx); spl_parse_prog(ctx);
if (ctx->has_error) if (ctx->has_error)
return -1; return -1;
/* Phase 5: Patch all function call fixups (forward references) */
spl_patch_call_fixups(ctx);
return 0; return 0;
} }

View File

@@ -64,6 +64,7 @@ struct spl_type_info {
spl_field_vec_t fields; /* for TYPE_STRUCT */ spl_field_vec_t fields; /* for TYPE_STRUCT */
spl_enum_variant_vec_t variants; /* for TYPE_ENUM */ spl_enum_variant_vec_t variants; /* for TYPE_ENUM */
spl_method_info_vec_t methods; /* methods */ spl_method_info_vec_t methods; /* methods */
MAP(const char *, spl_type_info_t *) children; /* nested type namespace */
usize byte_size; /* total byte size (cached) */ usize byte_size; /* total byte size (cached) */
usize slot_count; /* stack slot count */ usize slot_count; /* stack slot count */
int is_pub; /* public visibility */ int is_pub; /* public visibility */
@@ -173,8 +174,7 @@ typedef struct spl_comp {
spl_type_info_t *current_ret_type; spl_type_info_t *current_ret_type;
int current_local_bytes; /* next free local byte offset */ int current_local_bytes; /* next free local byte offset */
int peak_local_bytes; /* peak current_local_bytes for ALLOC sizing */ int peak_local_bytes; /* peak current_local_bytes for ALLOC sizing */
const char *current_type_name; /* name of type whose body we're parsing (for method short-name VEC(spl_type_info_t *) ns_chain; /* type namespace scope chain */
lookup) */
/* Loop context for break/continue */ /* Loop context for break/continue */
int in_loop; int in_loop;
@@ -194,6 +194,12 @@ typedef struct spl_comp {
MAP(const char *, spl_val_t) const_values; MAP(const char *, spl_val_t) const_values;
int addr_of_mode; /* 1 = inside & operator, suppress loads */ int addr_of_mode; /* 1 = inside & operator, suppress loads */
/* Fixup list: PUSH instructions whose immediate (function address) must
* be patched after ALL function bodies are compiled. This handles forward
* references — method A calling method B defined later in the same type. */
VEC(spl_val_t) call_fixups; /* instruction indices of PUSH insns to patch */
VEC(int) call_fixup_funcs; /* prog->funcs index for each fixup */
} spl_comp_t; } spl_comp_t;
/* Initialize/destroy compiler context */ /* Initialize/destroy compiler context */
@@ -303,9 +309,16 @@ int spl_add_global_data(spl_comp_t *ctx, void *data, usize size);
void spl_push_scope(spl_comp_t *ctx); void spl_push_scope(spl_comp_t *ctx);
void spl_pop_scope(spl_comp_t *ctx); void spl_pop_scope(spl_comp_t *ctx);
/* Namespace chain management */
void spl_ns_push(spl_comp_t *ctx, spl_type_info_t *type);
void spl_ns_pop(spl_comp_t *ctx);
/* Register runtime natives */ /* Register runtime natives */
void spl_comp_register(spl_prog_t *prog); void spl_comp_register(spl_prog_t *prog);
/* Patch all CALL fixups after all function bodies are compiled */
void spl_patch_call_fixups(spl_comp_t *ctx);
/* Defer */ /* Defer */
void spl_emit_defer(spl_comp_t *ctx); void spl_emit_defer(spl_comp_t *ctx);
void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth); void spl_emit_defer_epilogue(spl_comp_t *ctx, int depth);

View File

@@ -547,9 +547,20 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
skip_nl(ctx); skip_nl(ctx);
} }
} else if (type->kind == TYPE_ENUM) { } else if (type->kind == TYPE_ENUM) {
if (peek(ctx)->type == TOK_DOT) /* Parse variant name with optional type qualifier(s):
* .name, TypeName.name, or bare name (same pattern as
* spl_emit_match_enum_cmp for consistency) */
spl_tok_t *vtok;
if (peek(ctx)->type == TOK_DOT) {
advance(ctx); advance(ctx);
spl_tok_t *vtok = advance(ctx); vtok = advance(ctx);
} else {
vtok = advance(ctx);
while (peek(ctx)->type == TOK_DOT) {
advance(ctx);
vtok = advance(ctx);
}
}
char vname[256]; char vname[256];
spl_tok_copy_name(vtok, vname, sizeof(vname)); spl_tok_copy_name(vtok, vname, sizeof(vname));
skip_nl(ctx); skip_nl(ctx);
@@ -654,11 +665,6 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
/* Check if it's a function call: ident(...) */ /* Check if it's a function call: ident(...) */
if (peek(ctx)->type == TOK_L_PAREN) { if (peek(ctx)->type == TOK_L_PAREN) {
int fi = spl_lookup_func(ctx, name); int fi = spl_lookup_func(ctx, name);
if (fi < 0 && ctx->current_type_name) {
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", ctx->current_type_name, name);
fi = spl_lookup_func(ctx, qualified);
}
if (fi < 0) { if (fi < 0) {
spl_comp_error(ctx, "unknown function '%s'", name); spl_comp_error(ctx, "unknown function '%s'", name);
spl_expr_result_t r = {0}; spl_expr_result_t r = {0};
@@ -675,9 +681,12 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_emit(ctx, SPL_PUSH, SPL_I32, nidx); spl_emit(ctx, SPL_PUSH, SPL_I32, nidx);
spl_emit(ctx, SPL_NCALL, SPL_VOID, nargs); spl_emit(ctx, SPL_NCALL, SPL_VOID, nargs);
} else { } else {
spl_val_t addr = vec_at(ctx->prog.funcs, f->func_idx).address; /* Record fixup for forward-reference resolution */
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr); spl_val_t fixup_idx = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_PUSH, SPL_PTR, 0); /* placeholder address */
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs); spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
vec_push(ctx->call_fixups, fixup_idx);
vec_push(ctx->call_fixup_funcs, f->func_idx);
} }
spl_expr_result_t r = {f->ret_type, 0}; spl_expr_result_t r = {f->ret_type, 0};
@@ -941,9 +950,12 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
nargs += parse_call_args(ctx); nargs += parse_call_args(ctx);
expect(ctx, TOK_R_PAREN); expect(ctx, TOK_R_PAREN);
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address; /* Record fixup for forward-reference resolution */
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr); spl_val_t fixup_idx = vec_size(ctx->prog.insns);
spl_emit(ctx, SPL_PUSH, SPL_PTR, 0); /* placeholder address */
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs); spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
vec_push(ctx->call_fixups, fixup_idx);
vec_push(ctx->call_fixup_funcs, func->func_idx);
left = (spl_expr_result_t){func->ret_type, 0}; left = (spl_expr_result_t){func->ret_type, 0};
break; break;
@@ -1220,12 +1232,44 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *enum_type, spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *enum_type,
int val_offset) { int val_offset) {
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *vtok = advance(ctx);
char vname[256]; char vname[256];
spl_tok_copy_name(vtok, vname, sizeof(vname));
/* Parse variant reference, reusing the same type resolution path
* as the expression parser (parse_ident + postfix DOT handler):
*
* .unknown — leading DOT shortcut
* unknown — bare variant name
* Tag.unknown — type-qualified (resolves Tag via spl_resolve_type)
* Token.Tag.unknown — fully qualified (walks all segments)
*
* Only the final segment is the variant name; preceding segments
* are optional type qualifiers resolved through the type system. */
if (peek(ctx)->type == TOK_DOT) {
advance(ctx); /* . */
} else {
/* Read first name; if followed by DOT, it's a type qualifier —
* verify it resolves via spl_resolve_type (same as parse_ident). */
spl_tok_t *tok = advance(ctx);
spl_tok_copy_name(tok, vname, sizeof(vname));
while (peek(ctx)->type == TOK_DOT) {
spl_type_info_t *qt = spl_resolve_type(ctx, vname);
(void)qt; /* qualifier verified through type system */
advance(ctx); /* . */
tok = advance(ctx);
spl_tok_copy_name(tok, vname, sizeof(vname));
}
/* Now vname holds the final segment — the variant name */
goto lookup;
}
{
spl_tok_t *vtok = advance(ctx);
spl_tok_copy_name(vtok, vname, sizeof(vname));
}
lookup:
vec_for(enum_type->variants, vi) { vec_for(enum_type->variants, vi) {
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi); spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
if (strcmp(v->name, vname) == 0) { if (strcmp(v->name, vname) == 0) {

View File

@@ -181,14 +181,8 @@ static void parse_method_decl(spl_comp_t *ctx, spl_type_info_t *container) {
skip_nl(ctx); skip_nl(ctx);
} }
/* Set current_type_name for short-name resolution inside method body */
const char *saved_type_name = ctx->current_type_name;
ctx->current_type_name = container->name;
int fi = parse_fn_body(ctx, qualified, ret_type, nparams, pnames, ptypes, 0); int fi = parse_fn_body(ctx, qualified, ret_type, nparams, pnames, ptypes, 0);
ctx->current_type_name = saved_type_name;
{ {
spl_func_info_t *f = &vec_at(ctx->funcs, fi); spl_func_info_t *f = &vec_at(ctx->funcs, fi);
f->param_types = calloc(nparams, sizeof(spl_type_info_t *)); f->param_types = calloc(nparams, sizeof(spl_type_info_t *));
@@ -256,6 +250,9 @@ static void parse_type_body(spl_comp_t *ctx, spl_type_info_t *container, int is_
return; return;
advance(ctx); /* { */ advance(ctx); /* { */
/* Push type onto namespace chain for short-name resolution inside body */
spl_ns_push(ctx, container);
/* === Pass 1: Parse all nested type declarations first === /* === Pass 1: Parse all nested type declarations first ===
* This allows fields/variants to reference types defined later. */ * This allows fields/variants to reference types defined later. */
{ {
@@ -280,6 +277,38 @@ static void parse_type_body(spl_comp_t *ctx, spl_type_info_t *container, int is_
ctx->tok_idx = saved; ctx->tok_idx = saved;
} }
/* === Pre-register method names for forward references === */
if (container->name) {
usize saved = ctx->tok_idx;
int depth = 1;
while (depth > 0 && ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_type_t tt = peek(ctx)->type;
if (tt == TOK_L_BRACE) {
depth++;
advance(ctx);
} else if (tt == TOK_R_BRACE) {
depth--;
if (depth == 0)
break;
advance(ctx);
} else if (tt == KW_FN && depth == 1) {
advance(ctx); /* fn */
skip_nl(ctx);
spl_tok_t *name_tok = advance(ctx);
char mname[256];
spl_tok_copy_name(name_tok, mname, sizeof(mname));
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", container->name, mname);
int fi = spl_declare_func(ctx, qualified, NULL, 0, 0, 0);
/* Register in type->methods immediately so ns_chain lookup works */
spl_type_add_method(container, mname, fi);
} else {
advance(ctx);
}
}
ctx->tok_idx = saved;
}
/* === Pass 2: Parse fields/variants and methods === */ /* === Pass 2: Parse fields/variants and methods === */
{ {
int depth = 1; int depth = 1;
@@ -359,6 +388,7 @@ static void parse_type_body(spl_comp_t *ctx, spl_type_info_t *container, int is_
} }
} }
spl_ns_pop(ctx);
spl_type_compute_layout(container); spl_type_compute_layout(container);
} }
@@ -380,17 +410,25 @@ void parse_type_decl(spl_comp_t *ctx) {
expect(ctx, TOK_ASSIGN); expect(ctx, TOK_ASSIGN);
skip_nl(ctx); skip_nl(ctx);
/* Determine parent type if inside a type body (for nested type registration) */
spl_type_info_t *parent =
vec_size(ctx->ns_chain) > 0 ? vec_at(ctx->ns_chain, vec_size(ctx->ns_chain) - 1) : NULL;
if (peek(ctx)->type == KW_STRUCT) { if (peek(ctx)->type == KW_STRUCT) {
advance(ctx); advance(ctx);
spl_type_info_t *st = spl_type_struct(tname); spl_type_info_t *st = spl_type_struct(tname);
/* Register type early to allow self-referential fields */ /* Register type early to allow self-referential fields */
map_put(ctx->type_defs, strdup(tname), st); map_put(ctx->type_defs, strdup(tname), st);
if (parent)
map_put(parent->children, strdup(tname), st);
skip_nl(ctx); skip_nl(ctx);
parse_type_body(ctx, st, 0); parse_type_body(ctx, st, 0);
} else if (peek(ctx)->type == KW_UNION) { } else if (peek(ctx)->type == KW_UNION) {
advance(ctx); advance(ctx);
spl_type_info_t *ut = spl_type_union(tname); spl_type_info_t *ut = spl_type_union(tname);
map_put(ctx->type_defs, strdup(tname), ut); map_put(ctx->type_defs, strdup(tname), ut);
if (parent)
map_put(parent->children, strdup(tname), ut);
skip_nl(ctx); skip_nl(ctx);
parse_type_body(ctx, ut, 0); parse_type_body(ctx, ut, 0);
} else if (peek(ctx)->type == KW_ENUM) { } else if (peek(ctx)->type == KW_ENUM) {
@@ -398,6 +436,8 @@ void parse_type_decl(spl_comp_t *ctx) {
spl_type_info_t *et = spl_type_enum(tname); spl_type_info_t *et = spl_type_enum(tname);
/* Register type early to allow self-referential variants */ /* Register type early to allow self-referential variants */
map_put(ctx->type_defs, strdup(tname), et); map_put(ctx->type_defs, strdup(tname), et);
if (parent)
map_put(parent->children, strdup(tname), et);
skip_nl(ctx); skip_nl(ctx);
parse_type_body(ctx, et, 1); parse_type_body(ctx, et, 1);
} else if (peek(ctx)->type == TOK_IDENT || } else if (peek(ctx)->type == TOK_IDENT ||

View File

@@ -134,6 +134,7 @@ spl_type_info_t *spl_type_struct(const char *name) {
t->name = strdup(name); t->name = strdup(name);
vec_init(t->fields); vec_init(t->fields);
vec_init(t->methods); vec_init(t->methods);
map_init(t->children, MAP_HASH_STR, MAP_CMP_STR);
t->resolved = 0; t->resolved = 0;
return t; return t;
} }
@@ -145,6 +146,7 @@ spl_type_info_t *spl_type_union(const char *name) {
t->name = strdup(name); t->name = strdup(name);
vec_init(t->fields); vec_init(t->fields);
vec_init(t->methods); vec_init(t->methods);
map_init(t->children, MAP_HASH_STR, MAP_CMP_STR);
t->resolved = 0; t->resolved = 0;
return t; return t;
} }
@@ -156,6 +158,7 @@ spl_type_info_t *spl_type_enum(const char *name) {
t->name = strdup(name); t->name = strdup(name);
vec_init(t->variants); vec_init(t->variants);
vec_init(t->methods); vec_init(t->methods);
map_init(t->children, MAP_HASH_STR, MAP_CMP_STR);
t->byte_size = 4; t->byte_size = 4;
t->slot_count = 1; t->slot_count = 1;
t->resolved = 0; t->resolved = 0;
@@ -179,6 +182,14 @@ void spl_type_add_variant(spl_type_info_t *et, const char *name, spl_type_info_t
} }
void spl_type_add_method(spl_type_info_t *t, const char *name, int func_idx) { void spl_type_add_method(spl_type_info_t *t, const char *name, int func_idx) {
/* Check for existing entry — update instead of duplicating
* (handles pre-registration + actual method declaration) */
vec_for(t->methods, i) {
if (strcmp(vec_at(t->methods, i).name, name) == 0) {
vec_at(t->methods, i).func_idx = func_idx;
return;
}
}
spl_method_info_t m; spl_method_info_t m;
m.name = strdup(name); m.name = strdup(name);
m.func_idx = func_idx; m.func_idx = func_idx;
@@ -336,7 +347,9 @@ spl_type_info_t *spl_type_clone(spl_type_info_t *t) {
return NULL; return NULL;
spl_type_info_t *c = calloc(1, sizeof(spl_type_info_t)); spl_type_info_t *c = calloc(1, sizeof(spl_type_info_t));
memcpy(c, t, sizeof(spl_type_info_t)); memcpy(c, t, sizeof(spl_type_info_t));
/* Don't deep-copy fields/variants for now — shallow is fine for our use */ /* Don't deep-copy fields/variants — shallow is fine for our use.
* Clone doesn't own children (aliases never need them). */
memset(&c->children, 0, sizeof(c->children));
return c; return c;
} }
@@ -463,9 +476,45 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
memcpy(id_buf, name, cplen); memcpy(id_buf, name, cplen);
id_buf[cplen] = '\0'; id_buf[cplen] = '\0';
spl_type_info_t *found = NULL; spl_type_info_t *found = spl_resolve_type(ctx, id_buf);
if (map_get(ctx->type_defs, id_buf, &found)) { if (found) {
ctx->tok_idx++; ctx->tok_idx++;
/* Handle qualified type names: Token.Tag, etc.
* Walks DOT-separated segments, resolving each via type_defs.
* Same resolution path as spl_resolve_type_member in expr: try
* qualified name first, then bare-name fallback. */
while (ctx->tok_idx < vec_size(ctx->toks)) {
spl_tok_t *next = &vec_at(ctx->toks, ctx->tok_idx);
if (next->type != TOK_DOT)
break;
if (ctx->tok_idx + 1 >= vec_size(ctx->toks))
break;
spl_tok_t *ntok = &vec_at(ctx->toks, ctx->tok_idx + 1);
char part[256];
usize plen = ntok->len < 255 ? ntok->len : 255;
memcpy(part, ntok->lexeme, plen);
part[plen] = '\0';
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", id_buf, part);
spl_type_info_t *qfound = NULL;
if (map_get(ctx->type_defs, qualified, &qfound)) {
found = qfound;
strncpy(id_buf, qualified, sizeof(id_buf) - 1);
ctx->tok_idx += 2;
} else if (map_get(ctx->type_defs, part, &qfound)) {
/* Bare-name fallback (nested types often only
* registered with short name, not qualified) */
found = qfound;
strncpy(id_buf, part, sizeof(id_buf) - 1);
ctx->tok_idx += 2;
} else {
break;
}
}
return found; return found;
} }
@@ -489,6 +538,16 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) {
spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name) { spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name) {
if (!ctx || !name) if (!ctx || !name)
return NULL; return NULL;
/* 1. Walk ns_chain from innermost to outermost, check each type's children */
for (usize i = vec_size(ctx->ns_chain); i > 0; i--) {
spl_type_info_t *type = vec_at(ctx->ns_chain, i - 1);
spl_type_info_t *found = NULL;
if (map_get(type->children, name, &found))
return found;
}
/* 2. Fallback to flat map */
spl_type_info_t *found = NULL; spl_type_info_t *found = NULL;
map_get(ctx->type_defs, name, &found); map_get(ctx->type_defs, name, &found);
return found; return found;