stage1 修复bug
This commit is contained in:
@@ -294,6 +294,7 @@ static int spl_type_size(spl_type_t t) {
|
||||
case SPL_U64: \
|
||||
case SPL_USIZE: \
|
||||
case SPL_ISIZE: \
|
||||
case SPL_PTR: \
|
||||
_r = _a OP _b; \
|
||||
break; \
|
||||
case SPL_F32: { \
|
||||
|
||||
@@ -133,9 +133,34 @@ spl_type_t spl_type_emit_type(spl_type_info_t *type) {
|
||||
return type->basic_type;
|
||||
if (type->kind == TYPE_PTR)
|
||||
return SPL_PTR;
|
||||
if (type->kind == TYPE_ENUM) {
|
||||
/* Simple enum (no data variants): tag is I32 */
|
||||
vec_for(type->variants, i) {
|
||||
if (vec_at(type->variants, i).data_type)
|
||||
return SPL_PTR; /* has data — treat as aggregate */
|
||||
}
|
||||
return SPL_I32;
|
||||
}
|
||||
return SPL_PTR;
|
||||
}
|
||||
|
||||
/* Scalar types fit in one slot, are auto-loaded on field access,
|
||||
* and support == / != comparison directly. */
|
||||
int spl_type_is_scalar(spl_type_info_t *type) {
|
||||
if (!type)
|
||||
return 1;
|
||||
if (type->kind == TYPE_BASIC || type->kind == TYPE_PTR)
|
||||
return 1;
|
||||
if (type->kind == TYPE_ENUM) {
|
||||
vec_for(type->variants, i) {
|
||||
if (vec_at(type->variants, i).data_type)
|
||||
return 0; /* has data — aggregate */
|
||||
}
|
||||
return 1; /* simple enum — scalar */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- Load from [saved_ptr+offset], store to local var ---- */
|
||||
|
||||
void spl_emit_load_to_var(spl_comp_t *ctx, int ptr_slot_offset, usize byte_offset,
|
||||
|
||||
@@ -91,8 +91,10 @@ const char *spl_type_str(spl_type_info_t *t);
|
||||
int spl_type_is_integer(spl_type_t bt);
|
||||
spl_type_info_t *spl_type_clone(spl_type_info_t *t);
|
||||
|
||||
/* Determine the uniform type for LOAD/STORE codegen (i32→SPL_I32, ptr→SPL_PTR, else→SPL_PTR) */
|
||||
/* Determine the uniform type for LOAD/STORE codegen */
|
||||
spl_type_t spl_type_emit_type(spl_type_info_t *type);
|
||||
/* Returns 1 if type is scalar (fits in one slot, auto-loadable, comparable with ==/!=) */
|
||||
int spl_type_is_scalar(spl_type_info_t *type);
|
||||
|
||||
/* Emit LOAD from [saved_ptr + byte_offset] and STORE to local var at var_offset.
|
||||
* Stack: [] → []
|
||||
@@ -259,7 +261,7 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
||||
* For enum: parses .VariantName, emits tag comparison, returns variant.
|
||||
* For value: parses expression, emits equality comparison. */
|
||||
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, int by_value);
|
||||
void spl_emit_match_value_cmp(spl_comp_t *ctx, int val_offset);
|
||||
|
||||
/* ============================================================
|
||||
|
||||
@@ -128,7 +128,7 @@ static int spl_resolve_type_member(spl_comp_t *ctx, spl_type_info_t *type, const
|
||||
vec_for(type->variants, i) {
|
||||
if (strcmp(vec_at(type->variants, i).name, field) == 0) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(type->variants, i).value);
|
||||
*result = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
*result = (spl_expr_result_t){type, 0};
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -633,7 +633,7 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
|
||||
|
||||
if (sz <= sizeof(spl_val_t)) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||
spl_emit(ctx, SPL_LOAD, spl_type_emit_type(type), 0);
|
||||
return (spl_expr_result_t){type, 0};
|
||||
} else {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
|
||||
@@ -698,7 +698,7 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
||||
if (v) {
|
||||
spl_val_t cv = 0;
|
||||
if (map_get(ctx->const_values, name, &cv)) {
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, cv);
|
||||
spl_emit(ctx, SPL_PUSH, spl_type_emit_type(v->type), cv);
|
||||
spl_expr_result_t r = {v->type, 0};
|
||||
return r;
|
||||
}
|
||||
@@ -736,10 +736,9 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
|
||||
|
||||
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result,
|
||||
spl_type_info_t *type) {
|
||||
if (type->kind == TYPE_BASIC || type->kind == TYPE_PTR) {
|
||||
if (spl_type_is_scalar(type)) {
|
||||
if (!ctx->addr_of_mode) {
|
||||
spl_type_t bt = (type->kind == TYPE_BASIC) ? type->basic_type : SPL_PTR;
|
||||
spl_emit(ctx, SPL_LOAD, bt, 0);
|
||||
spl_emit(ctx, SPL_LOAD, spl_type_emit_type(type), 0);
|
||||
*result = (spl_expr_result_t){type, 0};
|
||||
return;
|
||||
}
|
||||
@@ -758,14 +757,14 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
||||
|
||||
switch (op->type) {
|
||||
case TOK_SUB:
|
||||
spl_emit(ctx, SPL_NEG, SPL_I32, 0);
|
||||
spl_emit(ctx, SPL_NEG, spl_type_emit_type(right.type), 0);
|
||||
break;
|
||||
case TOK_NOT:
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
|
||||
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
||||
spl_emit(ctx, SPL_EQ, spl_type_emit_type(right.type), 0);
|
||||
break;
|
||||
case TOK_BIT_NOT:
|
||||
spl_emit(ctx, SPL_NOT, SPL_I32, 0);
|
||||
spl_emit(ctx, SPL_NOT, spl_type_emit_type(right.type), 0);
|
||||
break;
|
||||
case TOK_AND:
|
||||
if (!right.is_lvalue) {
|
||||
@@ -1193,9 +1192,7 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
||||
ctx->addr_of_mode = saved_addr_of_mode;
|
||||
|
||||
if (left.is_lvalue) {
|
||||
spl_type_t bt = left.type
|
||||
? (left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_PTR)
|
||||
: SPL_I32;
|
||||
spl_type_t bt = spl_type_emit_type(left.type);
|
||||
if (op == TOK_ASSIGN) {
|
||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||
} else {
|
||||
@@ -1213,12 +1210,20 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
|
||||
|
||||
/* Regular binary op */
|
||||
spl_parse_expr(ctx, next_prec);
|
||||
int sop = binop_to_sir(op, left.type ? left.type->basic_type : SPL_I32);
|
||||
spl_type_t bt = left.type && left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_I32;
|
||||
/* Forbid comparison of non-scalar types (struct, enum-with-data) */
|
||||
if ((op == TOK_EQ || op == TOK_NEQ) && left.type && !spl_type_is_scalar(left.type)) {
|
||||
spl_comp_error(ctx, "type '%s' does not support comparison", spl_type_str(left.type));
|
||||
}
|
||||
spl_type_t bt = spl_type_emit_type(left.type);
|
||||
int sop = binop_to_sir(op, bt);
|
||||
if (sop >= 0) {
|
||||
spl_emit(ctx, sop, bt, 0);
|
||||
}
|
||||
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
|
||||
/* Comparisons return boolean (I32), other binary ops match operand type */
|
||||
int is_compare = (op == TOK_EQ || op == TOK_NEQ || op == TOK_LT || op == TOK_GT ||
|
||||
op == TOK_LE || op == TOK_GE);
|
||||
spl_type_info_t *result_type = is_compare ? spl_type_basic(SPL_I32) : left.type;
|
||||
return (spl_expr_result_t){result_type, 0};
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -1231,7 +1236,7 @@ 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) {
|
||||
int val_offset, int by_value) {
|
||||
char vname[256];
|
||||
|
||||
/* Parse variant reference, reusing the same type resolution path
|
||||
@@ -1274,10 +1279,16 @@ lookup:
|
||||
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);
|
||||
if (strcmp(v->name, vname) == 0) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
if (by_value) {
|
||||
/* Scalar enum: raw tag stored directly in slot */
|
||||
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
|
||||
} else {
|
||||
/* Enum with data or *Enum: slot has a pointer, dereference it */
|
||||
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
|
||||
spl_emit(ctx, SPL_PUSH, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
|
||||
spl_emit(ctx, SPL_LOAD, SPL_I32, 0);
|
||||
}
|
||||
spl_emit(ctx, SPL_PUSH, SPL_I32, v->value);
|
||||
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
|
||||
return v;
|
||||
@@ -1299,15 +1310,7 @@ 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 = SPL_VOID;
|
||||
if (ret_type) {
|
||||
if (ret_type->kind == TYPE_BASIC) {
|
||||
rt = ret_type->basic_type;
|
||||
} else {
|
||||
/* Pointer, struct, enum, etc: return address of value */
|
||||
rt = SPL_PTR;
|
||||
}
|
||||
}
|
||||
spl_type_t rt = ret_type ? spl_type_emit_type(ret_type) : SPL_VOID;
|
||||
spl_emit(ctx, SPL_RET, rt, 0);
|
||||
}
|
||||
|
||||
@@ -1321,14 +1324,14 @@ void spl_emit_store_init(spl_comp_t *ctx, int var_offset, spl_type_info_t *var_t
|
||||
if (sz <= sizeof(spl_val_t)) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(var_type), 0);
|
||||
} else {
|
||||
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
|
||||
spl_emit_copy_slots(ctx, var_offset, nslots);
|
||||
}
|
||||
} else if (var_type && var_type->kind == TYPE_ARRAY) {
|
||||
spl_type_info_t *elem = var_type->elem;
|
||||
spl_type_t bt = (elem && elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_I32;
|
||||
spl_type_t bt = spl_type_emit_type(elem);
|
||||
usize stride = spl_type_elem_stride(elem);
|
||||
for (int i = (int)var_type->array_len - 1; i >= 0; i--) {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset + (int)(i * stride));
|
||||
@@ -1344,9 +1347,7 @@ void spl_emit_store_init(spl_comp_t *ctx, int var_offset, spl_type_info_t *var_t
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
} else {
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, var_offset);
|
||||
spl_type_t bt = (var_type->kind == TYPE_BASIC) ? var_type->basic_type
|
||||
: (var_type->kind == TYPE_PTR) ? SPL_PTR
|
||||
: SPL_I32;
|
||||
spl_type_t bt = spl_type_emit_type(var_type);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, bt, 0);
|
||||
}
|
||||
|
||||
@@ -182,8 +182,7 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) {
|
||||
/* Expression statement: drop value, consume ; */
|
||||
if (!is_assign && expr.type && expr.type->kind == TYPE_BASIC &&
|
||||
expr.type->basic_type != SPL_VOID)
|
||||
if (!is_assign && expr.type && spl_type_emit_type(expr.type) != SPL_VOID)
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
while (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE)
|
||||
advance(ctx);
|
||||
@@ -545,8 +544,8 @@ static void parse_defer_stmt(spl_comp_t *ctx) {
|
||||
* Delegates comparison to expr layer (spl_emit_match_enum_cmp).
|
||||
* Returns the variant for binding parsing, or NULL on error. */
|
||||
static spl_enum_variant_t *parse_match_enum_variant(spl_comp_t *ctx, spl_type_info_t *enum_type,
|
||||
int val_offset) {
|
||||
return spl_emit_match_enum_cmp(ctx, enum_type, val_offset);
|
||||
int val_offset, int by_value) {
|
||||
return spl_emit_match_enum_cmp(ctx, enum_type, val_offset, by_value);
|
||||
}
|
||||
|
||||
/* Parse a value pattern in a match arm (non-enum).
|
||||
@@ -642,6 +641,9 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scalar enums store the raw tag directly; others store a pointer */
|
||||
int match_by_value = (t && t->kind == TYPE_ENUM && spl_type_is_scalar(t));
|
||||
|
||||
/* Save match value to temp slot */
|
||||
int val_offset = ctx->current_local_bytes;
|
||||
ctx->current_local_bytes += (int)sizeof(spl_val_t);
|
||||
@@ -649,7 +651,7 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
ctx->peak_local_bytes = ctx->current_local_bytes;
|
||||
spl_emit(ctx, SPL_LADDR, SPL_PTR, val_offset);
|
||||
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
|
||||
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
|
||||
spl_emit(ctx, SPL_STORE, spl_type_emit_type(t), 0);
|
||||
|
||||
skip_nl(ctx);
|
||||
if (peek(ctx)->type == TOK_L_BRACE)
|
||||
@@ -684,7 +686,8 @@ static void parse_match_stmt(spl_comp_t *ctx) {
|
||||
} else {
|
||||
for (;;) {
|
||||
if (is_enum_match) {
|
||||
arm_variant = parse_match_enum_variant(ctx, enum_type, val_offset);
|
||||
arm_variant =
|
||||
parse_match_enum_variant(ctx, enum_type, val_offset, match_by_value);
|
||||
if (ctx->has_error)
|
||||
break;
|
||||
skip_nl(ctx);
|
||||
@@ -887,8 +890,7 @@ static void parse_expr_stmt(spl_comp_t *ctx) {
|
||||
if (is_assign)
|
||||
ctx->addr_of_mode = 0;
|
||||
|
||||
if (!is_assign && expr.type && expr.type->kind == TYPE_BASIC &&
|
||||
expr.type->basic_type != SPL_VOID)
|
||||
if (!is_assign && expr.type && spl_type_emit_type(expr.type) != SPL_VOID)
|
||||
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
|
||||
if (peek(ctx)->type == TOK_SEMICOLON)
|
||||
advance(ctx);
|
||||
|
||||
Reference in New Issue
Block a user