stage1 修复错误 提供类型检查

This commit is contained in:
zzy
2026-07-22 18:04:35 +08:00
parent a2d5dd9ce8
commit da9dae734c
5 changed files with 136 additions and 30 deletions

View File

@@ -194,6 +194,13 @@ static spl_val_t vm_printf(int nargs, spl_val_t *args) {
continue; continue;
} }
switch (fmt[i]) { switch (fmt[i]) {
case '.': {
Assert(i + 2 < fmt_len && arg_idx + 1 <= nargs && fmt[i + 1] == '*' &&
fmt[i + 2] == 's');
for (usize j = 0; j < args[arg_idx]; ++j) {
vec_push(buffer, ((const char *)args[arg_idx + 1])[j]);
}
} break;
case 'd': case 'd':
snprintf(tmp_buf, sizeof(tmp_buf), "%zd", args[arg_idx]); snprintf(tmp_buf, sizeof(tmp_buf), "%zd", args[arg_idx]);
for (usize j = 0; j < strlen(tmp_buf); ++j) { for (usize j = 0; j < strlen(tmp_buf); ++j) {

View File

@@ -185,6 +185,9 @@ void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog) {
if (fe->func_idx >= 0 && fe->func_idx < (int)vec_size(prog->funcs)) { if (fe->func_idx >= 0 && fe->func_idx < (int)vec_size(prog->funcs)) {
spl_val_t addr = vec_at(prog->funcs, fe->func_idx).address; spl_val_t addr = vec_at(prog->funcs, fe->func_idx).address;
vec_at(prog->insns, fe->insn_idx).imm = addr; vec_at(prog->insns, fe->insn_idx).imm = addr;
} else {
fprintf(stderr, "WARN: fixup func_idx=%d out of bounds [0,%zu), insn_idx=%zu\n",
fe->func_idx, vec_size(prog->funcs), fe->insn_idx);
} }
} }
} }

View File

@@ -609,26 +609,109 @@ static int parse_call_args(spl_comp_t *ctx) {
return nargs; return nargs;
} }
static int types_equal(spl_type_ctx_t *tctx, int a, int b) {
if (a < 0 || b < 0)
return 0;
a = spl_type_resolve_underlying(tctx, a);
b = spl_type_resolve_underlying(tctx, b);
if (a == b)
return 1;
spl_type_kind_t ak = spl_type_kind(tctx, a);
spl_type_kind_t bk = spl_type_kind(tctx, b);
if (ak != bk)
return 0;
switch (ak) {
case TYPE_VOID:
return 1;
case TYPE_BASIC:
return spl_type_basic_type(tctx, a) == spl_type_basic_type(tctx, b);
case TYPE_PTR:
return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_ARRAY:
return spl_type_array_len(tctx, a) == spl_type_array_len(tctx, b) &&
types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_SLICE:
return types_equal(tctx, spl_type_elem_type(tctx, a), spl_type_elem_type(tctx, b));
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM: {
const char *an = spl_type_name(tctx, a);
const char *bn = spl_type_name(tctx, b);
return an && bn && strcmp(an, bn) == 0;
}
default:
return 0;
}
}
static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, int arg_type_idx, static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, int arg_type_idx,
int param_type_idx, int arg_idx) { int param_type_idx, int arg_idx) {
if (arg_type_idx < 0 || param_type_idx < 0) if (arg_type_idx < 0 || param_type_idx < 0)
return; return;
if (spl_type_kind(&ctx->tctx, param_type_idx) == TYPE_PTR &&
spl_type_elem_type(&ctx->tctx, param_type_idx) >= 0 && /* Level 1: structurally equal types */
spl_type_kind(&ctx->tctx, arg_type_idx) != TYPE_PTR && if (types_equal(&ctx->tctx, arg_type_idx, param_type_idx))
spl_type_name(&ctx->tctx, arg_type_idx) && return;
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx)) &&
strcmp(spl_type_name(&ctx->tctx, arg_type_idx), int arg_u = spl_type_resolve_underlying(&ctx->tctx, arg_type_idx);
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx))) == 0) { int param_u = spl_type_resolve_underlying(&ctx->tctx, param_type_idx);
/* Level 1b: void pointer (*_) accepts any pointer */
if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) {
int param_elem = spl_type_elem_type(&ctx->tctx, param_u);
int param_elem_u = spl_type_resolve_underlying(&ctx->tctx, param_elem);
if (param_elem_u >= 0 && spl_type_kind(&ctx->tctx, param_elem_u) == TYPE_BASIC &&
spl_type_basic_type(&ctx->tctx, param_elem_u) == SPL_VOID &&
spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) {
return;
}
}
/* Level 2: pointer indirection mismatch with same inner type */
if (spl_type_kind(&ctx->tctx, param_u) == TYPE_PTR) {
int param_elem = spl_type_elem_type(&ctx->tctx, param_u);
if (param_elem < 0)
goto type_mismatch;
/* 2a: param = *T, arg = T (missing '&') */
if (spl_type_kind(&ctx->tctx, arg_u) != TYPE_PTR) {
if (types_equal(&ctx->tctx, arg_type_idx, param_elem)) {
const char *is = spl_type_str(&ctx->tctx, param_elem);
fprintf(stderr, fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', " "%s: warning: argument %d of '%s' expects '%s*', "
"got '%s' (missing '&'?)\n", "got '%s' (missing '&'?)\n",
ctx->fname, arg_idx + 1, fname, ctx->fname, arg_idx + 1, fname, is, is);
spl_type_name(&ctx->tctx, spl_type_elem_type(&ctx->tctx, param_type_idx)), return;
spl_type_name(&ctx->tctx, arg_type_idx));
} }
} }
/* 2b: param = *T, arg = **T (extra '&') */
if (spl_type_kind(&ctx->tctx, arg_u) == TYPE_PTR) {
int arg_elem = spl_type_elem_type(&ctx->tctx, arg_u);
int arg_elem_u = spl_type_resolve_underlying(&ctx->tctx, arg_elem);
if (spl_type_kind(&ctx->tctx, arg_elem_u) == TYPE_PTR) {
if (types_equal(&ctx->tctx, spl_type_elem_type(&ctx->tctx, arg_elem), param_elem)) {
const char *is = spl_type_str(&ctx->tctx, param_elem);
fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', "
"got '%s**' (extra '&'?)\n",
ctx->fname, arg_idx + 1, fname, is, is);
return;
}
}
}
}
/* Level 3: general type mismatch → error */
type_mismatch:;
const char *as = spl_type_str(&ctx->tctx, arg_type_idx);
const char *ps = spl_type_str(&ctx->tctx, param_type_idx);
spl_comp_error(ctx, "argument %d of '%s' type mismatch: expected '%s', got '%s'", arg_idx + 1,
fname, ps, as);
}
static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, int *param_type_indices, static int parse_call_args_checked(spl_comp_t *ctx, const char *fname, int *param_type_indices,
int nparams) { int nparams) {
int nargs = 0; int nargs = 0;
@@ -975,6 +1058,10 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
} }
expect(ctx, TOK_R_PAREN); expect(ctx, TOK_R_PAREN);
if (func->func_idx < 0) {
fprintf(stderr, "WARN: method call '%s.' with invalid func_idx=%d\n",
func->name, func->func_idx);
}
emit_call_with_fixup(&ctx->emit, nargs, func->func_idx); emit_call_with_fixup(&ctx->emit, nargs, func->func_idx);
left = (spl_expr_result_t){func->ret_type_idx, 0}; left = (spl_expr_result_t){func->ret_type_idx, 0};

View File

@@ -90,8 +90,14 @@ static int parse_fn_body(spl_comp_t *ctx, const char *fn_name, int ret_type_idx,
if ((usize)ctx->emit.frame.peak_bytes < min_bytes) if ((usize)ctx->emit.frame.peak_bytes < min_bytes)
ctx->emit.frame.peak_bytes = (int)min_bytes; ctx->emit.frame.peak_bytes = (int)min_bytes;
} }
emit_patch(&ctx->emit, alloc_addr, int alloc_slots = ctx->emit.frame.peak_bytes / (int)sizeof(spl_val_t) - total_phys_slots;
ctx->emit.frame.peak_bytes / (int)sizeof(spl_val_t) - total_phys_slots); if (alloc_slots < 0 || alloc_slots > 65536) {
fprintf(
stderr,
"WARN: parse_fn_body: suspicious alloc_slots=%d (peak_bytes=%d, phys_slots=%d)\n",
alloc_slots, ctx->emit.frame.peak_bytes, total_phys_slots);
}
emit_patch(&ctx->emit, alloc_addr, alloc_slots);
expect(ctx, TOK_R_BRACE); expect(ctx, TOK_R_BRACE);
} }

View File

@@ -575,7 +575,14 @@ spl_type_t spl_type_emit_type(spl_type_ctx_t *tctx, int type_idx) {
return SPL_PTR; return SPL_PTR;
} }
#define TYPE_STR_BUF_COUNT 8
#define TYPE_STR_BUF_SIZE 64
const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) { const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) {
static char b[TYPE_STR_BUF_COUNT][TYPE_STR_BUF_SIZE];
static int bi = 0;
int my = (bi++) % TYPE_STR_BUF_COUNT;
if (type_idx < 0) if (type_idx < 0)
return "<null>"; return "<null>";
spl_type_info_t *t = &vec_at(tctx->types, type_idx); spl_type_info_t *t = &vec_at(tctx->types, type_idx);
@@ -616,22 +623,18 @@ const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) {
return "<basic>"; return "<basic>";
} }
} }
case TYPE_PTR: { case TYPE_PTR:
static char buf[64]; snprintf(b[my], TYPE_STR_BUF_SIZE, "*%s",
snprintf(buf, sizeof(buf), "*%s", spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return buf;
}
case TYPE_ARRAY: {
static char buf[64];
snprintf(buf, sizeof(buf), "[%zu]%s", spl_type_array_len(tctx, type_idx),
spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return buf; return b[my];
} case TYPE_ARRAY:
case TYPE_SLICE: { snprintf(b[my], TYPE_STR_BUF_SIZE, "[%zu]%s", spl_type_array_len(tctx, type_idx),
static char buf[64]; spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
snprintf(buf, sizeof(buf), "[]%s", spl_type_str(tctx, spl_type_elem_type(tctx, type_idx))); return b[my];
return buf; case TYPE_SLICE:
} snprintf(b[my], TYPE_STR_BUF_SIZE, "[]%s",
spl_type_str(tctx, spl_type_elem_type(tctx, type_idx)));
return b[my];
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
case TYPE_ENUM: case TYPE_ENUM: