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

@@ -547,9 +547,20 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
skip_nl(ctx);
}
} 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);
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];
spl_tok_copy_name(vtok, vname, sizeof(vname));
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(...) */
if (peek(ctx)->type == TOK_L_PAREN) {
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) {
spl_comp_error(ctx, "unknown function '%s'", name);
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_NCALL, SPL_VOID, nargs);
} else {
spl_val_t addr = vec_at(ctx->prog.funcs, f->func_idx).address;
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
/* Record fixup for forward-reference resolution */
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);
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};
@@ -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);
expect(ctx, TOK_R_PAREN);
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address;
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
/* Record fixup for forward-reference resolution */
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);
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};
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,
int val_offset) {
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *vtok = advance(ctx);
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) {
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
if (strcmp(v->name, vname) == 0) {