stage1 修复vm 提供简单参数检查 修复聚合类型bug

This commit is contained in:
zzy
2026-07-14 22:30:19 +08:00
parent f7f71c5f52
commit ab63c8ed90
7 changed files with 367 additions and 32 deletions

View File

@@ -457,7 +457,11 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields, int b
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_parse_expr(ctx, PREC_MIN);
spl_emit(ctx, SPL_STORE, st, 0);
if (elem_type && !spl_type_is_scalar(elem_type)) {
spl_emit_copy_addr_to_addr(ctx, spl_type_slot_count(elem_type), 1);
} else {
spl_emit(ctx, SPL_STORE, st, 0);
}
skip_nl(ctx);
}
if (peek(ctx)->type == TOK_COMMA)
@@ -657,6 +661,67 @@ static int parse_call_args(spl_comp_t *ctx) {
return nargs;
}
/* Type check: warn when a value is passed where a pointer of the same type is expected.
* This catches bugs like passing `tok` (Token) where `*Token` is expected. */
static void spl_check_arg_type(spl_comp_t *ctx, const char *fname, spl_type_info_t *arg_type,
spl_type_info_t *param_type, int arg_idx) {
if (!arg_type || !param_type)
return;
if (param_type->kind == TYPE_PTR && param_type->elem && arg_type->kind != TYPE_PTR &&
arg_type->name && param_type->elem->name &&
strcmp(arg_type->name, param_type->elem->name) == 0) {
fprintf(stderr,
"%s: warning: argument %d of '%s' expects '%s*', "
"got '%s' (missing '&'?)\n",
ctx->fname, arg_idx + 1, fname, param_type->elem->name, arg_type->name);
}
}
/* Wrapper: parse_call_args with type checking against parameter types */
static int parse_call_args_checked(spl_comp_t *ctx, const char *fname,
spl_type_info_t **param_types, int nparams) {
int nargs = 0; /* physical slot count (for CALL) */
int nlogical = 0; /* logical arg index (for param_types lookup) */
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
if (param_types && nlogical < nparams && param_types[nlogical])
spl_check_arg_type(ctx, fname, arg.type, param_types[nlogical], nlogical);
/* For multi-slot struct/enum by-value parameters, expand
* the address left on the stack into multiple data slots. */
int arg_slots = 1;
if (param_types && nlogical < nparams && param_types[nlogical] && arg.type &&
param_types[nlogical]->kind != TYPE_PTR &&
!spl_type_is_scalar(param_types[nlogical]) &&
spl_type_size(param_types[nlogical]) > sizeof(spl_val_t)) {
usize nslots = (spl_type_size(param_types[nlogical]) + sizeof(spl_val_t) - 1) /
sizeof(spl_val_t);
for (usize i = 0; i < nslots; i++) {
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
if (i > 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, i * sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
}
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
arg_slots = (int)nslots;
}
nargs += arg_slots;
nlogical++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
return nargs;
}
static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
char name[256];
@@ -673,7 +738,7 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
advance(ctx); /* skip ( */
int nargs = parse_call_args(ctx);
int nargs = parse_call_args_checked(ctx, f->name, f->param_types, f->nparams);
expect(ctx, TOK_R_PAREN);
if (f->is_extern) {
@@ -690,6 +755,23 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
}
spl_expr_result_t r = {f->ret_type, 0};
/* Multi-slot struct return: copy from returned address to caller's
* temp space. The returned address points to fp[1] in callee's frame
* (fp[0] is a gap). After RET, sp = callee_fp, so the first PUSH in
* emit_copy_slots (DUP) writes to the gap slot, not data. */
if (f->ret_type && !spl_type_is_scalar(f->ret_type) &&
spl_type_size(f->ret_type) > sizeof(spl_val_t)) {
usize nslots = spl_type_slot_count(f->ret_type);
int temp_offset = ctx->current_local_bytes;
ctx->current_local_bytes += (int)(nslots * sizeof(spl_val_t));
if (ctx->current_local_bytes > ctx->peak_local_bytes)
ctx->peak_local_bytes = ctx->current_local_bytes;
spl_emit_copy_slots(ctx, temp_offset, nslots);
spl_emit(ctx, SPL_LADDR, SPL_PTR, temp_offset);
r.is_lvalue = 1;
}
return r;
}
@@ -946,7 +1028,15 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
nargs = 0;
}
nargs += parse_call_args(ctx);
{
spl_type_info_t **cp = func->param_types;
int cn = func->nparams;
if (is_instance && cn > 0) {
cp++;
cn--;
}
nargs += parse_call_args_checked(ctx, func->name, cp, cn);
}
expect(ctx, TOK_R_PAREN);
/* Record fixup for forward-reference resolution */
@@ -957,6 +1047,20 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
vec_push(ctx->call_fixup_funcs, func->func_idx);
left = (spl_expr_result_t){func->ret_type, 0};
/* Multi-slot return: copy to temp, keep address */
if (func->ret_type && !spl_type_is_scalar(func->ret_type) &&
spl_type_size(func->ret_type) > sizeof(spl_val_t)) {
usize nslots = spl_type_slot_count(func->ret_type);
int temp_offset = ctx->current_local_bytes;
ctx->current_local_bytes += (int)(nslots * sizeof(spl_val_t));
if (ctx->current_local_bytes > ctx->peak_local_bytes)
ctx->peak_local_bytes = ctx->current_local_bytes;
spl_emit_copy_slots(ctx, temp_offset, nslots);
spl_emit(ctx, SPL_LADDR, SPL_PTR, temp_offset);
left.is_lvalue = 1;
}
break;
}
}
@@ -1193,7 +1297,10 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
if (left.is_lvalue) {
spl_type_t bt = spl_type_emit_type(left.type);
if (op == TOK_ASSIGN) {
if (op == TOK_ASSIGN && left.type && !spl_type_is_scalar(left.type) &&
right.is_lvalue) {
spl_emit_copy_addr_to_addr(ctx, spl_type_slot_count(left.type), 0);
} else if (op == TOK_ASSIGN) {
spl_emit(ctx, SPL_STORE, bt, 0);
} else {
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
@@ -1310,8 +1417,20 @@ void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset) {
* ============================================================ */
void spl_emit_ret(spl_comp_t *ctx, spl_type_info_t *ret_type) {
spl_type_t rt = ret_type ? spl_type_emit_type(ret_type) : SPL_VOID;
spl_emit(ctx, SPL_RET, rt, 0);
if (ret_type && !spl_type_is_scalar(ret_type) && spl_type_size(ret_type) > sizeof(spl_val_t)) {
/* Multi-slot struct return: copy to fp[0..nslots-1] (above saved_sp),
* then return address of fp[0]. Caller copies from that address to its
* own temp space (see parse_ident / method call handling). */
usize nslots = spl_type_slot_count(ret_type);
/* Store at fp[1..nslots] (skip fp[0] as gap) so that RET's PUSH
* and caller's LADDR both write to the gap slot, not the data. */
spl_emit_copy_slots(ctx, (int)sizeof(spl_val_t), nslots);
spl_emit(ctx, SPL_LADDR, SPL_PTR, (int)sizeof(spl_val_t));
spl_emit(ctx, SPL_RET, SPL_PTR, 0);
} else {
spl_type_t rt = ret_type ? spl_type_emit_type(ret_type) : SPL_VOID;
spl_emit(ctx, SPL_RET, rt, 0);
}
}
/* ============================================================
@@ -1336,7 +1455,11 @@ void spl_emit_store_init(spl_comp_t *ctx, int var_offset, spl_type_info_t *var_t
for (int i = (int)var_type->array_len - 1; i >= 0; i--) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset + (int)(i * stride));
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, bt, 0);
if (elem && !spl_type_is_scalar(elem)) {
spl_emit_copy_addr_to_addr(ctx, spl_type_slot_count(elem), 0);
} else {
spl_emit(ctx, SPL_STORE, bt, 0);
}
}
} else if (var_type && var_type->kind == TYPE_SLICE) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset + (int)sizeof(spl_val_t));