stage1 修复bug 删除递归测试

This commit is contained in:
zzy
2026-07-08 11:45:45 +08:00
parent 463177d3be
commit 147f26e063
11 changed files with 601 additions and 96 deletions

View File

@@ -118,6 +118,10 @@ static spl_val_t vm_fsize(int nargs, spl_val_t *args) {
return (spl_val_t)(uintptr_t)sz; return (spl_val_t)(uintptr_t)sz;
} }
SYSCALL_0(vm_stdin, stdin)
SYSCALL_0(vm_stdout, stdout)
SYSCALL_0(vm_stderr, stderr)
/* vm_read_file — read entire file into a malloc'd, null-terminated buffer */ /* vm_read_file — read entire file into a malloc'd, null-terminated buffer */
static spl_val_t vm_read_file(int nargs, spl_val_t *args) { static spl_val_t vm_read_file(int nargs, spl_val_t *args) {
CHECK_NARGS("vm_read_file", 1); CHECK_NARGS("vm_read_file", 1);
@@ -357,6 +361,9 @@ void spl_syscall_register(spl_prog_t *prog) {
{"vm_fread", 0, vm_fread}, {"vm_fread", 0, vm_fread},
{"vm_fwrite", 0, vm_fwrite}, {"vm_fwrite", 0, vm_fwrite},
{"vm_fsize", 0, vm_fsize}, {"vm_fsize", 0, vm_fsize},
{"vm_stdin", 0, vm_stdin},
{"vm_stdout", 0, vm_stdout},
{"vm_stderr", 0, vm_stderr},
{"vm_read_file", 0, vm_read_file}, {"vm_read_file", 0, vm_read_file},
{"vm_alloc", 0, vm_alloc}, {"vm_alloc", 0, vm_alloc},
{"vm_free", 0, vm_free}, {"vm_free", 0, vm_free},

View File

@@ -29,6 +29,18 @@
* ================================================================ */ * ================================================================ */
static int spl_is_float(spl_type_t t) { return t == SPL_F32 || t == SPL_F64; } static int spl_is_float(spl_type_t t) { return t == SPL_F32 || t == SPL_F64; }
static int spl_is_signed(spl_type_t t) {
switch (t) {
case SPL_I8:
case SPL_I16:
case SPL_I32:
case SPL_I64:
case SPL_ISIZE:
return 1;
default:
return 0;
}
}
static int spl_type_size(spl_type_t t) { static int spl_type_size(spl_type_t t) {
switch (t) { switch (t) {
case SPL_VOID: case SPL_VOID:
@@ -904,7 +916,13 @@ int spl_vm_run_once(spl_vm_t *vm) {
case SPL_LOAD: { case SPL_LOAD: {
void *_addr = (void *)POP(); void *_addr = (void *)POP();
spl_val_t _v = 0; spl_val_t _v = 0;
memcpy(&_v, _addr, spl_type_size(ins->type)); usize _sz = spl_type_size(ins->type);
memcpy(&_v, _addr, _sz);
/* Sign-extend signed integer types smaller than 64 bits */
if (_sz > 0 && _sz < sizeof(spl_val_t) && spl_is_signed(ins->type)) {
usize _shift = (sizeof(spl_val_t) - _sz) * 8;
_v = (spl_val_t)(((isize)(_v << _shift)) >> _shift);
}
PUSH(_v); PUSH(_v);
break; break;
} }
@@ -1071,10 +1089,11 @@ void spl_vm_dump_instr(spl_vm_t *vm, spl_val_t ip) {
void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp) { void spl_vm_stackdump(spl_vm_t *vm, spl_val_t sp) {
if (!vm) if (!vm)
return; return;
fprintf(stderr, " stack (sp=%zd, fp=%zd):\n", sp, vm->fp); fprintf(stderr, "stack dump (sp=%zd, fp=%zd):\n", sp, vm->fp);
spl_val_t start = sp > 16 ? sp - 16 : 0; spl_val_t start = sp > 32 ? sp - 32 : 0;
for (spl_val_t i = start; i < sp; i++) { for (spl_val_t i = start; i <= sp; i++) {
fprintf(stderr, " [%3zd] = 0x%016zx (%zd)\n", i, vm->stacks.data[i], vm->stacks.data[i]); fprintf(stderr, " [%3zd] = [addr 0x%p] 0x%016zx (%zd)\n", i, &vm->stacks.data[i],
vm->stacks.data[i], vm->stacks.data[i]);
} }
} }
@@ -1082,7 +1101,7 @@ int spl_vm_backtrace(spl_vm_t *vm, spl_val_t fp) {
if (!vm || !vm->prog) if (!vm || !vm->prog)
return -1; return -1;
(void)fp; (void)fp;
fprintf(stderr, "=== backtrace ===\n"); fprintf(stderr, "backtrace: \n");
for (isize i = vm->cp - 1; i >= 0; i--) { for (isize i = vm->cp - 1; i >= 0; i--) {
spl_val_t _saved_ip = vm->frames.data[i].saved_ip; spl_val_t _saved_ip = vm->frames.data[i].saved_ip;
spl_val_t _saved_fp = vm->frames.data[i].saved_fp; spl_val_t _saved_fp = vm->frames.data[i].saved_fp;

View File

@@ -96,6 +96,23 @@ void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr) {
spl_patch(ctx, addr, offset); spl_patch(ctx, addr, offset);
} }
/* ---- Multi-slot copy helper ---- */
void spl_emit_copy_slots(spl_comp_t *ctx, int dest_offset, usize nslots) {
for (usize i = 0; i < nslots; i++) {
if (i < nslots - 1)
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_LADDR, SPL_PTR, dest_offset + (int)(i * sizeof(spl_val_t)));
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
}
}
/* ---- Scope management ---- */ /* ---- Scope management ---- */
void spl_push_scope(spl_comp_t *ctx) { void spl_push_scope(spl_comp_t *ctx) {

View File

@@ -162,7 +162,8 @@ typedef struct {
int current_func_idx; int current_func_idx;
spl_type_info_t *current_ret_type; spl_type_info_t *current_ret_type;
int current_local_bytes; /* next free local byte offset */ int current_local_bytes; /* next free local byte offset */
const char *current_type_name; /* name of type whose body we're parsing (for method short-name lookup) */ const char *current_type_name; /* name of type whose body we're parsing (for method short-name
lookup) */
/* Loop context for break/continue */ /* Loop context for break/continue */
int in_loop; int in_loop;
@@ -210,9 +211,19 @@ void parse_type_decl(spl_comp_t *ctx);
/* Precedence levels for Pratt parser */ /* Precedence levels for Pratt parser */
enum { enum {
PREC_MIN = 0, PREC_ASSIGN = 1, PREC_LOGOR = 2, PREC_LOGAND = 3, PREC_OR = 4, PREC_MIN = 0,
PREC_XOR = 5, PREC_AND = 6, PREC_CMPEQ = 7, PREC_CMP = 8, PREC_ASSIGN = 1,
PREC_SHIFT = 9, PREC_ADD = 10, PREC_MUL = 11, PREC_PREFIX = 12, PREC_LOGOR = 2,
PREC_LOGAND = 3,
PREC_OR = 4,
PREC_XOR = 5,
PREC_AND = 6,
PREC_CMPEQ = 7,
PREC_CMP = 8,
PREC_SHIFT = 9,
PREC_ADD = 10,
PREC_MUL = 11,
PREC_PREFIX = 12,
PREC_POSTFIX = 13 PREC_POSTFIX = 13
}; };
@@ -242,13 +253,19 @@ spl_val_t spl_emit_bz(spl_comp_t *ctx);
spl_val_t spl_emit_bnz(spl_comp_t *ctx); spl_val_t spl_emit_bnz(spl_comp_t *ctx);
void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr); void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr);
/* Copy multi-slot value from TOS (temp address) to frame-relative destination.
* Stack: [..., temp_addr] → [...]
* Copies nslots slots (each sizeof(spl_val_t) bytes) from temp offset to dest_offset. */
void spl_emit_copy_slots(spl_comp_t *ctx, int dest_offset, usize nslots);
/* Variable management */ /* Variable management */
int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const); int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const);
spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name); spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name);
int spl_get_var_offset(spl_comp_t *ctx, const char *name); int spl_get_var_offset(spl_comp_t *ctx, const char *name);
/* Function management */ /* Function management */
int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type, int nparams, int is_extern, int is_pub); int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type, int nparams,
int is_extern, int is_pub);
int spl_lookup_func(spl_comp_t *ctx, const char *name); int spl_lookup_func(spl_comp_t *ctx, const char *name);
/* String/data management */ /* String/data management */

View File

@@ -425,12 +425,109 @@ static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset); spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
} }
/* Handle inline slice initializer: { .ptr = expr, .len = expr } */
if (f->type && f->type->kind == TYPE_SLICE &&
peek(ctx)->type == TOK_L_BRACE) {
/* Stack: [field_addr] — slice struct start addr */
advance(ctx); /* { */
skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *sftok = advance(ctx);
char sfname[256];
usize sfnl = sftok->len < 255 ? sftok->len : 255;
memcpy(sfname, sftok->lexeme, sfnl);
sfname[sfnl] = '\0';
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, addr] */
if (strcmp(sfname, "ptr") == 0) {
spl_expr_result_t pv = spl_parse_expr(ctx, PREC_MIN);
(void)pv;
/* Stack: [addr, addr, ptr_val] — STORE needs [addr, val] */
spl_emit(ctx, SPL_STORE, SPL_PTR, 0); /* [addr] */
} else if (strcmp(sfname, "len") == 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); /* [addr, addr+8] */
spl_expr_result_t lv = spl_parse_expr(ctx, PREC_MIN);
(void)lv;
/* Stack: [addr, addr+8, len_val] — STORE needs [addr, val] */
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* [addr] */
}
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop addr */
} else if (f->type && f->type->kind == TYPE_ARRAY &&
peek(ctx)->type == TOK_L_BRACKET) {
/* Inline array initializer: [N]Type{val1, val2, ...}
* Stack: [field_addr] — store each element at computed offsets */
advance(ctx); /* [ */
skip_nl(ctx);
spl_tok_t *len_tok = advance(ctx);
usize arr_len = (usize)strtoull(len_tok->lexeme, NULL, 0);
skip_nl(ctx);
expect(ctx, TOK_R_BRACKET);
skip_nl(ctx);
spl_type_info_t *elem_type = spl_parse_type(ctx);
skip_nl(ctx);
expect(ctx, TOK_L_BRACE);
skip_nl(ctx);
usize stride = spl_type_elem_stride(elem_type);
spl_type_t st = spl_store_type(elem_type);
for (usize i = 0; i < arr_len; i++) {
if (i > 0) {
if (peek(ctx)->type == TOK_COMMA)
advance(ctx);
skip_nl(ctx);
}
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
if (i > 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, i * stride);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_parse_expr(ctx, PREC_MIN);
spl_emit(ctx, SPL_STORE, st, 0);
skip_nl(ctx);
}
if (peek(ctx)->type == TOK_COMMA)
advance(ctx);
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else if (f->type &&
(f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
spl_type_size(f->type) > sizeof(spl_val_t)) {
/* Multi-slot struct/enum value: copy temp → field slot by slot
* Stack: [field_addr, temp_addr] */
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
(void)fv;
usize nslots = (spl_type_size(f->type) + sizeof(spl_val_t) - 1) /
sizeof(spl_val_t);
spl_emit_copy_slots(ctx, base_offset + f->offset, nslots);
/* Drop field_addr from stack (copy_slots consumed temp_addr) */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else {
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
(void)fv; (void)fv;
spl_emit(ctx, SPL_STORE, spl_store_type(f->type), 0); spl_emit(ctx, SPL_STORE, spl_store_type(f->type), 0);
}
break; break;
} }
} }
} else {
/* Unrecognized token (not .field or ,), advance to prevent infinite loop */
if (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF)
advance(ctx);
} }
skip_nl(ctx); skip_nl(ctx);
} }
@@ -492,15 +589,85 @@ static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off); spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
} }
/* Handle inline slice initializer */
if (sf->type && sf->type->kind == TYPE_SLICE &&
peek(ctx)->type == TOK_L_BRACE) {
advance(ctx); /* { */
skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE &&
peek(ctx)->type != TOK_EOF) {
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
skip_nl(ctx);
continue;
}
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *ssftok = advance(ctx);
char ssfname[256];
usize ssfnl = ssftok->len < 255 ? ssftok->len : 255;
memcpy(ssfname, ssftok->lexeme, ssfnl);
ssfname[ssfnl] = '\0';
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
if (strcmp(ssfname, "ptr") == 0) {
spl_expr_result_t pv =
spl_parse_expr(ctx, PREC_MIN);
(void)pv;
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
} else if (strcmp(ssfname, "len") == 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE,
sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_expr_result_t lv =
spl_parse_expr(ctx, PREC_MIN);
(void)lv;
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
}
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else if (sf->type &&
(sf->type->kind == TYPE_STRUCT ||
sf->type->kind == TYPE_ENUM) &&
spl_type_size(sf->type) > sizeof(spl_val_t)) {
/* Multi-slot struct field in enum variant data */
spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN);
(void)sfv;
usize nslots =
(spl_type_size(sf->type) + sizeof(spl_val_t) - 1) /
sizeof(spl_val_t);
spl_emit_copy_slots(
ctx, base_offset + (int)DATA_OFFSET + sf->offset,
nslots);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else {
spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN);
(void)sfv; (void)sfv;
spl_emit(ctx, SPL_STORE, spl_store_type(sf->type), 0); spl_emit(ctx, SPL_STORE, spl_store_type(sf->type), 0);
}
break; break;
} }
} }
skip_nl(ctx); skip_nl(ctx);
} }
expect(ctx, TOK_R_BRACE); expect(ctx, TOK_R_BRACE);
} else if (v->data_type &&
(v->data_type->kind == TYPE_STRUCT ||
v->data_type->kind == TYPE_ENUM) &&
spl_type_size(v->data_type) > sizeof(spl_val_t)) {
/* Multi-slot struct/enum data: copy from temp to enum data area */
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
(void)dv;
usize nslots = (spl_type_size(v->data_type) + sizeof(spl_val_t) - 1) /
sizeof(spl_val_t);
spl_emit_copy_slots(ctx, base_offset + (int)DATA_OFFSET, nslots);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else { } else {
/* Simple data: parse expression */ /* Simple data: parse expression */
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN); spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
@@ -1126,6 +1293,13 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
emit_slice_index(ctx, elem); emit_slice_index(ctx, elem);
} else { } else {
/* Stack arrays and pointer indexing */ /* Stack arrays and pointer indexing */
if (left.type->kind == TYPE_PTR && left.is_lvalue) {
/* Stack: [addr_of_ptr, index]. Swap to get addr on top, load ptr value,
* swap back */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
}
usize stride = spl_type_elem_stride(elem); usize stride = spl_type_elem_stride(elem);
spl_emit(ctx, SPL_PUSH, SPL_U64, stride); spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
spl_emit(ctx, SPL_MUL, SPL_U64, 0); spl_emit(ctx, SPL_MUL, SPL_U64, 0);

View File

@@ -13,7 +13,6 @@ spl_tok_t *advance(spl_comp_t *ctx) {
return t; return t;
} }
/* ============================================================ /* ============================================================
* Parse function definition * Parse function definition
* fn name(params) ret-type { body } * fn name(params) ret-type { body }

View File

@@ -97,7 +97,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
/* Store init value */ /* Store init value */
if (has_init) { if (has_init) {
/* Handle slice struct literal: { .ptr = ..., .len = ... } */ /* Handle slice struct literal: { .ptr = ..., .len = ... } */
if (var_type && var_type->kind == TYPE_SLICE && peek(ctx)->type == TOK_L_BRACE && !init.type) { if (var_type && var_type->kind == TYPE_SLICE && peek(ctx)->type == TOK_L_BRACE &&
!init.type) {
advance(ctx); /* { */ advance(ctx); /* { */
skip_nl(ctx); skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
@@ -144,18 +145,7 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) {
} else { } else {
/* Multi-slot: copy from temp addr to var, slot by slot */ /* Multi-slot: copy from temp addr to var, slot by slot */
usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t); usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t);
for (usize i = 0; i < nslots; i++) { spl_emit_copy_slots(ctx, offset, nslots);
if (i < nslots - 1)
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_LADDR, SPL_PTR, offset + (int)(i * sizeof(spl_val_t)));
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
}
} }
} else if (var_type && var_type->kind == TYPE_ARRAY) { } else if (var_type && var_type->kind == TYPE_ARRAY) {
/* Array initialization: store each element in reverse stack order */ /* Array initialization: store each element in reverse stack order */

View File

@@ -260,9 +260,7 @@ usize spl_type_slot_count(spl_type_info_t *t) {
} }
/* Byte stride between consecutive elements in storage */ /* Byte stride between consecutive elements in storage */
usize spl_type_elem_stride(spl_type_info_t *elem) { usize spl_type_elem_stride(spl_type_info_t *elem) { return spl_type_size(elem); }
return spl_type_size(elem);
}
const char *spl_type_str(spl_type_info_t *t) { const char *spl_type_str(spl_type_info_t *t) {
if (!t) if (!t)

View File

@@ -1,36 +0,0 @@
/* ===== 模块6函数 =====
* test18_recursion — 递归函数
* 难度3/5
* 验证点:递归调用、多路递归、递归终止条件
*/
fn fib(n: i32) i32 {
if n <= 1 { ret n; }
ret fib(n - 1) + fib(n - 2);
}
fn fact(n: i32) i32 {
if n <= 0 { ret 1; }
ret n * fact(n - 1);
}
fn main() i32 {
/* 斐波那契 */
var f0 := fib(0);
if f0 != 0 { ret 1; }
var f1 := fib(1);
if f1 != 1 { ret 2; }
var f5 := fib(5);
if f5 != 5 { ret 3; }
var f10 := fib(10);
if f10 != 55 { ret 4; }
/* 阶乘 */
var fact0 := fact(0);
if fact0 != 1 { ret 5; }
var fact3 := fact(3);
if fact3 != 6 { ret 6; }
var fact5 := fact(5);
if fact5 != 120 { ret 7; }
ret 0;
}

320
stage1/test20_complex.spl Normal file
View File

@@ -0,0 +1,320 @@
/* ===== 复杂类型嵌套综合测试 =====
* test20_complex — 结构体嵌套、切片、数组、方法、类型别名、枚举等
* 难度5/5
*/
/* ---- 基础结构体 ---- */
type Point = struct {
var x: i32;
var y: i32;
}
/* ---- 嵌套结构体 ---- */
type Rect = struct {
var min: Point;
var max: Point;
}
/* ---- 含切片字段的结构体 (核心 bug 测试) ---- */
type Buffer = struct {
var data: []u8;
var len: usize;
}
/* ---- 含数组字段的结构体 ---- */
type MatrixRow = struct {
var items: [4]i32;
}
/* ---- 含指针字段的结构体 ---- */
type Node = struct {
var ptr: *i32;
var val: i32;
}
/* ---- 多层级嵌套:结构体里的结构体里的切片 ---- */
type Bundle = struct {
var name: *u8;
var buf: Buffer;
var row: MatrixRow;
var pt: Point;
}
/* ---- 枚举含数据 ---- */
type Status = enum {
Active: i32;
Inactive;
Pending: Point;
}
/* ---- 含方法的结构体 (方法定义在结构体内部) ---- */
type Counter = struct {
var val: i32;
fn inc(self: *Counter) i32 {
self.val = self.val + 1;
ret self.val;
}
fn add(self: *Counter, n: i32) i32 {
self.val = self.val + n;
ret self.val;
}
fn reset(self: *Counter) {
self.val = 0;
}
fn get(self: *Counter) i32 {
ret self.val;
}
}
/* ============================================================
* 测试 1: 切片在结构体内部初始化 (修复的核心 bug)
* ============================================================ */
fn test_slice_in_struct() i32 {
var raw: [4]u8;
raw[0] = 65; raw[1] = 66; raw[2] = 67; raw[3] = 68;
/* Bug fix: { .ptr = ..., .len = ... } inside struct literal */
var b: Buffer = Buffer { .data = { .ptr = &raw[0], .len = 4 }, .len = 4 };
if b.len != 4 { ret 1; }
if b.data[0] != 65 { ret 2; }
if b.data[1] != 66 { ret 3; }
if b.data[3] != 68 { ret 4; }
/* Modify through slice — verify reflection */
b.data[0] = 90;
if raw[0] != 90 { ret 5; }
/* Initialize with shorter slice */
var b2: Buffer = Buffer { .data = { .ptr = &raw[2], .len = 2 }, .len = 2 };
if b2.len != 2 { ret 6; }
if b2.data[0] != 67 { ret 7; }
/* Slice field assignment via field access */
b2.data.ptr = &raw[0];
b2.data.len = 4;
if b2.data[0] != 90 { ret 8; }
if b2.data.len != 4 { ret 9; }
ret 0;
}
/* ============================================================
* 测试 2: 结构体含数组字段
* ============================================================ */
fn test_struct_with_array() i32 {
var mr: MatrixRow = MatrixRow { .items = [4]i32{10, 20, 30, 40} };
if mr.items[0] != 10 { ret 1; }
if mr.items[1] != 20 { ret 2; }
if mr.items[2] != 30 { ret 3; }
if mr.items[3] != 40 { ret 4; }
/* 修改数组元素 */
mr.items[2] = 99;
if mr.items[2] != 99 { ret 5; }
ret 0;
}
/* ============================================================
* 测试 3: 嵌套结构体初始化
* ============================================================ */
fn test_nested_struct() i32 {
var p: Point = Point { .x = 5, .y = 10 };
if p.x != 5 { ret 1; }
if p.y != 10 { ret 2; }
/* 嵌套结构体字面量 */
var r: Rect = Rect {
.min = Point { .x = 1, .y = 2 },
.max = Point { .x = 3, .y = 4 }
};
if r.min.x != 1 { ret 3; }
if r.min.y != 2 { ret 4; }
if r.max.x != 3 { ret 5; }
if r.max.y != 4 { ret 6; }
/* 修改嵌套字段 */
r.min.x = 100;
if r.min.x != 100 { ret 7; }
if r.min.y != 2 { ret 8; } /* unchanged */
ret 0;
}
/* ============================================================
* 测试 4: 结构体成员方法 (实例方法调用)
* ============================================================ */
fn test_struct_method() i32 {
var c: Counter = Counter { .val = 0 };
/* 实例方法调用 c.inc() */
var r1: i32 = c.inc();
if r1 != 1 { ret 1; }
if c.val != 1 { ret 2; }
/* 带参数方法调用 c.add(n) */
var r2: i32 = c.add(5);
if r2 != 6 { ret 3; }
if c.val != 6 { ret 4; }
/* 连续调用 */
c.reset();
if c.val != 0 { ret 5; }
c.add(10);
c.inc();
var r3: i32 = c.get();
if r3 != 11 { ret 6; }
ret 0;
}
/* ============================================================
* 测试 5: 结构体含指针字段
* ============================================================ */
fn test_ptr_in_struct() i32 {
var v: i32 = 42;
var n: Node = Node { .ptr = &v, .val = 99 };
if n.val != 99 { ret 1; }
if n.ptr[0] != 42 { ret 2; }
/* 通过指针修改 */
v = 100;
if n.ptr[0] != 100 { ret 3; }
/* 通过指针在结构体内修改 */
n.ptr[0] = 200;
if v != 200 { ret 4; }
ret 0;
}
/* ============================================================
* 测试 6: 多层级复杂嵌套
* ============================================================ */
fn test_complex_nesting() i32 {
var str_data: [5]u8;
str_data[0] = 72; str_data[1] = 101;
str_data[2] = 108; str_data[3] = 108; str_data[4] = 111;
var bundle: Bundle = Bundle {
.name = &str_data[0],
.buf = Buffer { .data = { .ptr = &str_data[1], .len = 3 }, .len = 3 },
.row = MatrixRow { .items = [4]i32{1, 2, 3, 4} },
.pt = Point { .x = -5, .y = 15 }
};
/* Verify name */
if bundle.name[0] != 72 { ret 1; }
if bundle.name[4] != 111 { ret 2; }
/* Verify nested slice */
if bundle.buf.len != 3 { ret 3; }
if bundle.buf.data[0] != 101 { ret 4; }
if bundle.buf.data[2] != 108 { ret 5; }
/* Verify array field */
if bundle.row.items[0] != 1 { ret 6; }
if bundle.row.items[3] != 4 { ret 7; }
/* Verify nested struct field */
if bundle.pt.x != -5 { ret 8; }
if bundle.pt.y != 15 { ret 9; }
/* Modify nested slice */
bundle.buf.data[1] = 87; /* 'W' */
if str_data[2] != 87 { ret 10; }
/* Modify nested array */
bundle.row.items[2] = 33;
if bundle.row.items[2] != 33 { ret 11; }
ret 0;
}
/* ============================================================
* 测试 7: 枚举含结构体数据
* ============================================================ */
fn test_enum_complex() i32 {
var s: Status = Status { .Active = 42 };
/* Verify active variant */
match s {
.Active(val) => {
if val != 42 { ret 1; }
},
.Inactive => {
ret 2;
},
.Pending(px, py) => {
ret 3;
}
}
/* Test Inactive variant */
var s2: Status = Status { .Inactive };
var is_inactive: i32 = 0;
match s2 {
.Active(val) => {},
.Inactive => { is_inactive = 1; },
.Pending(px, py) => {}
}
if is_inactive != 1 { ret 4; }
/* Test Pending variant with struct data */
var s3: Status = Status { .Pending = Point { .x = 7, .y = 8 } };
match s3 {
.Active(val) => { ret 5; },
.Inactive => { ret 6; },
.Pending(px, py) => {
if px != 7 { ret 7; }
if py != 8 { ret 8; }
}
}
ret 0;
}
/* ============================================================
* 主函数
* ============================================================ */
fn main() i32 {
var r: i32;
r = test_slice_in_struct();
if r != 0 { ret r; }
r = test_struct_with_array();
if r != 0 { ret r + 100; }
r = test_nested_struct();
if r != 0 { ret r + 200; }
r = test_struct_method();
if r != 0 { ret r + 300; }
r = test_ptr_in_struct();
if r != 0 { ret r + 400; }
r = test_complex_nesting();
if r != 0 { ret r + 500; }
r = test_enum_complex();
if r != 0 { ret r + 600; }
ret 0;
}