stage1 修复vm 提供简单参数检查 修复聚合类型bug
This commit is contained in:
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user