From 147f26e063c649eb1728238f4b06d3ad5d42ade4 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 8 Jul 2026 11:45:45 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E4=BF=AE=E5=A4=8Dbug=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E9=80=92=E5=BD=92=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage0/spl_syscall.c | 7 + stage0/spl_vm.c | 31 +++- stage1/spl_comp.c | 17 ++ stage1/spl_comp.h | 73 ++++---- stage1/spl_expr.c | 190 ++++++++++++++++++++- stage1/spl_lexer.h | 2 +- stage1/spl_parser.c | 1 - stage1/spl_stmt.c | 16 +- stage1/spl_type.c | 4 +- stage1/test18_recursion.spl | 36 ---- stage1/test20_complex.spl | 320 ++++++++++++++++++++++++++++++++++++ 11 files changed, 601 insertions(+), 96 deletions(-) delete mode 100644 stage1/test18_recursion.spl create mode 100644 stage1/test20_complex.spl diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index 52256ff..e540a95 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -118,6 +118,10 @@ static spl_val_t vm_fsize(int nargs, spl_val_t *args) { 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 */ static spl_val_t vm_read_file(int nargs, spl_val_t *args) { CHECK_NARGS("vm_read_file", 1); @@ -357,6 +361,9 @@ void spl_syscall_register(spl_prog_t *prog) { {"vm_fread", 0, vm_fread}, {"vm_fwrite", 0, vm_fwrite}, {"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_alloc", 0, vm_alloc}, {"vm_free", 0, vm_free}, diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index f794f8f..4795531 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -29,6 +29,18 @@ * ================================================================ */ 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) { switch (t) { case SPL_VOID: @@ -904,7 +916,13 @@ int spl_vm_run_once(spl_vm_t *vm) { case SPL_LOAD: { void *_addr = (void *)POP(); 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); 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) { if (!vm) return; - fprintf(stderr, " stack (sp=%zd, fp=%zd):\n", sp, vm->fp); - spl_val_t start = sp > 16 ? sp - 16 : 0; - 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, "stack dump (sp=%zd, fp=%zd):\n", sp, vm->fp); + spl_val_t start = sp > 32 ? sp - 32 : 0; + for (spl_val_t i = start; i <= sp; 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) return -1; (void)fp; - fprintf(stderr, "=== backtrace ===\n"); + fprintf(stderr, "backtrace: \n"); for (isize i = vm->cp - 1; i >= 0; i--) { spl_val_t _saved_ip = vm->frames.data[i].saved_ip; spl_val_t _saved_fp = vm->frames.data[i].saved_fp; diff --git a/stage1/spl_comp.c b/stage1/spl_comp.c index 104523d..5f5dcff 100644 --- a/stage1/spl_comp.c +++ b/stage1/spl_comp.c @@ -96,6 +96,23 @@ void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr) { 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 ---- */ void spl_push_scope(spl_comp_t *ctx) { diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h index e989aa9..d605d40 100644 --- a/stage1/spl_comp.h +++ b/stage1/spl_comp.h @@ -23,9 +23,9 @@ typedef enum { TYPE_STRUCT, TYPE_UNION, TYPE_ENUM, - TYPE_ENUM_VARIANT, /* enum variant with data */ - TYPE_NAME, /* named alias */ - TYPE_INFER, /* _ (to be inferred) */ + TYPE_ENUM_VARIANT, /* enum variant with data */ + TYPE_NAME, /* named alias */ + TYPE_INFER, /* _ (to be inferred) */ } spl_type_kind_t; /* Forward declaration */ @@ -50,23 +50,23 @@ typedef VEC(spl_enum_variant_t) spl_enum_variant_vec_t; /* Method info (struct/enum methods) */ typedef struct { char *name; - int func_idx; /* index in ctx->funcs */ + int func_idx; /* index in ctx->funcs */ } spl_method_info_t; typedef VEC(spl_method_info_t) spl_method_info_vec_t; struct spl_type_info { spl_type_kind_t kind; - spl_type_t basic_type; /* for TYPE_BASIC */ - spl_type_info_t *elem; /* for PTR/ARRAY/SLICE element type */ - usize array_len; /* for TYPE_ARRAY */ - char *name; /* type name for TYPE_NAME/STRUCT/ENUM */ - spl_field_vec_t fields; /* for TYPE_STRUCT */ + spl_type_t basic_type; /* for TYPE_BASIC */ + spl_type_info_t *elem; /* for PTR/ARRAY/SLICE element type */ + usize array_len; /* for TYPE_ARRAY */ + char *name; /* type name for TYPE_NAME/STRUCT/ENUM */ + spl_field_vec_t fields; /* for TYPE_STRUCT */ spl_enum_variant_vec_t variants; /* for TYPE_ENUM */ - spl_method_info_vec_t methods; /* methods */ - usize byte_size; /* total byte size (cached) */ - usize slot_count; /* stack slot count */ - int is_pub; /* public visibility */ - int resolved; /* type fully resolved */ + spl_method_info_vec_t methods; /* methods */ + usize byte_size; /* total byte size (cached) */ + usize slot_count; /* stack slot count */ + int is_pub; /* public visibility */ + int resolved; /* type fully resolved */ }; /* Type constructor helpers */ @@ -96,9 +96,9 @@ spl_type_info_t *spl_type_clone(spl_type_info_t *t); typedef struct spl_var_info { char *name; spl_type_info_t *type; - int offset; /* byte offset from fp */ + int offset; /* byte offset from fp */ int is_const; - int depth; /* scope depth */ + int depth; /* scope depth */ } spl_var_info_t; typedef VEC(spl_var_info_t) spl_var_vec_t; @@ -114,8 +114,8 @@ typedef struct spl_func_info { spl_type_info_t **param_types; char **param_names; int nparams; - int func_idx; /* index in prog->funcs */ - int is_extern; /* #[extern("vm")] */ + int func_idx; /* index in prog->funcs */ + int is_extern; /* #[extern("vm")] */ int is_pub; } spl_func_info_t; typedef VEC(spl_func_info_t) spl_func_info_vec_t; @@ -161,15 +161,16 @@ typedef struct { /* Current function context */ int current_func_idx; spl_type_info_t *current_ret_type; - 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) */ + 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) */ /* Loop context for break/continue */ int in_loop; - usize *break_patches; /* instruction addresses to patch */ + usize *break_patches; /* instruction addresses to patch */ usize break_patch_count; usize break_patch_cap; - usize continue_target; /* ip to jump to for continue */ + usize continue_target; /* ip to jump to for continue */ /* Defer stack */ spl_defer_entry_t defer_stack[DEFER_MAX]; @@ -181,7 +182,7 @@ typedef struct { /* Const values */ MAP(const char *, spl_val_t) const_values; - int addr_of_mode; /* 1 = inside & operator, suppress loads */ + int addr_of_mode; /* 1 = inside & operator, suppress loads */ } spl_comp_t; /* Initialize/destroy compiler context */ @@ -210,16 +211,26 @@ void parse_type_decl(spl_comp_t *ctx); /* Precedence levels for Pratt parser */ enum { - PREC_MIN = 0, PREC_ASSIGN = 1, 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_MIN = 0, + PREC_ASSIGN = 1, + 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 }; /* Result of expression codegen */ typedef struct { spl_type_info_t *type; - int is_lvalue; /* 1 = address on stack, 0 = value on stack */ + int is_lvalue; /* 1 = address on stack, 0 = value on stack */ } spl_expr_result_t; spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec); @@ -242,13 +253,19 @@ spl_val_t spl_emit_bz(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); +/* 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 */ 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); int spl_get_var_offset(spl_comp_t *ctx, const char *name); /* 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); /* String/data management */ diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 6a2207c..aa44e3b 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -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_ADD, SPL_USIZE, 0); } - spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN); - (void)fv; - spl_emit(ctx, SPL_STORE, spl_store_type(f->type), 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); + (void)fv; + spl_emit(ctx, SPL_STORE, spl_store_type(f->type), 0); + } 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); } @@ -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_ADD, SPL_USIZE, 0); } - spl_expr_result_t sfv = spl_parse_expr(ctx, PREC_MIN); - (void)sfv; - spl_emit(ctx, SPL_STORE, spl_store_type(sf->type), 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); + (void)sfv; + spl_emit(ctx, SPL_STORE, spl_store_type(sf->type), 0); + } break; } } skip_nl(ctx); } 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 { /* Simple data: parse expression */ spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN); @@ -1090,11 +1257,11 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { /* Stack: [struct_addr, begin, end]. * Inline ptr/len: ptr = data_ptr + begin*stride, len = end - begin. */ spl_emit(ctx, SPL_PICK, SPL_VOID, 2); - spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [s,b,e,data_ptr] */ + spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [s,b,e,data_ptr] */ spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [s,b,e,d,begin] */ spl_emit(ctx, SPL_PUSH, SPL_U64, stride); spl_emit(ctx, SPL_MUL, SPL_U64, 0); - spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [s,b,e,ptr] */ + spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [s,b,e,ptr] */ spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [s,b,e,ptr,end] */ spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [s,b,e,ptr,end,begin] */ spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [s,b,e,ptr,len] */ @@ -1126,6 +1293,13 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { emit_slice_index(ctx, elem); } else { /* 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); spl_emit(ctx, SPL_PUSH, SPL_U64, stride); spl_emit(ctx, SPL_MUL, SPL_U64, 0); diff --git a/stage1/spl_lexer.h b/stage1/spl_lexer.h index b51b35e..050f3c6 100644 --- a/stage1/spl_lexer.h +++ b/stage1/spl_lexer.h @@ -118,7 +118,7 @@ typedef enum { typedef struct { spl_tok_type_t type; const char *lexeme; - usize len; /* token length in bytes */ + usize len; /* token length in bytes */ const char *fname; usize offset; usize line; diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c index ba2e401..5a2489d 100644 --- a/stage1/spl_parser.c +++ b/stage1/spl_parser.c @@ -13,7 +13,6 @@ spl_tok_t *advance(spl_comp_t *ctx) { return t; } - /* ============================================================ * Parse function definition * fn name(params) ret-type { body } diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index ebac0b9..3230503 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -97,7 +97,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { /* Store init value */ if (has_init) { /* 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); /* { */ skip_nl(ctx); 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 { /* Multi-slot: copy from temp addr to var, slot by slot */ usize nslots = (sz + sizeof(spl_val_t) - 1) / sizeof(spl_val_t); - 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, offset + (int)(i * sizeof(spl_val_t))); - spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); - spl_emit(ctx, SPL_STORE, SPL_PTR, 0); - } + spl_emit_copy_slots(ctx, offset, nslots); } } else if (var_type && var_type->kind == TYPE_ARRAY) { /* Array initialization: store each element in reverse stack order */ diff --git a/stage1/spl_type.c b/stage1/spl_type.c index ccc90bb..3f739aa 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -260,9 +260,7 @@ usize spl_type_slot_count(spl_type_info_t *t) { } /* Byte stride between consecutive elements in storage */ -usize spl_type_elem_stride(spl_type_info_t *elem) { - return spl_type_size(elem); -} +usize spl_type_elem_stride(spl_type_info_t *elem) { return spl_type_size(elem); } const char *spl_type_str(spl_type_info_t *t) { if (!t) diff --git a/stage1/test18_recursion.spl b/stage1/test18_recursion.spl deleted file mode 100644 index 1ba7b38..0000000 --- a/stage1/test18_recursion.spl +++ /dev/null @@ -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; -} diff --git a/stage1/test20_complex.spl b/stage1/test20_complex.spl new file mode 100644 index 0000000..17f60e8 --- /dev/null +++ b/stage1/test20_complex.spl @@ -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; +}